-
Notifications
You must be signed in to change notification settings - Fork 23
/
etw.go
132 lines (111 loc) · 2.72 KB
/
etw.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package logs
import (
"bytes"
"fmt"
"os"
"github.com/Microsoft/go-winio/pkg/etw"
"github.com/Microsoft/go-winio/pkg/etwlogrus"
"github.com/Microsoft/go-winio/pkg/guid"
"github.com/pkg/errors"
"github.com/rancher/wins/pkg/profilings"
"github.com/sirupsen/logrus"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc/eventlog"
)
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
)
type eventLogHook struct {
log *eventlog.Log
}
func (h *eventLogHook) Levels() []logrus.Level {
return logrus.AllLevels
}
func (h *eventLogHook) 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.New("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 NewEventLogHook(serviceName string) (logrus.Hook, error) {
elog, err := eventlog.Open(serviceName)
if err != nil {
return nil, err
}
return &eventLogHook{log: elog}, nil
}
func etwCallback(_ guid.GUID, state etw.ProviderState, _ etw.Level, _ uint64, _ uint64, _ uintptr) {
if state == etw.ProviderStateCaptureState {
logrus.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", profilings.DumpStacks())
}
}
func NewEtwProviderHook(serviceName string) (logrus.Hook, error) {
p, err := etw.NewProvider(serviceName, etwCallback)
if err != nil {
return nil, err
}
return etwlogrus.NewHookFromProvider(p)
}