Expand description

TraceLoggingDynamic for Rust

tracelogging_dynamic provides a flexible way to log TraceLogging (manifest-free) events to ETW (Event Tracing for Windows). The events can be generated and collected on Windows Vista or later. The events can be decoded on Windows 10 or later.

This “dynamic” implementation of TraceLogging is more flexible than the implementation in the tracelogging crate. For example, it supports runtime-defined schema and can easily log arrays of strings. However, it is harder to use, it has higher runtime costs, and it depends on the alloc crate. This dynamic implementation is intended for use only when the set of events cannot be determined at compile-time. For example, tracelogging_dynamic might be used to implement a middle-layer library providing ETW support to a scripting language like JavaScript or Python. In other cases, use the tracelogging crate instead of this crate.

Overview

  • Create a pinned Provider object, e.g.

    • let provider = pin!(Provider::new("MyCompany.MyComponent", &tld::Provider::options()));
    • let provider = Box::pin(Provider::new("MyCompany.MyComponent", &tld::Provider::options()));
  • Call Provider::register to open the connection to ETW, e.g.

    unsafe { provider.as_ref().register(); }

    • Safety: Provider::register is unsafe because a registered provider must be properly unregistered. This happens automatically when the provider is dropped, so you usually don’t need to worry about this, but it can be an issue in cases where dropping does not occur such as with static variables.
  • As needed, use an EventBuilder to construct and write events.

  • The provider will automatically unregister when it is dropped. You can manually call Provider::unregister if you want to unregister sooner or if the provider is a static variable.

Example

use tracelogging_dynamic as tld;

// Pinning is required because the register() method sets up a callback with ETW.
let provider = Box::pin(tld::Provider::new(
    "MyCompany.MyComponent",
    &tld::Provider::options()));

// Register the provider. If you don't register (or if register fails) then enabled()
// will always return false and write() will be a  no-op.
unsafe {
    provider.as_ref().register();
}

// If provider is not enabled for a given level + keyword, the write() call will do
// nothing. Check enabled(level, keyword) before building the event so we don't waste
// time on an event that nobody will receive.
let my_event_level = tld::Level::Verbose; // Severity level.
let my_event_keyword = 0x123; // User-defined category bits.
if provider.enabled(my_event_level, my_event_keyword) {
    let field1_value = "FieldValue";
    let field2_value = b'A';
    // Create and write an event with two fields:
    tld::EventBuilder::new()
        // Most events specify 0 for event tag.
        .reset("MyEventName", my_event_level, my_event_keyword, 0)
        // Most fields use Default for event format and 0 for field tag.
        .add_str8("FieldName1", field1_value, tld::OutType::Default, 0)
        .add_u8("FieldName2", field2_value, tld::OutType::String, 0)
        // If activity_id is None, event uses the current thread's activity.
        // If related_id is None, event will not have a related activity.
        .write(&provider, None, None);
}

Notes

The EventBuilder object is reusable. You may get a small performance benefit by reusing an EventBuilder object for multiple events rather than using a new EventBuilder for each event.

ETW events are limited in size (event size = headers + metadata + data). Windows will ignore any event that is larger than 64KB and will ignore any event that is larger than the buffer size of the recording session.

Most ETW decoding tools are unable to decode an event with more than 128 fields.

Collect the events using Windows SDK tools like traceview or tracelog. Decode the events using Windows SDK tools like traceview or tracefmt. For example, to collect events from a provider that was registered as provider.register("MyCompany.MyComponent", ...):

tracelog -start MyTrace -f MyTraceFile.etl -guid *MyCompany.MyComponent -level 5 -matchanykw 0xf
<run your program>
tracelog -stop MyTrace
tracefmt -o MyTraceData.txt MyTraceFile.etl

Modules

Macros

Structs

  • Advanced: Indicates routing and decoding for an event.
  • EventBuilder is a builder for events to be written through a Provider.
  • GUID (UUID). with host-endian in-memory representation (as expected by the ETW APIs).
  • Advanced: Used to indicate the field’s type for raw metadata operations.
  • Indicates the severity of an event. Use Verbose if unsure.
  • Indicates special semantics to be used by the event decoder for grouping and organizing events, e.g. for activities.
  • Data formatting hint that may be used or ignored by decoders.
  • Represents a connection for writing dynamic TraceLogging (manifest-free) events to ETW.
  • Builder for advanced provider configuration. Used when registering a provider.

Enums

  • Possible configurations under which this crate can be compiled: Windows or Other.

Constants

Type Definitions