Skip to content

Commit e265e47

Browse files
pichlermarctrentm
andauthored
feat(sdk-trace-base)!: drop ability to auto-instantiate propagators beyond defaults (#5355)
Co-authored-by: Trent Mick <[email protected]>
1 parent a04284c commit e265e47

File tree

15 files changed

+259
-329
lines changed

15 files changed

+259
-329
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,19 @@ For semantic convention package changes, see the [semconv CHANGELOG](packages/se
5252
* (user-facing): deprecated `AlwaysOffSampler` has moved to `@opentelemetry/sdk-trace-base`
5353
* (user-facing): deprecated `TraceIdRatioSampler` has moved to `@opentelemetry/sdk-trace-base`
5454
* (user-facing): deprecated `TraceIdRatioSampler` has moved to `@opentelemetry/sdk-trace-base`
55+
* feat(sdk-trace-base)!: drop ability to instantiate propagators beyond defaults [#5355](https://github.com/open-telemetry/opentelemetry-js/pull/5355) @pichlermarc
56+
* (user-facing): only a non-env-var based default is now used on `BasicTracerProvider#register()`.
57+
* propagators can now not be configured via `OTEL_PROPAGATORS` or `window.OTEL_PROPAGATORS` anymore, please pass the propagator to `NodeTracerProvider#register()` instead.
58+
* if not configured directly via code, `BasicTracerProvider#register()` will now fall back to defaults (`tracecontext` and `baggage`)
59+
* feat(sdk-trace-node)!: drop ability to instantiate propagators beyond defaults [#5355](https://github.com/open-telemetry/opentelemetry-js/pull/5355) @pichlermarc
60+
* (user-facing): only a non-env-var based default is now used on `NodeTracerProvider#register()`.
61+
* propagators can now not be configured via `OTEL_PROPAGATORS` anymore, please pass the propagator to `NodeTracerProvider#register()` instead.
62+
* if not configured via code, `NodeTracerProvider#register()` will now fall back to the defaults (`tracecontext` and `baggage`)
63+
* if autoconfiguration based on enviornment variables is needed, please use `NodeSDK` from `@opentelemetry/sdk-node`.
64+
* feat(sdk-trace-web)!: drop ability to instantiate propagators beyond defaults [#5355](https://github.com/open-telemetry/opentelemetry-js/pull/5355) @pichlermarc
65+
* (user-facing): only a non-env-var based default is now used on `WebTracerProvider#register()`.
66+
* propagators can now not be configured via `window.OTEL_PROPAGATORS` anymore, please pass the propagator to `WebTracerProvider#register()` instead.
67+
* if not configured via code, `WebTracerProvider#register()` will now fall back to defaults (`tracecontext` and `baggage`)
5568

5669
### :rocket: (Enhancement)
5770

experimental/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ All notable changes to experimental packages in this project will be documented
3434
* chore(instrumentation-grpc): remove unused findIndex() function [#5372](https://github.com/open-telemetry/opentelemetry-js/pull/5372) @cjihrig
3535
* refactor(otlp-exporter-base): remove unnecessary isNaN() checks [#5374](https://github.com/open-telemetry/opentelemetry-js/pull/5374) @cjihrig
3636
* refactor(exporter-prometheus): remove unnecessary isNaN() check [#5377](https://github.com/open-telemetry/opentelemetry-js/pull/5377) @cjihrig
37+
* refactor(sdk-node): move code to auto-instantiate propagators into utils [#5355](https://github.com/open-telemetry/opentelemetry-js/pull/5355) @pichlermarc
3738

3839
## 0.57.0
3940

experimental/packages/opentelemetry-sdk-node/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@
6363
"@opentelemetry/sdk-metrics": "1.30.0",
6464
"@opentelemetry/sdk-trace-base": "1.30.0",
6565
"@opentelemetry/sdk-trace-node": "1.30.0",
66-
"@opentelemetry/semantic-conventions": "1.28.0"
66+
"@opentelemetry/semantic-conventions": "1.28.0",
67+
"@opentelemetry/propagator-jaeger": "1.30.0",
68+
"@opentelemetry/propagator-b3": "1.30.0"
6769
},
6870
"peerDependencies": {
6971
"@opentelemetry/api": ">=1.3.0 <1.10.0"

experimental/packages/opentelemetry-sdk-node/src/sdk.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import {
7474
getResourceDetectorsFromEnv,
7575
getSpanProcessorsFromEnv,
7676
filterBlanksAndNulls,
77+
getPropagatorFromEnv,
7778
} from './utils';
7879

7980
/** This class represents everything needed to register a fully configured OpenTelemetry Node.js SDK */
@@ -376,7 +377,9 @@ export class NodeSDK {
376377
this._tracerProviderConfig?.contextManager ??
377378
// _tracerProviderConfig may be undefined if trace-specific settings are not provided - fall back to raw config
378379
this._configuration?.contextManager,
379-
propagator: this._tracerProviderConfig?.textMapPropagator,
380+
propagator:
381+
this._tracerProviderConfig?.textMapPropagator ??
382+
getPropagatorFromEnv(),
380383
});
381384
}
382385

experimental/packages/opentelemetry-sdk-node/src/utils.ts

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { diag } from '@opentelemetry/api';
18-
import { getEnv, getEnvWithoutDefaults } from '@opentelemetry/core';
17+
import { diag, TextMapPropagator } from '@opentelemetry/api';
18+
import {
19+
CompositePropagator,
20+
getEnv,
21+
getEnvWithoutDefaults,
22+
W3CTraceContextPropagator,
23+
} from '@opentelemetry/core';
1924
import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
2025
import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
2126
import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
@@ -35,6 +40,8 @@ import {
3540
SpanExporter,
3641
SpanProcessor,
3742
} from '@opentelemetry/sdk-trace-base';
43+
import { B3InjectEncoding, B3Propagator } from '@opentelemetry/propagator-b3';
44+
import { JaegerPropagator } from '@opentelemetry/propagator-jaeger';
3845

3946
const RESOURCE_DETECTOR_ENVIRONMENT = 'env';
4047
const RESOURCE_DETECTOR_HOST = 'host';
@@ -180,3 +187,66 @@ export function getSpanProcessorsFromEnv(): SpanProcessor[] {
180187

181188
return processors;
182189
}
190+
191+
/**
192+
* Get a propagator as defined by environment variables
193+
*/
194+
export function getPropagatorFromEnv(): TextMapPropagator | null | undefined {
195+
// Empty and undefined MUST be treated equal.
196+
if (
197+
process.env.OTEL_PROPAGATORS === undefined ||
198+
process.env.OTEL_PROPAGATORS?.trim() === ''
199+
) {
200+
// return undefined to fall back to default
201+
return undefined;
202+
}
203+
204+
// Implementation note: this only contains specification required propagators that are actually hosted in this repo.
205+
// Any other propagators (like aws, aws-lambda, should go into `@opentelemetry/auto-configuration-propagators` instead).
206+
const propagatorsFactory = new Map<string, () => TextMapPropagator>([
207+
['tracecontext', () => new W3CTraceContextPropagator()],
208+
['baggage', () => new W3CTraceContextPropagator()],
209+
['b3', () => new B3Propagator()],
210+
[
211+
'b3multi',
212+
() => new B3Propagator({ injectEncoding: B3InjectEncoding.MULTI_HEADER }),
213+
],
214+
['jaeger', () => new JaegerPropagator()],
215+
]);
216+
217+
// Values MUST be deduplicated in order to register a Propagator only once.
218+
const uniquePropagatorNames = Array.from(new Set(getEnv().OTEL_PROPAGATORS));
219+
220+
const propagators = uniquePropagatorNames.map(name => {
221+
const propagator = propagatorsFactory.get(name)?.();
222+
if (!propagator) {
223+
diag.warn(
224+
`Propagator "${name}" requested through environment variable is unavailable.`
225+
);
226+
return undefined;
227+
}
228+
229+
return propagator;
230+
});
231+
232+
const validPropagators = propagators.reduce<TextMapPropagator[]>(
233+
(list, item) => {
234+
if (item) {
235+
list.push(item);
236+
}
237+
return list;
238+
},
239+
[]
240+
);
241+
242+
if (validPropagators.length === 0) {
243+
// null to signal that the default should **not** be used in its place.
244+
return null;
245+
} else if (uniquePropagatorNames.length === 1) {
246+
return validPropagators[0];
247+
} else {
248+
return new CompositePropagator({
249+
propagators: validPropagators,
250+
});
251+
}
252+
}

experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,21 @@ describe('Node SDK', () => {
414414
assert.equal(actualContextManager, expectedContextManager);
415415
await sdk.shutdown();
416416
});
417+
418+
it('should register propagators as defined in OTEL_PROPAGATORS if trace SDK is configured', async () => {
419+
process.env.OTEL_PROPAGATORS = 'b3';
420+
const sdk = new NodeSDK({
421+
traceExporter: new ConsoleSpanExporter(),
422+
autoDetectResources: false,
423+
});
424+
425+
sdk.start();
426+
427+
assert.deepStrictEqual(propagation.fields(), ['b3']);
428+
429+
await sdk.shutdown();
430+
delete process.env.OTEL_PROPAGATORS;
431+
});
417432
});
418433

419434
async function waitForNumberOfMetrics(
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { getPropagatorFromEnv } from '../src/utils';
18+
import * as assert from 'assert';
19+
import * as sinon from 'sinon';
20+
import { diag } from '@opentelemetry/api';
21+
22+
describe('getPropagatorFromEnv', function () {
23+
afterEach(() => {
24+
delete process.env.OTEL_PROPAGATORS;
25+
sinon.restore();
26+
});
27+
28+
describe('should default to undefined', function () {
29+
it('when not defined', function () {
30+
delete process.env.OTEL_PROPAGATORS;
31+
32+
const propagator = getPropagatorFromEnv();
33+
34+
assert.deepStrictEqual(propagator, undefined);
35+
});
36+
37+
it('on empty string', function () {
38+
(process.env as any).OTEL_PROPAGATORS = '';
39+
40+
const propagator = getPropagatorFromEnv();
41+
42+
assert.deepStrictEqual(propagator, undefined);
43+
});
44+
45+
it('on space-only string', function () {
46+
(process.env as any).OTEL_PROPAGATORS = ' ';
47+
48+
const propagator = getPropagatorFromEnv();
49+
50+
assert.deepStrictEqual(propagator, undefined);
51+
});
52+
});
53+
54+
it('should return the selected propagator when one is in the list', () => {
55+
process.env.OTEL_PROPAGATORS = 'tracecontext';
56+
assert.deepStrictEqual(getPropagatorFromEnv()?.fields(), [
57+
'traceparent',
58+
'tracestate',
59+
]);
60+
});
61+
62+
it('should return the selected propagators when multiple are in the list', () => {
63+
process.env.OTEL_PROPAGATORS = 'tracecontext,baggage,b3,b3multi,jaeger';
64+
assert.deepStrictEqual(getPropagatorFromEnv()?.fields(), [
65+
'traceparent',
66+
'tracestate',
67+
'b3',
68+
'x-b3-traceid',
69+
'x-b3-spanid',
70+
'x-b3-flags',
71+
'x-b3-sampled',
72+
'x-b3-parentspanid',
73+
'uber-trace-id',
74+
]);
75+
});
76+
77+
it('should return null and warn if propagators are unknown', () => {
78+
const warnStub = sinon.stub(diag, 'warn');
79+
80+
process.env.OTEL_PROPAGATORS = 'my, unknown, propagators';
81+
assert.deepStrictEqual(getPropagatorFromEnv(), null);
82+
sinon.assert.calledWithExactly(
83+
warnStub,
84+
'Propagator "my" requested through environment variable is unavailable.'
85+
);
86+
sinon.assert.calledWithExactly(
87+
warnStub,
88+
'Propagator "unknown" requested through environment variable is unavailable.'
89+
);
90+
sinon.assert.calledWithExactly(
91+
warnStub,
92+
'Propagator "propagators" requested through environment variable is unavailable.'
93+
);
94+
sinon.assert.calledThrice(warnStub);
95+
});
96+
97+
it('should return null if only "none" is selected', () => {
98+
process.env.OTEL_PROPAGATORS = 'none';
99+
100+
assert.deepStrictEqual(getPropagatorFromEnv(), null);
101+
});
102+
});

experimental/packages/opentelemetry-sdk-node/tsconfig.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424
{
2525
"path": "../../../packages/opentelemetry-exporter-zipkin"
2626
},
27+
{
28+
"path": "../../../packages/opentelemetry-propagator-b3"
29+
},
30+
{
31+
"path": "../../../packages/opentelemetry-propagator-jaeger"
32+
},
2733
{
2834
"path": "../../../packages/opentelemetry-resources"
2935
},

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)