mirror of
https://github.com/rclone/rclone.git
synced 2025-06-20 19:57:51 +02:00
log: add --windows-event-log-level to support Windows Event Log
This provides JSON logs in the Windows Event Log.
This commit is contained in:
parent
dfa4d94827
commit
15510c66d4
@ -1515,6 +1515,33 @@ warnings and significant events.
|
||||
|
||||
`ERROR` is equivalent to `-q`. It only outputs error messages.
|
||||
|
||||
### --windows-event-log LEVEL ###
|
||||
|
||||
If this is configured (the default is `OFF`) then logs of this level
|
||||
and above will be logged to the Windows event log in **addition** to
|
||||
the normal logs. These will be logged in JSON format as described
|
||||
below regardless of what format the main logs are configured for.
|
||||
|
||||
The Windows event log only has 3 levels of severity `Info`, `Warning`
|
||||
and `Error`. If enabled we map rclone levels like this.
|
||||
|
||||
- `Error` ← `ERROR` (and above)
|
||||
- `Warning` ← `WARNING` (note that this level is defined but not currently used).
|
||||
- `Info` ← `NOTICE`, `INFO` and `DEBUG`.
|
||||
|
||||
Rclone will declare its log source as "rclone" if it is has enough
|
||||
permissions to create the registry key needed. If not then logs will
|
||||
appear as "Application". You can run `rclone version --windows-event-log DEBUG`
|
||||
once as administrator to create the registry key in advance.
|
||||
|
||||
**Note** that the `--windows-event-log` level must be greater (more
|
||||
severe) than or equal to the `--log-level`. For example to log DEBUG
|
||||
to a log file but ERRORs to the event log you would use
|
||||
|
||||
--log-file rclone.log --log-level DEBUG --windows-event-log ERROR
|
||||
|
||||
This option is only supported Windows platforms.
|
||||
|
||||
### --use-json-log ###
|
||||
|
||||
This switches the log format to JSON for rclone. The fields of JSON
|
||||
|
@ -32,6 +32,7 @@ const (
|
||||
LogLevelNotice // Normal logging, -q suppresses
|
||||
LogLevelInfo // Transfers, needs -v
|
||||
LogLevelDebug // Debug level, needs -vv
|
||||
LogLevelOff
|
||||
)
|
||||
|
||||
type logLevelChoices struct{}
|
||||
@ -46,6 +47,7 @@ func (logLevelChoices) Choices() []string {
|
||||
LogLevelNotice: "NOTICE",
|
||||
LogLevelInfo: "INFO",
|
||||
LogLevelDebug: "DEBUG",
|
||||
LogLevelOff: "OFF",
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,6 +68,7 @@ const (
|
||||
SlogLevelCritical = slog.Level(12) // More severe than Error
|
||||
SlogLevelAlert = slog.Level(16) // More severe than Critical
|
||||
SlogLevelEmergency = slog.Level(20) // Most severe
|
||||
SlogLevelOff = slog.Level(24) // A very high value
|
||||
)
|
||||
|
||||
// Map our level numbers to slog level numbers
|
||||
@ -78,6 +81,7 @@ var levelToSlog = []slog.Level{
|
||||
LogLevelNotice: SlogLevelNotice,
|
||||
LogLevelInfo: slog.LevelInfo,
|
||||
LogLevelDebug: slog.LevelDebug,
|
||||
LogLevelOff: SlogLevelOff,
|
||||
}
|
||||
|
||||
// LogValueItem describes keyed item for a JSON log entry
|
||||
|
15
fs/log/event_log.go
Normal file
15
fs/log/event_log.go
Normal file
@ -0,0 +1,15 @@
|
||||
// Windows event logging stubs for non windows machines
|
||||
|
||||
//go:build !windows
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Starts windows event log if configured.
|
||||
func startWindowsEventLog(*OutputHandler) error {
|
||||
return fmt.Errorf("windows event log not supported on %s platform", runtime.GOOS)
|
||||
}
|
79
fs/log/event_log_windows.go
Normal file
79
fs/log/event_log_windows.go
Normal file
@ -0,0 +1,79 @@
|
||||
// Windows event logging
|
||||
|
||||
//go:build windows
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/rclone/rclone/lib/atexit"
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
)
|
||||
|
||||
const (
|
||||
errorID = uint32(windows.ERROR_INTERNAL_ERROR)
|
||||
infoID = uint32(windows.ERROR_SUCCESS)
|
||||
sourceName = "rclone"
|
||||
)
|
||||
|
||||
var (
|
||||
windowsEventLog *eventlog.Log
|
||||
)
|
||||
|
||||
func startWindowsEventLog(handler *OutputHandler) error {
|
||||
// Don't install Windows event log if it is disabled.
|
||||
if Opt.WindowsEventLogLevel == fs.LogLevelOff {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Install the event source - we don't care if this fails as Windows has sensible fallbacks.
|
||||
_ = eventlog.InstallAsEventCreate(sourceName, eventlog.Info|eventlog.Warning|eventlog.Error)
|
||||
|
||||
// Open the event log
|
||||
// If sourceName didn't get registered then Windows will use "Application" instead which is fine.
|
||||
// Though in my tests it seemsed to use sourceName regardless.
|
||||
elog, err := eventlog.Open(sourceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open event log: %w", err)
|
||||
}
|
||||
|
||||
// Set the global for the handler
|
||||
windowsEventLog = elog
|
||||
|
||||
// Close it on exit
|
||||
atexit.Register(func() {
|
||||
err := elog.Close()
|
||||
if err != nil {
|
||||
fs.Errorf(nil, "Failed to close Windows event log: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
// Add additional JSON logging to the eventLog handler.
|
||||
handler.AddOutput(true, eventLog)
|
||||
|
||||
fs.Infof(nil, "Logging to Windows event log at level %v", Opt.WindowsEventLogLevel)
|
||||
return nil
|
||||
}
|
||||
|
||||
// We use levels ERROR, NOTICE, INFO, DEBUG
|
||||
// Need to map to ERROR, WARNING, INFO
|
||||
func eventLog(level slog.Level, text string) {
|
||||
// Check to see if this level is required
|
||||
if level < fs.LogLevelToSlog(Opt.WindowsEventLogLevel) {
|
||||
return
|
||||
}
|
||||
|
||||
// Now log to windows eventLog
|
||||
switch level {
|
||||
case fs.SlogLevelEmergency, fs.SlogLevelAlert, fs.SlogLevelCritical, slog.LevelError:
|
||||
_ = windowsEventLog.Error(errorID, text)
|
||||
case slog.LevelWarn:
|
||||
_ = windowsEventLog.Warning(infoID, text)
|
||||
case fs.SlogLevelNotice, slog.LevelInfo, slog.LevelDebug:
|
||||
_ = windowsEventLog.Info(infoID, text)
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
@ -38,15 +39,27 @@ var OptionsInfo = fs.Options{{
|
||||
Default: false,
|
||||
Help: "Activate systemd integration for the logger",
|
||||
Groups: "Logging",
|
||||
}, {
|
||||
Name: "windows_event_log_level",
|
||||
Default: fs.LogLevelOff,
|
||||
Help: "Windows Event Log level DEBUG|INFO|NOTICE|ERROR|OFF",
|
||||
Groups: "Logging",
|
||||
Hide: func() fs.OptionVisibility {
|
||||
if runtime.GOOS == "windows" {
|
||||
return 0
|
||||
}
|
||||
return fs.OptionHideBoth
|
||||
}(),
|
||||
}}
|
||||
|
||||
// Options contains options for controlling the logging
|
||||
type Options struct {
|
||||
File string `config:"log_file"` // Log everything to this file
|
||||
Format logFormat `config:"log_format"` // Comma separated list of log format options
|
||||
UseSyslog bool `config:"syslog"` // Use Syslog for logging
|
||||
SyslogFacility string `config:"syslog_facility"` // Facility for syslog, e.g. KERN,USER,...
|
||||
LogSystemdSupport bool `config:"log_systemd"` // set if using systemd logging
|
||||
File string `config:"log_file"` // Log everything to this file
|
||||
Format logFormat `config:"log_format"` // Comma separated list of log format options
|
||||
UseSyslog bool `config:"syslog"` // Use Syslog for logging
|
||||
SyslogFacility string `config:"syslog_facility"` // Facility for syslog, e.g. KERN,USER,...
|
||||
LogSystemdSupport bool `config:"log_systemd"` // set if using systemd logging
|
||||
WindowsEventLogLevel fs.LogLevel `config:"windows_event_log_level"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -149,6 +162,11 @@ func Stack(o any, info string) {
|
||||
// externally visible in the rc.
|
||||
func logReload(ci *fs.ConfigInfo) error {
|
||||
Handler.SetLevel(fs.LogLevelToSlog(ci.LogLevel))
|
||||
|
||||
if Opt.WindowsEventLogLevel != fs.LogLevelOff && Opt.WindowsEventLogLevel > ci.LogLevel {
|
||||
return fmt.Errorf("--windows-event-log-level %q must be >= --log-level %q", Opt.WindowsEventLogLevel, ci.LogLevel)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -207,6 +225,14 @@ func InitLogging() {
|
||||
if Opt.LogSystemdSupport {
|
||||
startSystemdLog(Handler)
|
||||
}
|
||||
|
||||
// Windows event logging
|
||||
if Opt.WindowsEventLogLevel != fs.LogLevelOff {
|
||||
err := startWindowsEventLog(Handler)
|
||||
if err != nil {
|
||||
fs.Fatalf(nil, "Failed to start windows event log: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Redirected returns true if the log has been redirected from stdout
|
||||
|
Loading…
x
Reference in New Issue
Block a user