How to figure out the relationship between tracing spans from the headers when using W3C Trace Context

Viewed 441

I've been reading the W3C Trace Context spec and I can't figure out how to get child-of relationships between spans from just looking at the headers in my requests.

Assuming I understand the processing model correctly, the first service generates a traceparent, while subsequent services replace the parentId within the traceparent for downstream requests.

So Service A generates a traceparent and sends a request to Service B:

host: service-b
traceparent: 00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01

Service B receives the requests and does two downstream requests to Service C and Service D each time changing the parentId:

host: service-c
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
host: service-d
traceparent: 00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01

At the end I have three traceparents in my requests

00-0af7651916cd43dd8448eb211c80319c-00f067aa0ba902b7-01
00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
00-0af7651916cd43dd8448eb211c80319c-b9c7c989f97918e1-01

It's easy to see that they all belong to the trace 0af7651916cd43dd8448eb211c80319c, but how do I figure out the parent child relationship between them?

My initial thought was that this is done using tracestate, but the spec states:

tracestate extends traceparent with vendor-specific data represented by a set of name/value pairs. Storing information in tracestate is optional.

1 Answers

As you said before, the tracestate field is responsible for propagate only the vendor-specific data. Moreover, the traceparent itself doesn't carry enough upstream-downstream relationship information. The trace context solves three problems: provide an unique identifier for individual traces, provide an agreed-upon mechanism to forward vendor-specific trace data (tracestate) and provide an industry standard that intermediaries, platforms, and hardware providers can support. If you want to build the upstream-downstream (or parent-child) relationship you'll need the traceparent of the current span scope and also the upstream's traceparent. Take a look at an example in c# .NET 5:

using System;
using System.Diagnostics;

var upstreamActivity = new Activity("Upstream");

upstreamActivity.Start();
Console.WriteLine(upstreamActivity.OperationName);
Console.WriteLine("traceparent: {0}", upstreamActivity.Id);
Console.WriteLine("upstream traceparent: {0}", upstreamActivity.ParentId);
CallChildActivity();
upstreamActivity.Stop();

void CallChildActivity()
{
    var downstreamActivity = new Activity("Downstream Dependency");

    downstreamActivity.Start();
    Console.WriteLine(downstreamActivity.OperationName);
    Console.WriteLine("traceparent: {0}", downstreamActivity.Id);
    Console.WriteLine("upstream traceparent: {0}", downstreamActivity.ParentId);
    downstreamActivity.Stop();
}

the stdout will show something like this:

Upstream
traceparent: 00-192400a99d30ee459dce14655b09bc41-587841dea0e59b47-00
upstream traceparent:

Downstream Dependency
traceparent: 00-192400a99d30ee459dce14655b09bc41-d95c56215cddd74c-00
upstream traceparent: 00-192400a99d30ee459dce14655b09bc41-587841dea0e59b47-00

the upstream traceparent of the first Activity is empty, this means: that's the first activity of the whole trace. On the other hand, the second method has a not empty ParentId, so that's the identification of the upstream activity. Note that the term ParentId is different from the parent-id of the w3c spec, in .NET 5 it represents the upstream identification. Besides that, the parent-id field is called span-id in .NET 5.

That's the same concept of the stack trace, you need both ids to build the parent-child relationship (I wrote about it in this article). If you're using a framework, middleware or library different from System.Diagnostics and it doesn't provide the upstream traceparent, keep in mind that you'll need to store it in the moment it arrives at the new span scope. In other words, before the parent-id/span-id traceparent's update.

Related