Implement Stackdriver Propagation · Issue #1992 · census-instrumentation/opencensus-java · GitHub
Skip to content
This repository was archived by the owner on Dec 23, 2023. It is now read-only.
This repository was archived by the owner on Dec 23, 2023. It is now read-only.

Implement Stackdriver Propagation #1992

Open

Description

@philicious

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

Activity

  1. philicious commented on Dec 10, 2019

    @philicious
    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)
        }
    }
  2. danielcompton commented on Mar 11, 2020

    @danielcompton

    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 join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions