Merge pull request #46585 from cpuguy83/fix_etwlogs

Revert "daemon/logger/etwlogs: rewrite to use go-winio/pkg/etw"
This commit is contained in:
Sebastiaan van Stijn 2023-10-11 17:07:50 +02:00 committed by GitHub
commit d7caea206e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -14,12 +14,11 @@ package etwlogs // import "github.com/docker/docker/daemon/logger/etwlogs"
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"sync" "sync"
"unsafe" "unsafe"
"github.com/Microsoft/go-winio/pkg/etw"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/containerd/containerd/log" "github.com/containerd/containerd/log"
"github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/logger"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
@ -34,21 +33,18 @@ type etwLogs struct {
const ( const (
name = "etwlogs" name = "etwlogs"
providerGUID = `a3693192-9ed6-46d2-a981-f8226c8363bd`
win32CallSuccess = 0 win32CallSuccess = 0
) )
var ( var (
modAdvapi32 = windows.NewLazySystemDLL("Advapi32.dll") modAdvapi32 = windows.NewLazySystemDLL("Advapi32.dll")
procEventRegister = modAdvapi32.NewProc("EventRegister")
procEventWriteString = modAdvapi32.NewProc("EventWriteString") procEventWriteString = modAdvapi32.NewProc("EventWriteString")
procEventUnregister = modAdvapi32.NewProc("EventUnregister")
) )
var providerHandle windows.Handle
var ( var refCount int
providerHandle windows.Handle var mu sync.Mutex
mu sync.Mutex
refCount int
provider *etw.Provider
)
func init() { func init() {
providerHandle = windows.InvalidHandle providerHandle = windows.InvalidHandle
@ -74,7 +70,12 @@ func New(info logger.Info) (logger.Logger, error) {
// Log logs the message to the ETW stream. // Log logs the message to the ETW stream.
func (etwLogger *etwLogs) Log(msg *logger.Message) error { func (etwLogger *etwLogs) Log(msg *logger.Message) error {
// TODO(thaJeztah): log structured events instead and use provider.WriteEvent(). if providerHandle == windows.InvalidHandle {
// This should never be hit, if it is, it indicates a programming error.
errorMessage := "ETWLogs cannot log the message, because the event provider has not been registered."
log.G(context.TODO()).Error(errorMessage)
return errors.New(errorMessage)
}
m := createLogMessage(etwLogger, msg) m := createLogMessage(etwLogger, msg)
logger.PutMessage(msg) logger.PutMessage(msg)
return callEventWriteString(m) return callEventWriteString(m)
@ -105,8 +106,7 @@ func registerETWProvider() error {
defer mu.Unlock() defer mu.Unlock()
if refCount == 0 { if refCount == 0 {
var err error var err error
provider, err = callEventRegister() if err = callEventRegister(); err != nil {
if err != nil {
return err return err
} }
} }
@ -119,43 +119,51 @@ func unregisterETWProvider() {
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
if refCount == 1 { if refCount == 1 {
if err := callEventUnregister(); err != nil { if callEventUnregister() {
// Not returning an error if EventUnregister fails, because etwLogs will continue to work
return
}
refCount-- refCount--
provider = nil
providerHandle = windows.InvalidHandle providerHandle = windows.InvalidHandle
}
// Not returning an error if EventUnregister fails, because etwLogs will continue to work
} else { } else {
refCount-- refCount--
} }
} }
func callEventRegister() (*etw.Provider, error) { func callEventRegister() error {
providerID, _ := guid.FromString(providerGUID) // The provider's GUID is {a3693192-9ed6-46d2-a981-f8226c8363bd}
p, err := etw.NewProviderWithOptions("", etw.WithID(providerID)) guid := windows.GUID{
if err != nil { Data1: 0xa3693192,
log.G(context.TODO()).WithError(err).Error("Failed to register ETW provider") Data2: 0x9ed6,
return nil, fmt.Errorf("failed to register ETW provider: %v", err) Data3: 0x46d2,
Data4: [8]byte{0xa9, 0x81, 0xf8, 0x22, 0x6c, 0x83, 0x63, 0xbd},
} }
return p, nil
ret, _, _ := procEventRegister.Call(uintptr(unsafe.Pointer(&guid)), 0, 0, uintptr(unsafe.Pointer(&providerHandle)))
if ret != win32CallSuccess {
errorMessage := fmt.Sprintf("Failed to register ETW provider. Error: %d", ret)
log.G(context.TODO()).Error(errorMessage)
return errors.New(errorMessage)
}
return nil
} }
// TODO(thaJeztah): port this function to github.com/Microsoft/go-winio/pkg/etw.
func callEventWriteString(message string) error { func callEventWriteString(message string) error {
utf16message, err := windows.UTF16FromString(message) utf16message, err := windows.UTF16FromString(message)
if err != nil { if err != nil {
return err return err
} }
ret, _, _ := procEventWriteString.Call(uintptr(providerHandle), 0, 0, uintptr(unsafe.Pointer(&utf16message[0]))) ret, _, _ := procEventWriteString.Call(uintptr(providerHandle), 0, 0, uintptr(unsafe.Pointer(&utf16message[0])))
if ret != win32CallSuccess { if ret != win32CallSuccess {
log.G(context.TODO()).WithError(err).Error("ETWLogs provider failed to log message") errorMessage := fmt.Sprintf("ETWLogs provider failed to log message. Error: %d", ret)
return fmt.Errorf("ETWLogs provider failed to log message: %v", err) log.G(context.TODO()).Error(errorMessage)
return errors.New(errorMessage)
} }
return nil return nil
} }
func callEventUnregister() error { func callEventUnregister() bool {
return provider.Close() ret, _, _ := procEventUnregister.Call(uintptr(providerHandle))
return ret == win32CallSuccess
} }