diff --git a/packages/dd-trace/src/opentelemetry/context_manager.js b/packages/dd-trace/src/opentelemetry/context_manager.js index 430626bbd7e..800a309dc47 100644 --- a/packages/dd-trace/src/opentelemetry/context_manager.js +++ b/packages/dd-trace/src/opentelemetry/context_manager.js @@ -1,7 +1,7 @@ 'use strict' const { storage } = require('../../../datadog-core') -const { trace, ROOT_CONTEXT } = require('@opentelemetry/api') +const { trace, ROOT_CONTEXT, propagation } = require('@opentelemetry/api') const DataDogSpanContext = require('../opentracing/span_context') const SpanContext = require('./span_context') @@ -21,14 +21,25 @@ class ContextManager { return context } + let otelBaggages + const baggages = JSON.parse(activeSpan.getAllBaggageItems()) + if (Object.keys(baggages).length) { + const entries = {} + for (const [key, value] of Object.entries(baggages)) { + entries[key] = { value } + } + otelBaggages = propagation.createBaggage(entries) + } + if (!context._otelSpanContext) { const newSpanContext = new SpanContext(context) context._otelSpanContext = newSpanContext } if (store && trace.getSpanContext(store) === context._otelSpanContext) { - return store + return otelBaggages ? propagation.setBaggage(store, otelBaggages) : store } - return trace.setSpanContext(store || ROOT_CONTEXT, context._otelSpanContext) + const wrappedContext = trace.setSpanContext(store || ROOT_CONTEXT, context._otelSpanContext) + return otelBaggages ? propagation.setBaggage(wrappedContext, otelBaggages) : wrappedContext } with (context, fn, thisArg, ...args) { @@ -39,6 +50,18 @@ class ContextManager { return this._store.run(context, cb, ...args) } if (span && span._ddSpan) { + // remove all baggage items? + const baggages = propagation.getBaggage(context) + if (baggages) { + const baggageItems = baggages.getAllEntries() + if (baggageItems.length) { + for (const baggage of baggageItems) { + const key = baggage[0] + const value = baggage[1].value + span._ddSpan.setBaggageItem(key, value) + } + } + } return ddScope.activate(span._ddSpan, run) } return run() diff --git a/packages/dd-trace/test/opentelemetry/context_manager.spec.js b/packages/dd-trace/test/opentelemetry/context_manager.spec.js index ebf8f122d87..3121ca1df54 100644 --- a/packages/dd-trace/test/opentelemetry/context_manager.spec.js +++ b/packages/dd-trace/test/opentelemetry/context_manager.spec.js @@ -4,8 +4,17 @@ require('../setup/tap') const { expect } = require('chai') const ContextManager = require('../../src/opentelemetry/context_manager') -const { ROOT_CONTEXT } = require('@opentelemetry/api') +const TracerProvider = require('../../src/opentelemetry/tracer_provider') +const { context, propagation, trace, ROOT_CONTEXT } = require('@opentelemetry/api') const api = require('@opentelemetry/api') +const tracer = require('../../').init() + +function makeSpan (...args) { + const tracerProvider = new TracerProvider() + tracerProvider.register() + const tracer = tracerProvider.getTracer() + return tracer.startSpan(...args) +} describe('OTel Context Manager', () => { let contextManager @@ -114,4 +123,61 @@ describe('OTel Context Manager', () => { }) expect(ret).to.equal('return value') }) + + it('should propagate baggage from an otel span to a datadog span', () => { + const entries = { + foo : { value: 'bar' } + } + const baggage = propagation.createBaggage(entries) + const contextWithBaggage = propagation.setBaggage(context.active(), baggage) + const span = makeSpan('otel-to-dd') + const contextWithSpan = trace.setSpan(contextWithBaggage, span) + api.context.with(contextWithSpan, () => { + expect(span._ddSpan.getBaggageItem('foo')).to.be.equal('bar') + }) + }) + + it('should propagate baggage from a datadog span to an otel span', () => { + const baggageKey = 'raccoon' + const baggageVal = 'chunky' + const ddSpan = tracer.startSpan('dd-to-otel') + ddSpan.setBaggageItem(baggageKey, baggageVal) + tracer.scope().activate(ddSpan, () => { + const baggages = propagation.getBaggage(api.context.active()).getAllEntries() + expect(baggages.length).to.equal(1) + const baggage = baggages[0] + expect(baggage[0]).to.equal(baggageKey) + expect(baggage[1].value).to.equal(baggageVal) + }) + }) + + // it('should handle dd-otel baggage conflict on a datadog span', () => { + // // const ddSpan = tracer.startSpan('dd') + // // ddSpan.setBaggageItem('key', 'dd') + // // let baggageContext + // // tracer.scope().activate(ddSpan, () => { + // // const entries = { + // // key : { value: 'otel' }, + // // } + // // const baggage = propagation.createBaggage(entries) + // // baggageContext = propagation.setBaggage(api.context.active(), baggage) + // // }) + // // const otelSpan = makeSpan('otel') + // // const contextWithSpan = trace.setSpan(baggageContext, otelSpan) + // // api.context.with(contextWithSpan, () => { + // // expect(span._ddSpan.getBaggageItem('foo')).to.be.equal('bar') + // // }) + // tracer.trace('ddSpan', (ddSpan) => { + // ddSpan.setBaggageItem('key', 'dd') + // const otelSpan = makeSpan('otelSpan') + // const entries = { + // key : { value: 'otel' }, + // } + // const baggage = propagation.createBaggage(entries) + // baggageContext = propagation.setBaggage(otelSpan.spanContext(), baggage) + // // api.context.with(baggageContext, () => { + // // console.log(ddSpan.context()) + // // }) + // }) + // }) })