TRACELOGGING_DEFINE_PROVIDER macro (traceloggingprovider.h)
Defines a handle for a TraceLogging provider.
Syntax
void TRACELOGGING_DEFINE_PROVIDER(
[in] handleVariable,
[in] providerName,
[in] providerId,
[in, optional] __VA_ARGS__
);
Parameters
[in] handleVariable
The name to use for the provider's handle, using your component's naming
conventions for global variables, e.g. MyComponentLog
or g_hMyProvider
.
[in] providerName
A string literal with the name of the TraceLogging provider. This name should be
specific to your organization and component so that it does not conflict with
providers from other components. This name string will be included within each
ETW event generated by the provider, so try to use a relatively short name. For
example, you might use a name like "MyCompany.MyComponent"
or
"MyCompany.MyOrganization.MyComponent"
.
This must be a string literal. Do not use a variable.
[in] providerId
The ETW Control GUID for the provider, specified as a comma-separated list of 11
integers in parentheses. For example, the GUID
{ce5fa4ea-ab00-5402-8b76-9f76ac858fb5}
would be expressed as
(0xce5fa4ea,0xab00,0x5402,0x8b,0x76,0x9f,0x76,0xac,0x85,0x8f,0xb5)
.
While any unique GUID can be used for the provider ID, Microsoft recommends using a GUID generated from the provider name using the ETW name-hashing algorithm. See below for information about generating the provider ID.
[in, optional] __VA_ARGS__
Optional parameters for the provider. Most providers do not need to specify any optional parameters.
If you want your provider to be associated with an
ETW provider group, add the
TraceLoggingOptionGroup
macro to specify the provider's group GUID. Otherwise, do not specify any
__VA_ARGS__
parameters.
Return value
None
Remarks
A TraceLogging provider is a connection by which events can be sent to ETW. The
TRACELOGGING_DEFINE_PROVIDER
macro defines a TraceLogging provider and creates
a handle that can be used to access it. It also records provider information
such as the provider's name and GUID.
This macro should be invoked in a .c or .cpp file to define the handle for a
TraceLogging provider. For example, if my provider is named
MyCompany.MyComponent
and the control GUID is
{ce5fa4ea-ab00-5402-8b76-9f76ac858fb5}
then I would define the provider by
adding the following code to one of the .c or .cpp files in my component:
TRACELOGGING_DEFINE_PROVIDER( // defines g_hProvider
g_hProvider, // Name of the provider handle
"MyCompany.MyComponent", // Human-readable name for the provider
// {ce5fa4ea-ab00-5402-8b76-9f76ac858fb5}
(0xce5fa4ea,0xab00,0x5402,0x8b,0x76,0x9f,0x76,0xac,0x85,0x8f,0xb5));
The above TRACELOGGING_DEFINE_PROVIDER
macro can be thought of as defining a
g_hMyProvider
provider handle constant, similar to code like:
const TraceLoggingHProvider g_hMyProvider = ...;
The resulting handle has module scope and can be used anywhere within the EXE, DLL, or SYS module in which it is defined. Use the TRACELOGGING_DECLARE_PROVIDER macro as needed (e.g. in a header) to forward-declare the handle so that it can be used by other .c or .cpp files in your component.
When a component starts running, the provider will be in an unregistered state.
Any attempts to use it to generate events will be silently ignored. Before it
can respond to any write calls, you need to register the provider using
TraceLoggingRegister. This
is typically done during component startup, e.g. in main
, wmain
, WinMain
,
DllMain(DLL_PROCESS_ATTACH)
, or DriverEntry
. At component shutdown,
unregister the provider by calling
TraceLoggingUnregister.
Note
The provider handle defined by TRACELOGGING_DEFINE_PROVIDER
is
scoped to the module. The handle can be used as needed within the EXE, DLL, or
SYS file, but it should not be used outside the scope of the module, i.e. it
should not be passed to other DLLs in the same process. Each EXE, DLL, or SYS
file should use its own provider handle and should perform its own Register
and Unregister. In debug builds, an assertion will fire if you attempt to
write using a provider handle from another module.
Provider Name and ID
ETW performs event filtering and routing using the provider ID (also called the
Provider GUID or Control GUID). For example, if you have a provider named
MyCompany.MyComponent
with provider ID
{ce5fa4ea-ab00-5402-8b76-9f76ac858fb5}
then you might start a trace to capture
events from this provider using a
tracelog command like
tracelog -start MySessionName -f MySession.etl -guid #ce5fa4ea-ab00-5402-8b76-9f76ac858fb5
.
All ETW providers are identified by both provider name and provider ID. Both the name and the ID need to be unique so they do not conflict with other providers. In addition, the name and the ID should be linked: once a particular name is used with a particular ID for an ETW provider, that name should not be used with any other ID and that ID should not be used with any other name.
The provider ID can be any unique GUID, such one generated using the guidgen
SDK tool or https://uuidgen.org. However, instead of
using a randomly-generated GUID for the provider ID, Microsoft recommends
generating the provider ID from the provider name using the ETW name-hashing
algorithm described below. This provides several benefits: it's easier to
remember just the name; the ID and the name are automatically linked; tools such
as tracelog, traceview, EventSource, and WPR have special support for providers
that use IDs generated using this algorithm.
For example, if you have a provider named MyCompany.MyComponent
with provider
ID {ce5fa4ea-ab00-5402-8b76-9f76ac858fb5}
then you might start a trace to
capture events from this provider using a
tracelog command like
tracelog -start MySessionName -f MySession.etl -guid *MyCompany.MyComponent
.
This works because provider ID {ce5fa4ea-ab00-5402-8b76-9f76ac858fb5}
was
generated by hashing the provider name MyCompany.MyComponent
, so the tracefmt
tool considers -guid *MyCompany.MyComponent
to be equivalent to
-guid #ce5fa4ea-ab00-5402-8b76-9f76ac858fb5
.
You can use PowerShell to obtain the provider ID for a particular provider name using the ETW name-hashing algorithm via the EventSource class:
[System.Diagnostics.Tracing.EventSource]::new("MyCompany.MyComponent").Guid
Results:
Guid
----
ce5fa4ea-ab00-5402-8b76-9f76ac858fb5
In C#, the ETW name-hashing algorithm can be implemented as follows:
static Guid ProviderIdFromName(string name)
{
var signature = new byte[] {
0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8,
0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB };
var nameBytes = System.Text.Encoding.BigEndianUnicode.GetBytes(name.ToUpperInvariant());
using (var sha1 = new System.Security.Cryptography.SHA1Managed())
{
sha1.TransformBlock(signature, 0, signature.Length, null, 0);
sha1.TransformFinalBlock(nameBytes, 0, nameBytes.Length);
var hash = sha1.Hash;
Array.Resize(ref hash, 16);
hash[7] = (byte)((hash[7] & 0x0F) | 0x50);
return new Guid(hash);
}
}
Examples
#include <windows.h> // or <wdm.h> for kernel-mode.
#include <winmeta.h> // For event level definitions.
#include <TraceLoggingProvider.h>
TRACELOGGING_DEFINE_PROVIDER( // defines g_hProvider
g_hProvider, // Name of the provider handle
"MyCompany.MyComponent", // Human-readable name for the provider
// {ce5fa4ea-ab00-5402-8b76-9f76ac858fb5}
(0xce5fa4ea,0xab00,0x5402,0x8b,0x76,0x9f,0x76,0xac,0x85,0x8f,0xb5));
int main(int argc, char* argv[]) // or DriverEntry for kernel-mode.
{
TraceLoggingRegister(g_hProvider);
TraceLoggingWrite(
g_hProvider,
"MyEvent1",
TraceLoggingLevel(WINEVENT_LEVEL_WARNING), // Levels defined in <winmeta.h>
TraceLoggingKeyword(MyEventCategories), // Provider-defined categories
TraceLoggingString(argv[0], "arg0"), // field name is "arg0"
TraceLoggingInt32(argc)); // field name is implicitly "argc"
TraceLoggingUnregister(g_hProvider);
return 0;
}
Requirements
Requirement | Value |
---|---|
Minimum supported client | Windows Vista [desktop apps | UWP apps] |
Minimum supported server | Windows Server 2008 [desktop apps | UWP apps] |
Target Platform | Windows |
Header | traceloggingprovider.h |