mirror of
https://github.com/rwinkhart/go-winio.git
synced 2026-09-05 16:47:31 -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.
|
// AddString appends the data for a string to the end of the buffer.
|
||||||
func (ed *EventData) AddString(data string) {
|
func (ed *EventData) AddString(data string) {
|
||||||
ed.buffer.Write([]byte(data))
|
ed.buffer.WriteString(data)
|
||||||
ed.buffer.WriteByte(0)
|
ed.buffer.WriteByte(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type InType byte
|
|||||||
const (
|
const (
|
||||||
InTypeNull InType = iota
|
InTypeNull InType = iota
|
||||||
InTypeUnicodeString
|
InTypeUnicodeString
|
||||||
InTypeAnsiString
|
InTypeANSIString
|
||||||
InTypeInt8
|
InTypeInt8
|
||||||
InTypeUint8
|
InTypeUint8
|
||||||
InTypeInt16
|
InTypeInt16
|
||||||
@@ -25,6 +25,52 @@ const (
|
|||||||
InTypeFloat
|
InTypeFloat
|
||||||
InTypeDouble
|
InTypeDouble
|
||||||
InTypeBool32
|
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
|
// EventMetadata maintains a buffer which builds up the metadatadata for an ETW
|
||||||
@@ -38,15 +84,84 @@ type EventMetadata struct {
|
|||||||
func NewEventMetadata(name string) *EventMetadata {
|
func NewEventMetadata(name string) *EventMetadata {
|
||||||
em := EventMetadata{}
|
em := EventMetadata{}
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
|
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Tags
|
em.writeTags(0)
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, []byte(name)) // Event name
|
em.buffer.WriteString(name)
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Null terminator for name
|
em.buffer.WriteByte(0) // Null terminator for name
|
||||||
return &em
|
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.
|
// AddField appends a single field to the end of the event metadata buffer.
|
||||||
func (em *EventMetadata) AddField(name string, inType InType) {
|
func (em *EventMetadata) AddField(name string, inType InType, opts ...fieldOpt) {
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, []byte(name)) // Field name
|
f := field{
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Null terminator for name
|
name: name,
|
||||||
binary.Write(&em.buffer, binary.LittleEndian, byte(inType)) // In type
|
inType: inType,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&f)
|
||||||
|
}
|
||||||
|
|
||||||
|
em.writeField(f)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ func NewProvider(name string, id *windows.GUID, callback EnableCallback) (provid
|
|||||||
|
|
||||||
metadata := &bytes.Buffer{}
|
metadata := &bytes.Buffer{}
|
||||||
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
|
binary.Write(metadata, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
|
||||||
metadata.WriteString(name) // Provider name
|
metadata.WriteString(name)
|
||||||
metadata.WriteByte(0) // Null terminator for 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
|
binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer
|
||||||
provider.metadata = metadata.Bytes()
|
provider.metadata = metadata.Bytes()
|
||||||
|
|||||||
@@ -57,16 +57,16 @@ func (h *Hook) Fire(e *logrus.Entry) error {
|
|||||||
|
|
||||||
event := etw.NewEvent("LogrusEntry", descriptor)
|
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)
|
event.Data.AddString(e.Message)
|
||||||
|
|
||||||
for k, v := range e.Data {
|
for k, v := range e.Data {
|
||||||
switch v := v.(type) {
|
switch v := v.(type) {
|
||||||
case string:
|
case string:
|
||||||
event.Metadata.AddField(k, etw.InTypeAnsiString)
|
event.Metadata.AddField(k, etw.InTypeANSIString, etw.WithOutType(etw.OutTypeUTF8))
|
||||||
event.Data.AddString(v)
|
event.Data.AddString(v)
|
||||||
default:
|
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))
|
event.Data.AddString(fmt.Sprintf("<unknown type: %v> %v", reflect.TypeOf(v), v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user