From 865ff5c88dd133eb81a1128f8d4765b4be0cbd22 Mon Sep 17 00:00:00 2001 From: blotus Date: Tue, 19 Jul 2022 09:48:02 +0200 Subject: [PATCH] windows: log fatal and panic errors to event log (#1667) --- cmd/crowdsec/event_log_hook_windows.go | 39 ++++++++++++++++++++++++++ cmd/crowdsec/win_service.go | 37 ++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 cmd/crowdsec/event_log_hook_windows.go diff --git a/cmd/crowdsec/event_log_hook_windows.go b/cmd/crowdsec/event_log_hook_windows.go new file mode 100644 index 000000000..bacc00526 --- /dev/null +++ b/cmd/crowdsec/event_log_hook_windows.go @@ -0,0 +1,39 @@ +package main + +import ( + log "github.com/sirupsen/logrus" + "golang.org/x/sys/windows/svc/eventlog" +) + +type EventLogHook struct { + LogLevels []log.Level + evtlog *eventlog.Log +} + +func (e *EventLogHook) Fire(entry *log.Entry) error { + line, err := entry.String() + if err != nil { + return err + } + switch entry.Level { + case log.PanicLevel: + return e.evtlog.Error(300, line) + case log.FatalLevel: + return e.evtlog.Error(301, line) + case log.ErrorLevel: + return e.evtlog.Error(302, line) + case log.WarnLevel: + return e.evtlog.Warning(303, line) + case log.InfoLevel: + return e.evtlog.Info(304, line) + case log.DebugLevel: + return e.evtlog.Info(305, line) + case log.TraceLevel: + return e.evtlog.Info(306, line) + } + return nil +} + +func (e *EventLogHook) Levels() []log.Level { + return e.LogLevels +} diff --git a/cmd/crowdsec/win_service.go b/cmd/crowdsec/win_service.go index 9be89c7eb..94dfbf495 100644 --- a/cmd/crowdsec/win_service.go +++ b/cmd/crowdsec/win_service.go @@ -8,13 +8,16 @@ package main import ( + "syscall" "time" "github.com/crowdsecurity/crowdsec/pkg/csconfig" "github.com/crowdsecurity/crowdsec/pkg/types" "github.com/pkg/errors" log "github.com/sirupsen/logrus" + "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/eventlog" ) type crowdsec_winservice struct { @@ -61,6 +64,40 @@ func (m *crowdsec_winservice) Execute(args []string, r <-chan svc.ChangeRequest, } func runService(name string) error { + + //All the calls to logging before the logger is configured are pretty much useless, but we keep them for clarity + err := eventlog.InstallAsEventCreate("CrowdSec", eventlog.Error|eventlog.Warning|eventlog.Info) + if err != nil { + if errno, ok := err.(syscall.Errno); ok { + if errno == windows.ERROR_ACCESS_DENIED { + log.Warnf("Access denied when installing event source, running as non-admin ?") + } else { + log.Warnf("Failed to install event log: %s (%d)", err, errno) + } + } else { + log.Warnf("Failed to install event log: %s", err) + } + } + + //Let's use our source even if we could not install it: + // - It could have been created earlier + // - No permission to create it (e.g. running as non-admin when working on crowdsec) + //It will still work, windows will just display some additional errors in the event log + evtlog, err := eventlog.Open("CrowdSec") + + if err == nil { + //Send panic and fatal to event log, as they can happen before the logger is configured. + log.AddHook(&EventLogHook{ + LogLevels: []log.Level{ + log.PanicLevel, + log.FatalLevel, + }, + evtlog: evtlog, + }) + } else { + log.Warnf("Failed to open event log: %s", err) + } + cConfig, err := csconfig.NewConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI) if err != nil { return err