Skip to content
This repository has been archived by the owner on Dec 23, 2023. It is now read-only.

Implement Stackdriver Propagation #1992

Open
philicious opened this issue Oct 31, 2019 · 2 comments
Open

Implement Stackdriver Propagation #1992

philicious opened this issue Oct 31, 2019 · 2 comments

Comments

@philicious
Copy link

For distributed tracing in GCP (Google Cloud Platform), the Google LoadBalancers add x-cloud-trace-context header with format "X-Cloud-Trace-Context: TRACE_ID/SPAN_ID;o=TRACE_TRUE"

These 3 values need to be set in SpanContext

@philicious
Copy link
Author

as we needed this feature, my dear colleague @martinheld implemented the class directly in our service to save time. ( inspired by https://github.com/census-instrumentation/opencensus-node/blob/master/packages/opencensus-propagation-stackdriver/src/stackdriver-format.ts )

unfortunately we didnt find the time afterwards to make a proper PR here. reasons:

  • it was coded in Kotlin and not Java as the opencensus lib
  • inject fun is still missing (we didnt need it)
  • trace-options from header ( ;o=TRACE_TRUE (0 or 1) ) is not respected and hardcoded as true

however wanted to share the code as it might help people. anyone is invited to take it and maybe someone makes a proper PR for this !

its used simply like

val tracer = Tracing.getTracer()
val spanContext = OpencensusStackdriverPropagation.extract(call.request)
val rootSpan = tracer.spanBuilderWithRemoteParent("my-span-name", spanContext).startScopedSpan()
...
import io.ktor.request.ApplicationRequest
import io.ktor.request.header
import io.opencensus.trace.SpanContext
import io.opencensus.trace.TraceId
import io.opencensus.trace.SpanId
import io.opencensus.trace.TraceOptions
import io.opencensus.trace.Tracestate

object OpencensusStackdriverPropagation {

    val TRACE_CONTEXT_HEADER_NAME = "x-cloud-trace-context"
    val TRACE_TRUE = 0x1

    fun extract(request: ApplicationRequest): SpanContext? {
        val traceContextHeader = request.header(TRACE_CONTEXT_HEADER_NAME)

        logger.debug("$TRACE_CONTEXT_HEADER_NAME: $traceContextHeader")

        if (traceContextHeader == null) return null

        lateinit var traceParams: Triple<String?, String?, Int?>

        try {
            traceParams = getTraceParams(traceContextHeader)
        } catch (e: Exception) {
            logger.error(e.message)
            return null
        }

        return getSpanContext(traceParams)
    }

    private fun getSpanContext(traceParams: Triple<String?, String?, Int?>): SpanContext? {
        val (traceId, spanId, options) = traceParams

        if (traceId != null && spanId != null && options != null) {
            val traceIdObj  = TraceId.fromLowerBase16(traceId)
            val spanIdObj  = SpanId.fromLowerBase16(spanId)
            val optionsObj = TraceOptions.fromByte(options.toByte())

            val spanContext = SpanContext.create(traceIdObj, spanIdObj, optionsObj, Tracestate.builder().build())
            logger.debug("returning SpanContext: $spanContext")
            return spanContext
        }

        return null
    }

    private fun getTraceParams(traceContextHeader: String): Triple<String?, String?, Int?> {

        val regex = """([0-9a-fA-F]+)(?:\/([0-9]+))""".toRegex()
        val matchResult = regex.find(traceContextHeader)

        if (matchResult == null || matchResult.groups.size <3) {
            logger.debug("Parsing tracing context header failed")
            return Triple(null, null, null)
        }

        val(traceId, parsedSpanId) = matchResult.destructured

        val spanIdHex = parsedSpanId.toULong().toString(16)
        val spanId = "0000000000000000$spanIdHex".takeLast(16)

        val options = TRACE_TRUE

        return Triple(traceId, spanId, options)
    }
}

@danielcompton
Copy link

danielcompton commented Mar 11, 2020

Thanks for the tips here @philicious. I was working on this yesterday, and I found the algorithm Zipkin uses for parsing the X-Cloud-Trace-Context header:

https://github.com/openzipkin/zipkin-gcp/blob/14b59d13ac5126e3fa677952a86ce1fcb96e9e3a/propagation-stackdriver/src/main/java/zipkin2/propagation/stackdriver/XCloudTraceContextExtractor.java#L44-L95

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants