Skip to content

Trace Configuration

The Trace feature of the Windows SDK injects distributed trace headers into HTTP requests and associates the generated trace_id and span_id with the corresponding RUM Resources. The SDK does not create or upload independent APM Spans.

Trace Initialization Configuration

GuanceSdk.Init(new GuanceConfig
{
    DatawayUrl = "https://openway.truewatch.com",
    ClientToken = "<client-token>",
    RumAppId = "<rum-app-id>",
    Trace = new TraceConfig
    {
        EnableAutoTrace = true,
        EnableLinkRumData = true,
        SampleRate = 1.0,
        TraceType = TraceType.TraceParent,
        ShouldTrace = uri =>
            uri.Scheme == Uri.UriSchemeHttps &&
            uri.Host == "api.example.com"
    }
});
#include <string>

static int should_trace(const char* url, const char*, void*)
{
    const std::string value = url == nullptr ? "" : url;
    return value == "https://api.example.com" ||
        value.rfind("https://api.example.com/", 0) == 0;
}

guance_trace_config trace;
guance_trace_config_init(&trace);
trace.enable_auto_trace = 1;
trace.enable_link_rum_data = 1;
trace.sample_rate = 1.0;
trace.trace_type = GUANCE_TRACE_TRACEPARENT;
trace.should_trace = should_trace;

if (!guance_trace_configure(rum, &trace)) {
    // Invalid configuration, Trace not enabled.
}

Configuration Parameters

Description .NET / C# Native C/C++ Default
Auto-generate Trace Context EnableAutoTrace enable_auto_trace false / 0
Link RUM Resources EnableLinkRumData enable_link_rum_data false / 0
Propagation Sample Rate SampleRate sample_rate 1.0
Propagation Format TraceType trace_type DDTrace
Target Filter ShouldTrace should_trace Empty
Custom Context ContextProvider context_provider Empty
Callback Context Closure user_data Empty

The Trace sample rate only controls the sampled flag in the propagation protocol; it does not replace the RUM Session sample rate.

Supported Propagation Formats

C# Native C/C++ Header
TraceType.DdTrace GUANCE_TRACE_DDTRACE x-datadog-*
TraceType.ZipkinMultiHeader GUANCE_TRACE_ZIPKIN_MULTI_HEADER X-B3-TraceIdX-B3-SpanIdX-B3-Sampled
TraceType.ZipkinSingleHeader GUANCE_TRACE_ZIPKIN_SINGLE_HEADER b3
TraceType.TraceParent GUANCE_TRACE_TRACEPARENT traceparent
TraceType.SkyWalking GUANCE_TRACE_SKYWALKING sw8
TraceType.Jaeger GUANCE_TRACE_JAEGER uber-trace-id

The server or Agent must support the selected propagation format.

Tracer Network Distributed Tracing

After enabling automatic collection for HttpClient, the SDK applies the Trace configuration before sending the request:

GuanceSdk.EnableAutomaticInstrumentation(new AutomaticInstrumentationOptions
{
    EnableHttpClient = true
});

using var http = new HttpClient();
await http.GetAsync("https://api.example.com/items");

When you need to explicitly control the Handler, use:

using var http = new HttpClient(
    GuanceSdk.CreateHttpMessageHandler(new HttpClientHandler()));

C++ WinHTTP applications use guance_rum_winhttp.hpp. The adapter generates headers, completes the request, and writes the same IDs into the RUM Resource:

guance::rum::WinHttpResource resource(
    rum,
    request,
    "https://api.example.com/items",
    "GET");

if (resource.send()) {
    resource.receive();
}

Asynchronous WinHTTP requires the WinHttpRequestMode::asynchronous mode; keep the object alive until the completion callback, and call complete_from_response() after the headers are available.

Custom Trace Context

ContextProvider can return custom headers and associated identifiers:

ContextProvider = request => new TraceContext(
    new Dictionary<string, string>
    {
        ["traceparent"] = CreateTraceParent()
    },
    traceId: currentTraceId,
    spanId: currentSpanId)

When the Provider returns null or an invalid Header, the SDK skips the Trace for this request without interrupting the host request.

Non-WinHTTP network libraries can generate a context and write the headers themselves:

guance_trace_context context;
guance_trace_context_init(&context);

if (guance_trace_create_context(
        rum,
        "https://api.example.com/items",
        "GET",
        &context)) {
    for (uint32_t index = 0; index < context.header_count; ++index) {
        const char* name = context.headers[index].name;
        const char* value = context.headers[index].value;
        // Write the header using the current network library.
    }
}

When collecting the Resource manually, pass context.trace_id and context.span_id to guance_rum_stop_resource_ext(). Only associate them when context.link_rum_data != 0.

Security Boundaries

Restrict Destination of Trace Headers

When no target filter is configured, any absolute URL that enters the automatic Trace collection boundary may receive Trace Headers. In production, set an explicit whitelist based on protocol, hostname, and port to avoid sending trace context to third parties.

The native configuration copies strings, but retains the callback and user_data. They must remain valid until reconfiguration or guance_sdk_shutdown(). The callback may be called concurrently by multiple request threads; do not let C++ exceptions cross the C ABI.