Skip to content

Commit 0b720f6

Browse files
authored
feat(sdk-node): always set up propagation and context manager (#5930)
1 parent 9145fd6 commit 0b720f6

File tree

5 files changed

+507
-398
lines changed

5 files changed

+507
-398
lines changed

experimental/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
1010

1111
### :rocket: Features
1212

13+
* feat(sdk-node): always set up propagtion and context manager [#5930](https://github.com/open-telemetry/opentelemetry-js/pull/5930)
14+
* using `(new NodeSDK).start()` will now automatically set up a context management and propagation, even if no Trace SDK
15+
is initialized.
1316
* feat(otlp-exporter-base, otlp-grpc-exporter-base): add an option to let an SDK distribution prepend their own user-agent string in HTTP & GRPC exporters [#5928](https://github.com/open-telemetry/opentelemetry-js/pull/5928) @david-luna
1417

1518
### :bug: Bug Fixes

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

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

17-
import {
18-
ContextManager,
19-
TextMapPropagator,
20-
metrics,
21-
diag,
22-
DiagConsoleLogger,
23-
} from '@opentelemetry/api';
17+
import { metrics, trace, diag, DiagConsoleLogger } from '@opentelemetry/api';
2418
import { logs } from '@opentelemetry/api-logs';
2519
import {
2620
Instrumentation,
@@ -79,9 +73,14 @@ import {
7973
getResourceDetectorsFromEnv,
8074
getSpanProcessorsFromEnv,
8175
getPropagatorFromEnv,
76+
setupPropagator,
77+
setupContextManager,
8278
} from './utils';
8379

84-
/** This class represents everything needed to register a fully configured OpenTelemetry Node.js SDK */
80+
type TracerProviderConfig = {
81+
tracerConfig: NodeTracerConfig;
82+
spanProcessors: SpanProcessor[];
83+
};
8584

8685
export type MeterProviderConfig = {
8786
/**
@@ -129,6 +128,7 @@ function configureMetricProviderFromEnv(): IMetricReader[] {
129128
);
130129
return metricReaders;
131130
}
131+
132132
enabledExporters.forEach(exporter => {
133133
if (exporter === 'otlp') {
134134
const protocol =
@@ -201,13 +201,27 @@ function configureMetricProviderFromEnv(): IMetricReader[] {
201201

202202
return metricReaders;
203203
}
204+
205+
/**
206+
* A setup helper for the OpenTelemetry SDKs (logs, metrics, traces).
207+
* <p> After successful setup using {@link NodeSDK#start()}, use `@opentelemetry/api` to obtain the registered components.
208+
* <p> Use the shutdown handler {@link NodeSDK#shutdown()} to ensure your telemetry is exported before the process exits.
209+
*
210+
* @example <caption> Register SDK by using environment variables </caption>
211+
* const nodeSdk = new NodeSDK(); // providing no options uses OTEL_* environment variables for SDK setup.
212+
* nodeSdk.start(); // registers all configured SDK components
213+
* @example <caption> Override environment variable config with your own components </caption>
214+
* const nodeSdk = new NodeSDK({
215+
* // override the list of metric reader with your own options and ignore environment variable config
216+
* // explore the docs of other options to learn more!
217+
* metricReaders: [ new PeriodicExportingMetricReader({
218+
* exporter: new OTLPMetricsExporter()
219+
* })]
220+
* });
221+
* nodeSdk.start(); // registers all configured SDK components
222+
*/
204223
export class NodeSDK {
205-
private _tracerProviderConfig?: {
206-
tracerConfig: NodeTracerConfig;
207-
spanProcessors: SpanProcessor[];
208-
contextManager?: ContextManager;
209-
textMapPropagator?: TextMapPropagator;
210-
};
224+
private _tracerProviderConfig?: TracerProviderConfig;
211225
private _loggerProviderConfig?: LoggerProviderConfig;
212226
private _meterProviderConfig?: MeterProviderConfig;
213227
private _instrumentations: Instrumentation[];
@@ -292,8 +306,6 @@ export class NodeSDK {
292306
this._tracerProviderConfig = {
293307
tracerConfig: tracerProviderConfig,
294308
spanProcessors,
295-
contextManager: configuration.contextManager,
296-
textMapPropagator: configuration.textMapPropagator,
297309
};
298310
}
299311

@@ -350,6 +362,13 @@ export class NodeSDK {
350362
instrumentations: this._instrumentations,
351363
});
352364

365+
setupContextManager(this._configuration?.contextManager);
366+
setupPropagator(
367+
this._configuration?.textMapPropagator === null
368+
? null // null means don't set, so we cannot fall back to env config.
369+
: (this._configuration?.textMapPropagator ?? getPropagatorFromEnv())
370+
);
371+
353372
if (this._autoDetectResources) {
354373
const internalConfig: ResourceDetectionConfig = {
355374
detectors: this._resourceDetectors,
@@ -371,23 +390,14 @@ export class NodeSDK {
371390
? this._tracerProviderConfig.spanProcessors
372391
: getSpanProcessorsFromEnv();
373392

374-
this._tracerProvider = new NodeTracerProvider({
375-
...this._configuration,
376-
resource: this._resource,
377-
spanProcessors,
378-
});
379-
380393
// Only register if there is a span processor
381394
if (spanProcessors.length > 0) {
382-
this._tracerProvider.register({
383-
contextManager:
384-
this._tracerProviderConfig?.contextManager ??
385-
// _tracerProviderConfig may be undefined if trace-specific settings are not provided - fall back to raw config
386-
this._configuration?.contextManager,
387-
propagator:
388-
this._tracerProviderConfig?.textMapPropagator ??
389-
getPropagatorFromEnv(),
395+
this._tracerProvider = new NodeTracerProvider({
396+
...this._configuration,
397+
resource: this._resource,
398+
spanProcessors,
390399
});
400+
trace.setGlobalTracerProvider(this._tracerProvider);
391401
}
392402

393403
if (this._loggerProviderConfig) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
export interface NodeSDKConfiguration {
3232
autoDetectResources: boolean;
3333
contextManager: ContextManager;
34-
textMapPropagator: TextMapPropagator;
34+
textMapPropagator: TextMapPropagator | null;
3535
/** @deprecated use logRecordProcessors instead*/
3636
logRecordProcessor: LogRecordProcessor;
3737
logRecordProcessors?: LogRecordProcessor[];

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

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { diag, TextMapPropagator } from '@opentelemetry/api';
17+
import {
18+
context,
19+
ContextManager,
20+
diag,
21+
propagation,
22+
TextMapPropagator,
23+
} from '@opentelemetry/api';
1824
import {
1925
CompositePropagator,
2026
getStringFromEnv,
@@ -43,6 +49,7 @@ import {
4349
} from '@opentelemetry/sdk-trace-base';
4450
import { B3InjectEncoding, B3Propagator } from '@opentelemetry/propagator-b3';
4551
import { JaegerPropagator } from '@opentelemetry/propagator-jaeger';
52+
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
4653

4754
const RESOURCE_DETECTOR_ENVIRONMENT = 'env';
4855
const RESOURCE_DETECTOR_HOST = 'host';
@@ -198,6 +205,10 @@ export function getPropagatorFromEnv(): TextMapPropagator | null | undefined {
198205
return undefined;
199206
}
200207

208+
if (propagatorsEnvVarValue.includes('none')) {
209+
return null;
210+
}
211+
201212
// Implementation note: this only contains specification required propagators that are actually hosted in this repo.
202213
// Any other propagators (like aws, aws-lambda, should go into `@opentelemetry/auto-configuration-propagators` instead).
203214
const propagatorsFactory = new Map<string, () => TextMapPropagator>([
@@ -247,3 +258,47 @@ export function getPropagatorFromEnv(): TextMapPropagator | null | undefined {
247258
});
248259
}
249260
}
261+
262+
export function setupContextManager(
263+
contextManager: ContextManager | null | undefined
264+
) {
265+
// null means 'do not register'
266+
if (contextManager === null) {
267+
return;
268+
}
269+
270+
// undefined means 'register default'
271+
if (contextManager === undefined) {
272+
const defaultContextManager = new AsyncLocalStorageContextManager();
273+
defaultContextManager.enable();
274+
context.setGlobalContextManager(defaultContextManager);
275+
return;
276+
}
277+
278+
contextManager.enable();
279+
context.setGlobalContextManager(contextManager);
280+
}
281+
282+
export function setupPropagator(
283+
propagator: TextMapPropagator | null | undefined
284+
) {
285+
// null means 'do not register'
286+
if (propagator === null) {
287+
return;
288+
}
289+
290+
// undefined means 'register default'
291+
if (propagator === undefined) {
292+
propagation.setGlobalPropagator(
293+
new CompositePropagator({
294+
propagators: [
295+
new W3CTraceContextPropagator(),
296+
new W3CBaggagePropagator(),
297+
],
298+
})
299+
);
300+
return;
301+
}
302+
303+
propagation.setGlobalPropagator(propagator);
304+
}

0 commit comments

Comments
 (0)