// +build windows // +build amd64 arm64 386 package etw import ( "bytes" "encoding/binary" "unsafe" "github.com/Microsoft/go-winio/pkg/guid" "golang.org/x/sys/windows" ) // NewProviderWithOptions creates and registers a new ETW provider, allowing // the provider ID and Group to be manually specified. This is most useful when // there is an existing provider ID that must be used to conform to existing // diagnostic infrastructure. func NewProviderWithOptions(name string, options ...ProviderOpt) (provider *Provider, err error) { var opts providerOpts for _, opt := range options { opt(&opts) } if opts.id == (guid.GUID{}) { opts.id = providerIDFromName(name) } providerCallbackOnce.Do(func() { globalProviderCallback = windows.NewCallback(providerCallbackAdapter) }) provider = providers.newProvider() defer func(provider *Provider) { if err != nil { providers.removeProvider(provider) } }(provider) provider.ID = opts.id provider.callback = opts.callback if err := eventRegister((*windows.GUID)(&provider.ID), globalProviderCallback, uintptr(provider.index), &provider.handle); err != nil { return nil, err } trait := &bytes.Buffer{} if opts.group != (guid.GUID{}) { binary.Write(trait, binary.LittleEndian, uint16(0)) // Write empty size for buffer (update later) binary.Write(trait, binary.LittleEndian, uint8(1)) // EtwProviderTraitTypeGroup traitArray := opts.group.ToWindowsArray() // Append group guid trait.Write(traitArray[:]) binary.LittleEndian.PutUint16(trait.Bytes(), uint16(trait.Len())) // Update size } metadata := &bytes.Buffer{} 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 trait.WriteTo(metadata) // Add traits if applicable binary.LittleEndian.PutUint16(metadata.Bytes(), uint16(metadata.Len())) // Update the size at the beginning of the buffer provider.metadata = metadata.Bytes() if err := eventSetInformation( provider.handle, eventInfoClassProviderSetTraits, uintptr(unsafe.Pointer(&provider.metadata[0])), uint32(len(provider.metadata))); err != nil { return nil, err } return provider, nil }