mirror of
https://github.com/rwinkhart/go-winio.git
synced 2026-08-28 04:46:50 -04:00
Add ETW support for out type and tags
This commit is contained in:
@@ -17,6 +17,6 @@ func NewEventData() *EventData {
|
||||
|
||||
// AddString appends the data for a string to the end of the buffer.
|
||||
func (ed *EventData) AddString(data string) {
|
||||
ed.buffer.Write([]byte(data))
|
||||
ed.buffer.WriteString(data)
|
||||
ed.buffer.WriteByte(0)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ type InType byte
|
||||
const (
|
||||
InTypeNull InType = iota
|
||||
InTypeUnicodeString
|
||||
InTypeAnsiString
|
||||
InTypeANSIString
|
||||
InTypeInt8
|
||||
InTypeUint8
|
||||
InTypeInt16
|
||||
@@ -25,6 +25,52 @@ const (
|
||||
InTypeFloat
|
||||
InTypeDouble
|
||||
InTypeBool32
|
||||
InTypeBinary
|
||||
InTypeGUID
|
||||
InTypePointerUnsupported
|
||||
InTypeFileTime
|
||||
InTypeSystemTime
|
||||
InTypeSID
|
||||
InTypeHexInt32
|
||||
InTypeHexInt64
|
||||
InTypeCountedString
|
||||
InTypeCountedANSIString
|
||||
InTypeStruct
|
||||
InTypeCountedBinary
|
||||
)
|
||||
|
||||
// OutType specifies a hint to the event decoder for how the value should be
|
||||
// formatted.
|
||||
type OutType byte
|
||||
|
||||
// Various OutType definitions for TraceLogging. These must match the
|
||||
// definitions found in TraceLoggingProvider.h in the Windows SDK.
|
||||
const (
|
||||
// OutTypeDefault indicates that the default formatting for the in type will
|
||||
// be used by the event decoder.
|
||||
OutTypeDefault OutType = iota
|
||||
OutTypeNoPrint
|
||||
OutTypeString
|
||||
OutTypeBoolean
|
||||
OutTypeHex
|
||||
OutTypePID
|
||||
OutTypeTID
|
||||
OutTypePort
|
||||
OutTypeIPv4
|
||||
OutTypeIPv6
|
||||
OutTypeSocketAddress
|
||||
OutTypeXML
|
||||
OutTypeJSON
|
||||
OutTypeWin32Error
|
||||
OutTypeNTStatus
|
||||
OutTypeHResult
|
||||
OutTypeFileTime
|
||||
OutTypeSigned
|
||||
OutTypeUnsigned
|
||||
OutTypeUTF8 OutType = 35
|
||||
OutTypePKCS7WithTypeInfo OutType = 36
|
||||
OutTypeCodePointer OutType = 37
|
||||
OutTypeDateTimeUTC OutType = 38
|
||||
)
|
||||
|
||||
// EventMetadata maintains a buffer which builds up the metadatadata for an ETW
|
||||
@@ -37,16 +83,85 @@ type EventMetadata struct {
|
||||
// metadata written to the buffer.
|
||||
func NewEventMetadata(name string) *EventMetadata {
|
||||
em := EventMetadata{}
|
||||
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
|
||||
binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Tags
|
||||
binary.Write(&em.buffer, binary.LittleEndian, []byte(name)) // Event name
|
||||
binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Null terminator for name
|
||||
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
|
||||
em.writeTags(0)
|
||||
em.buffer.WriteString(name)
|
||||
em.buffer.WriteByte(0) // Null terminator for name
|
||||
return &em
|
||||
}
|
||||
|
||||
type field struct {
|
||||
name string
|
||||
inType InType
|
||||
outType OutType
|
||||
tags uint32
|
||||
}
|
||||
|
||||
func (em *EventMetadata) writeField(f field) {
|
||||
em.buffer.WriteString(f.name)
|
||||
em.buffer.WriteByte(0) // Null terminator for name
|
||||
|
||||
if f.outType == OutTypeDefault && f.tags == 0 {
|
||||
em.buffer.WriteByte(byte(f.inType))
|
||||
} else {
|
||||
em.buffer.WriteByte(byte(f.inType | 128))
|
||||
if f.tags == 0 {
|
||||
em.buffer.WriteByte(byte(f.outType))
|
||||
} else {
|
||||
em.buffer.WriteByte(byte(f.outType | 128))
|
||||
em.writeTags(f.tags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (em *EventMetadata) writeTags(tags uint32) {
|
||||
tags &= 0xfffffff
|
||||
|
||||
for {
|
||||
val := tags >> 21
|
||||
|
||||
if tags&0x1fffff == 0 {
|
||||
em.buffer.WriteByte(byte(val & 0x7f))
|
||||
return
|
||||
}
|
||||
|
||||
em.buffer.WriteByte(byte(val | 0x80))
|
||||
|
||||
tags <<= 7
|
||||
}
|
||||
}
|
||||
|
||||
type fieldOpt func(f *field)
|
||||
|
||||
// WithOutType specifies the out type for the field. This value is used as a
|
||||
// hint by the event decoder for how the field value should be formatted. If no
|
||||
// out type is specified, a default formatting based on the in type will be
|
||||
// used.
|
||||
func WithOutType(outType OutType) fieldOpt {
|
||||
return func(f *field) {
|
||||
f.outType = outType
|
||||
}
|
||||
}
|
||||
|
||||
// WithTags adds a tag to the field. Tags are 28-bit values that have meaning
|
||||
// only to the event consumer. The top 4 bits of the value will be ignored.
|
||||
// Multiple uses of this option will cause the tags to be OR'd together.
|
||||
func WithTags(tags uint32) fieldOpt {
|
||||
return func(f *field) {
|
||||
f.tags |= tags
|
||||
}
|
||||
}
|
||||
|
||||
// AddField appends a single field to the end of the event metadata buffer.
|
||||
func (em *EventMetadata) AddField(name string, inType InType) {
|
||||
binary.Write(&em.buffer, binary.LittleEndian, []byte(name)) // Field name
|
||||
binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Null terminator for name
|
||||
binary.Write(&em.buffer, binary.LittleEndian, byte(inType)) // In type
|
||||
func (em *EventMetadata) AddField(name string, inType InType, opts ...fieldOpt) {
|
||||
f := field{
|
||||
name: name,
|
||||
inType: inType,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(&f)
|
||||
}
|
||||
|
||||
em.writeField(f)
|
||||
}
|
||||
|
||||
@@ -153,8 +153,8 @@ func NewProvider(name string, id *windows.GUID, callback EnableCallback) (provid
|
||||
}
|
||||
|
||||
metadata := &bytes.Buffer{}
|
||||
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
|
||||
metadata.WriteString(name) // Provider name
|
||||
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
|
||||
metadata.WriteString(name)
|
||||
metadata.WriteByte(0) // Null terminator for name
|
||||
binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
|
||||
provider.metadata = metadata.Bytes()
|
||||
|
||||
@@ -57,16 +57,16 @@ func (h *Hook) Fire(e *logrus.Entry) error {
|
||||
|
||||
event := etw.NewEvent("LogrusEntry", descriptor)
|
||||
|
||||
event.Metadata.AddField("Message", etw.InTypeAnsiString)
|
||||
event.Metadata.AddField("Message", etw.InTypeANSIString, etw.WithOutType(etw.OutTypeUTF8))
|
||||
event.Data.AddString(e.Message)
|
||||
|
||||
for k, v := range e.Data {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
event.Metadata.AddField(k, etw.InTypeAnsiString)
|
||||
event.Metadata.AddField(k, etw.InTypeANSIString, etw.WithOutType(etw.OutTypeUTF8))
|
||||
event.Data.AddString(v)
|
||||
default:
|
||||
event.Metadata.AddField(k, etw.InTypeAnsiString)
|
||||
event.Metadata.AddField(k, etw.InTypeANSIString, etw.WithOutType(etw.OutTypeUTF8))
|
||||
event.Data.AddString(fmt.Sprintf("<unknown type: %v> %v", reflect.TypeOf(v), v))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user