diff --git a/internal/etw/eventopt.go b/internal/etw/eventopt.go index 3fe0cda..5c752dc 100644 --- a/internal/etw/eventopt.go +++ b/internal/etw/eventopt.go @@ -1,9 +1,20 @@ package etw +import ( + "golang.org/x/sys/windows" +) + +type eventOptions struct { + descriptor *EventDescriptor + activityID *windows.GUID + relatedActivityID *windows.GUID + tags uint32 +} + // EventOpt defines the option function type that can be passed to // Provider.WriteEvent to specify general event options, such as level and // keyword. -type EventOpt func(*EventDescriptor, *uint32) +type EventOpt func(options *eventOptions) // WithEventOpts returns the variadic arguments as a single slice. func WithEventOpts(opts ...EventOpt) []EventOpt { @@ -12,23 +23,35 @@ func WithEventOpts(opts ...EventOpt) []EventOpt { // WithLevel specifies the level of the event to be written. func WithLevel(level Level) EventOpt { - return func(descriptor *EventDescriptor, tags *uint32) { - descriptor.Level = level + return func(options *eventOptions) { + options.descriptor.Level = level } } // WithKeyword specifies the keywords of the event to be written. Multiple uses // of this option are OR'd together. func WithKeyword(keyword uint64) EventOpt { - return func(descriptor *EventDescriptor, tags *uint32) { - descriptor.Keyword |= keyword + return func(options *eventOptions) { + options.descriptor.Keyword |= keyword } } // WithTags specifies the tags of the event to be written. Tags is a 28-bit // value (top 4 bits are ignored) which are interpreted by the event consumer. func WithTags(newTags uint32) EventOpt { - return func(descriptor *EventDescriptor, tags *uint32) { - *tags |= newTags + return func(options *eventOptions) { + options.tags |= newTags + } +} + +func WithActivityID(activityID *windows.GUID) EventOpt { + return func(options *eventOptions) { + options.activityID = activityID + } +} + +func WithRelatedActivityID(activityID *windows.GUID) EventOpt { + return func(options *eventOptions) { + options.relatedActivityID = activityID } } diff --git a/internal/etw/provider.go b/internal/etw/provider.go index c413351..c9d5468 100644 --- a/internal/etw/provider.go +++ b/internal/etw/provider.go @@ -181,28 +181,27 @@ func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uin // constructed based on the EventOpt and FieldOpt values that are passed as // opts. func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error { - tags := uint32(0) - descriptor := NewEventDescriptor() + options := eventOptions{descriptor: NewEventDescriptor()} em := &EventMetadata{} ed := &EventData{} // We need to evaluate the EventOpts first since they might change tags, and // we write out the tags before evaluating FieldOpts. for _, opt := range eventOpts { - opt(descriptor, &tags) + opt(&options) } - if !provider.IsEnabledForLevelAndKeywords(descriptor.Level, descriptor.Keyword) { + if !provider.IsEnabledForLevelAndKeywords(options.descriptor.Level, options.descriptor.Keyword) { return nil } - em.WriteEventHeader(name, tags) + em.WriteEventHeader(name, options.tags) for _, opt := range fieldOpts { opt(em, ed) } - return provider.WriteEventRaw(descriptor, [][]byte{em.Bytes()}, [][]byte{ed.Bytes()}) + return provider.WriteEventRaw(options.descriptor, nil, nil, [][]byte{em.Bytes()}, [][]byte{ed.Bytes()}) } // WriteEventRaw writes a single ETW event from the provider. This function is @@ -212,7 +211,13 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt // schema. The functions on EventMetadata and EventData can help with creating // these blobs. The blobs of each type are effectively concatenated together by // the ETW infrastructure. -func (provider *Provider) WriteEventRaw(descriptor *EventDescriptor, metadataBlobs [][]byte, dataBlobs [][]byte) error { +func (provider *Provider) WriteEventRaw( + descriptor *EventDescriptor, + activityID *windows.GUID, + relatedActivityID *windows.GUID, + metadataBlobs [][]byte, + dataBlobs [][]byte) error { + dataDescriptorCount := uint32(1 + len(metadataBlobs) + len(dataBlobs)) dataDescriptors := make([]eventDataDescriptor, 0, dataDescriptorCount) @@ -224,5 +229,5 @@ func (provider *Provider) WriteEventRaw(descriptor *EventDescriptor, metadataBlo dataDescriptors = append(dataDescriptors, newEventDataDescriptor(eventDataDescriptorTypeUserData, blob)) } - return eventWriteTransfer(provider.handle, descriptor, nil, nil, dataDescriptorCount, &dataDescriptors[0]) + return eventWriteTransfer(provider.handle, descriptor, activityID, relatedActivityID, dataDescriptorCount, &dataDescriptors[0]) } diff --git a/internal/etw/sample/sample.go b/internal/etw/sample/sample.go index 20cef4a..ed544a2 100644 --- a/internal/etw/sample/sample.go +++ b/internal/etw/sample/sample.go @@ -102,7 +102,7 @@ func main() { ed.WriteString("Item3") ed.WriteString("Item4") ed.WriteString("Item5") - if err := provider.WriteEventRaw(descriptor, [][]byte{em.Bytes()}, [][]byte{ed.Bytes()}); err != nil { + if err := provider.WriteEventRaw(descriptor, nil, nil, [][]byte{em.Bytes()}, [][]byte{ed.Bytes()}); err != nil { logrus.Error(err) return }