mirror of
https://github.com/rwinkhart/go-winio.git
synced 2026-09-01 06:46:48 -04:00
168 lines
3.9 KiB
Go
168 lines
3.9 KiB
Go
package etw
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
)
|
|
|
|
// InType indicates the type of data contained in the ETW event.
|
|
type InType byte
|
|
|
|
// Various InType definitions for TraceLogging. These must match the definitions
|
|
// found in TraceLoggingProvider.h in the Windows SDK.
|
|
const (
|
|
InTypeNull InType = iota
|
|
InTypeUnicodeString
|
|
InTypeANSIString
|
|
InTypeInt8
|
|
InTypeUint8
|
|
InTypeInt16
|
|
InTypeUint16
|
|
InTypeInt32
|
|
InTypeUint32
|
|
InTypeInt64
|
|
InTypeUint64
|
|
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
|
|
// event. It needs to be paired with EventData which describes the event.
|
|
type EventMetadata struct {
|
|
buffer bytes.Buffer
|
|
}
|
|
|
|
// NewEventMetadata returns a new EventMetadata with event name and initial
|
|
// metadata written to the buffer.
|
|
func NewEventMetadata(name string) *EventMetadata {
|
|
em := EventMetadata{}
|
|
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, opts ...fieldOpt) {
|
|
f := field{
|
|
name: name,
|
|
inType: inType,
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
opt(&f)
|
|
}
|
|
|
|
em.writeField(f)
|
|
}
|