Reduce exported surface area of ETW package

This commit is contained in:
Kevin Parsons
2019-03-18 23:43:37 -07:00
parent 4de24ed3e8
commit 063573a7d1
9 changed files with 254 additions and 283 deletions
+1 -1
View File
@@ -11,5 +11,5 @@ package etw
//sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister //sys eventRegister(providerId *windows.GUID, callback uintptr, callbackContext uintptr, providerHandle *providerHandle) (win32err error) = advapi32.EventRegister
//sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister //sys eventUnregister(providerHandle providerHandle) (win32err error) = advapi32.EventUnregister
//sys eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer //sys eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) = advapi32.EventWriteTransfer
//sys eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation //sys eventSetInformation(providerHandle providerHandle, class eventInfoClass, information uintptr, length uint32) (win32err error) = advapi32.EventSetInformation
+23 -23
View File
@@ -5,61 +5,61 @@ import (
"encoding/binary" "encoding/binary"
) )
// EventData maintains a buffer which builds up the data for an ETW event. It // eventData maintains a buffer which builds up the data for an ETW event. It
// needs to be paired with EventMetadata which describes the event. // needs to be paired with EventMetadata which describes the event.
type EventData struct { type eventData struct {
buffer bytes.Buffer buffer bytes.Buffer
} }
// Bytes returns the raw binary data containing the event data. The returned // bytes returns the raw binary data containing the event data. The returned
// value is not copied from the internal buffer, so it can be mutated by the // value is not copied from the internal buffer, so it can be mutated by the
// EventData object after it is returned. // eventData object after it is returned.
func (ed *EventData) Bytes() []byte { func (ed *eventData) bytes() []byte {
return ed.buffer.Bytes() return ed.buffer.Bytes()
} }
// WriteString appends a string, including the null terminator, to the buffer. // writeString appends a string, including the null terminator, to the buffer.
func (ed *EventData) WriteString(data string) { func (ed *eventData) writeString(data string) {
ed.buffer.WriteString(data) ed.buffer.WriteString(data)
ed.buffer.WriteByte(0) ed.buffer.WriteByte(0)
} }
// WriteInt8 appends a int8 to the buffer. // writeInt8 appends a int8 to the buffer.
func (ed *EventData) WriteInt8(value int8) { func (ed *eventData) writeInt8(value int8) {
ed.buffer.WriteByte(uint8(value)) ed.buffer.WriteByte(uint8(value))
} }
// WriteInt16 appends a int16 to the buffer. // writeInt16 appends a int16 to the buffer.
func (ed *EventData) WriteInt16(value int16) { func (ed *eventData) writeInt16(value int16) {
binary.Write(&ed.buffer, binary.LittleEndian, value) binary.Write(&ed.buffer, binary.LittleEndian, value)
} }
// WriteInt32 appends a int32 to the buffer. // writeInt32 appends a int32 to the buffer.
func (ed *EventData) WriteInt32(value int32) { func (ed *eventData) writeInt32(value int32) {
binary.Write(&ed.buffer, binary.LittleEndian, value) binary.Write(&ed.buffer, binary.LittleEndian, value)
} }
// WriteInt64 appends a int64 to the buffer. // writeInt64 appends a int64 to the buffer.
func (ed *EventData) WriteInt64(value int64) { func (ed *eventData) writeInt64(value int64) {
binary.Write(&ed.buffer, binary.LittleEndian, value) binary.Write(&ed.buffer, binary.LittleEndian, value)
} }
// WriteUint8 appends a uint8 to the buffer. // writeUint8 appends a uint8 to the buffer.
func (ed *EventData) WriteUint8(value uint8) { func (ed *eventData) writeUint8(value uint8) {
ed.buffer.WriteByte(value) ed.buffer.WriteByte(value)
} }
// WriteUint16 appends a uint16 to the buffer. // writeUint16 appends a uint16 to the buffer.
func (ed *EventData) WriteUint16(value uint16) { func (ed *eventData) writeUint16(value uint16) {
binary.Write(&ed.buffer, binary.LittleEndian, value) binary.Write(&ed.buffer, binary.LittleEndian, value)
} }
// WriteUint32 appends a uint32 to the buffer. // writeUint32 appends a uint32 to the buffer.
func (ed *EventData) WriteUint32(value uint32) { func (ed *eventData) writeUint32(value uint32) {
binary.Write(&ed.buffer, binary.LittleEndian, value) binary.Write(&ed.buffer, binary.LittleEndian, value)
} }
// WriteUint64 appends a uint64 to the buffer. // writeUint64 appends a uint64 to the buffer.
func (ed *EventData) WriteUint64(value uint64) { func (ed *eventData) writeUint64(value uint64) {
binary.Write(&ed.buffer, binary.LittleEndian, value) binary.Write(&ed.buffer, binary.LittleEndian, value)
} }
+12 -12
View File
@@ -28,24 +28,24 @@ const (
) )
// EventDescriptor represents various metadata for an ETW event. // EventDescriptor represents various metadata for an ETW event.
type EventDescriptor struct { type eventDescriptor struct {
id uint16 id uint16
version uint8 version uint8
Channel Channel channel Channel
Level Level level Level
Opcode uint8 opcode uint8
Task uint16 task uint16
Keyword uint64 keyword uint64
} }
// NewEventDescriptor returns an EventDescriptor initialized for use with // NewEventDescriptor returns an EventDescriptor initialized for use with
// TraceLogging. // TraceLogging.
func NewEventDescriptor() *EventDescriptor { func newEventDescriptor() *eventDescriptor {
// Standard TraceLogging events default to the TraceLogging channel, and // Standard TraceLogging events default to the TraceLogging channel, and
// verbose level. // verbose level.
return &EventDescriptor{ return &eventDescriptor{
Channel: ChannelTraceLogging, channel: ChannelTraceLogging,
Level: LevelVerbose, level: LevelVerbose,
} }
} }
@@ -53,7 +53,7 @@ func NewEventDescriptor() *EventDescriptor {
// should uniquely identify the other event metadata (contained in // should uniquely identify the other event metadata (contained in
// EventDescriptor, and field metadata). Only the lower 24 bits of this value // EventDescriptor, and field metadata). Only the lower 24 bits of this value
// are relevant. // are relevant.
func (ed *EventDescriptor) Identity() uint32 { func (ed *eventDescriptor) identity() uint32 {
return (uint32(ed.version) << 16) | uint32(ed.id) return (uint32(ed.version) << 16) | uint32(ed.id)
} }
@@ -61,7 +61,7 @@ func (ed *EventDescriptor) Identity() uint32 {
// should uniquely identify the other event metadata (contained in // should uniquely identify the other event metadata (contained in
// EventDescriptor, and field metadata). Only the lower 24 bits of this value // EventDescriptor, and field metadata). Only the lower 24 bits of this value
// are relevant. // are relevant.
func (ed *EventDescriptor) SetIdentity(identity uint32) { func (ed *eventDescriptor) setIdentity(identity uint32) {
ed.id = uint16(identity) ed.id = uint16(identity)
ed.version = uint8(identity >> 16) ed.version = uint8(identity >> 16)
} }
+80 -80
View File
@@ -5,107 +5,107 @@ import (
"encoding/binary" "encoding/binary"
) )
// InType indicates the type of data contained in the ETW event. // inType indicates the type of data contained in the ETW event.
type InType byte type inType byte
// Various InType definitions for TraceLogging. These must match the definitions // Various inType definitions for TraceLogging. These must match the definitions
// found in TraceLoggingProvider.h in the Windows SDK. // found in TraceLoggingProvider.h in the Windows SDK.
const ( const (
InTypeNull InType = iota inTypeNull inType = iota
InTypeUnicodeString inTypeUnicodeString
InTypeANSIString inTypeANSIString
InTypeInt8 inTypeInt8
InTypeUint8 inTypeUint8
InTypeInt16 inTypeInt16
InTypeUint16 inTypeUint16
InTypeInt32 inTypeInt32
InTypeUint32 inTypeUint32
InTypeInt64 inTypeInt64
InTypeUint64 inTypeUint64
InTypeFloat inTypeFloat
InTypeDouble inTypeDouble
InTypeBool32 inTypeBool32
InTypeBinary inTypeBinary
InTypeGUID inTypeGUID
InTypePointerUnsupported inTypePointerUnsupported
InTypeFileTime inTypeFileTime
InTypeSystemTime inTypeSystemTime
InTypeSID inTypeSID
InTypeHexInt32 inTypeHexInt32
InTypeHexInt64 inTypeHexInt64
InTypeCountedString inTypeCountedString
InTypeCountedANSIString inTypeCountedANSIString
InTypeStruct inTypeStruct
InTypeCountedBinary inTypeCountedBinary
InTypeCountedArray InType = 32 inTypeCountedArray inType = 32
InTypeArray InType = 64 inTypeArray inType = 64
) )
// OutType specifies a hint to the event decoder for how the value should be // outType specifies a hint to the event decoder for how the value should be
// formatted. // formatted.
type OutType byte type outType byte
// Various OutType definitions for TraceLogging. These must match the // Various outType definitions for TraceLogging. These must match the
// definitions found in TraceLoggingProvider.h in the Windows SDK. // definitions found in TraceLoggingProvider.h in the Windows SDK.
const ( const (
// OutTypeDefault indicates that the default formatting for the InType will // outTypeDefault indicates that the default formatting for the inType will
// be used by the event decoder. // be used by the event decoder.
OutTypeDefault OutType = iota outTypeDefault outType = iota
OutTypeNoPrint outTypeNoPrint
OutTypeString outTypeString
OutTypeBoolean outTypeBoolean
OutTypeHex outTypeHex
OutTypePID outTypePID
OutTypeTID outTypeTID
OutTypePort outTypePort
OutTypeIPv4 outTypeIPv4
OutTypeIPv6 outTypeIPv6
OutTypeSocketAddress outTypeSocketAddress
OutTypeXML outTypeXML
OutTypeJSON outTypeJSON
OutTypeWin32Error outTypeWin32Error
OutTypeNTStatus outTypeNTStatus
OutTypeHResult outTypeHResult
OutTypeFileTime outTypeFileTime
OutTypeSigned outTypeSigned
OutTypeUnsigned outTypeUnsigned
OutTypeUTF8 OutType = 35 outTypeUTF8 outType = 35
OutTypePKCS7WithTypeInfo OutType = 36 outTypePKCS7WithTypeInfo outType = 36
OutTypeCodePointer OutType = 37 outTypeCodePointer outType = 37
OutTypeDateTimeUTC OutType = 38 outTypeDateTimeUTC outType = 38
) )
// EventMetadata maintains a buffer which builds up the metadata 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. // event. It needs to be paired with EventData which describes the event.
type EventMetadata struct { type eventMetadata struct {
buffer bytes.Buffer buffer bytes.Buffer
} }
// Bytes returns the raw binary data containing the event metadata. Before being // bytes returns the raw binary data containing the event metadata. Before being
// returned, the current size of the buffer is written to the start of the // returned, the current size of the buffer is written to the start of the
// buffer. The returned value is not copied from the internal buffer, so it can // buffer. The returned value is not copied from the internal buffer, so it can
// be mutated by the EventMetadata object after it is returned. // be mutated by the eventMetadata object after it is returned.
func (em *EventMetadata) Bytes() []byte { func (em *eventMetadata) bytes() []byte {
// Finalize the event metadata buffer by filling in the buffer length at the // Finalize the event metadata buffer by filling in the buffer length at the
// beginning. // beginning.
binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len())) binary.LittleEndian.PutUint16(em.buffer.Bytes(), uint16(em.buffer.Len()))
return em.buffer.Bytes() return em.buffer.Bytes()
} }
// WriteEventHeader writes the metadata for the start of an event to the buffer. // writeEventHeader writes the metadata for the start of an event to the buffer.
// This specifies the event name and tags. // This specifies the event name and tags.
func (em *EventMetadata) WriteEventHeader(name string, tags uint32) { func (em *eventMetadata) writeEventHeader(name string, tags uint32) {
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
em.writeTags(tags) em.writeTags(tags)
em.buffer.WriteString(name) em.buffer.WriteString(name)
em.buffer.WriteByte(0) // Null terminator for name em.buffer.WriteByte(0) // Null terminator for name
} }
func (em *EventMetadata) writeField(name string, inType InType, outType OutType, tags uint32, arrSize uint16) { func (em *eventMetadata) writeFieldInner(name string, inType inType, outType outType, tags uint32, arrSize uint16) {
em.buffer.WriteString(name) em.buffer.WriteString(name)
em.buffer.WriteByte(0) // Null terminator for name em.buffer.WriteByte(0) // Null terminator for name
if outType == OutTypeDefault && tags == 0 { if outType == outTypeDefault && tags == 0 {
em.buffer.WriteByte(byte(inType)) em.buffer.WriteByte(byte(inType))
} else { } else {
em.buffer.WriteByte(byte(inType | 128)) em.buffer.WriteByte(byte(inType | 128))
@@ -129,7 +129,7 @@ func (em *EventMetadata) writeField(name string, inType InType, outType OutType,
// bytes, each containing 7 bits of tag value, with the high bit set if there is // bytes, each containing 7 bits of tag value, with the high bit set if there is
// more tag data in the following byte. This allows for a more compact // more tag data in the following byte. This allows for a more compact
// representation when not all of the tag bits are needed. // representation when not all of the tag bits are needed.
func (em *EventMetadata) writeTags(tags uint32) { func (em *eventMetadata) writeTags(tags uint32) {
// Only use the top 28 bits of the tags value. // Only use the top 28 bits of the tags value.
tags &= 0xfffffff tags &= 0xfffffff
@@ -150,28 +150,28 @@ func (em *EventMetadata) writeTags(tags uint32) {
} }
} }
// WriteField writes the metadata for a simple field to the buffer. // writeField writes the metadata for a simple field to the buffer.
func (em *EventMetadata) WriteField(name string, inType InType, outType OutType, tags uint32) { func (em *eventMetadata) writeField(name string, inType inType, outType outType, tags uint32) {
em.writeField(name, inType, outType, tags, 0) em.writeFieldInner(name, inType, outType, tags, 0)
} }
// WriteArray writes the metadata for an array field to the buffer. The number // writeArray writes the metadata for an array field to the buffer. The number
// of elements in the array must be written as a uint16 in the event data, // of elements in the array must be written as a uint16 in the event data,
// immediately preceeding the event data. // immediately preceeding the event data.
func (em *EventMetadata) WriteArray(name string, inType InType, outType OutType, tags uint32) { func (em *eventMetadata) writeArray(name string, inType inType, outType outType, tags uint32) {
em.writeField(name, inType|InTypeArray, outType, tags, 0) em.writeFieldInner(name, inType|inTypeArray, outType, tags, 0)
} }
// WriteCountedArray writes the metadata for an array field to the buffer. The // writeCountedArray writes the metadata for an array field to the buffer. The
// size of a counted array is fixed, and the size is written into the metadata // size of a counted array is fixed, and the size is written into the metadata
// directly. // directly.
func (em *EventMetadata) WriteCountedArray(name string, count uint16, inType InType, outType OutType, tags uint32) { func (em *eventMetadata) writeCountedArray(name string, count uint16, inType inType, outType outType, tags uint32) {
em.writeField(name, inType|InTypeCountedArray, outType, tags, count) em.writeFieldInner(name, inType|inTypeCountedArray, outType, tags, count)
} }
// WriteStruct writes the metadata for a nested struct to the buffer. The struct // writeStruct writes the metadata for a nested struct to the buffer. The struct
// contains the next N fields in the metadata, where N is specified by the // contains the next N fields in the metadata, where N is specified by the
// fieldCount argument. // fieldCount argument.
func (em *EventMetadata) WriteStruct(name string, fieldCount uint8, tags uint32) { func (em *eventMetadata) writeStruct(name string, fieldCount uint8, tags uint32) {
em.writeField(name, InTypeStruct, OutType(fieldCount), tags, 0) em.writeFieldInner(name, inTypeStruct, outType(fieldCount), tags, 0)
} }
+4 -4
View File
@@ -5,7 +5,7 @@ import (
) )
type eventOptions struct { type eventOptions struct {
descriptor *EventDescriptor descriptor *eventDescriptor
activityID *windows.GUID activityID *windows.GUID
relatedActivityID *windows.GUID relatedActivityID *windows.GUID
tags uint32 tags uint32
@@ -24,7 +24,7 @@ func WithEventOpts(opts ...EventOpt) []EventOpt {
// WithLevel specifies the level of the event to be written. // WithLevel specifies the level of the event to be written.
func WithLevel(level Level) EventOpt { func WithLevel(level Level) EventOpt {
return func(options *eventOptions) { return func(options *eventOptions) {
options.descriptor.Level = level options.descriptor.level = level
} }
} }
@@ -32,13 +32,13 @@ func WithLevel(level Level) EventOpt {
// of this option are OR'd together. // of this option are OR'd together.
func WithKeyword(keyword uint64) EventOpt { func WithKeyword(keyword uint64) EventOpt {
return func(options *eventOptions) { return func(options *eventOptions) {
options.descriptor.Keyword |= keyword options.descriptor.keyword |= keyword
} }
} }
func WithChannel(channel Channel) EventOpt { func WithChannel(channel Channel) EventOpt {
return func(options *eventOptions) { return func(options *eventOptions) {
options.descriptor.Channel = channel options.descriptor.channel = channel
} }
} }
+122 -122
View File
@@ -7,7 +7,7 @@ import (
// FieldOpt defines the option function type that can be passed to // FieldOpt defines the option function type that can be passed to
// Provider.WriteEvent to add fields to the event. // Provider.WriteEvent to add fields to the event.
type FieldOpt func(em *EventMetadata, ed *EventData) type FieldOpt func(em *eventMetadata, ed *eventData)
// WithFields returns the variadic arguments as a single slice. // WithFields returns the variadic arguments as a single slice.
func WithFields(opts ...FieldOpt) []FieldOpt { func WithFields(opts ...FieldOpt) []FieldOpt {
@@ -16,46 +16,46 @@ func WithFields(opts ...FieldOpt) []FieldOpt {
// BoolField adds a single bool field to the event. // BoolField adds a single bool field to the event.
func BoolField(name string, value bool) FieldOpt { func BoolField(name string, value bool) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeUint8, OutTypeBoolean, 0) em.writeField(name, inTypeUint8, outTypeBoolean, 0)
bool8 := uint8(0) bool8 := uint8(0)
if value { if value {
bool8 = uint8(1) bool8 = uint8(1)
} }
ed.WriteUint8(bool8) ed.writeUint8(bool8)
} }
} }
// BoolArray adds an array of bool to the event. // BoolArray adds an array of bool to the event.
func BoolArray(name string, values []bool) FieldOpt { func BoolArray(name string, values []bool) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeUint8, OutTypeBoolean, 0) em.writeArray(name, inTypeUint8, outTypeBoolean, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
bool8 := uint8(0) bool8 := uint8(0)
if v { if v {
bool8 = uint8(1) bool8 = uint8(1)
} }
ed.WriteUint8(bool8) ed.writeUint8(bool8)
} }
} }
} }
// StringField adds a single string field to the event. // StringField adds a single string field to the event.
func StringField(name string, value string) FieldOpt { func StringField(name string, value string) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeANSIString, OutTypeUTF8, 0) em.writeField(name, inTypeANSIString, outTypeUTF8, 0)
ed.WriteString(value) ed.writeString(value)
} }
} }
// StringArray adds an array of string to the event. // StringArray adds an array of string to the event.
func StringArray(name string, values []string) FieldOpt { func StringArray(name string, values []string) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeANSIString, OutTypeUTF8, 0) em.writeArray(name, inTypeANSIString, outTypeUTF8, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteString(v) ed.writeString(v)
} }
} }
} }
@@ -74,22 +74,22 @@ func IntField(name string, value int) FieldOpt {
// IntArray adds an array of int to the event. // IntArray adds an array of int to the event.
func IntArray(name string, values []int) FieldOpt { func IntArray(name string, values []int) FieldOpt {
inType := InTypeNull inType := inTypeNull
var writeItem func(*EventData, int) var writeItem func(*eventData, int)
switch unsafe.Sizeof(values[0]) { switch unsafe.Sizeof(values[0]) {
case 4: case 4:
inType = InTypeInt32 inType = inTypeInt32
writeItem = func(ed *EventData, item int) { ed.WriteInt32(int32(item)) } writeItem = func(ed *eventData, item int) { ed.writeInt32(int32(item)) }
case 8: case 8:
inType = InTypeInt64 inType = inTypeInt64
writeItem = func(ed *EventData, item int) { ed.WriteInt64(int64(item)) } writeItem = func(ed *eventData, item int) { ed.writeInt64(int64(item)) }
default: default:
panic("Unsupported int size") panic("Unsupported int size")
} }
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, inType, OutTypeDefault, 0) em.writeArray(name, inType, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
writeItem(ed, v) writeItem(ed, v)
} }
@@ -98,76 +98,76 @@ func IntArray(name string, values []int) FieldOpt {
// Int8Field adds a single int8 field to the event. // Int8Field adds a single int8 field to the event.
func Int8Field(name string, value int8) FieldOpt { func Int8Field(name string, value int8) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeInt8, OutTypeDefault, 0) em.writeField(name, inTypeInt8, outTypeDefault, 0)
ed.WriteInt8(value) ed.writeInt8(value)
} }
} }
// Int8Array adds an array of int8 to the event. // Int8Array adds an array of int8 to the event.
func Int8Array(name string, values []int8) FieldOpt { func Int8Array(name string, values []int8) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeInt8, OutTypeDefault, 0) em.writeArray(name, inTypeInt8, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteInt8(v) ed.writeInt8(v)
} }
} }
} }
// Int16Field adds a single int16 field to the event. // Int16Field adds a single int16 field to the event.
func Int16Field(name string, value int16) FieldOpt { func Int16Field(name string, value int16) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeInt16, OutTypeDefault, 0) em.writeField(name, inTypeInt16, outTypeDefault, 0)
ed.WriteInt16(value) ed.writeInt16(value)
} }
} }
// Int16Array adds an array of int16 to the event. // Int16Array adds an array of int16 to the event.
func Int16Array(name string, values []int16) FieldOpt { func Int16Array(name string, values []int16) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeInt16, OutTypeDefault, 0) em.writeArray(name, inTypeInt16, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteInt16(v) ed.writeInt16(v)
} }
} }
} }
// Int32Field adds a single int32 field to the event. // Int32Field adds a single int32 field to the event.
func Int32Field(name string, value int32) FieldOpt { func Int32Field(name string, value int32) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeInt32, OutTypeDefault, 0) em.writeField(name, inTypeInt32, outTypeDefault, 0)
ed.WriteInt32(value) ed.writeInt32(value)
} }
} }
// Int32Array adds an array of int32 to the event. // Int32Array adds an array of int32 to the event.
func Int32Array(name string, values []int32) FieldOpt { func Int32Array(name string, values []int32) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeInt32, OutTypeDefault, 0) em.writeArray(name, inTypeInt32, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteInt32(v) ed.writeInt32(v)
} }
} }
} }
// Int64Field adds a single int64 field to the event. // Int64Field adds a single int64 field to the event.
func Int64Field(name string, value int64) FieldOpt { func Int64Field(name string, value int64) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeInt64, OutTypeDefault, 0) em.writeField(name, inTypeInt64, outTypeDefault, 0)
ed.WriteInt64(value) ed.writeInt64(value)
} }
} }
// Int64Array adds an array of int64 to the event. // Int64Array adds an array of int64 to the event.
func Int64Array(name string, values []int64) FieldOpt { func Int64Array(name string, values []int64) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeInt64, OutTypeDefault, 0) em.writeArray(name, inTypeInt64, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteInt64(v) ed.writeInt64(v)
} }
} }
} }
@@ -186,22 +186,22 @@ func UintField(name string, value uint) FieldOpt {
// UintArray adds an array of uint to the event. // UintArray adds an array of uint to the event.
func UintArray(name string, values []uint) FieldOpt { func UintArray(name string, values []uint) FieldOpt {
inType := InTypeNull inType := inTypeNull
var writeItem func(*EventData, uint) var writeItem func(*eventData, uint)
switch unsafe.Sizeof(values[0]) { switch unsafe.Sizeof(values[0]) {
case 4: case 4:
inType = InTypeUint32 inType = inTypeUint32
writeItem = func(ed *EventData, item uint) { ed.WriteUint32(uint32(item)) } writeItem = func(ed *eventData, item uint) { ed.writeUint32(uint32(item)) }
case 8: case 8:
inType = InTypeUint64 inType = inTypeUint64
writeItem = func(ed *EventData, item uint) { ed.WriteUint64(uint64(item)) } writeItem = func(ed *eventData, item uint) { ed.writeUint64(uint64(item)) }
default: default:
panic("Unsupported uint size") panic("Unsupported uint size")
} }
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, inType, OutTypeDefault, 0) em.writeArray(name, inType, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
writeItem(ed, v) writeItem(ed, v)
} }
@@ -210,119 +210,119 @@ func UintArray(name string, values []uint) FieldOpt {
// Uint8Field adds a single uint8 field to the event. // Uint8Field adds a single uint8 field to the event.
func Uint8Field(name string, value uint8) FieldOpt { func Uint8Field(name string, value uint8) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeUint8, OutTypeDefault, 0) em.writeField(name, inTypeUint8, outTypeDefault, 0)
ed.WriteUint8(value) ed.writeUint8(value)
} }
} }
// Uint8Array adds an array of uint8 to the event. // Uint8Array adds an array of uint8 to the event.
func Uint8Array(name string, values []uint8) FieldOpt { func Uint8Array(name string, values []uint8) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeUint8, OutTypeDefault, 0) em.writeArray(name, inTypeUint8, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteUint8(v) ed.writeUint8(v)
} }
} }
} }
// Uint16Field adds a single uint16 field to the event. // Uint16Field adds a single uint16 field to the event.
func Uint16Field(name string, value uint16) FieldOpt { func Uint16Field(name string, value uint16) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeUint16, OutTypeDefault, 0) em.writeField(name, inTypeUint16, outTypeDefault, 0)
ed.WriteUint16(value) ed.writeUint16(value)
} }
} }
// Uint16Array adds an array of uint16 to the event. // Uint16Array adds an array of uint16 to the event.
func Uint16Array(name string, values []uint16) FieldOpt { func Uint16Array(name string, values []uint16) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeUint16, OutTypeDefault, 0) em.writeArray(name, inTypeUint16, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteUint16(v) ed.writeUint16(v)
} }
} }
} }
// Uint32Field adds a single uint32 field to the event. // Uint32Field adds a single uint32 field to the event.
func Uint32Field(name string, value uint32) FieldOpt { func Uint32Field(name string, value uint32) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeUint32, OutTypeDefault, 0) em.writeField(name, inTypeUint32, outTypeDefault, 0)
ed.WriteUint32(value) ed.writeUint32(value)
} }
} }
// Uint32Array adds an array of uint32 to the event. // Uint32Array adds an array of uint32 to the event.
func Uint32Array(name string, values []uint32) FieldOpt { func Uint32Array(name string, values []uint32) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeUint32, OutTypeDefault, 0) em.writeArray(name, inTypeUint32, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteUint32(v) ed.writeUint32(v)
} }
} }
} }
// Uint64Field adds a single uint64 field to the event. // Uint64Field adds a single uint64 field to the event.
func Uint64Field(name string, value uint64) FieldOpt { func Uint64Field(name string, value uint64) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeUint64, OutTypeDefault, 0) em.writeField(name, inTypeUint64, outTypeDefault, 0)
ed.WriteUint64(value) ed.writeUint64(value)
} }
} }
// Uint64Array adds an array of uint64 to the event. // Uint64Array adds an array of uint64 to the event.
func Uint64Array(name string, values []uint64) FieldOpt { func Uint64Array(name string, values []uint64) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeUint64, OutTypeDefault, 0) em.writeArray(name, inTypeUint64, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteUint64(v) ed.writeUint64(v)
} }
} }
} }
// UintptrField adds a single uintptr field to the event. // UintptrField adds a single uintptr field to the event.
func UintptrField(name string, value uintptr) FieldOpt { func UintptrField(name string, value uintptr) FieldOpt {
inType := InTypeNull inType := inTypeNull
var writeItem func(*EventData, uintptr) var writeItem func(*eventData, uintptr)
switch unsafe.Sizeof(value) { switch unsafe.Sizeof(value) {
case 4: case 4:
inType = InTypeHexInt32 inType = inTypeHexInt32
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) } writeItem = func(ed *eventData, item uintptr) { ed.writeUint32(uint32(item)) }
case 8: case 8:
inType = InTypeHexInt64 inType = inTypeHexInt64
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) } writeItem = func(ed *eventData, item uintptr) { ed.writeUint64(uint64(item)) }
default: default:
panic("Unsupported uintptr size") panic("Unsupported uintptr size")
} }
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, inType, OutTypeDefault, 0) em.writeField(name, inType, outTypeDefault, 0)
writeItem(ed, value) writeItem(ed, value)
} }
} }
// UintptrArray adds an array of uintptr to the event. // UintptrArray adds an array of uintptr to the event.
func UintptrArray(name string, values []uintptr) FieldOpt { func UintptrArray(name string, values []uintptr) FieldOpt {
inType := InTypeNull inType := inTypeNull
var writeItem func(*EventData, uintptr) var writeItem func(*eventData, uintptr)
switch unsafe.Sizeof(values[0]) { switch unsafe.Sizeof(values[0]) {
case 4: case 4:
inType = InTypeHexInt32 inType = inTypeHexInt32
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint32(uint32(item)) } writeItem = func(ed *eventData, item uintptr) { ed.writeUint32(uint32(item)) }
case 8: case 8:
inType = InTypeHexInt64 inType = inTypeHexInt64
writeItem = func(ed *EventData, item uintptr) { ed.WriteUint64(uint64(item)) } writeItem = func(ed *eventData, item uintptr) { ed.writeUint64(uint64(item)) }
default: default:
panic("Unsupported uintptr size") panic("Unsupported uintptr size")
} }
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, inType, OutTypeDefault, 0) em.writeArray(name, inType, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
writeItem(ed, v) writeItem(ed, v)
} }
@@ -331,38 +331,38 @@ func UintptrArray(name string, values []uintptr) FieldOpt {
// Float32Field adds a single float32 field to the event. // Float32Field adds a single float32 field to the event.
func Float32Field(name string, value float32) FieldOpt { func Float32Field(name string, value float32) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeFloat, OutTypeDefault, 0) em.writeField(name, inTypeFloat, outTypeDefault, 0)
ed.WriteUint32(math.Float32bits(value)) ed.writeUint32(math.Float32bits(value))
} }
} }
// Float32Array adds an array of float32 to the event. // Float32Array adds an array of float32 to the event.
func Float32Array(name string, values []float32) FieldOpt { func Float32Array(name string, values []float32) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeFloat, OutTypeDefault, 0) em.writeArray(name, inTypeFloat, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteUint32(math.Float32bits(v)) ed.writeUint32(math.Float32bits(v))
} }
} }
} }
// Float64Field adds a single float64 field to the event. // Float64Field adds a single float64 field to the event.
func Float64Field(name string, value float64) FieldOpt { func Float64Field(name string, value float64) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteField(name, InTypeDouble, OutTypeDefault, 0) em.writeField(name, inTypeDouble, outTypeDefault, 0)
ed.WriteUint64(math.Float64bits(value)) ed.writeUint64(math.Float64bits(value))
} }
} }
// Float64Array adds an array of float64 to the event. // Float64Array adds an array of float64 to the event.
func Float64Array(name string, values []float64) FieldOpt { func Float64Array(name string, values []float64) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteArray(name, InTypeDouble, OutTypeDefault, 0) em.writeArray(name, inTypeDouble, outTypeDefault, 0)
ed.WriteUint16(uint16(len(values))) ed.writeUint16(uint16(len(values)))
for _, v := range values { for _, v := range values {
ed.WriteUint64(math.Float64bits(v)) ed.writeUint64(math.Float64bits(v))
} }
} }
} }
@@ -370,8 +370,8 @@ func Float64Array(name string, values []float64) FieldOpt {
// Struct adds a nested struct to the event, the FieldOpts in the opts argument // Struct adds a nested struct to the event, the FieldOpts in the opts argument
// are used to specify the fields of the struct. // are used to specify the fields of the struct.
func Struct(name string, opts ...FieldOpt) FieldOpt { func Struct(name string, opts ...FieldOpt) FieldOpt {
return func(em *EventMetadata, ed *EventData) { return func(em *eventMetadata, ed *eventData) {
em.WriteStruct(name, uint8(len(opts)), 0) em.writeStruct(name, uint8(len(opts)), 0)
for _, opt := range opts { for _, opt := range opts {
opt(em, ed) opt(em, ed)
} }
+11 -11
View File
@@ -219,9 +219,9 @@ func (provider *Provider) IsEnabledForLevelAndKeywords(level Level, keywords uin
// constructed based on the EventOpt and FieldOpt values that are passed as // constructed based on the EventOpt and FieldOpt values that are passed as
// opts. // opts.
func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error { func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpts []FieldOpt) error {
options := eventOptions{descriptor: NewEventDescriptor()} options := eventOptions{descriptor: newEventDescriptor()}
em := &EventMetadata{} em := &eventMetadata{}
ed := &EventData{} ed := &eventData{}
// We need to evaluate the EventOpts first since they might change tags, and // We need to evaluate the EventOpts first since they might change tags, and
// we write out the tags before evaluating FieldOpts. // we write out the tags before evaluating FieldOpts.
@@ -229,11 +229,11 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt
opt(&options) opt(&options)
} }
if !provider.IsEnabledForLevelAndKeywords(options.descriptor.Level, options.descriptor.Keyword) { if !provider.IsEnabledForLevelAndKeywords(options.descriptor.level, options.descriptor.keyword) {
return nil return nil
} }
em.WriteEventHeader(name, options.tags) em.writeEventHeader(name, options.tags)
for _, opt := range fieldOpts { for _, opt := range fieldOpts {
opt(em, ed) opt(em, ed)
@@ -243,22 +243,22 @@ func (provider *Provider) WriteEvent(name string, eventOpts []EventOpt, fieldOpt
// event metadata (e.g. for the name) so we don't need to do this check for // event metadata (e.g. for the name) so we don't need to do this check for
// the metadata. // the metadata.
dataBlobs := [][]byte{} dataBlobs := [][]byte{}
if len(ed.Bytes()) > 0 { if len(ed.bytes()) > 0 {
dataBlobs = [][]byte{ed.Bytes()} dataBlobs = [][]byte{ed.bytes()}
} }
return provider.WriteEventRaw(options.descriptor, nil, nil, [][]byte{em.Bytes()}, dataBlobs) return provider.writeEventRaw(options.descriptor, nil, nil, [][]byte{em.bytes()}, dataBlobs)
} }
// WriteEventRaw writes a single ETW event from the provider. This function is // writeEventRaw writes a single ETW event from the provider. This function is
// less abstracted than WriteEvent, and presents a fairly direct interface to // less abstracted than WriteEvent, and presents a fairly direct interface to
// the event writing functionality. It expects a series of event metadata and // the event writing functionality. It expects a series of event metadata and
// event data blobs to be passed in, which must conform to the TraceLogging // event data blobs to be passed in, which must conform to the TraceLogging
// schema. The functions on EventMetadata and EventData can help with creating // schema. The functions on EventMetadata and EventData can help with creating
// these blobs. The blobs of each type are effectively concatenated together by // these blobs. The blobs of each type are effectively concatenated together by
// the ETW infrastructure. // the ETW infrastructure.
func (provider *Provider) WriteEventRaw( func (provider *Provider) writeEventRaw(
descriptor *EventDescriptor, descriptor *eventDescriptor,
activityID *windows.GUID, activityID *windows.GUID,
relatedActivityID *windows.GUID, relatedActivityID *windows.GUID,
metadataBlobs [][]byte, metadataBlobs [][]byte,
-29
View File
@@ -36,7 +36,6 @@ func main() {
fmt.Println("Press enter to log events") fmt.Println("Press enter to log events")
reader.ReadString('\n') reader.ReadString('\n')
// Write using high-level API.
if err := provider.WriteEvent( if err := provider.WriteEvent(
"TestEvent", "TestEvent",
etw.WithEventOpts( etw.WithEventOpts(
@@ -60,32 +59,4 @@ func main() {
logrus.Error(err) logrus.Error(err)
return return
} }
// Write using low-level API.
descriptor := etw.NewEventDescriptor()
descriptor.Level = etw.LevelInfo
descriptor.Keyword = 0x140
em := &etw.EventMetadata{}
ed := &etw.EventData{}
em.WriteEventHeader("TestEvent", 0)
em.WriteField("TestField", etw.InTypeANSIString, etw.OutTypeUTF8, 0)
ed.WriteString("Foo")
em.WriteField("TestField2", etw.InTypeANSIString, etw.OutTypeUTF8, 0)
ed.WriteString("Bar")
em.WriteStruct("TestStruct", 2, 0)
em.WriteField("Field1", etw.InTypeANSIString, etw.OutTypeUTF8, 0)
ed.WriteString("Value1")
em.WriteField("Field2", etw.InTypeANSIString, etw.OutTypeUTF8, 0)
ed.WriteString("Value2")
em.WriteArray("TestArray", etw.InTypeANSIString, etw.OutTypeDefault, 0)
ed.WriteUint16(5)
ed.WriteString("Item1")
ed.WriteString("Item2")
ed.WriteString("Item3")
ed.WriteString("Item4")
ed.WriteString("Item5")
if err := provider.WriteEventRaw(descriptor, nil, nil, [][]byte{em.Bytes()}, [][]byte{ed.Bytes()}); err != nil {
logrus.Error(err)
return
}
} }
+1 -1
View File
@@ -61,7 +61,7 @@ func eventUnregister(providerHandle providerHandle) (win32err error) {
return return
} }
func eventWriteTransfer(providerHandle providerHandle, descriptor *EventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) { func eventWriteTransfer(providerHandle providerHandle, descriptor *eventDescriptor, activityID *windows.GUID, relatedActivityID *windows.GUID, dataDescriptorCount uint32, dataDescriptors *eventDataDescriptor) (win32err error) {
r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors))) r0, _, _ := syscall.Syscall6(procEventWriteTransfer.Addr(), 6, uintptr(providerHandle), uintptr(unsafe.Pointer(descriptor)), uintptr(unsafe.Pointer(activityID)), uintptr(unsafe.Pointer(relatedActivityID)), uintptr(dataDescriptorCount), uintptr(unsafe.Pointer(dataDescriptors)))
if r0 != 0 { if r0 != 0 {
win32err = syscall.Errno(r0) win32err = syscall.Errno(r0)