rebuilding trees with span links

Home Feed
2026-10-25 observability

So when a service needs to take payment, the control moves through its own processes and out across the network. At the moments that matter, the developer adds print statements to flush some logs at runtime. Each log is a span in the telemetry world, and the timestamp tells you when the event occurred.

The payment service is usually run by a different company. Your backend calls makePayment(card, amount) and the call leaves the system. Control is no longer inside your app. The service waits, the payment service does its work, and a response comes back. Until that moment, you can keep a tree of spans, but once the call leaves, the tree stops. The internals of makePayment are invisible and you only get the response. The same break happens across microservices. One service’s code is not visible to the next. They talk through RPCs or queues.

In the early days of Dapper, the developers at Google wanted a view of the entire request, even when it spanned multiple machines. Spans share a trace ID when linked. When everything stays inside systems you control and stays synchronous, you can see through to the end by travelling the tree. When the work is async, or when control leaves and comes back later, the pure tree does not hold. The logs can stop in the middle.

Span links exist for that case. You connect the end of one piece of work to the start of another. The spans stay loosely (causally) coupled because the control itself was loosely coupled. You can still walk from the initial request to the final response, but the graph has gaps and extra edges instead of a single hierarchy.

One way to causally couple is to insert the ID of the last span of the previous trace into the first span in the next trace. Even though neither side shares a continuous stack, the ID is just carried across, so the logical connection does not die when control leaves and returns. That is useful when a request comes from a different place, goes out to an external service, and the response arrives async.