Remove Windows EventLog logging hook

EventLog is very old and provides a poor experience. We have supported
ETW for logging for a while, which is much better. We have also
observed an issue where EventLog keeps containerd.exe open, preventing
containerd from being upgraded to a new version. Due to all of this,
it makes sense to remove the old EventLog hook in favor of using ETW
logging on Windows as the primary diagnostic experience.

Signed-off-by: Kevin Parsons <kevpar@microsoft.com>
This commit is contained in:
Kevin Parsons 2019-08-19 10:24:37 -07:00
parent 6cb56bb605
commit 5023d96ad2

View File

@ -17,7 +17,6 @@
package command package command
import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
@ -35,7 +34,6 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/debug" "golang.org/x/sys/windows/svc/debug"
"golang.org/x/sys/windows/svc/eventlog"
"golang.org/x/sys/windows/svc/mgr" "golang.org/x/sys/windows/svc/mgr"
) )
@ -54,18 +52,6 @@ var (
service *handler service *handler
) )
const (
// These should match the values in event_messages.mc.
eventInfo = 1
eventWarn = 1
eventError = 1
eventDebug = 2
eventPanic = 3
eventFatal = 4
eventExtraOffset = 10 // Add this to any event to get a string that supports extended data
)
// serviceFlags returns an array of flags for configuring containerd to run // serviceFlags returns an array of flags for configuring containerd to run
// as a Windows service under control of SCM. // as a Windows service under control of SCM.
func serviceFlags() []cli.Flag { func serviceFlags() []cli.Flag {
@ -124,93 +110,6 @@ type handler struct {
done chan struct{} // Indicates back to app main to quit done chan struct{} // Indicates back to app main to quit
} }
type etwHook struct {
log *eventlog.Log
}
func (h *etwHook) Levels() []logrus.Level {
return []logrus.Level{
logrus.PanicLevel,
logrus.FatalLevel,
logrus.ErrorLevel,
logrus.WarnLevel,
logrus.InfoLevel,
logrus.DebugLevel,
}
}
func (h *etwHook) Fire(e *logrus.Entry) error {
var (
etype uint16
eid uint32
)
switch e.Level {
case logrus.PanicLevel:
etype = windows.EVENTLOG_ERROR_TYPE
eid = eventPanic
case logrus.FatalLevel:
etype = windows.EVENTLOG_ERROR_TYPE
eid = eventFatal
case logrus.ErrorLevel:
etype = windows.EVENTLOG_ERROR_TYPE
eid = eventError
case logrus.WarnLevel:
etype = windows.EVENTLOG_WARNING_TYPE
eid = eventWarn
case logrus.InfoLevel:
etype = windows.EVENTLOG_INFORMATION_TYPE
eid = eventInfo
case logrus.DebugLevel:
etype = windows.EVENTLOG_INFORMATION_TYPE
eid = eventDebug
default:
return errors.Wrap(errdefs.ErrInvalidArgument, "unknown level")
}
// If there is additional data, include it as a second string.
exts := ""
if len(e.Data) > 0 {
fs := bytes.Buffer{}
for k, v := range e.Data {
fs.WriteString(k)
fs.WriteByte('=')
fmt.Fprint(&fs, v)
fs.WriteByte(' ')
}
exts = fs.String()[:fs.Len()-1]
eid += eventExtraOffset
}
if h.log == nil {
fmt.Fprintf(os.Stderr, "%s [%s]\n", e.Message, exts)
return nil
}
var (
ss [2]*uint16
err error
)
ss[0], err = windows.UTF16PtrFromString(e.Message)
if err != nil {
return err
}
count := uint16(1)
if exts != "" {
ss[1], err = windows.UTF16PtrFromString(exts)
if err != nil {
return err
}
count++
}
return windows.ReportEvent(h.log.Handle, etype, 0, eid, 0, count, 0, &ss[0], nil)
}
func getServicePath() (string, error) { func getServicePath() (string, error) {
p, err := exec.LookPath(os.Args[0]) p, err := exec.LookPath(os.Args[0])
if err != nil { if err != nil {
@ -283,7 +182,7 @@ func registerService() error {
return err return err
} }
return eventlog.Install(serviceNameFlag, p, false, eventlog.Info|eventlog.Warning|eventlog.Error) return nil
} }
func unregisterService() error { func unregisterService() error {
@ -299,7 +198,6 @@ func unregisterService() error {
} }
defer s.Close() defer s.Close()
eventlog.Remove(serviceNameFlag)
err = s.Delete() err = s.Delete()
if err != nil { if err != nil {
return err return err
@ -345,20 +243,6 @@ func registerUnregisterService(root string) (bool, error) {
return true, err return true, err
} }
interactive, err := svc.IsAnInteractiveSession()
if err != nil {
return true, err
}
var log *eventlog.Log
if !interactive {
log, err = eventlog.Open(serviceNameFlag)
if err != nil {
return true, err
}
}
logrus.AddHook(&etwHook{log})
logrus.SetOutput(ioutil.Discard) logrus.SetOutput(ioutil.Discard)
} }
return false, nil return false, nil