Add comments

This commit is contained in:
Kevin Parsons
2018-12-12 18:20:51 -08:00
parent 899181905d
commit 083046a6cd
4 changed files with 70 additions and 16 deletions
+43 -10
View File
@@ -1,13 +1,23 @@
package etw package etw
// Channel represents the ETW logging channel that is used. It can be used by
// event consumers to give an event special treatment.
type Channel uint8 type Channel uint8
const ( const (
// ChannelTracelogging is the default channel for tracelogging events. It is
// not required to be used for tracelogging, but will prevent decoding
// issues for these events on older operating systems.
ChannelTracelogging Channel = 11 ChannelTracelogging Channel = 11
) )
// Level represents the ETW logging level. There are several predefined levels
// that are commonly used, but technically anything from 0-255 is allowed.
// Lower levels indicate more important events, and 0 indicates an event that
// will always be collected.
type Level uint8 type Level uint8
// Predefined ETW log levels.
const ( const (
LevelAlways Level = iota LevelAlways Level = iota
LevelCritical LevelCritical
@@ -17,15 +27,27 @@ const (
LevelVerbose LevelVerbose
) )
// Event represents a single ETW event. It can have field metadata and data
// added to it, and then be logged via a provider to actually send it to ETW.
type Event struct { type Event struct {
Descriptor *EventDescriptor Descriptor *EventDescriptor
Metadata *EventMetadata Metadata *EventMetadata
Data *EventData Data *EventData
} }
// NewEvent returns a new instance of an event object.
func NewEvent(name string, descriptor *EventDescriptor) *Event {
return &Event{
Descriptor: descriptor,
Metadata: NewEventMetadata(name),
Data: &EventData{},
}
}
// 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
@@ -33,10 +55,12 @@ type EventDescriptor struct {
Keyword uint64 Keyword uint64
} }
// NewEventDescriptor returns an EventDescriptor initialized for use with
// tracelogging.
func NewEventDescriptor() *EventDescriptor { func NewEventDescriptor() *EventDescriptor {
return &EventDescriptor{ return &EventDescriptor{
ID: 0, id: 0,
Version: 0, version: 0,
Channel: ChannelTracelogging, Channel: ChannelTracelogging,
Level: LevelVerbose, Level: LevelVerbose,
Opcode: 0, Opcode: 0,
@@ -45,10 +69,19 @@ func NewEventDescriptor() *EventDescriptor {
} }
} }
func NewEvent(name string, descriptor *EventDescriptor) *Event { // Identity returns the identity of the event. If the identity is not 0, it
return &Event{ // should uniquely identify the other event metadata (contained in
Descriptor: descriptor, // EventDescriptor, and field metadata). Only the lower 24 bits of this value
Metadata: NewEventMetadata(name), // are relevant.
Data: &EventData{}, func (ed *EventDescriptor) Identity() uint32 {
} return (uint32(ed.version) << 16) & uint32(ed.id)
}
// SetIdentity sets the identity of the event. If the identity is not 0, it
// should uniquely identify the other event metadata (contained in
// EventDescriptor, and field metadata). Only the lower 24 bits of this value
// are relevant.
func (ed *EventDescriptor) SetIdentity(identity uint32) {
ed.id = uint16(identity)
ed.version = uint8(identity >> 16)
} }
+8
View File
@@ -5,10 +5,18 @@ import (
"encoding/binary" "encoding/binary"
) )
// EventData maintains a buffer which builds up the data for an ETW event. It
// needs to be paired with EventMetadata which describes the event.
type EventData struct { type EventData struct {
buffer bytes.Buffer buffer bytes.Buffer
} }
// NewEventData returns a new EventData with an empty buffer.
func NewEventData() *EventData {
return &EventData{}
}
// AddString appends the data for a string to the end of the buffer.
func (ed *EventData) AddString(data string) { func (ed *EventData) AddString(data string) {
binary.Write(&ed.buffer, binary.LittleEndian, []byte(data)) binary.Write(&ed.buffer, binary.LittleEndian, []byte(data))
binary.Write(&ed.buffer, binary.LittleEndian, byte(0)) binary.Write(&ed.buffer, binary.LittleEndian, byte(0))
+7
View File
@@ -5,8 +5,10 @@ import (
"encoding/binary" "encoding/binary"
) )
// InType indicates the type of data contained in the ETW event.
type InType byte type InType byte
// Various InType definitions for tracelogging.
const ( const (
InTypeNull InType = iota InTypeNull InType = iota
InTypeUnicodeString InTypeUnicodeString
@@ -24,10 +26,14 @@ const (
InTypeBool32 InTypeBool32
) )
// 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 { type EventMetadata struct {
buffer bytes.Buffer buffer bytes.Buffer
} }
// NewEventMetadata returns a new EventMetadata with event name and initial
// metadata written to the buffer.
func NewEventMetadata(name string) *EventMetadata { func NewEventMetadata(name string) *EventMetadata {
em := EventMetadata{} em := EventMetadata{}
binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder binary.Write(&em.buffer, binary.LittleEndian, uint16(0)) // Length placeholder
@@ -37,6 +43,7 @@ func NewEventMetadata(name string) *EventMetadata {
return &em return &em
} }
// AddField appends a single field to the end of the event metadata buffer.
func (em *EventMetadata) AddField(name string, inType InType) { 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(name)) // Field name
binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Null terminator for name binary.Write(&em.buffer, binary.LittleEndian, byte(0)) // Null terminator for name
+12 -6
View File
@@ -16,6 +16,9 @@ const (
eventDataDescriptorTypeProviderMetadata eventDataDescriptorTypeProviderMetadata
) )
// Provider represents an ETW event provider. It is identified by a provider
// name and ID (GUID), which should always have a 1:1 mapping to each other
// (e.g. don't use multiple provider names with the same ID, or vice versa).
type Provider struct { type Provider struct {
handle providerHandle handle providerHandle
metadata *bytes.Buffer metadata *bytes.Buffer
@@ -23,6 +26,8 @@ type Provider struct {
type providerHandle windows.Handle type providerHandle windows.Handle
// EnableCallback is the form of the callback function that receives provider
// enable/disable notifications from ETW.
type EnableCallback func(*windows.GUID, uint32, byte, uint64, uint64, uintptr) type EnableCallback func(*windows.GUID, uint32, byte, uint64, uint64, uintptr)
type eventDataDescriptor struct { type eventDataDescriptor struct {
@@ -34,8 +39,9 @@ type eventDataDescriptor struct {
} }
func (descriptor *eventDataDescriptor) set(dataType eventDataDescriptorType, buffer *bytes.Buffer) { func (descriptor *eventDataDescriptor) set(dataType eventDataDescriptorType, buffer *bytes.Buffer) {
// Passing a pointer to Go-managed memory as part of a block of memory is risky since the GC doesn't know about it. // Passing a pointer to Go-managed memory as part of a block of memory is
// If we find a better way to do this we should use it instead. // risky since the GC doesn't know about it. If we find a better way to do
// this we should use it instead.
descriptor.ptr = uint64(uintptr(unsafe.Pointer(&buffer.Bytes()[0]))) descriptor.ptr = uint64(uintptr(unsafe.Pointer(&buffer.Bytes()[0])))
descriptor.size = uint32(buffer.Len()) descriptor.size = uint32(buffer.Len())
descriptor.dataType = dataType descriptor.dataType = dataType
@@ -56,10 +62,10 @@ func NewProvider(name string, id *windows.GUID, callback EnableCallback) (*Provi
} }
var metadataBuffer bytes.Buffer var metadataBuffer bytes.Buffer
binary.Write(&metadataBuffer, binary.LittleEndian, uint16(0)) binary.Write(&metadataBuffer, binary.LittleEndian, uint16(0)) // Write empty size for buffer (to update later)
binary.Write(&metadataBuffer, binary.LittleEndian, []byte(name)) binary.Write(&metadataBuffer, binary.LittleEndian, []byte(name)) // Provider name
binary.Write(&metadataBuffer, binary.LittleEndian, byte(0)) binary.Write(&metadataBuffer, binary.LittleEndian, byte(0)) // Null terminator for name
binary.LittleEndian.PutUint16(metadataBuffer.Bytes(), uint16(metadataBuffer.Len())) binary.LittleEndian.PutUint16(metadataBuffer.Bytes(), uint16(metadataBuffer.Len())) // Update the size at the beginning of the buffer
return &Provider{ return &Provider{
handle: providerHandle, handle: providerHandle,