Sitemap
Expedia Group Technology

Stories from the Expedia Group Technology teams

EXPEDIA GROUP TECHNOLOGY — SOFTWARE

How we got Zipkin Brave to accept UUIDs

7 min readAug 27, 2020

--

Photo by Bhumika Singh on Unsplash
the /my-trips trace consists of several spans, a /auth one, and a /trips one which itself has /tracking and /flights spans
The whole graph represents a trace and every box represents a span

Once upon a time…

/**
* Extra holds the information of the inbound context to be kept
* and use as replacement in propagation and reporting.
*/
internal data class OriginalIDs(
val traceIdAsUUID: String, // The incoming trace ID in UUID
val spanIdAsUUID: String, // The incoming span ID in UUID
val parentSpanIdAsUUID: String?, // The incoming parent span ID
// in UUID
val syntheticRootSpanId: Long, // The synthetic local root span
// ID for the trace
)
// Copied from Brave as we need to generate IDs in the same way https://github.com/openzipkin/brave/blob/ae2b26adda/brave/src/main/java/brave/Tracer.java#L645private fun nextId(): Long {
var nextId = Platform.get().randomLong()
while (nextId < 0L) {
nextId = Platform.get().randomLong()
}
return nextId
}
internal class Extractor<C, K>(
private val propagation: UUIDPropagation,
private val getter: Propagation.Getter<C, K>,
): TraceContext.Extractor<C> {
override fun extract(carrier: C): TraceContextOrSamplingFlags {
var samplingFlags = SamplingFlags.EMPTY
if (getter.get(carrier, propagation.debugKey) != null) {
samplingFlags = SamplingFlags.DEBUG
}
val traceIdAsUIDString = getter.get(carrier, propagation.traceIdKey) ?: return TraceContextOrSamplingFlags.create(samplingFlags)

val spanIdAsUIDString = getter.get(carrier, propagation.spanIdKey) ?: return TraceContextOrSamplingFlags.create(samplingFlags)
val parentIdAsUIDString = getter.get(carrier, propagation.parentSpanIdKey) ?: null var result = TraceContext.newBuilder() val syntheticRootSpanId = nextId() val extra = OriginalIDs(traceIdAsUIDString, spanIdAsUIDString, parentIdAsUIDString, syntheticRootSpanId) result = result
.sampled(true)
.debug(samplingFlags.debug())
// we will always replace the traceId
.traceId(nextId())
.traceIdHigh(nextId())
// if spanId == syntheticRootSpanId we replace the
// spanId from the original IDs
.spanId(syntheticRootSpanId)
.extra(listOf(extra))
if (parentIdAsUIDString != null) {
// if spanId == syntheticRootSpanId we replace the
// parent from the original IDs
result.parentId(nextId())
}

return TraceContextOrSamplingFlags.create(result.build())
}}
val spanIdAsUUID = new UUID(0L, context.spanId)
import zipkin2.Span;...public interface Reporter<S> {
/**
* Schedules the span to be sent onto the transport.
*
* @param span Span, should not be <code>null</code>.
*/
void report(S span);
}
...import brave.handler.MutableSpan as ZipkinMutableSpanobject SyntheticTagsHandler : FinishedSpanHandler() {
private const val SYNTHETIC_ID = "x-message-propagation-synthetic-id"
private const val TRACE_ID = "x-message-propagation-trace-id"
private const val SPAN_ID = "x-message-propagation-span-id"
private const val PARENT_SPAN_ID = "x-message-propagation-parent-id"
override fun handle(context: TraceContext, span: ZipkinMutableSpan): Boolean {
val originalIDs = context.findExtra(OriginalIDs::class.java) ?: return
span.tag(SYNTHETIC_ID, originalIDs.syntheticId.toString(16).padStart(16, ‘0’))
span.tag(TRACE_ID, originalIDs.traceId)
span.tag(SPAN_ID, originalIDs.spanId)
if (originalIDs.parentSpanId != null) {
span.tag(PARENT_SPAN_ID, originalIDs.parentSpanId)
}
return true
}
internal fun isSyntheticTag(key: String): Boolean {
return key == SYNTHETIC_ID
|| key == TRACE_ID
|| key == SPAN_ID
|| key == PARENT_SPAN_ID
}
private fun getTraceId(tags: Map<String, String>): String = tags[TRACE_ID] ?: throw NullPointerException("Missing $TRACE_ID synthetic tag") private fun getSyntheticId(tags: Map<String, String>): String = tags[SYNTHETIC_ID] ?: throw NullPointerException("Missing $SYNTHETIC_ID synthetic tag") private fun getSpanId(tags: Map<String, String>): String = tags[SPAN_ID] ?: throw NullPointerException("Missing $SPAN_ID synthetic tag") private fun getParentId(tags: Map<String, String>): String? = tags[PARENT_SPAN_ID]
}

--

--

Expedia Group Technology
Expedia Group Technology
José Carlos Chávez
José Carlos Chávez

Written by José Carlos Chávez

Software Engineer @Traceableai, ex @ExpediaGroup. Wine lover and Llama ambassador

Responses (1)