From 7c26c75173d3cb859842ddde21505b0f1bbdfd54 Mon Sep 17 00:00:00 2001 From: Kevin Parsons Date: Fri, 21 Dec 2018 10:06:18 -0800 Subject: [PATCH] Add ETW support for arrays --- internal/etw/eventdata.go | 8 ++++++++ internal/etw/eventmetadata.go | 36 ++++++++++++++++++++++++++++++----- internal/etw/sample/sample.go | 7 +++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/internal/etw/eventdata.go b/internal/etw/eventdata.go index 7d62799..6296099 100644 --- a/internal/etw/eventdata.go +++ b/internal/etw/eventdata.go @@ -2,6 +2,7 @@ package etw import ( "bytes" + "encoding/binary" ) // EventData maintains a buffer which builds up the data for an ETW event. It @@ -20,3 +21,10 @@ func (ed *EventData) AddString(data string) { ed.buffer.WriteString(data) ed.buffer.WriteByte(0) } + +// This is mostly added for testing purposes, and will be removed later, as we +// shouldn't take a dependency on binary.Write knowing how to marshal values +// correctly for TraceLogging. +func (ed *EventData) AddSimple(data interface{}) { + binary.Write(&ed.buffer, binary.LittleEndian, data) +} diff --git a/internal/etw/eventmetadata.go b/internal/etw/eventmetadata.go index cdcbfc8..4d74db9 100644 --- a/internal/etw/eventmetadata.go +++ b/internal/etw/eventmetadata.go @@ -37,6 +37,9 @@ const ( InTypeCountedANSIString InTypeStruct InTypeCountedBinary + + InTypeCountedArray InType = 32 + InTypeArray InType = 64 ) // OutType specifies a hint to the event decoder for how the value should be @@ -73,7 +76,7 @@ const ( OutTypeDateTimeUTC OutType = 38 ) -// EventMetadata maintains a buffer which builds up the metadatadata for an ETW +// EventMetadata maintains a buffer which builds up the metadata for an ETW // event. It needs to be paired with EventData which describes the event. type EventMetadata struct { buffer bytes.Buffer @@ -91,10 +94,11 @@ func NewEventMetadata(name string) *EventMetadata { } type field struct { - name string - inType InType - outType OutType - tags uint32 + name string + inType InType + outType OutType + tags uint32 + countedArraySize uint16 } func (em *EventMetadata) writeField(f field) { @@ -112,6 +116,10 @@ func (em *EventMetadata) writeField(f field) { em.writeTags(f.tags) } } + + if f.countedArraySize != 0 { + binary.Write(&em.buffer, binary.LittleEndian, f.countedArraySize) + } } // writeTags writes out the tags value to the event metadata. Tags is a 28-bit @@ -163,6 +171,24 @@ func WithTags(tags uint32) fieldOpt { } } +// WithCountedArray marks the field as being an array of a fixed number of +// elements. The number of elements is encoded directly into the field metadata. +func WithCountedArray(count uint16) fieldOpt { + return func(f *field) { + f.inType |= InTypeCountedArray + f.countedArraySize = count + } +} + +// WithArray marks the field as being an array of a dynamic number of elements. +// The number of elements must be written as a uint16 to the data block, +// immediately preceeding the array elements. +func WithArray() fieldOpt { + return func(f *field) { + f.inType |= InTypeArray + } +} + // 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{ diff --git a/internal/etw/sample/sample.go b/internal/etw/sample/sample.go index 1b9d002..f041434 100644 --- a/internal/etw/sample/sample.go +++ b/internal/etw/sample/sample.go @@ -59,6 +59,13 @@ func main() { event.Data.AddString("Foo") event.Metadata.AddField("TestField2", etw.InTypeANSIString) event.Data.AddString("Bar") + event.Metadata.AddField("TestArray", etw.InTypeANSIString, etw.WithArray()) + event.Data.AddSimple(uint16(5)) + event.Data.AddString("Item1") + event.Data.AddString("Item2") + event.Data.AddString("Item3") + event.Data.AddString("Item4") + event.Data.AddString("Item5") if err := provider.WriteEvent(event); err != nil { fmt.Println(err)