Add ETW support for out type and tags

This commit is contained in:
Kevin Parsons
2018-12-20 01:28:55 -08:00
parent 824a366a22
commit 82ad381699
4 changed files with 130 additions and 15 deletions
+1 -1
View File
@@ -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)
}
+124 -9
View File
@@ -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)
}
+2 -2
View File
@@ -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()
+3 -3
View File
@@ -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))
}
}