Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: requires user to pass context to propagation APIs #1734

Merged
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const axios = require("axios");
const { HttpTraceContext } = require("@opentelemetry/core");
const { BasicTracerProvider } = require("@opentelemetry/tracing");
const { context, propagation, trace } = require("@opentelemetry/api");
const { context, propagation, trace, ROOT_CONTEXT } = require("@opentelemetry/api");
const {
AsyncHooksContextManager,
} = require("@opentelemetry/context-async-hooks");
Expand Down Expand Up @@ -31,14 +31,14 @@ app.use(bodyParser.json());

// Mount our demo route
app.post("/verify-tracecontext", (req, res) => {
context.with(propagation.extract(req.headers), () => {
context.with(propagation.extract(ROOT_CONTEXT, req.headers), () => {
Promise.all(
req.body.map((action) => {
const span = tracer.startSpan("propagate-w3c");
let promise;
tracer.withSpan(span, () => {
const headers = {};
propagation.inject(headers);
propagation.inject(context.active(), headers);
promise = axios
.post(
action.url,
Expand All @@ -57,8 +57,8 @@ app.post("/verify-tracecontext", (req, res) => {
return promise;
})
)
.then(() => res.send("hello"))
.catch((err) => res.status(500).send(err));
.then(() => res.send("hello"))
.catch((err) => res.status(500).send(err));
});
});

Expand Down
15 changes: 6 additions & 9 deletions packages/opentelemetry-api/src/api/propagation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,13 @@ import {
TextMapPropagator,
TextMapSetter,
} from '../context/propagation/TextMapPropagator';
import { ContextAPI } from './context';
import {
API_BACKWARDS_COMPATIBILITY_VERSION,
GLOBAL_PROPAGATION_API_KEY,
makeGetter,
_global,
} from './global-utils';

const contextApi = ContextAPI.getInstance();

/**
* Singleton object which represents the entry point to the OpenTelemetry Propagation API
*/
Expand Down Expand Up @@ -72,29 +69,29 @@ export class PropagationAPI {
/**
* Inject context into a carrier to be propagated inter-process
*
* @param context Context carrying tracing data to inject
* @param carrier carrier to inject context into
* @param setter Function used to set values on the carrier
* @param context Context carrying tracing data to inject. Defaults to the currently active context.
*/
public inject<Carrier>(
context: Context,
carrier: Carrier,
setter: TextMapSetter<Carrier> = defaultTextMapSetter,
context: Context = contextApi.active()
setter: TextMapSetter<Carrier> = defaultTextMapSetter
): void {
return this._getGlobalPropagator().inject(context, carrier, setter);
}

/**
* Extract context from a carrier
*
* @param context Context which the newly created context will inherit from
* @param carrier Carrier to extract context from
* @param getter Function used to extract keys from a carrier
* @param context Context which the newly created context will inherit from. Defaults to the currently active context.
*/
public extract<Carrier>(
context: Context,
carrier: Carrier,
getter: TextMapGetter<Carrier> = defaultTextMapGetter,
context: Context = contextApi.active()
getter: TextMapGetter<Carrier> = defaultTextMapGetter
): Context {
return this._getGlobalPropagator().extract(context, carrier, getter);
}
Expand Down
83 changes: 83 additions & 0 deletions packages/opentelemetry-api/test/api/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ import api, {
trace,
propagation,
metrics,
TextMapPropagator,
Context,
TextMapSetter,
TextMapGetter,
ROOT_CONTEXT,
defaultTextMapSetter,
defaultTextMapGetter,
} from '../../src';

describe('API', () => {
Expand Down Expand Up @@ -84,5 +91,81 @@ describe('API', () => {
return new TestTracer();
}
}

describe('should use the global propagation', () => {
const testKey = Symbol('kTestKey');

interface Carrier {
context?: Context;
setter?: TextMapSetter;
}

class TestTextMapPropagation implements TextMapPropagator<Carrier> {
inject(
context: Context,
carrier: Carrier,
setter: TextMapSetter
): void {
carrier.context = context;
carrier.setter = setter;
}

extract(
context: Context,
carrier: Carrier,
getter: TextMapGetter
): Context {
return context.setValue(testKey, {
context,
carrier,
getter,
});
}

fields(): string[] {
return ['TestField'];
}
}

it('inject', () => {
api.propagation.setGlobalPropagator(new TestTextMapPropagation());

const context = ROOT_CONTEXT.setValue(testKey, 15);
const carrier: Carrier = {};
api.propagation.inject(context, carrier);
assert.strictEqual(carrier.context, context);
assert.strictEqual(carrier.setter, defaultTextMapSetter);

const setter: TextMapSetter = {
set: () => {},
};
api.propagation.inject(context, carrier, setter);
assert.strictEqual(carrier.context, context);
assert.strictEqual(carrier.setter, setter);
});

it('extract', () => {
api.propagation.setGlobalPropagator(new TestTextMapPropagation());

const carrier: Carrier = {};
let context = api.propagation.extract(ROOT_CONTEXT, carrier);
let data: any = context.getValue(testKey);
assert.ok(data != null);
assert.strictEqual(data.context, ROOT_CONTEXT);
assert.strictEqual(data.carrier, carrier);
assert.strictEqual(data.getter, defaultTextMapGetter);

const getter: TextMapGetter = {
keys: () => [],
get: () => undefined,
};
context = api.propagation.extract(ROOT_CONTEXT, carrier, getter);
data = context.getValue(testKey);
assert.ok(data != null);
assert.strictEqual(data.context, ROOT_CONTEXT);
assert.strictEqual(data.carrier, carrier);
assert.strictEqual(data.getter, getter);
});
});
});
});
8 changes: 4 additions & 4 deletions packages/opentelemetry-instrumentation-http/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
setActiveSpan,
SpanContext,
TraceFlags,
ROOT_CONTEXT,
} from '@opentelemetry/api';
import { NoRecordingSpan } from '@opentelemetry/core';
import type * as http from 'http';
Expand Down Expand Up @@ -403,7 +404,7 @@ export class HttpInstrumentation extends InstrumentationBase<Http> {
}),
};

return context.with(propagation.extract(headers), () => {
return context.with(propagation.extract(ROOT_CONTEXT, headers), () => {
const span = instrumentation._startHttpSpan(
`${component.toLocaleUpperCase()} ${method}`,
spanOptions
Expand Down Expand Up @@ -539,9 +540,8 @@ export class HttpInstrumentation extends InstrumentationBase<Http> {
optionsParsed.headers = {};
}
propagation.inject(
optionsParsed.headers,
undefined,
setActiveSpan(context.active(), span)
setActiveSpan(context.active(), span),
optionsParsed.headers
);

const request: http.ClientRequest = safeExecuteInTheMiddle(
Expand Down
2 changes: 1 addition & 1 deletion packages/opentelemetry-instrumentation-http/src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
*/

// this is autogenerated file, see scripts/version-update.js
export const VERSION = '0.12.0';
export const VERSION = '0.13.0';
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class XMLHttpRequestInstrumentation extends InstrumentationBase<XMLHttpRe
return;
}
const headers: { [key: string]: unknown } = {};
api.propagation.inject(headers);
api.propagation.inject(api.context.active(), headers);
Object.keys(headers).forEach(key => {
xhr.setRequestHeader(key, String(headers[key]));
});
Expand Down
7 changes: 3 additions & 4 deletions packages/opentelemetry-plugin-fetch/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import * as web from '@opentelemetry/web';
import { AttributeNames } from './enums/AttributeNames';
import { FetchError, FetchResponse, SpanData } from './types';
import { VERSION } from './version';
import { setActiveSpan } from '@opentelemetry/api';

// how long to wait for observer to collect information about resources
// this is needed as event "load" is called before observer
Expand Down Expand Up @@ -69,7 +68,7 @@ export class FetchPlugin extends core.BasePlugin<Promise<Response>> {
{
startTime: corsPreFlightRequest[web.PerformanceTimingNames.FETCH_START],
},
setActiveSpan(api.context.active(), span)
api.setActiveSpan(api.context.active(), span)
);
web.addSpanNetworkEvents(childSpan, corsPreFlightRequest);
childSpan.end(
Expand Down Expand Up @@ -113,12 +112,12 @@ export class FetchPlugin extends core.BasePlugin<Promise<Response>> {
}

if (options instanceof Request) {
api.propagation.inject(options.headers, {
api.propagation.inject(api.context.active(), options.headers, {
set: (h, k, v) => h.set(k, typeof v === 'string' ? v : String(v)),
});
} else {
const headers: Partial<Record<string, unknown>> = {};
api.propagation.inject(headers);
api.propagation.inject(api.context.active(), headers);
options.headers = Object.assign({}, headers, options.headers || {});
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/opentelemetry-plugin-grpc-js/src/client/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
StatusCode,
Status,
propagation,
context,
} from '@opentelemetry/api';
import { RpcAttribute } from '@opentelemetry/semantic-conventions';
import type * as grpcJs from '@grpc/grpc-js';
Expand Down Expand Up @@ -243,7 +244,7 @@ function getMetadata(
* @param metadata
*/
export function setSpanContext(metadata: grpcJs.Metadata): void {
propagation.inject(metadata, {
propagation.inject(context.active(), metadata, {
set: (metadata, k, v) => metadata.set(k, v as grpcJs.MetadataValue),
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
SpanKind,
propagation,
Span,
ROOT_CONTEXT,
} from '@opentelemetry/api';
import { RpcAttribute } from '@opentelemetry/semantic-conventions';
import { clientStreamAndUnaryHandler } from './clientStreamAndUnary';
Expand Down Expand Up @@ -101,7 +102,7 @@ export function patchServer(
plugin.logger.debug('patch func: %s', JSON.stringify(spanOptions));

context.with(
propagation.extract(call.metadata, {
propagation.extract(ROOT_CONTEXT, call.metadata, {
get: (carrier, key) => carrier.get(key).map(String),
keys: carrier => Object.keys(carrier.getMap()),
}),
Expand Down
5 changes: 3 additions & 2 deletions packages/opentelemetry-plugin-grpc/src/grpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
SpanKind,
SpanOptions,
Status,
ROOT_CONTEXT,
} from '@opentelemetry/api';
import { RpcAttribute } from '@opentelemetry/semantic-conventions';
import { BasePlugin } from '@opentelemetry/core';
Expand Down Expand Up @@ -124,7 +125,7 @@ export class GrpcPlugin extends BasePlugin<grpc> {
}

private _setSpanContext(metadata: grpcTypes.Metadata): void {
propagation.inject(metadata, {
propagation.inject(context.active(), metadata, {
set: (metadata, k, v) => metadata.set(k, v as grpcTypes.MetadataValue),
});
}
Expand Down Expand Up @@ -182,7 +183,7 @@ export class GrpcPlugin extends BasePlugin<grpc> {
);

context.with(
propagation.extract(call.metadata, {
propagation.extract(ROOT_CONTEXT, call.metadata, {
get: (metadata, key) => metadata.get(key).map(String),
keys: metadata => Object.keys(metadata.getMap()),
}),
Expand Down
8 changes: 4 additions & 4 deletions packages/opentelemetry-plugin-http/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
SpanContext,
TraceFlags,
setActiveSpan,
ROOT_CONTEXT,
} from '@opentelemetry/api';
import { BasePlugin, NoRecordingSpan } from '@opentelemetry/core';
import type {
Expand Down Expand Up @@ -306,7 +307,7 @@ export class HttpPlugin extends BasePlugin<Http> {
}),
};

return context.with(propagation.extract(headers), () => {
return context.with(propagation.extract(ROOT_CONTEXT, headers), () => {
const span = plugin._startHttpSpan(`HTTP ${method}`, spanOptions);

return plugin._tracer.withSpan(span, () => {
Expand Down Expand Up @@ -414,9 +415,8 @@ export class HttpPlugin extends BasePlugin<Http> {
optionsParsed.headers = {};
}
propagation.inject(
optionsParsed.headers,
undefined,
setActiveSpan(context.active(), span)
setActiveSpan(context.active(), span),
optionsParsed.headers
);

const request: ClientRequest = plugin._safeExecute(
Expand Down
10 changes: 6 additions & 4 deletions packages/opentelemetry-shim-opentracing/src/shim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,11 @@ export class TracerShim extends opentracing.Tracer {
case opentracing.FORMAT_HTTP_HEADERS:
case opentracing.FORMAT_TEXT_MAP: {
api.propagation.inject(
carrier,
api.defaultTextMapSetter,
setCorrelationContext(
api.setExtractedSpanContext(api.ROOT_CONTEXT, oTelSpanContext),
oTelSpanCorrelationContext
)
),
carrier
);
return;
}
Expand All @@ -199,7 +198,10 @@ export class TracerShim extends opentracing.Tracer {
switch (format) {
case opentracing.FORMAT_HTTP_HEADERS:
case opentracing.FORMAT_TEXT_MAP: {
const context: api.Context = api.propagation.extract(carrier);
const context: api.Context = api.propagation.extract(
api.ROOT_CONTEXT,
carrier
);
const spanContext = api.getParentSpanContext(context);
const correlationContext = getCorrelationContext(context);

Expand Down