Files
go-winio/internal/etw/eventmetadata.go
T

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)
}