From 42dfbf4c0bf201c91385991fecd3428b99ba42d9 Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 21 Nov 2025 19:12:53 -0500 Subject: [PATCH 01/13] add resources and lof provider setup --- .../opentelemetry-sdk-node/src/start.ts | 151 ++++++++++++++++++ .../opentelemetry-sdk-node/src/types.ts | 5 + .../opentelemetry-sdk-node/src/utils.ts | 31 ++++ 3 files changed, 187 insertions(+) diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index f4cb368b42d..887a26f7e65 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -15,16 +15,46 @@ */ import { ConfigFactory, + ConfigurationModel, createConfigFactory, + LogRecordExporterModel, } from '@opentelemetry/configuration'; import { diag, DiagConsoleLogger } from '@opentelemetry/api'; import { getPropagatorFromConfiguration, + getResourceDetectorsFromConfiguration, setupDefaultContextManager, setupPropagator, } from './utils'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; import type { SDKOptions } from './types'; +import { + BatchLogRecordProcessor, + ConsoleLogRecordExporter, + LoggerProvider, + LogRecordExporter, + LogRecordProcessor, + SimpleLogRecordProcessor, +} from '@opentelemetry/sdk-logs'; +import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; +import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc'; +import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'; +import { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base'; +import { logs } from '@opentelemetry/api-logs'; +import { + defaultResource, + detectResources, + envDetector, + hostDetector, + osDetector, + processDetector, + Resource, + ResourceDetectionConfig, + ResourceDetector, + resourceFromAttributes, + serviceInstanceIdDetector, +} from '@opentelemetry/resources'; +import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; /** * @experimental Function to start the OpenTelemetry Node SDK @@ -54,9 +84,14 @@ export function startNodeSDK(sdkOptions: SDKOptions): { : (sdkOptions?.textMapPropagator ?? getPropagatorFromConfiguration(config)) ); + const resource = setupResource(config, sdkOptions); + const loggerProvider = setupLoggerProvider(config, sdkOptions, resource); const shutdownFn = async () => { const promises: Promise[] = []; + if (loggerProvider) { + promises.push(loggerProvider.shutdown()); + } await Promise.all(promises); }; return { shutdown: shutdownFn }; @@ -64,3 +99,119 @@ export function startNodeSDK(sdkOptions: SDKOptions): { const NOOP_SDK = { shutdown: async () => {}, }; + +function setupResource( + config: ConfigurationModel, + sdkOptions: SDKOptions +): Resource { + let resource: Resource = sdkOptions.resource ?? defaultResource(); + const autoDetectResources = sdkOptions.autoDetectResources ?? true; + let resourceDetectors: ResourceDetector[]; + + if (!autoDetectResources) { + resourceDetectors = []; + } else if (sdkOptions.resourceDetectors != null) { + resourceDetectors = sdkOptions.resourceDetectors; + } else if (config.node_resource_detectors) { + resourceDetectors = getResourceDetectorsFromConfiguration(config); + } else { + resourceDetectors = [ + envDetector, + processDetector, + hostDetector, + osDetector, + serviceInstanceIdDetector, + ]; + } + + if (autoDetectResources) { + const internalConfig: ResourceDetectionConfig = { + detectors: resourceDetectors, + }; + + resource = resource.merge(detectResources(internalConfig)); + } + + resource = + sdkOptions.serviceName === undefined + ? resource + : resource.merge( + resourceFromAttributes({ + [ATTR_SERVICE_NAME]: sdkOptions.serviceName, + }) + ); + + return resource; +} + +function setupLoggerProvider( + config: ConfigurationModel, + sdkOptions: SDKOptions, + resource: Resource | undefined +): LoggerProvider | undefined { + const logProcessors = + sdkOptions.logRecordProcessors ?? + getLogRecordProcessorsFromConfiguration(config); + + if (logProcessors) { + const loggerProvider = new LoggerProvider({ + resource: resource, + processors: logProcessors, + }); + + logs.setGlobalLoggerProvider(loggerProvider); + return loggerProvider; + } + return undefined; +} + +function getExporterType(exporter: LogRecordExporterModel): LogRecordExporter { + if (exporter.otlp_http) { + if (exporter.otlp_http.encoding === 'json') { + return new OTLPHttpLogExporter({ + compression: + exporter.otlp_http.compression === 'gzip' + ? CompressionAlgorithm.GZIP + : CompressionAlgorithm.NONE, + }); + } + if (exporter.otlp_http.encoding === 'protobuf') { + return new OTLPProtoLogExporter(); + } + diag.warn(`Unsupported OTLP logs protocol. Using http/protobuf.`); + return new OTLPProtoLogExporter(); + } else if (exporter.otlp_grpc) { + return new OTLPGrpcLogExporter(); + } else if (exporter.console) { + return new ConsoleLogRecordExporter(); + } + diag.warn(`Unsupported Exporter value. Using OTLP http/protobuf.`); + return new OTLPProtoLogExporter(); +} + +function getLogRecordProcessorsFromConfiguration( + config: ConfigurationModel +): LogRecordProcessor[] | undefined { + const logRecordProcessors: LogRecordProcessor[] = []; + config.logger_provider?.processors?.forEach(processor => { + if (processor.batch) { + logRecordProcessors.push( + new BatchLogRecordProcessor(getExporterType(processor.batch.exporter), { + maxQueueSize: processor.batch.max_queue_size, + maxExportBatchSize: processor.batch.max_export_batch_size, + scheduledDelayMillis: processor.batch.schedule_delay, + exportTimeoutMillis: processor.batch.export_timeout, + }) + ); + } + if (processor.simple) { + logRecordProcessors.push( + new SimpleLogRecordProcessor(getExporterType(processor.simple.exporter)) + ); + } + }); + if (logRecordProcessors.length > 0) { + return logRecordProcessors; + } + return undefined; +} diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index 8afe1a2ca08..19d3998f2eb 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -55,6 +55,11 @@ export interface NodeSDKConfiguration { * @experimental Options for new experimental SDK setup */ export interface SDKOptions { + autoDetectResources?: boolean; instrumentations?: (Instrumentation | Instrumentation[])[]; + logRecordProcessors?: LogRecordProcessor[]; + resource?: Resource; + resourceDetectors?: ResourceDetector[]; + serviceName?: string; textMapPropagator?: TextMapPropagator | null; } diff --git a/experimental/packages/opentelemetry-sdk-node/src/utils.ts b/experimental/packages/opentelemetry-sdk-node/src/utils.ts index d8f11efc8c1..aab47f38dd7 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/utils.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/utils.ts @@ -91,6 +91,37 @@ export function getResourceDetectorsFromEnv(): Array { }); } +export function getResourceDetectorsFromConfiguration( + config: ConfigurationModel +): Array { + // When updating this list, make sure to also update the section `resourceDetectors` on README. + const resourceDetectors = new Map([ + [RESOURCE_DETECTOR_ENVIRONMENT, envDetector], + [RESOURCE_DETECTOR_HOST, hostDetector], + [RESOURCE_DETECTOR_OS, osDetector], + [RESOURCE_DETECTOR_SERVICE_INSTANCE_ID, serviceInstanceIdDetector], + [RESOURCE_DETECTOR_PROCESS, processDetector], + ]); + + const resourceDetectorsFromConfig = config.node_resource_detectors ?? ['all']; + + if (resourceDetectorsFromConfig.includes('all')) { + return [...resourceDetectors.values()].flat(); + } + + if (resourceDetectorsFromConfig.includes('none')) { + return []; + } + + return resourceDetectorsFromConfig.flatMap(detector => { + const resourceDetector = resourceDetectors.get(detector); + if (!resourceDetector) { + diag.warn(`Invalid resource detector "${detector}" specified`); + } + return resourceDetector || []; + }); +} + export function getOtlpProtocolFromEnv(): string { return ( getStringFromEnv('OTEL_EXPORTER_OTLP_TRACES_PROTOCOL') ?? From 1946cd6ae2c7b3517e74cac5d0481b9723cd5dc0 Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 21 Nov 2025 19:16:01 -0500 Subject: [PATCH 02/13] changelog --- experimental/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 45e471cb99b..beacbfa3e46 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -20,6 +20,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2 * refactor(configuration): dont have a default value for node resource detectors [#6131](https://github.com/open-telemetry/opentelemetry-js/pull/6131) @maryliag * feat(configuration): doesnt set meter,tracer,logger provider by default [#6130](https://github.com/open-telemetry/opentelemetry-js/pull/6130) @maryliag * feat(opentelemetry-sdk-node): set instrumentation and propagators for experimental start [#6148](https://github.com/open-telemetry/opentelemetry-js/pull/6148) @maryliag +* feat(opentelemetry-sdk-node): set resources and log provider for experimental start [#6152](https://github.com/open-telemetry/opentelemetry-js/pull/6152) @maryliag ### :bug: Bug Fixes From 3aee374ba2e2a7716c47363763804b0208b37642 Mon Sep 17 00:00:00 2001 From: maryliag Date: Fri, 21 Nov 2025 19:22:44 -0500 Subject: [PATCH 03/13] rename --- .../opentelemetry-sdk-node/src/start.ts | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index 887a26f7e65..0a32ba848b4 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -165,7 +165,9 @@ function setupLoggerProvider( return undefined; } -function getExporterType(exporter: LogRecordExporterModel): LogRecordExporter { +function getLogRecordExporter( + exporter: LogRecordExporterModel +): LogRecordExporter { if (exporter.otlp_http) { if (exporter.otlp_http.encoding === 'json') { return new OTLPHttpLogExporter({ @@ -196,17 +198,22 @@ function getLogRecordProcessorsFromConfiguration( config.logger_provider?.processors?.forEach(processor => { if (processor.batch) { logRecordProcessors.push( - new BatchLogRecordProcessor(getExporterType(processor.batch.exporter), { - maxQueueSize: processor.batch.max_queue_size, - maxExportBatchSize: processor.batch.max_export_batch_size, - scheduledDelayMillis: processor.batch.schedule_delay, - exportTimeoutMillis: processor.batch.export_timeout, - }) + new BatchLogRecordProcessor( + getLogRecordExporter(processor.batch.exporter), + { + maxQueueSize: processor.batch.max_queue_size, + maxExportBatchSize: processor.batch.max_export_batch_size, + scheduledDelayMillis: processor.batch.schedule_delay, + exportTimeoutMillis: processor.batch.export_timeout, + } + ) ); } if (processor.simple) { logRecordProcessors.push( - new SimpleLogRecordProcessor(getExporterType(processor.simple.exporter)) + new SimpleLogRecordProcessor( + getLogRecordExporter(processor.simple.exporter) + ) ); } }); From 31ebe4971c2f5c5705e177d571a76612bb6b0089 Mon Sep 17 00:00:00 2001 From: maryliag Date: Mon, 24 Nov 2025 19:52:23 -0500 Subject: [PATCH 04/13] add tests --- .../{test => src}/semconv.ts | 0 .../opentelemetry-sdk-node/src/start.ts | 13 +- .../opentelemetry-sdk-node/src/utils.ts | 12 + .../opentelemetry-sdk-node/test/sdk.test.ts | 2 +- .../opentelemetry-sdk-node/test/start.test.ts | 622 +++++++++++++++++- .../test/util/resource-assertions.ts | 2 +- 6 files changed, 645 insertions(+), 6 deletions(-) rename experimental/packages/opentelemetry-sdk-node/{test => src}/semconv.ts (100%) diff --git a/experimental/packages/opentelemetry-sdk-node/test/semconv.ts b/experimental/packages/opentelemetry-sdk-node/src/semconv.ts similarity index 100% rename from experimental/packages/opentelemetry-sdk-node/test/semconv.ts rename to experimental/packages/opentelemetry-sdk-node/src/semconv.ts diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index 0a32ba848b4..1d869ca8987 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -21,6 +21,7 @@ import { } from '@opentelemetry/configuration'; import { diag, DiagConsoleLogger } from '@opentelemetry/api'; import { + getInstanceID, getPropagatorFromConfiguration, getResourceDetectorsFromConfiguration, setupDefaultContextManager, @@ -55,6 +56,7 @@ import { serviceInstanceIdDetector, } from '@opentelemetry/resources'; import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; +import { ATTR_SERVICE_INSTANCE_ID } from './semconv'; /** * @experimental Function to start the OpenTelemetry Node SDK @@ -100,7 +102,7 @@ const NOOP_SDK = { shutdown: async () => {}, }; -function setupResource( +export function setupResource( config: ConfigurationModel, sdkOptions: SDKOptions ): Resource { @@ -140,6 +142,15 @@ function setupResource( [ATTR_SERVICE_NAME]: sdkOptions.serviceName, }) ); + const instanceId = getInstanceID(config); + resource = + instanceId === undefined + ? resource + : resource.merge( + resourceFromAttributes({ + [ATTR_SERVICE_INSTANCE_ID]: instanceId, + }) + ); return resource; } diff --git a/experimental/packages/opentelemetry-sdk-node/src/utils.ts b/experimental/packages/opentelemetry-sdk-node/src/utils.ts index aab47f38dd7..aa6f12fc2f9 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/utils.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/utils.ts @@ -381,3 +381,15 @@ export function getKeyListFromObjectArray( .map(item => Object.keys(item)) .reduce((prev, curr) => prev.concat(curr), []); } + +export function getInstanceID(config: ConfigurationModel): string | undefined { + if (config.resource?.attributes) { + for (let i = 0; i < config.resource.attributes.length; i++) { + const element = config.resource.attributes[i]; + if (element.name === 'service.instance.id') { + return element.value?.toString(); + } + } + } + return undefined; +} diff --git a/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts b/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts index 3314f613a20..c4cb5904ecc 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts @@ -82,7 +82,7 @@ import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/expo import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; -import { ATTR_HOST_NAME, ATTR_PROCESS_PID } from './semconv'; +import { ATTR_HOST_NAME, ATTR_PROCESS_PID } from '../src/semconv'; function assertDefaultContextManagerRegistered() { assert.ok( diff --git a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts index d6789845054..0f001b0b1e5 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts @@ -15,12 +15,97 @@ */ import * as assert from 'assert'; -import { startNodeSDK } from '../src/start'; -import { context, diag } from '@opentelemetry/api'; -import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; +import { setupResource, startNodeSDK } from '../src/start'; import * as Sinon from 'sinon'; +import { + context, + propagation, + ProxyTracerProvider, + trace, + diag, + DiagLogLevel, + metrics, + DiagConsoleLogger, +} from '@opentelemetry/api'; +import { + // AsyncHooksContextManager, + AsyncLocalStorageContextManager, +} from '@opentelemetry/context-async-hooks'; +import { W3CTraceContextPropagator } from '@opentelemetry/core'; +import { + // AggregationTemporality, + // ConsoleMetricExporter, + // InMemoryMetricExporter, + // InstrumentType, + MeterProvider, + // PeriodicExportingMetricReader, +} from '@opentelemetry/sdk-metrics'; +// import { OTLPMetricExporter as OTLPGrpcMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; +// import { OTLPMetricExporter as OTLPProtoMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'; +// import { OTLPMetricExporter as OTLPHttpMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'; +// import { PrometheusExporter as PrometheusMetricExporter } from '@opentelemetry/exporter-prometheus'; +// import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; +import { + assertServiceInstanceIdIsUUID, + // assertServiceInstanceIdIsUUID, + assertServiceResource, +} from './util/resource-assertions'; +// import { +// ConsoleSpanExporter, +// SimpleSpanProcessor, +// BatchSpanProcessor, +// NoopSpanProcessor, +// IdGenerator, +// AlwaysOffSampler, +// SpanProcessor, +// } from '@opentelemetry/sdk-trace-base'; +import { + envDetector, + processDetector, + hostDetector, + serviceInstanceIdDetector, + DetectedResource, +} from '@opentelemetry/resources'; +// import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; +import { logs, ProxyLoggerProvider } from '@opentelemetry/api-logs'; +import { + SimpleLogRecordProcessor, + InMemoryLogRecordExporter, + LoggerProvider, + ConsoleLogRecordExporter, + BatchLogRecordProcessor, +} from '@opentelemetry/sdk-logs'; +import { + ConfigFactory, + createConfigFactory, +} from '@opentelemetry/configuration'; +import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'; +import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; +import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc'; +// import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; +// import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; +// import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; + +import { ATTR_HOST_NAME, ATTR_PROCESS_PID } from '../src/semconv'; describe('startNodeSDK', function () { + let delegate: any; + let logsDelegate: any; + + beforeEach(() => { + diag.disable(); + context.disable(); + trace.disable(); + propagation.disable(); + metrics.disable(); + logs.disable(); + + delegate = (trace.getTracerProvider() as ProxyTracerProvider).getDelegate(); + logsDelegate = ( + logs.getLoggerProvider() as ProxyLoggerProvider + )._getDelegate(); + }); + const _origEnvVariables = { ...process.env }; afterEach(function () { @@ -52,6 +137,529 @@ describe('startNodeSDK', function () { sdk.shutdown(); }); + + it('should not register more than the minimal SDK components', async () => { + // need to set these to none, since the default value is 'otlp' + process.env.OTEL_TRACES_EXPORTER = 'none'; + process.env.OTEL_LOGS_EXPORTER = 'none'; + process.env.OTEL_METRICS_EXPORTER = 'none'; + const sdk = startNodeSDK({}); + + // These are minimal OTel functionality and always registered. + assertDefaultContextManagerRegistered(); + assertDefaultPropagatorRegistered(); + + assert.strictEqual( + (trace.getTracerProvider() as ProxyTracerProvider).getDelegate(), + delegate, + 'tracer provider should not have changed' + ); + assert.ok(!(metrics.getMeterProvider() instanceof MeterProvider)); + assert.strictEqual( + (logs.getLoggerProvider() as ProxyLoggerProvider)._getDelegate(), + logsDelegate, + 'logger provider should not have changed' + ); + + await sdk.shutdown(); + }); + + it('should register a diag logger with OTEL_LOG_LEVEL', () => { + process.env.OTEL_LOG_LEVEL = 'ERROR'; + + const spy = Sinon.spy(diag, 'setLogger'); + const sdk = startNodeSDK({}); + + assert.strictEqual(spy.callCount, 1); + assert.ok(spy.args[0][0] instanceof DiagConsoleLogger); + assert.deepStrictEqual(spy.args[0][1], { + logLevel: DiagLogLevel.ERROR, + }); + + sdk.shutdown(); + }); + + it('should register a diag logger as info as default', () => { + const spy = Sinon.spy(diag, 'setLogger'); + const sdk = startNodeSDK({}); + + assert.strictEqual(spy.callCount, 1); + assert.ok(spy.args[0][0] instanceof DiagConsoleLogger); + assert.deepStrictEqual(spy.args[0][1], { + logLevel: DiagLogLevel.INFO, + }); + + sdk.shutdown(); + }); + + it('should register a logger provider if a log record processor is provided', async () => { + const logRecordExporter = new InMemoryLogRecordExporter(); + const logRecordProcessor = new SimpleLogRecordProcessor(logRecordExporter); + const sdk = startNodeSDK({ logRecordProcessors: [logRecordProcessor] }); + + assertDefaultContextManagerRegistered(); + assertDefaultPropagatorRegistered(); + + assert.ok( + (logs.getLoggerProvider() as ProxyLoggerProvider) instanceof + LoggerProvider + ); + await sdk.shutdown(); + }); + + it('should register a logger provider if multiple log record processors are provided', async () => { + const logRecordExporter = new InMemoryLogRecordExporter(); + const simpleLogRecordProcessor = new SimpleLogRecordProcessor( + logRecordExporter + ); + const batchLogRecordProcessor = new BatchLogRecordProcessor( + logRecordExporter + ); + const sdk = startNodeSDK({ + logRecordProcessors: [simpleLogRecordProcessor, batchLogRecordProcessor], + }); + + const loggerProvider = logs.getLoggerProvider(); + const sharedState = (loggerProvider as any)['_sharedState']; + assert.ok(sharedState.registeredLogRecordProcessors.length === 2); + assert.ok( + sharedState.registeredLogRecordProcessors[0]._exporter instanceof + InMemoryLogRecordExporter + ); + assert.ok( + sharedState.registeredLogRecordProcessors[0] instanceof + SimpleLogRecordProcessor + ); + assert.ok( + sharedState.registeredLogRecordProcessors[1]._exporter instanceof + InMemoryLogRecordExporter + ); + assert.ok( + sharedState.registeredLogRecordProcessors[1] instanceof + BatchLogRecordProcessor + ); + await sdk.shutdown(); + }); + + it('should register a propagator if only a propagator is provided', async () => { + const expectedPropagator = new W3CTraceContextPropagator(); + const sdk = startNodeSDK({ + textMapPropagator: expectedPropagator, + }); + + const actualPropagator = propagation['_getGlobalPropagator'](); + assert.equal(actualPropagator, expectedPropagator); + await sdk.shutdown(); + }); + + it('should not register propagators OTEL_PROPAGATORS contains "none"', async () => { + process.env.OTEL_PROPAGATORS = 'none'; + const sdk = startNodeSDK({}); + + assert.deepStrictEqual(propagation.fields(), []); + + await sdk.shutdown(); + }); + + it('should not register propagators OTEL_PROPAGATORS contains "none" alongside valid propagator', async () => { + process.env.OTEL_PROPAGATORS = 'b3, none'; + const sdk = startNodeSDK({}); + + assert.deepStrictEqual(propagation.fields(), []); + + await sdk.shutdown(); + }); + + it('should not register propagators OTEL_PROPAGATORS contains valid propagator but option is set to null', async () => { + process.env.OTEL_PROPAGATORS = 'b3'; + const sdk = startNodeSDK({ textMapPropagator: null }); + + assert.deepStrictEqual(propagation.fields(), []); + + await sdk.shutdown(); + }); + + describe('detectResources', async () => { + beforeEach(() => { + process.env.OTEL_RESOURCE_ATTRIBUTES = + 'service.instance.id=627cc493,service.name=my-service,service.namespace=default,service.version=0.0.1'; + }); + + afterEach(() => { + delete process.env.OTEL_RESOURCE_ATTRIBUTES; + }); + + // Local function to test if a mocked method is ever called with a specific argument or regex matching for an argument. + // Needed because of race condition with parallel detectors. + const callArgsMatches = ( + mockedFunction: Sinon.SinonSpy, + regex: RegExp + ): boolean => { + return mockedFunction.getCalls().some(call => { + return call.args.some(callArgs => regex.test(callArgs.toString())); + }); + }; + + it('returns a merged resource with custom resource', async () => { + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, { + resourceDetectors: [ + processDetector, + { + detect(): DetectedResource { + return { + attributes: { customAttr: 'someValue' }, + }; + }, + }, + envDetector, + hostDetector, + ], + }); + await resource.waitForAsyncAttributes?.(); + + assert.strictEqual(resource.attributes['customAttr'], 'someValue'); + assertServiceResource(resource, { + instanceId: '627cc493', + name: 'my-service', + namespace: 'default', + version: '0.0.1', + }); + }); + + it('default detectors populate values properly', async () => { + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, {}); + await resource.waitForAsyncAttributes?.(); + + assertServiceResource(resource, { + instanceId: '627cc493', + name: 'my-service', + namespace: 'default', + version: '0.0.1', + }); + + assert.notEqual(resource.attributes[ATTR_PROCESS_PID], undefined); + assert.notEqual(resource.attributes[ATTR_HOST_NAME], undefined); + }); + + it('returns a merged resource with a buggy detector', async () => { + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, { + resourceDetectors: [ + processDetector, + { + detect() { + throw new Error('Buggy detector'); + }, + }, + envDetector, + hostDetector, + ], + }); + await resource.waitForAsyncAttributes?.(); + + assertServiceResource(resource, { + instanceId: '627cc493', + name: 'my-service', + namespace: 'default', + version: '0.0.1', + }); + }); + + // 1. If not auto-detecting resources, then NodeSDK should not + // complain about `OTEL_NODE_RESOURCE_DETECTORS` values. + // 2. If given resourceDetectors, then NodeSDK should not complain + // about `OTEL_NODE_RESOURCE_DETECTORS` values. + // + // Practically, these tests help ensure that there is no spurious + // diag error message when using OTEL_NODE_RESOURCE_DETECTORS with + // @opentelemetry/auto-instrumentations-node, which supports more values + // than this package (e.g. 'gcp'). + it('does not diag.warn when not using the envvar', async () => { + process.env.OTEL_NODE_RESOURCE_DETECTORS = 'env,os,no-such-detector'; + const diagMocks = { + error: Sinon.fake(), + warn: Sinon.fake(), + info: Sinon.fake(), + debug: Sinon.fake(), + verbose: Sinon.fake(), + }; + diag.setLogger(diagMocks, DiagLogLevel.DEBUG); + const sdk1 = startNodeSDK({ autoDetectResources: false }); + await sdk1.shutdown(); + + const sdk2 = startNodeSDK({ resourceDetectors: [envDetector] }); + await sdk2.shutdown(); + + assert.ok( + !callArgsMatches(diagMocks.error, /no-such-detector/), + 'diag.error() messages do not mention "no-such-detector"' + ); + }); + }); + + describe('configureServiceName', async () => { + it('should configure service name via config', async () => { + process.env.OTEL_RESOURCE_ATTRIBUTES = + 'service.instance.id=my-instance-id'; + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, { + serviceName: 'config-set-name', + }); + + assertServiceResource(resource, { + name: 'config-set-name', + instanceId: 'my-instance-id', + }); + }); + + it('should configure service name via OTEL_SERVICE_NAME env var', async () => { + process.env.OTEL_SERVICE_NAME = 'env-set-name'; + process.env.OTEL_RESOURCE_ATTRIBUTES = + 'service.instance.id=my-instance-id'; + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, {}); + await resource.waitForAsyncAttributes?.(); + + assertServiceResource(resource, { + name: 'env-set-name', + instanceId: 'my-instance-id', + }); + }); + + it('should favor config set service name over OTEL_SERVICE_NAME env set service name', async () => { + process.env.OTEL_SERVICE_NAME = 'env-set-name'; + process.env.OTEL_RESOURCE_ATTRIBUTES = + 'service.instance.id=my-instance-id'; + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, { + serviceName: 'config-set-name', + }); + await resource.waitForAsyncAttributes?.(); + + assertServiceResource(resource, { + name: 'config-set-name', + instanceId: 'my-instance-id', + }); + }); + + it('should configure service name via OTEL_RESOURCE_ATTRIBUTES env var', async () => { + process.env.OTEL_RESOURCE_ATTRIBUTES = + 'service.name=resource-env-set-name,service.instance.id=my-instance-id'; + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, {}); + await resource.waitForAsyncAttributes?.(); + + assertServiceResource(resource, { + name: 'resource-env-set-name', + instanceId: 'my-instance-id', + }); + }); + + it('should favor config set service name over OTEL_RESOURCE_ATTRIBUTES env set service name', async () => { + process.env.OTEL_RESOURCE_ATTRIBUTES = + 'service.name=resource-env-set-name,service.instance.id=my-instance-id'; + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, { + serviceName: 'config-set-name', + }); + await resource.waitForAsyncAttributes?.(); + + assertServiceResource(resource, { + name: 'config-set-name', + instanceId: 'my-instance-id', + }); + }); + }); + + describe('configureServiceInstanceId', async () => { + it('should configure service instance id via OTEL_RESOURCE_ATTRIBUTES env var', async () => { + process.env.OTEL_RESOURCE_ATTRIBUTES = + 'service.instance.id=627cc493,service.name=my-service,service.namespace'; + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, {}); + await resource.waitForAsyncAttributes?.(); + + assertServiceResource(resource, { + name: 'my-service', + instanceId: '627cc493', + }); + }); + + it('should configure service instance id via OTEL_NODE_RESOURCE_DETECTORS env var', async () => { + process.env.OTEL_NODE_RESOURCE_DETECTORS = 'env,host,os,serviceinstance'; + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, {}); + await resource.waitForAsyncAttributes?.(); + + assertServiceInstanceIdIsUUID(resource); + }); + + it('should configure service instance id with random UUID', async () => { + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, { + autoDetectResources: true, + resourceDetectors: [ + processDetector, + envDetector, + hostDetector, + serviceInstanceIdDetector, + ], + }); + await resource.waitForAsyncAttributes?.(); + + assertServiceInstanceIdIsUUID(resource); + }); + }); + + describe('A disabled SDK should be no-op', () => { + beforeEach(() => { + process.env.OTEL_SDK_DISABLED = 'true'; + }); + + it('should not register a trace provider', async () => { + const sdk = startNodeSDK({}); + + assert.strictEqual( + (trace.getTracerProvider() as ProxyTracerProvider).getDelegate(), + delegate, + 'sdk.start() should not change the global tracer provider' + ); + + await sdk.shutdown(); + }); + }); + + describe('configuring logger provider from env', () => { + let stubLogger: Sinon.SinonStub; + + beforeEach(() => { + stubLogger = Sinon.stub(diag, 'info'); + }); + + afterEach(() => { + stubLogger.reset(); + }); + + it('should not register the provider if OTEL_LOGS_EXPORTER contains none', async () => { + const logsAPIStub = Sinon.spy(logs, 'setGlobalLoggerProvider'); + process.env.OTEL_LOGS_EXPORTER = 'console,none'; + const sdk = startNodeSDK({}); + assert.strictEqual( + stubLogger.args[0][0], + 'OTEL_LOGS_EXPORTER contains "none". Logger provider will not be initialized.' + ); + + Sinon.assert.notCalled(logsAPIStub); + await sdk.shutdown(); + }); + + it('should not set logger provider by default', async () => { + const logsAPIStub = Sinon.spy(logs, 'setGlobalLoggerProvider'); + const sdk = startNodeSDK({}); + Sinon.assert.notCalled(logsAPIStub); + await sdk.shutdown(); + }); + + it('should set up all allowed exporters', async () => { + process.env.OTEL_LOGS_EXPORTER = 'console,otlp'; + const sdk = startNodeSDK({}); + + const loggerProvider = logs.getLoggerProvider(); + const sharedState = (loggerProvider as any)['_sharedState']; + assert.ok(sharedState.registeredLogRecordProcessors.length === 2); + assert.ok( + sharedState.registeredLogRecordProcessors[0]._exporter instanceof + ConsoleLogRecordExporter + ); + assert.ok( + sharedState.registeredLogRecordProcessors[0] instanceof + SimpleLogRecordProcessor + ); + // defaults to http/protobuf + assert.ok( + sharedState.registeredLogRecordProcessors[1]._exporter instanceof + OTLPProtoLogExporter + ); + assert.ok( + sharedState.registeredLogRecordProcessors[1] instanceof + BatchLogRecordProcessor + ); + await sdk.shutdown(); + }); + + it('should use OTEL_EXPORTER_OTLP_LOGS_PROTOCOL for otlp protocol', async () => { + process.env.OTEL_LOGS_EXPORTER = 'otlp'; + process.env.OTEL_EXPORTER_OTLP_LOGS_PROTOCOL = 'grpc'; + const sdk = startNodeSDK({}); + + const loggerProvider = logs.getLoggerProvider(); + const sharedState = (loggerProvider as any)['_sharedState']; + assert.ok(sharedState.registeredLogRecordProcessors.length === 1); + assert.ok( + sharedState.registeredLogRecordProcessors[0]._exporter instanceof + OTLPGrpcLogExporter + ); + await sdk.shutdown(); + }); + + it('should use OTLPHttpLogExporter when http/json is set', async () => { + process.env.OTEL_LOGS_EXPORTER = 'otlp'; + process.env.OTEL_EXPORTER_OTLP_LOGS_PROTOCOL = 'http/json'; + const sdk = startNodeSDK({}); + + const loggerProvider = logs.getLoggerProvider(); + const sharedState = (loggerProvider as any)['_sharedState']; + assert.ok(sharedState.registeredLogRecordProcessors.length === 1); + assert.ok( + sharedState.registeredLogRecordProcessors[0]._exporter instanceof + OTLPHttpLogExporter + ); + await sdk.shutdown(); + }); + + it('should fall back to OTEL_EXPORTER_OTLP_PROTOCOL', async () => { + process.env.OTEL_LOGS_EXPORTER = 'otlp'; + process.env.OTEL_EXPORTER_OTLP_PROTOCOL = 'grpc'; + const sdk = startNodeSDK({}); + + const loggerProvider = logs.getLoggerProvider(); + const sharedState = (loggerProvider as any)['_sharedState']; + assert.ok(sharedState.registeredLogRecordProcessors.length === 1); + assert.ok( + sharedState.registeredLogRecordProcessors[0]._exporter instanceof + OTLPGrpcLogExporter + ); + await sdk.shutdown(); + }); + + it('should fall back to http/protobuf if invalid protocol is set', async () => { + process.env.OTEL_LOGS_EXPORTER = 'otlp'; + process.env.OTEL_EXPORTER_OTLP_LOGS_PROTOCOL = 'grpc2'; + const sdk = startNodeSDK({}); + + const loggerProvider = logs.getLoggerProvider(); + const sharedState = (loggerProvider as any)['_sharedState']; + assert.ok(sharedState.registeredLogRecordProcessors.length === 1); + assert.ok( + sharedState.registeredLogRecordProcessors[0]._exporter instanceof + OTLPProtoLogExporter + ); + await sdk.shutdown(); + }); + }); }); function assertDefaultContextManagerRegistered() { @@ -60,3 +668,11 @@ function assertDefaultContextManagerRegistered() { AsyncLocalStorageContextManager.name ); } + +function assertDefaultPropagatorRegistered() { + assert.deepStrictEqual(propagation.fields(), [ + 'traceparent', + 'tracestate', + 'baggage', + ]); +} diff --git a/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts b/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts index 0938b6090fb..381f04af5cd 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts @@ -21,7 +21,7 @@ import { ATTR_SERVICE_VERSION, } from '@opentelemetry/semantic-conventions'; -import { ATTR_SERVICE_INSTANCE_ID, ATTR_SERVICE_NAMESPACE } from '../semconv'; +import { ATTR_SERVICE_INSTANCE_ID, ATTR_SERVICE_NAMESPACE } from '../../src/semconv'; /** * Test utility method to validate a service resource From 077e462d36ef7767aca3d4aa47ff6986baf7198d Mon Sep 17 00:00:00 2001 From: maryliag Date: Mon, 24 Nov 2025 20:22:18 -0500 Subject: [PATCH 05/13] move functions --- .../opentelemetry-sdk-node/src/start.ts | 83 +++---------------- .../opentelemetry-sdk-node/src/utils.ts | 83 +++++++++++++++++-- 2 files changed, 86 insertions(+), 80 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index 1d869ca8987..76cf0e4f79d 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -17,30 +17,18 @@ import { ConfigFactory, ConfigurationModel, createConfigFactory, - LogRecordExporterModel, } from '@opentelemetry/configuration'; -import { diag, DiagConsoleLogger } from '@opentelemetry/api'; +import { context, diag, DiagConsoleLogger } from '@opentelemetry/api'; import { getInstanceID, + getLogRecordProcessorsFromConfiguration, getPropagatorFromConfiguration, getResourceDetectorsFromConfiguration, - setupDefaultContextManager, setupPropagator, } from './utils'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; import type { SDKOptions } from './types'; -import { - BatchLogRecordProcessor, - ConsoleLogRecordExporter, - LoggerProvider, - LogRecordExporter, - LogRecordProcessor, - SimpleLogRecordProcessor, -} from '@opentelemetry/sdk-logs'; -import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; -import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc'; -import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'; -import { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base'; +import { LoggerProvider } from '@opentelemetry/sdk-logs'; import { logs } from '@opentelemetry/api-logs'; import { defaultResource, @@ -55,6 +43,7 @@ import { resourceFromAttributes, serviceInstanceIdDetector, } from '@opentelemetry/resources'; +import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; import { ATTR_SERVICE_INSTANCE_ID } from './semconv'; @@ -155,6 +144,12 @@ export function setupResource( return resource; } +function setupDefaultContextManager() { + const defaultContextManager = new AsyncLocalStorageContextManager(); + defaultContextManager.enable(); + context.setGlobalContextManager(defaultContextManager); +} + function setupLoggerProvider( config: ConfigurationModel, sdkOptions: SDKOptions, @@ -175,61 +170,3 @@ function setupLoggerProvider( } return undefined; } - -function getLogRecordExporter( - exporter: LogRecordExporterModel -): LogRecordExporter { - if (exporter.otlp_http) { - if (exporter.otlp_http.encoding === 'json') { - return new OTLPHttpLogExporter({ - compression: - exporter.otlp_http.compression === 'gzip' - ? CompressionAlgorithm.GZIP - : CompressionAlgorithm.NONE, - }); - } - if (exporter.otlp_http.encoding === 'protobuf') { - return new OTLPProtoLogExporter(); - } - diag.warn(`Unsupported OTLP logs protocol. Using http/protobuf.`); - return new OTLPProtoLogExporter(); - } else if (exporter.otlp_grpc) { - return new OTLPGrpcLogExporter(); - } else if (exporter.console) { - return new ConsoleLogRecordExporter(); - } - diag.warn(`Unsupported Exporter value. Using OTLP http/protobuf.`); - return new OTLPProtoLogExporter(); -} - -function getLogRecordProcessorsFromConfiguration( - config: ConfigurationModel -): LogRecordProcessor[] | undefined { - const logRecordProcessors: LogRecordProcessor[] = []; - config.logger_provider?.processors?.forEach(processor => { - if (processor.batch) { - logRecordProcessors.push( - new BatchLogRecordProcessor( - getLogRecordExporter(processor.batch.exporter), - { - maxQueueSize: processor.batch.max_queue_size, - maxExportBatchSize: processor.batch.max_export_batch_size, - scheduledDelayMillis: processor.batch.schedule_delay, - exportTimeoutMillis: processor.batch.export_timeout, - } - ) - ); - } - if (processor.simple) { - logRecordProcessors.push( - new SimpleLogRecordProcessor( - getLogRecordExporter(processor.simple.exporter) - ) - ); - } - }); - if (logRecordProcessors.length > 0) { - return logRecordProcessors; - } - return undefined; -} diff --git a/experimental/packages/opentelemetry-sdk-node/src/utils.ts b/experimental/packages/opentelemetry-sdk-node/src/utils.ts index aa6f12fc2f9..e2463148e04 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/utils.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/utils.ts @@ -50,7 +50,21 @@ import { import { B3InjectEncoding, B3Propagator } from '@opentelemetry/propagator-b3'; import { JaegerPropagator } from '@opentelemetry/propagator-jaeger'; import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; -import { ConfigurationModel } from '@opentelemetry/configuration'; +import { + BatchLogRecordProcessor, + ConsoleLogRecordExporter, + LogRecordExporter, + LogRecordProcessor, + SimpleLogRecordProcessor, +} from '@opentelemetry/sdk-logs'; +import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; +import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc'; +import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'; +import { CompressionAlgorithm } from '@opentelemetry/otlp-exporter-base'; +import { + ConfigurationModel, + LogRecordExporterModel, +} from '@opentelemetry/configuration'; const RESOURCE_DETECTOR_ENVIRONMENT = 'env'; const RESOURCE_DETECTOR_HOST = 'host'; @@ -341,12 +355,6 @@ export function setupContextManager( context.setGlobalContextManager(contextManager); } -export function setupDefaultContextManager() { - const defaultContextManager = new AsyncLocalStorageContextManager(); - defaultContextManager.enable(); - context.setGlobalContextManager(defaultContextManager); -} - export function setupPropagator( propagator: TextMapPropagator | null | undefined ) { @@ -382,6 +390,67 @@ export function getKeyListFromObjectArray( .reduce((prev, curr) => prev.concat(curr), []); } +export function getLogRecordExporter( + exporter: LogRecordExporterModel +): LogRecordExporter { + if (exporter.otlp_http) { + const encoding = exporter.otlp_http.encoding; + if (encoding === 'json') { + return new OTLPHttpLogExporter({ + compression: + exporter.otlp_http.compression === 'gzip' + ? CompressionAlgorithm.GZIP + : CompressionAlgorithm.NONE, + }); + } + if (encoding === 'protobuf') { + return new OTLPProtoLogExporter(); + } + diag.warn( + `Unsupported OTLP logs encoding: ${encoding}. Using http/protobuf.` + ); + return new OTLPProtoLogExporter(); + } else if (exporter.otlp_grpc) { + return new OTLPGrpcLogExporter(); + } else if (exporter.console) { + return new ConsoleLogRecordExporter(); + } + diag.warn(`Unsupported Exporter value. Using OTLP http/protobuf.`); + return new OTLPProtoLogExporter(); +} + +export function getLogRecordProcessorsFromConfiguration( + config: ConfigurationModel +): LogRecordProcessor[] | undefined { + const logRecordProcessors: LogRecordProcessor[] = []; + config.logger_provider?.processors?.forEach(processor => { + if (processor.batch) { + logRecordProcessors.push( + new BatchLogRecordProcessor( + getLogRecordExporter(processor.batch.exporter), + { + maxQueueSize: processor.batch.max_queue_size, + maxExportBatchSize: processor.batch.max_export_batch_size, + scheduledDelayMillis: processor.batch.schedule_delay, + exportTimeoutMillis: processor.batch.export_timeout, + } + ) + ); + } + if (processor.simple) { + logRecordProcessors.push( + new SimpleLogRecordProcessor( + getLogRecordExporter(processor.simple.exporter) + ) + ); + } + }); + if (logRecordProcessors.length > 0) { + return logRecordProcessors; + } + return undefined; +} + export function getInstanceID(config: ConfigurationModel): string | undefined { if (config.resource?.attributes) { for (let i = 0; i < config.resource.attributes.length; i++) { From 4643c5f9df91936f31399d138c7ec10c257788ba Mon Sep 17 00:00:00 2001 From: maryliag Date: Mon, 24 Nov 2025 20:26:29 -0500 Subject: [PATCH 06/13] fix lint --- .../opentelemetry-sdk-node/test/util/resource-assertions.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts b/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts index 381f04af5cd..ca7159206b1 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts @@ -21,7 +21,10 @@ import { ATTR_SERVICE_VERSION, } from '@opentelemetry/semantic-conventions'; -import { ATTR_SERVICE_INSTANCE_ID, ATTR_SERVICE_NAMESPACE } from '../../src/semconv'; +import { + ATTR_SERVICE_INSTANCE_ID, + ATTR_SERVICE_NAMESPACE, +} from '../../src/semconv'; /** * Test utility method to validate a service resource From 3e1103ca4cc64731cc33bd233e8572407e05ca77 Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 25 Nov 2025 10:37:18 -0500 Subject: [PATCH 07/13] remove sdk options --- .../opentelemetry-sdk-node/src/start.ts | 22 +- .../opentelemetry-sdk-node/src/types.ts | 3 - .../opentelemetry-sdk-node/src/utils.ts | 1 + .../test/fixtures/kitchen-sink.yaml | 950 ++++++++++++++++++ .../test/fixtures/logger-test.yaml | 117 +++ .../opentelemetry-sdk-node/test/start.test.ts | 131 +-- 6 files changed, 1089 insertions(+), 135 deletions(-) create mode 100644 experimental/packages/opentelemetry-sdk-node/test/fixtures/kitchen-sink.yaml create mode 100644 experimental/packages/opentelemetry-sdk-node/test/fixtures/logger-test.yaml diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index 76cf0e4f79d..2c94d705d4d 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -44,7 +44,6 @@ import { serviceInstanceIdDetector, } from '@opentelemetry/resources'; import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; -import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; import { ATTR_SERVICE_INSTANCE_ID } from './semconv'; /** @@ -96,15 +95,15 @@ export function setupResource( sdkOptions: SDKOptions ): Resource { let resource: Resource = sdkOptions.resource ?? defaultResource(); - const autoDetectResources = sdkOptions.autoDetectResources ?? true; + let autoDetectResources = false; let resourceDetectors: ResourceDetector[]; - if (!autoDetectResources) { - resourceDetectors = []; - } else if (sdkOptions.resourceDetectors != null) { + if (sdkOptions.resourceDetectors != null) { resourceDetectors = sdkOptions.resourceDetectors; + autoDetectResources = true; } else if (config.node_resource_detectors) { resourceDetectors = getResourceDetectorsFromConfiguration(config); + autoDetectResources = true; } else { resourceDetectors = [ envDetector, @@ -119,18 +118,9 @@ export function setupResource( const internalConfig: ResourceDetectionConfig = { detectors: resourceDetectors, }; - resource = resource.merge(detectResources(internalConfig)); } - resource = - sdkOptions.serviceName === undefined - ? resource - : resource.merge( - resourceFromAttributes({ - [ATTR_SERVICE_NAME]: sdkOptions.serviceName, - }) - ); const instanceId = getInstanceID(config); resource = instanceId === undefined @@ -155,9 +145,7 @@ function setupLoggerProvider( sdkOptions: SDKOptions, resource: Resource | undefined ): LoggerProvider | undefined { - const logProcessors = - sdkOptions.logRecordProcessors ?? - getLogRecordProcessorsFromConfiguration(config); + const logProcessors = getLogRecordProcessorsFromConfiguration(config); if (logProcessors) { const loggerProvider = new LoggerProvider({ diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index 19d3998f2eb..16ca3bba5d5 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -55,11 +55,8 @@ export interface NodeSDKConfiguration { * @experimental Options for new experimental SDK setup */ export interface SDKOptions { - autoDetectResources?: boolean; instrumentations?: (Instrumentation | Instrumentation[])[]; - logRecordProcessors?: LogRecordProcessor[]; resource?: Resource; resourceDetectors?: ResourceDetector[]; - serviceName?: string; textMapPropagator?: TextMapPropagator | null; } diff --git a/experimental/packages/opentelemetry-sdk-node/src/utils.ts b/experimental/packages/opentelemetry-sdk-node/src/utils.ts index e2463148e04..fa194074221 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/utils.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/utils.ts @@ -393,6 +393,7 @@ export function getKeyListFromObjectArray( export function getLogRecordExporter( exporter: LogRecordExporterModel ): LogRecordExporter { + console.log("AAA ", exporter); if (exporter.otlp_http) { const encoding = exporter.otlp_http.encoding; if (encoding === 'json') { diff --git a/experimental/packages/opentelemetry-sdk-node/test/fixtures/kitchen-sink.yaml b/experimental/packages/opentelemetry-sdk-node/test/fixtures/kitchen-sink.yaml new file mode 100644 index 00000000000..f44e11628dd --- /dev/null +++ b/experimental/packages/opentelemetry-sdk-node/test/fixtures/kitchen-sink.yaml @@ -0,0 +1,950 @@ +# kitchen-sink.yaml demonstrates all configurable surface area, including explanatory comments. +# +# It DOES NOT represent expected real world configuration, as it makes strange configuration +# choices in an effort to exercise the full surface area. +# +# Configuration values are set to their defaults when default values are defined. + +# The file format version. +# The yaml format is documented at +# https://github.com/open-telemetry/opentelemetry-configuration/tree/main/schema +file_format: "1.0-rc.2" +# Configure if the SDK is disabled or not. +# If omitted or null, false is used. +disabled: false +# Configure the log level of the internal logger used by the SDK. +# If omitted, info is used. +log_level: info +# Configure general attribute limits. See also tracer_provider.limits, logger_provider.limits. +attribute_limits: + # Configure max attribute value size. + # Value must be non-negative. + # If omitted or null, there is no limit. + attribute_value_length_limit: 4096 + # Configure max attribute count. + # Value must be non-negative. + # If omitted or null, 128 is used. + attribute_count_limit: 128 +# Configure logger provider. +# If omitted, a noop logger provider is used. +logger_provider: + # Configure log record processors. + processors: + - # Configure a batch log record processor. + batch: + # Configure delay interval (in milliseconds) between two consecutive exports. + # Value must be non-negative. + # If omitted or null, 1000 is used. + schedule_delay: 5000 + # Configure maximum allowed time (in milliseconds) to export data. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 30000 is used. + export_timeout: 30000 + # Configure maximum queue size. Value must be positive. + # If omitted or null, 2048 is used. + max_queue_size: 2048 + # Configure maximum batch size. Value must be positive. + # If omitted or null, 512 is used. + max_export_batch_size: 512 + # Configure exporter. + exporter: + # Configure exporter to be OTLP with HTTP transport. + otlp_http: + endpoint: http://localhost:4318/v1/logs + # Configure certificate used to verify a server's TLS credentials. + # Absolute path to certificate file in PEM format. + # If omitted or null, system default certificate verification is used for secure connections. + certificate_file: /app/cert.pem + # Configure mTLS private client key. + # Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + # If omitted or null, mTLS is not used. + client_key_file: /app/cert.pem + # Configure mTLS client certificate. + # Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + # If omitted or null, mTLS is not used. + client_certificate_file: /app/cert.pem + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: "api-key=1234" + # Configure compression. + # Values include: gzip, none. Implementations may support other compression algorithms. + # If omitted or null, none is used. + compression: gzip + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure the encoding used for messages. + # Values include: protobuf, json. Implementations may not support json. + # If omitted or null, protobuf is used. + encoding: protobuf + - # Configure a batch log record processor. + batch: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with gRPC transport. + otlp_grpc: + # Configure endpoint. + # If omitted or null, http://localhost:4317 is used. + endpoint: http://localhost:4317 + # Configure certificate used to verify a server's TLS credentials. + # Absolute path to certificate file in PEM format. + # If omitted or null, system default certificate verification is used for secure connections. + certificate_file: /app/cert.pem + # Configure mTLS private client key. + # Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + # If omitted or null, mTLS is not used. + client_key_file: /app/cert.pem + # Configure mTLS client certificate. + # Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + # If omitted or null, mTLS is not used. + client_certificate_file: /app/cert.pem + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: "api-key=1234" + # Configure compression. + # Values include: gzip, none. Implementations may support other compression algorithms. + # If omitted or null, none is used. + compression: gzip + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure client transport security for the exporter's connection. + # Only applicable when .endpoint is provided without http or https scheme. Implementations may choose to ignore .insecure. + # If omitted or null, false is used. + insecure: false + - # Configure a batch log record processor. + batch: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with file transport. + # This type is in development and subject to breaking changes in minor versions. + otlp_file/development: + # Configure output stream. + # Values include stdout, or scheme+destination. For example: file:///path/to/file.jsonl. + # If omitted or null, stdout is used. + output_stream: file:///var/log/logs.jsonl + - # Configure a batch log record processor. + batch: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with file transport. + # This type is in development and subject to breaking changes in minor versions. + otlp_file/development: + # Configure output stream. + # Values include stdout, or scheme+destination. For example: file:///path/to/file.jsonl. + # If omitted or null, stdout is used. + output_stream: stdout + - # Configure a simple log record processor. + simple: + # Configure exporter. + exporter: + # Configure exporter to be console. + console: + # Configure log record limits. See also attribute_limits. + limits: + # Configure max attribute value size. Overrides .attribute_limits.attribute_value_length_limit. + # Value must be non-negative. + # If omitted or null, there is no limit. + attribute_value_length_limit: 4096 + # Configure max attribute count. Overrides .attribute_limits.attribute_count_limit. + # Value must be non-negative. + # If omitted or null, 128 is used. + attribute_count_limit: 128 + # Configure loggers. + # This type is in development and subject to breaking changes in minor versions. + logger_configurator/development: + # Configure the default logger config used there is no matching entry in .logger_configurator/development.loggers. + default_config: + # Configure if the logger is enabled or not. + disabled: true + # Configure loggers. + loggers: + - # Configure logger names to match, evaluated as follows: + # + # * If the logger name exactly matches. + # * If the logger name matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + name: io.opentelemetry.contrib.* + # The logger config. + config: + # Configure if the logger is enabled or not. + disabled: false +# Configure meter provider. +# If omitted, a noop meter provider is used. +meter_provider: + # Configure metric readers. + readers: + - # Configure a pull based metric reader. + pull: + # Configure exporter. + exporter: + # Configure exporter to be prometheus. + # This type is in development and subject to breaking changes in minor versions. + prometheus/development: + # Configure host. + # If omitted or null, localhost is used. + host: localhost + # Configure port. + # If omitted or null, 9464 is used. + port: 9464 + # Configure Prometheus Exporter to produce metrics without a scope info metric. + # If omitted or null, false is used. + without_scope_info: false + # Configure Prometheus Exporter to add resource attributes as metrics attributes. + with_resource_constant_labels: + # Configure resource attributes to be included. + # Attribute keys from resources are evaluated to match as follows: + # * If the value of the attribute key exactly matches. + # * If the value of the attribute key matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + # If omitted, no resource attributes are included. + included: + - "service*" + # Configure resource attributes to be excluded. Applies after .with_resource_constant_labels.included (i.e. excluded has higher priority than included). + # Attribute keys from resources are evaluated to match as follows: + # * If the value of the attribute key exactly matches. + # * If the value of the attribute key matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + # If omitted, .included resource attributes are included. + excluded: + - "service.attr1" + # Configure how Prometheus metrics are exposed. Values include: + # + # * UnderscoreEscapingWithSuffixes, the default. This fully escapes metric names for classic Prometheus metric name compatibility, and includes appending type and unit suffixes. + # * UnderscoreEscapingWithoutSuffixes, metric names will continue to escape special characters to _, but suffixes won't be attached. + # * NoUTF8EscapingWithSuffixes will disable changing special characters to _. Special suffixes like units and _total for counters will be attached. + # * NoTranslation. This strategy bypasses all metric and label name translation, passing them through unaltered. + # + # If omitted or null, UnderscoreEscapingWithSuffixes is used. + translation_strategy: UnderscoreEscapingWithSuffixes + # Configure metric producers. + producers: + - # Configure metric producer to be opencensus. + opencensus: + # Configure cardinality limits. + cardinality_limits: + # Configure default cardinality limit for all instrument types. + # Instrument-specific cardinality limits take priority. + # If omitted or null, 2000 is used. + default: 2000 + # Configure default cardinality limit for counter instruments. + # If omitted or null, the value from .default is used. + counter: 2000 + # Configure default cardinality limit for gauge instruments. + # If omitted or null, the value from .default is used. + gauge: 2000 + # Configure default cardinality limit for histogram instruments. + # If omitted or null, the value from .default is used. + histogram: 2000 + # Configure default cardinality limit for observable_counter instruments. + # If omitted or null, the value from .default is used. + observable_counter: 2000 + # Configure default cardinality limit for observable_gauge instruments. + # If omitted or null, the value from .default is used. + observable_gauge: 2000 + # Configure default cardinality limit for observable_up_down_counter instruments. + # If omitted or null, the value from .default is used. + observable_up_down_counter: 2000 + # Configure default cardinality limit for up_down_counter instruments. + # If omitted or null, the value from .default is used. + up_down_counter: 2000 + - # Configure a periodic metric reader. + periodic: + # Configure delay interval (in milliseconds) between start of two consecutive exports. + # Value must be non-negative. + # If omitted or null, 60000 is used. + interval: 60000 + # Configure maximum allowed time (in milliseconds) to export data. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 30000 is used. + timeout: 30000 + # Configure exporter. + exporter: + # Configure exporter to be OTLP with HTTP transport. + otlp_http: + # Configure endpoint, including the metric specific path. + # If omitted or null, http://localhost:4318/v1/metrics is used. + endpoint: http://localhost:4318/v1/metrics + # Configure certificate used to verify a server's TLS credentials. + # Absolute path to certificate file in PEM format. + # If omitted or null, system default certificate verification is used for secure connections. + certificate_file: /app/cert.pem + # Configure mTLS private client key. + # Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + # If omitted or null, mTLS is not used. + client_key_file: /app/cert.pem + # Configure mTLS client certificate. + # Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + # If omitted or null, mTLS is not used. + client_certificate_file: /app/cert.pem + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: "api-key=1234" + # Configure compression. + # Values include: gzip, none. Implementations may support other compression algorithms. + # If omitted or null, none is used. + compression: gzip + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure the encoding used for messages. + # Values include: protobuf, json. Implementations may not support json. + # If omitted or null, protobuf is used. + encoding: protobuf + # Configure temporality preference. + # Values include: cumulative, delta, low_memory. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + # If omitted or null, cumulative is used. + temporality_preference: delta + # Configure default histogram aggregation. + # Values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + # If omitted or null, explicit_bucket_histogram is used. + default_histogram_aggregation: base2_exponential_bucket_histogram + # Configure metric producers. + producers: + - # Configure metric producer to be prometheus. + prometheus: + # Configure cardinality limits. + cardinality_limits: + # Configure default cardinality limit for all instrument types. + # Instrument-specific cardinality limits take priority. + # If omitted or null, 2000 is used. + default: 2000 + # Configure default cardinality limit for counter instruments. + # If omitted or null, the value from .default is used. + counter: 2000 + # Configure default cardinality limit for gauge instruments. + # If omitted or null, the value from .default is used. + gauge: 2000 + # Configure default cardinality limit for histogram instruments. + # If omitted or null, the value from .default is used. + histogram: 2000 + # Configure default cardinality limit for observable_counter instruments. + # If omitted or null, the value from .default is used. + observable_counter: 2000 + # Configure default cardinality limit for observable_gauge instruments. + # If omitted or null, the value from .default is used. + observable_gauge: 2000 + # Configure default cardinality limit for observable_up_down_counter instruments. + # If omitted or null, the value from .default is used. + observable_up_down_counter: 2000 + # Configure default cardinality limit for up_down_counter instruments. + # If omitted or null, the value from .default is used. + up_down_counter: 2000 + - # Configure a periodic metric reader. + periodic: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with gRPC transport. + otlp_grpc: + # Configure endpoint. + # If omitted or null, http://localhost:4317 is used. + endpoint: http://localhost:4317 + # Configure certificate used to verify a server's TLS credentials. + # Absolute path to certificate file in PEM format. + # If omitted or null, system default certificate verification is used for secure connections. + certificate_file: /app/cert.pem + # Configure mTLS private client key. + # Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + # If omitted or null, mTLS is not used. + client_key_file: /app/cert.pem + # Configure mTLS client certificate. + # Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + # If omitted or null, mTLS is not used. + client_certificate_file: /app/cert.pem + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: "api-key=1234" + # Configure compression. + # Values include: gzip, none. Implementations may support other compression algorithms. + # If omitted or null, none is used. + compression: gzip + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure client transport security for the exporter's connection. + # Only applicable when .endpoint is provided without http or https scheme. Implementations may choose to ignore .insecure. + # If omitted or null, false is used. + insecure: false + # Configure temporality preference. + # Values include: cumulative, delta, low_memory. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + # If omitted or null, cumulative is used. + temporality_preference: delta + # Configure default histogram aggregation. + # Values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + # If omitted or null, explicit_bucket_histogram is used. + default_histogram_aggregation: base2_exponential_bucket_histogram + - # Configure a periodic metric reader. + periodic: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with file transport. + # This type is in development and subject to breaking changes in minor versions. + otlp_file/development: + # Configure output stream. + # Values include stdout, or scheme+destination. For example: file:///path/to/file.jsonl. + # If omitted or null, stdout is used. + output_stream: file:///var/log/metrics.jsonl + # Configure temporality preference. Values include: cumulative, delta, low_memory. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + # If omitted or null, cumulative is used. + temporality_preference: delta + # Configure default histogram aggregation. Values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + # If omitted or null, explicit_bucket_histogram is used. + default_histogram_aggregation: base2_exponential_bucket_histogram + - # Configure a periodic metric reader. + periodic: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with file transport. + # This type is in development and subject to breaking changes in minor versions. + otlp_file/development: + # Configure output stream. + # Values include stdout, or scheme+destination. For example: file:///path/to/file.jsonl. + # If omitted or null, stdout is used. + output_stream: stdout + # Configure temporality preference. Values include: cumulative, delta, low_memory. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + # If omitted or null, cumulative is used. + temporality_preference: delta + # Configure default histogram aggregation. Values include: explicit_bucket_histogram, base2_exponential_bucket_histogram. For behavior of values, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk_exporters/otlp.md. + # If omitted or null, explicit_bucket_histogram is used. + default_histogram_aggregation: base2_exponential_bucket_histogram + - # Configure a periodic metric reader. + periodic: + # Configure exporter. + exporter: + # Configure exporter to be console. + console: + # Configure views. + # Each view has a selector which determines the instrument(s) it applies to, and a configuration for the resulting stream(s). + views: + - # Configure view selector. + # Selection criteria is additive as described in https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#instrument-selection-criteria. + selector: + # Configure instrument name selection criteria. + # If omitted or null, all instrument names match. + instrument_name: my-instrument + # Configure instrument type selection criteria. + # Values include: counter, gauge, histogram, observable_counter, observable_gauge, observable_up_down_counter, up_down_counter. + # If omitted or null, all instrument types match. + instrument_type: histogram + # Configure the instrument unit selection criteria. + # If omitted or null, all instrument units match. + unit: ms + # Configure meter name selection criteria. + # If omitted or null, all meter names match. + meter_name: my-meter + # Configure meter version selection criteria. + # If omitted or null, all meter versions match. + meter_version: 1.0.0 + # Configure meter schema url selection criteria. + # If omitted or null, all meter schema URLs match. + meter_schema_url: https://opentelemetry.io/schemas/1.16.0 + # Configure view stream. + stream: + # Configure metric name of the resulting stream(s). + # If omitted or null, the instrument's original name is used. + name: new_instrument_name + # Configure metric description of the resulting stream(s). + # If omitted or null, the instrument's origin description is used. + description: new_description + # Configure aggregation of the resulting stream(s). + # Values include: default, drop, explicit_bucket_histogram, base2_exponential_bucket_histogram, last_value, sum. For behavior of values see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#aggregation. + # If omitted, default is used. + aggregation: + # Configure aggregation to be explicit_bucket_histogram. + explicit_bucket_histogram: + # Configure bucket boundaries. + # If omitted, [0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000] is used. + boundaries: + [ + 0.0, + 5.0, + 10.0, + 25.0, + 50.0, + 75.0, + 100.0, + 250.0, + 500.0, + 750.0, + 1000.0, + 2500.0, + 5000.0, + 7500.0, + 10000.0 + ] + # Configure record min and max. + # If omitted or null, true is used. + record_min_max: true + # Configure the aggregation cardinality limit. + # If omitted or null, the metric reader's default cardinality limit is used. + aggregation_cardinality_limit: 2000 + # Configure attribute keys retained in the resulting stream(s). + attribute_keys: + # Configure list of attribute keys to include in the resulting stream(s). All other attributes are dropped. + # If omitted, all attributes are included. + included: + - key1 + - key2 + # Configure list of attribute keys to exclude from the resulting stream(s). Applies after .attribute_keys.included (i.e. excluded has higher priority than included). + # If omitted, .attribute_keys.included are included. + excluded: + - key3 + # Configure the exemplar filter. + # Values include: trace_based, always_on, always_off. For behavior of values see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#metrics-sdk-configuration. + # If omitted or null, trace_based is used. + exemplar_filter: trace_based + # Configure meters. + # This type is in development and subject to breaking changes in minor versions. + meter_configurator/development: + # Configure the default meter config used there is no matching entry in .meter_configurator/development.meters. + default_config: + # Configure if the meter is enabled or not. + disabled: true + # Configure meters. + meters: + - # Configure meter names to match, evaluated as follows: + # + # * If the meter name exactly matches. + # * If the meter name matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + name: io.opentelemetry.contrib.* + # The meter config. + config: + # Configure if the meter is enabled or not. + disabled: false +# Configure text map context propagators. +# If omitted, a noop propagator is used. +propagator: + # Configure the propagators in the composite text map propagator. Entries from .composite_list are appended to the list here with duplicates filtered out. + # Built-in propagator keys include: tracecontext, baggage, b3, b3multi, jaeger, ottrace. Known third party keys include: xray. + # If the resolved list of propagators (from .composite and .composite_list) is empty, a noop propagator is used. + composite: + - # Include the w3c trace context propagator. + tracecontext: + - # Include the w3c baggage propagator. + baggage: + - # Include the zipkin b3 propagator. + b3: + - # Include the zipkin b3 multi propagator. + b3multi: + - # Include the jaeger propagator. + jaeger: + - # Include the opentracing propagator. + ottrace: + # Configure the propagators in the composite text map propagator. Entries are appended to .composite with duplicates filtered out. + # The value is a comma separated list of propagator identifiers matching the format of OTEL_PROPAGATORS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration for details. + # Built-in propagator identifiers include: tracecontext, baggage, b3, b3multi, jaeger, ottrace. Known third party identifiers include: xray. + # If the resolved list of propagators (from .composite and .composite_list) is empty, a noop propagator is used. + composite_list: "tracecontext,baggage,b3,b3multi,jaeger,ottrace,xray" +# Configure tracer provider. +# If omitted, a noop tracer provider is used. +tracer_provider: + # Configure span processors. + processors: + - # Configure a batch span processor. + batch: + # Configure delay interval (in milliseconds) between two consecutive exports. + # Value must be non-negative. + # If omitted or null, 5000 is used. + schedule_delay: 5000 + # Configure maximum allowed time (in milliseconds) to export data. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 30000 is used. + export_timeout: 30000 + # Configure maximum queue size. Value must be positive. + # If omitted or null, 2048 is used. + max_queue_size: 2048 + # Configure maximum batch size. Value must be positive. + # If omitted or null, 512 is used. + max_export_batch_size: 512 + # Configure exporter. + exporter: + # Configure exporter to be OTLP with HTTP transport. + otlp_http: + # Configure endpoint, including the trace specific path. + # If omitted or null, http://localhost:4318/v1/traces is used. + endpoint: http://localhost:4318/v1/traces + # Configure certificate used to verify a server's TLS credentials. + # Absolute path to certificate file in PEM format. + # If omitted or null, system default certificate verification is used for secure connections. + certificate_file: /app/cert.pem + # Configure mTLS private client key. + # Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + # If omitted or null, mTLS is not used. + client_key_file: /app/cert.pem + # Configure mTLS client certificate. + # Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + # If omitted or null, mTLS is not used. + client_certificate_file: /app/cert.pem + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: "api-key=1234" + # Configure compression. + # Values include: gzip, none. Implementations may support other compression algorithms. + # If omitted or null, none is used. + compression: gzip + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure the encoding used for messages. + # Values include: protobuf, json. Implementations may not support json. + # If omitted or null, protobuf is used. + encoding: protobuf + - # Configure a batch span processor. + batch: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with gRPC transport. + otlp_grpc: + # Configure endpoint. + # If omitted or null, http://localhost:4317 is used. + endpoint: http://localhost:4317 + # Configure certificate used to verify a server's TLS credentials. + # Absolute path to certificate file in PEM format. + # If omitted or null, system default certificate verification is used for secure connections. + certificate_file: /app/cert.pem + # Configure mTLS private client key. + # Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + # If omitted or null, mTLS is not used. + client_key_file: /app/cert.pem + # Configure mTLS client certificate. + # Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + # If omitted or null, mTLS is not used. + client_certificate_file: /app/cert.pem + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: "api-key=1234" + # Configure compression. + # Values include: gzip, none. Implementations may support other compression algorithms. + # If omitted or null, none is used. + compression: gzip + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure client transport security for the exporter's connection. + # Only applicable when .endpoint is provided without http or https scheme. Implementations may choose to ignore .insecure. + # If omitted or null, false is used. + insecure: false + - # Configure a batch span processor. + batch: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with file transport. + # This type is in development and subject to breaking changes in minor versions. + otlp_file/development: + # Configure output stream. + # Values include stdout, or scheme+destination. For example: file:///path/to/file.jsonl. + # If omitted or null, stdout is used. + output_stream: file:///var/log/traces.jsonl + - # Configure a batch span processor. + batch: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with file transport. + # This type is in development and subject to breaking changes in minor versions. + otlp_file/development: + # Configure output stream. + # Values include stdout, or scheme+destination. For example: file:///path/to/file.jsonl. + # If omitted or null, stdout is used. + output_stream: stdout + - # Configure a batch span processor. + batch: + # Configure exporter. + exporter: + # Configure exporter to be zipkin. + zipkin: + # Configure endpoint. + # If omitted or null, http://localhost:9411/api/v2/spans is used. + endpoint: http://localhost:9411/api/v2/spans + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates indefinite. + # If omitted or null, 10000 is used. + timeout: 10000 + - # Configure a simple span processor. + simple: + # Configure exporter. + exporter: + # Configure exporter to be console. + console: + # Configure span limits. See also attribute_limits. + limits: + # Configure max attribute value size. Overrides .attribute_limits.attribute_value_length_limit. + # Value must be non-negative. + # If omitted or null, there is no limit. + attribute_value_length_limit: 4096 + # Configure max attribute count. Overrides .attribute_limits.attribute_count_limit. + # Value must be non-negative. + # If omitted or null, 128 is used. + attribute_count_limit: 128 + # Configure max span event count. + # Value must be non-negative. + # If omitted or null, 128 is used. + event_count_limit: 128 + # Configure max span link count. + # Value must be non-negative. + # If omitted or null, 128 is used. + link_count_limit: 128 + # Configure max attributes per span event. + # Value must be non-negative. + # If omitted or null, 128 is used. + event_attribute_count_limit: 128 + # Configure max attributes per span link. + # Value must be non-negative. + # If omitted or null, 128 is used. + link_attribute_count_limit: 128 + # Configure the sampler. + # If omitted, parent based sampler with a root of always_on is used. + sampler: + # Configure sampler to be parent_based. + parent_based: + # Configure root sampler. + # If omitted or null, always_on is used. + root: + # Configure sampler to be trace_id_ratio_based. + trace_id_ratio_based: + # Configure trace_id_ratio. + # If omitted or null, 1.0 is used. + ratio: 0.0001 + # Configure remote_parent_sampled sampler. + # If omitted or null, always_on is used. + remote_parent_sampled: + # Configure sampler to be always_on. + always_on: + # Configure remote_parent_not_sampled sampler. + # If omitted or null, always_off is used. + remote_parent_not_sampled: + # Configure sampler to be always_off. + always_off: + # Configure local_parent_sampled sampler. + # If omitted or null, always_on is used. + local_parent_sampled: + # Configure sampler to be always_on. + always_on: + # Configure local_parent_not_sampled sampler. + # If omitted or null, always_off is used. + local_parent_not_sampled: + # Configure sampler to be always_off. + always_off: + # Configure tracers. + # This type is in development and subject to breaking changes in minor versions. + tracer_configurator/development: + # Configure the default tracer config used there is no matching entry in .tracer_configurator/development.tracers. + default_config: + # Configure if the tracer is enabled or not. + disabled: true + # Configure tracers. + tracers: + - # Configure tracer names to match, evaluated as follows: + # + # * If the tracer name exactly matches. + # * If the tracer name matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + name: io.opentelemetry.contrib.* + # The tracer config. + config: + # Configure if the tracer is enabled or not. + disabled: false +# Configure resource for all signals. +# If omitted, the default resource is used. +resource: + # Configure resource attributes. Entries have higher priority than entries from .resource.attributes_list. + # Entries must contain .name and .value, and may optionally include .type. If an entry's .type omitted or null, string is used. + # The .value's type must match the .type. Values for .type include: string, bool, int, double, string_array, bool_array, int_array, double_array. + attributes: + - name: service.name + value: unknown_service + - name: string_key + value: value + type: string + - name: bool_key + value: true + type: bool + - name: int_key + value: 1 + type: int + - name: double_key + value: 1.1 + type: double + - name: string_array_key + value: [ "value1", "value2" ] + type: string_array + - name: bool_array_key + value: [ true, false ] + type: bool_array + - name: int_array_key + value: [ 1, 2 ] + type: int_array + - name: double_array_key + value: [ 1.1, 2.2 ] + type: double_array + # Configure resource attributes. Entries have lower priority than entries from .resource.attributes. + # The value is a list of comma separated key-value pairs matching the format of OTEL_RESOURCE_ATTRIBUTES. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration for details. + # If omitted or null, no resource attributes are added. + attributes_list: "service.namespace=my-namespace,service.version=1.0.0" + # Configure resource detection. + # This type is in development and subject to breaking changes in minor versions. + # If omitted or null, resource detection is disabled. + detection/development: + # Configure attributes provided by resource detectors. + attributes: + # Configure list of attribute key patterns to include from resource detectors. + # Attribute keys from resource detectors are evaluated to match as follows: + # * If the value of the attribute key exactly matches. + # * If the value of the attribute key matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + # If omitted, all attributes are included. + included: + - process.* + # Configure list of attribute key patterns to exclude from resource detectors. Applies after .resource.detectors.attributes.included (i.e. excluded has higher priority than included). + # Attribute keys from resource detectors are evaluated to match as follows: + # * If the value of the attribute key exactly matches. + # * If the value of the attribute key matches the wildcard pattern, where '?' matches any single character and '*' matches any number of characters including none. + # If omitted, .included attributes are included. + excluded: + - process.command_args + # Configure resource detectors. + # Resource detector names are dependent on the SDK language ecosystem. Please consult documentation for each respective language. + # If omitted or null, no resource detectors are enabled. + detectors: + - # Enable the container resource detector, which populates container.* attributes. + container: + - # Enable the host resource detector, which populates host.* and os.* attributes. + host: + - # Enable the process resource detector, which populates process.* attributes. + process: + - # Enable the service detector, which populates service.name based on the OTEL_SERVICE_NAME environment variable and service.instance.id. + service: + # Configure resource schema URL. + # If omitted or null, no schema URL is used. + schema_url: https://opentelemetry.io/schemas/1.16.0 +# Configure instrumentation. +# This type is in development and subject to breaking changes in minor versions. +instrumentation/development: + # Configure general SemConv options that may apply to multiple languages and instrumentations. + # Instrumenation may merge general config options with the language specific configuration at .instrumentation.. + general: + # Configure instrumentations following the peer semantic conventions. + # See peer semantic conventions: https://opentelemetry.io/docs/specs/semconv/attributes-registry/peer/ + peer: + # Configure the service mapping for instrumentations following peer.service semantic conventions. + # Each entry is a key value pair where "peer" defines the IP address and "service" defines the corresponding logical name of the service. + # See peer.service semantic conventions: https://opentelemetry.io/docs/specs/semconv/general/attributes/#general-remote-service-attributes + service_mapping: + - peer: 1.2.3.4 + service: FooService + - peer: 2.3.4.5 + service: BarService + # Configure instrumentations following the http semantic conventions. + # See http semantic conventions: https://opentelemetry.io/docs/specs/semconv/http/ + http: + # Configure instrumentations following the http client semantic conventions. + client: + # Configure headers to capture for outbound http requests. + request_captured_headers: + - Content-Type + - Accept + # Configure headers to capture for outbound http responses. + response_captured_headers: + - Content-Type + - Content-Encoding + # Configure instrumentations following the http server semantic conventions. + server: + # Configure headers to capture for inbound http requests. + request_captured_headers: + - Content-Type + - Accept + # Configure headers to capture for outbound http responses. + response_captured_headers: + - Content-Type + - Content-Encoding + # Configure C++ language-specific instrumentation libraries. + cpp: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure .NET language-specific instrumentation libraries. + dotnet: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure Erlang language-specific instrumentation libraries. + erlang: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure Go language-specific instrumentation libraries. + go: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure Java language-specific instrumentation libraries. + java: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure JavaScript language-specific instrumentation libraries. + js: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure PHP language-specific instrumentation libraries. + php: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure Python language-specific instrumentation libraries. + python: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure Ruby language-specific instrumentation libraries. + ruby: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure Rust language-specific instrumentation libraries. + rust: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" + # Configure Swift language-specific instrumentation libraries. + swift: + # Configure the instrumentation corresponding to key "example". + example: + property: "value" \ No newline at end of file diff --git a/experimental/packages/opentelemetry-sdk-node/test/fixtures/logger-test.yaml b/experimental/packages/opentelemetry-sdk-node/test/fixtures/logger-test.yaml new file mode 100644 index 00000000000..1a7e3ecf630 --- /dev/null +++ b/experimental/packages/opentelemetry-sdk-node/test/fixtures/logger-test.yaml @@ -0,0 +1,117 @@ +file_format: "1.0-rc.2" +disabled: false +logger_provider: + # Configure log record processors. + processors: + - # Configure a batch log record processor. + batch: + # Configure delay interval (in milliseconds) between two consecutive exports. + # Value must be non-negative. + # If omitted or null, 1000 is used. + schedule_delay: 5000 + # Configure maximum allowed time (in milliseconds) to export data. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 30000 is used. + export_timeout: 30000 + # Configure maximum queue size. Value must be positive. + # If omitted or null, 2048 is used. + max_queue_size: 2048 + # Configure maximum batch size. Value must be positive. + # If omitted or null, 512 is used. + max_export_batch_size: 512 + # Configure exporter. + exporter: + # Configure exporter to be OTLP with HTTP transport. + otlp_http: + endpoint: http://localhost:4318/v1/logs + # Configure certificate used to verify a server's TLS credentials. + # Absolute path to certificate file in PEM format. + # If omitted or null, system default certificate verification is used for secure connections. + certificate_file: /app/cert.pem + # Configure mTLS private client key. + # Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + # If omitted or null, mTLS is not used. + client_key_file: /app/cert.pem + # Configure mTLS client certificate. + # Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + # If omitted or null, mTLS is not used. + client_certificate_file: /app/cert.pem + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: "api-key=1234" + # Configure compression. + # Values include: gzip, none. Implementations may support other compression algorithms. + # If omitted or null, none is used. + compression: gzip + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure the encoding used for messages. + # Values include: protobuf, json. Implementations may not support json. + # If omitted or null, protobuf is used. + encoding: protobuf + - # Configure a batch log record processor. + batch: + # Configure exporter. + exporter: + # Configure exporter to be OTLP with gRPC transport. + otlp_grpc: + # Configure endpoint. + # If omitted or null, http://localhost:4317 is used. + endpoint: http://localhost:4317 + # Configure certificate used to verify a server's TLS credentials. + # Absolute path to certificate file in PEM format. + # If omitted or null, system default certificate verification is used for secure connections. + certificate_file: /app/cert.pem + # Configure mTLS private client key. + # Absolute path to client key file in PEM format. If set, .client_certificate must also be set. + # If omitted or null, mTLS is not used. + client_key_file: /app/cert.pem + # Configure mTLS client certificate. + # Absolute path to client certificate file in PEM format. If set, .client_key must also be set. + # If omitted or null, mTLS is not used. + client_certificate_file: /app/cert.pem + # Configure headers. Entries have higher priority than entries from .headers_list. + # If an entry's .value is null, the entry is ignored. + headers: + - name: api-key + value: "1234" + # Configure headers. Entries have lower priority than entries from .headers. + # The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details. + # If omitted or null, no headers are added. + headers_list: "api-key=1234" + # Configure compression. + # Values include: gzip, none. Implementations may support other compression algorithms. + # If omitted or null, none is used. + compression: gzip + # Configure max time (in milliseconds) to wait for each export. + # Value must be non-negative. A value of 0 indicates no limit (infinity). + # If omitted or null, 10000 is used. + timeout: 10000 + # Configure client transport security for the exporter's connection. + # Only applicable when .endpoint is provided without http or https scheme. Implementations may choose to ignore .insecure. + # If omitted or null, false is used. + insecure: false + - # Configure a simple log record processor. + simple: + # Configure exporter. + exporter: + # Configure exporter to be console. + console: + # Configure log record limits. See also attribute_limits. + limits: + # Configure max attribute value size. Overrides .attribute_limits.attribute_value_length_limit. + # Value must be non-negative. + # If omitted or null, there is no limit. + attribute_value_length_limit: 4096 + # Configure max attribute count. Overrides .attribute_limits.attribute_count_limit. + # Value must be non-negative. + # If omitted or null, 128 is used. + attribute_count_limit: 128 diff --git a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts index 0f001b0b1e5..56c27b6cd2e 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts @@ -33,32 +33,12 @@ import { } from '@opentelemetry/context-async-hooks'; import { W3CTraceContextPropagator } from '@opentelemetry/core'; import { - // AggregationTemporality, - // ConsoleMetricExporter, - // InMemoryMetricExporter, - // InstrumentType, MeterProvider, - // PeriodicExportingMetricReader, } from '@opentelemetry/sdk-metrics'; -// import { OTLPMetricExporter as OTLPGrpcMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc'; -// import { OTLPMetricExporter as OTLPProtoMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'; -// import { OTLPMetricExporter as OTLPHttpMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'; -// import { PrometheusExporter as PrometheusMetricExporter } from '@opentelemetry/exporter-prometheus'; -// import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import { assertServiceInstanceIdIsUUID, - // assertServiceInstanceIdIsUUID, assertServiceResource, } from './util/resource-assertions'; -// import { -// ConsoleSpanExporter, -// SimpleSpanProcessor, -// BatchSpanProcessor, -// NoopSpanProcessor, -// IdGenerator, -// AlwaysOffSampler, -// SpanProcessor, -// } from '@opentelemetry/sdk-trace-base'; import { envDetector, processDetector, @@ -66,12 +46,9 @@ import { serviceInstanceIdDetector, DetectedResource, } from '@opentelemetry/resources'; -// import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { logs, ProxyLoggerProvider } from '@opentelemetry/api-logs'; import { SimpleLogRecordProcessor, - InMemoryLogRecordExporter, - LoggerProvider, ConsoleLogRecordExporter, BatchLogRecordProcessor, } from '@opentelemetry/sdk-logs'; @@ -82,9 +59,6 @@ import { import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto'; import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc'; -// import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; -// import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; -// import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; import { ATTR_HOST_NAME, ATTR_PROCESS_PID } from '../src/semconv'; @@ -128,16 +102,6 @@ describe('startNodeSDK', function () { sdk.shutdown(); }); - it('should return NOOP_SDK when disabled is true', () => { - process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = - 'test/fixtures/kitchen-sink.yaml'; - const sdk = startNodeSDK({}); - - assertDefaultContextManagerRegistered(); - - sdk.shutdown(); - }); - it('should not register more than the minimal SDK components', async () => { // need to set these to none, since the default value is 'otlp' process.env.OTEL_TRACES_EXPORTER = 'none'; @@ -192,52 +156,38 @@ describe('startNodeSDK', function () { sdk.shutdown(); }); - it('should register a logger provider if a log record processor is provided', async () => { - const logRecordExporter = new InMemoryLogRecordExporter(); - const logRecordProcessor = new SimpleLogRecordProcessor(logRecordExporter); - const sdk = startNodeSDK({ logRecordProcessors: [logRecordProcessor] }); - - assertDefaultContextManagerRegistered(); - assertDefaultPropagatorRegistered(); - - assert.ok( - (logs.getLoggerProvider() as ProxyLoggerProvider) instanceof - LoggerProvider - ); - await sdk.shutdown(); - }); - it('should register a logger provider if multiple log record processors are provided', async () => { - const logRecordExporter = new InMemoryLogRecordExporter(); - const simpleLogRecordProcessor = new SimpleLogRecordProcessor( - logRecordExporter - ); - const batchLogRecordProcessor = new BatchLogRecordProcessor( - logRecordExporter - ); - const sdk = startNodeSDK({ - logRecordProcessors: [simpleLogRecordProcessor, batchLogRecordProcessor], - }); + process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = + 'test/fixtures/logger-test.yaml'; + const sdk = startNodeSDK({}); const loggerProvider = logs.getLoggerProvider(); const sharedState = (loggerProvider as any)['_sharedState']; - assert.ok(sharedState.registeredLogRecordProcessors.length === 2); + assert.ok(sharedState.registeredLogRecordProcessors.length === 3); assert.ok( sharedState.registeredLogRecordProcessors[0]._exporter instanceof - InMemoryLogRecordExporter + OTLPProtoLogExporter ); assert.ok( sharedState.registeredLogRecordProcessors[0] instanceof - SimpleLogRecordProcessor + BatchLogRecordProcessor ); assert.ok( sharedState.registeredLogRecordProcessors[1]._exporter instanceof - InMemoryLogRecordExporter + OTLPGrpcLogExporter ); assert.ok( sharedState.registeredLogRecordProcessors[1] instanceof BatchLogRecordProcessor ); + assert.ok( + sharedState.registeredLogRecordProcessors[2]._exporter instanceof + ConsoleLogRecordExporter + ); + assert.ok( + sharedState.registeredLogRecordProcessors[2] instanceof + SimpleLogRecordProcessor + ); await sdk.shutdown(); }); @@ -389,7 +339,7 @@ describe('startNodeSDK', function () { verbose: Sinon.fake(), }; diag.setLogger(diagMocks, DiagLogLevel.DEBUG); - const sdk1 = startNodeSDK({ autoDetectResources: false }); + const sdk1 = startNodeSDK({}); await sdk1.shutdown(); const sdk2 = startNodeSDK({ resourceDetectors: [envDetector] }); @@ -403,21 +353,6 @@ describe('startNodeSDK', function () { }); describe('configureServiceName', async () => { - it('should configure service name via config', async () => { - process.env.OTEL_RESOURCE_ATTRIBUTES = - 'service.instance.id=my-instance-id'; - const configFactory: ConfigFactory = createConfigFactory(); - const config = configFactory.getConfigModel(); - const resource = setupResource(config, { - serviceName: 'config-set-name', - }); - - assertServiceResource(resource, { - name: 'config-set-name', - instanceId: 'my-instance-id', - }); - }); - it('should configure service name via OTEL_SERVICE_NAME env var', async () => { process.env.OTEL_SERVICE_NAME = 'env-set-name'; process.env.OTEL_RESOURCE_ATTRIBUTES = @@ -433,23 +368,6 @@ describe('startNodeSDK', function () { }); }); - it('should favor config set service name over OTEL_SERVICE_NAME env set service name', async () => { - process.env.OTEL_SERVICE_NAME = 'env-set-name'; - process.env.OTEL_RESOURCE_ATTRIBUTES = - 'service.instance.id=my-instance-id'; - const configFactory: ConfigFactory = createConfigFactory(); - const config = configFactory.getConfigModel(); - const resource = setupResource(config, { - serviceName: 'config-set-name', - }); - await resource.waitForAsyncAttributes?.(); - - assertServiceResource(resource, { - name: 'config-set-name', - instanceId: 'my-instance-id', - }); - }); - it('should configure service name via OTEL_RESOURCE_ATTRIBUTES env var', async () => { process.env.OTEL_RESOURCE_ATTRIBUTES = 'service.name=resource-env-set-name,service.instance.id=my-instance-id'; @@ -463,22 +381,6 @@ describe('startNodeSDK', function () { instanceId: 'my-instance-id', }); }); - - it('should favor config set service name over OTEL_RESOURCE_ATTRIBUTES env set service name', async () => { - process.env.OTEL_RESOURCE_ATTRIBUTES = - 'service.name=resource-env-set-name,service.instance.id=my-instance-id'; - const configFactory: ConfigFactory = createConfigFactory(); - const config = configFactory.getConfigModel(); - const resource = setupResource(config, { - serviceName: 'config-set-name', - }); - await resource.waitForAsyncAttributes?.(); - - assertServiceResource(resource, { - name: 'config-set-name', - instanceId: 'my-instance-id', - }); - }); }); describe('configureServiceInstanceId', async () => { @@ -510,7 +412,6 @@ describe('startNodeSDK', function () { const configFactory: ConfigFactory = createConfigFactory(); const config = configFactory.getConfigModel(); const resource = setupResource(config, { - autoDetectResources: true, resourceDetectors: [ processDetector, envDetector, From b065522bfd2e816a78a5c96bef82ddbe2678d615 Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 25 Nov 2025 10:45:48 -0500 Subject: [PATCH 08/13] cleanup --- experimental/packages/opentelemetry-sdk-node/src/utils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/experimental/packages/opentelemetry-sdk-node/src/utils.ts b/experimental/packages/opentelemetry-sdk-node/src/utils.ts index fa194074221..e2463148e04 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/utils.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/utils.ts @@ -393,7 +393,6 @@ export function getKeyListFromObjectArray( export function getLogRecordExporter( exporter: LogRecordExporterModel ): LogRecordExporter { - console.log("AAA ", exporter); if (exporter.otlp_http) { const encoding = exporter.otlp_http.encoding; if (encoding === 'json') { From 11b32c0265ef49fa5502c675ab7e9f487f18bc54 Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 25 Nov 2025 10:49:28 -0500 Subject: [PATCH 09/13] lint --- .../packages/opentelemetry-sdk-node/test/start.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts index 56c27b6cd2e..4b18ac8e747 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts @@ -32,9 +32,7 @@ import { AsyncLocalStorageContextManager, } from '@opentelemetry/context-async-hooks'; import { W3CTraceContextPropagator } from '@opentelemetry/core'; -import { - MeterProvider, -} from '@opentelemetry/sdk-metrics'; +import { MeterProvider } from '@opentelemetry/sdk-metrics'; import { assertServiceInstanceIdIsUUID, assertServiceResource, From dd1a34cd788c6e32e08fdd0822bc12991a6ae580 Mon Sep 17 00:00:00 2001 From: maryliag Date: Tue, 25 Nov 2025 13:35:12 -0500 Subject: [PATCH 10/13] refactor resources --- .../opentelemetry-sdk-node/src/start.ts | 26 ++++-------- .../opentelemetry-sdk-node/src/utils.ts | 21 +++++++++- .../{logger-test.yaml => logger.yaml} | 0 .../test/fixtures/resources.yaml | 40 +++++++++++++++++++ .../opentelemetry-sdk-node/test/start.test.ts | 37 ++++++++++++++--- 5 files changed, 99 insertions(+), 25 deletions(-) rename experimental/packages/opentelemetry-sdk-node/test/fixtures/{logger-test.yaml => logger.yaml} (100%) create mode 100644 experimental/packages/opentelemetry-sdk-node/test/fixtures/resources.yaml diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index 2c94d705d4d..bac34cb2e5e 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -24,6 +24,7 @@ import { getLogRecordProcessorsFromConfiguration, getPropagatorFromConfiguration, getResourceDetectorsFromConfiguration, + getResourceFromConfiguration, setupPropagator, } from './utils'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; @@ -33,15 +34,10 @@ import { logs } from '@opentelemetry/api-logs'; import { defaultResource, detectResources, - envDetector, - hostDetector, - osDetector, - processDetector, Resource, ResourceDetectionConfig, ResourceDetector, resourceFromAttributes, - serviceInstanceIdDetector, } from '@opentelemetry/resources'; import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import { ATTR_SERVICE_INSTANCE_ID } from './semconv'; @@ -94,27 +90,19 @@ export function setupResource( config: ConfigurationModel, sdkOptions: SDKOptions ): Resource { - let resource: Resource = sdkOptions.resource ?? defaultResource(); - let autoDetectResources = false; - let resourceDetectors: ResourceDetector[]; + let resource: Resource = + sdkOptions.resource ?? + getResourceFromConfiguration(config) ?? + defaultResource(); + let resourceDetectors: ResourceDetector[] = []; if (sdkOptions.resourceDetectors != null) { resourceDetectors = sdkOptions.resourceDetectors; - autoDetectResources = true; } else if (config.node_resource_detectors) { resourceDetectors = getResourceDetectorsFromConfiguration(config); - autoDetectResources = true; - } else { - resourceDetectors = [ - envDetector, - processDetector, - hostDetector, - osDetector, - serviceInstanceIdDetector, - ]; } - if (autoDetectResources) { + if (resourceDetectors.length > 0) { const internalConfig: ResourceDetectionConfig = { detectors: resourceDetectors, }; diff --git a/experimental/packages/opentelemetry-sdk-node/src/utils.ts b/experimental/packages/opentelemetry-sdk-node/src/utils.ts index e2463148e04..1ed2ff98de2 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/utils.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/utils.ts @@ -33,11 +33,14 @@ import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/expor import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc'; import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; import { + DetectedResourceAttributes, envDetector, hostDetector, osDetector, processDetector, + Resource, ResourceDetector, + resourceFromAttributes, serviceInstanceIdDetector, } from '@opentelemetry/resources'; import { @@ -72,6 +75,22 @@ const RESOURCE_DETECTOR_OS = 'os'; const RESOURCE_DETECTOR_PROCESS = 'process'; const RESOURCE_DETECTOR_SERVICE_INSTANCE_ID = 'serviceinstance'; +export function getResourceFromConfiguration( + config: ConfigurationModel +): Resource | undefined { + if (config.resource && config.resource.attributes) { + const attr: DetectedResourceAttributes = {}; + for (let i = 0; i < config.resource.attributes.length; i++) { + const a = config.resource.attributes[i]; + attr[a.name] = a.value; + } + return resourceFromAttributes(attr, { + schemaUrl: config.resource.schema_url, + }); + } + return undefined; +} + export function getResourceDetectorsFromEnv(): Array { // When updating this list, make sure to also update the section `resourceDetectors` on README. const resourceDetectors = new Map([ @@ -117,7 +136,7 @@ export function getResourceDetectorsFromConfiguration( [RESOURCE_DETECTOR_PROCESS, processDetector], ]); - const resourceDetectorsFromConfig = config.node_resource_detectors ?? ['all']; + const resourceDetectorsFromConfig = config.node_resource_detectors ?? []; if (resourceDetectorsFromConfig.includes('all')) { return [...resourceDetectors.values()].flat(); diff --git a/experimental/packages/opentelemetry-sdk-node/test/fixtures/logger-test.yaml b/experimental/packages/opentelemetry-sdk-node/test/fixtures/logger.yaml similarity index 100% rename from experimental/packages/opentelemetry-sdk-node/test/fixtures/logger-test.yaml rename to experimental/packages/opentelemetry-sdk-node/test/fixtures/logger.yaml diff --git a/experimental/packages/opentelemetry-sdk-node/test/fixtures/resources.yaml b/experimental/packages/opentelemetry-sdk-node/test/fixtures/resources.yaml new file mode 100644 index 00000000000..37af42a9114 --- /dev/null +++ b/experimental/packages/opentelemetry-sdk-node/test/fixtures/resources.yaml @@ -0,0 +1,40 @@ +file_format: "1.0-rc.2" +disabled: false +resource: + # Configure resource attributes. Entries have higher priority than entries from .resource.attributes_list. + # Entries must contain .name and .value, and may optionally include .type. If an entry's .type omitted or null, string is used. + # The .value's type must match the .type. Values for .type include: string, bool, int, double, string_array, bool_array, int_array, double_array. + attributes: + - name: service.name + value: config-name + - name: string_key + value: value + type: string + - name: bool_key + value: true + type: bool + - name: int_key + value: 1 + type: int + - name: double_key + value: 1.1 + type: double + - name: string_array_key + value: [ "value1", "value2" ] + type: string_array + - name: bool_array_key + value: [ true, false ] + type: bool_array + - name: int_array_key + value: [ 1, 2 ] + type: int_array + - name: double_array_key + value: [ 1.1, 2.2 ] + type: double_array + # Configure resource attributes. Entries have lower priority than entries from .resource.attributes. + # The value is a list of comma separated key-value pairs matching the format of OTEL_RESOURCE_ATTRIBUTES. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration for details. + # If omitted or null, no resource attributes are added. + attributes_list: "service.namespace=config-namespace,service.version=1.0.0" + # Configure resource schema URL. + # If omitted or null, no schema URL is used. + schema_url: https://opentelemetry.io/schemas/1.16.0 diff --git a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts index 4b18ac8e747..e79a68e32fe 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/start.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/start.test.ts @@ -155,8 +155,7 @@ describe('startNodeSDK', function () { }); it('should register a logger provider if multiple log record processors are provided', async () => { - process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = - 'test/fixtures/logger-test.yaml'; + process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = 'test/fixtures/logger.yaml'; const sdk = startNodeSDK({}); const loggerProvider = logs.getLoggerProvider(); @@ -227,7 +226,7 @@ describe('startNodeSDK', function () { await sdk.shutdown(); }); - describe('detectResources', async () => { + describe('setupResources', async () => { beforeEach(() => { process.env.OTEL_RESOURCE_ATTRIBUTES = 'service.instance.id=627cc493,service.name=my-service,service.namespace=default,service.version=0.0.1'; @@ -289,8 +288,36 @@ describe('startNodeSDK', function () { version: '0.0.1', }); - assert.notEqual(resource.attributes[ATTR_PROCESS_PID], undefined); - assert.notEqual(resource.attributes[ATTR_HOST_NAME], undefined); + assert.equal(resource.attributes[ATTR_PROCESS_PID], undefined); + assert.equal(resource.attributes[ATTR_HOST_NAME], undefined); + }); + + it('should configure resources from config file', async () => { + process.env.OTEL_EXPERIMENTAL_CONFIG_FILE = + 'test/fixtures/resources.yaml'; + const configFactory: ConfigFactory = createConfigFactory(); + const config = configFactory.getConfigModel(); + const resource = setupResource(config, {}); + await resource.waitForAsyncAttributes?.(); + + assert.deepStrictEqual( + resource.schemaUrl, + 'https://opentelemetry.io/schemas/1.16.0' + ); + + assert.deepStrictEqual(resource.attributes, { + 'service.name': 'config-name', + 'service.namespace': 'config-namespace', + 'service.version': '1.0.0', + bool_array_key: [true, false], + bool_key: true, + double_array_key: [1.1, 2.2], + double_key: 1.1, + int_array_key: [1, 2], + int_key: 1, + string_array_key: ['value1', 'value2'], + string_key: 'value', + }); }); it('returns a merged resource with a buggy detector', async () => { From 5a8da6d4744d7064bc982606d029cbedce36692f Mon Sep 17 00:00:00 2001 From: maryliag Date: Wed, 26 Nov 2025 11:31:34 -0500 Subject: [PATCH 11/13] remove resource option --- experimental/packages/opentelemetry-sdk-node/src/start.ts | 4 +--- experimental/packages/opentelemetry-sdk-node/src/types.ts | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index bac34cb2e5e..2ca7687dbe3 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -91,9 +91,7 @@ export function setupResource( sdkOptions: SDKOptions ): Resource { let resource: Resource = - sdkOptions.resource ?? - getResourceFromConfiguration(config) ?? - defaultResource(); + getResourceFromConfiguration(config) ?? defaultResource(); let resourceDetectors: ResourceDetector[] = []; if (sdkOptions.resourceDetectors != null) { diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index 16ca3bba5d5..807ec4abc46 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -56,7 +56,6 @@ export interface NodeSDKConfiguration { */ export interface SDKOptions { instrumentations?: (Instrumentation | Instrumentation[])[]; - resource?: Resource; resourceDetectors?: ResourceDetector[]; textMapPropagator?: TextMapPropagator | null; } From 1466b03076a761662232df04a040f07eb7fcc7ca Mon Sep 17 00:00:00 2001 From: maryliag Date: Thu, 27 Nov 2025 11:41:47 -0500 Subject: [PATCH 12/13] have a separate create option --- .../opentelemetry-sdk-node/src/start.ts | 105 +++++++++++------- .../opentelemetry-sdk-node/src/types.ts | 13 ++- 2 files changed, 76 insertions(+), 42 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-node/src/start.ts b/experimental/packages/opentelemetry-sdk-node/src/start.ts index 2ca7687dbe3..5585e66f8dd 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/start.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/start.ts @@ -18,17 +18,21 @@ import { ConfigurationModel, createConfigFactory, } from '@opentelemetry/configuration'; -import { context, diag, DiagConsoleLogger } from '@opentelemetry/api'; +import { + context, + diag, + DiagConsoleLogger, + propagation, +} from '@opentelemetry/api'; import { getInstanceID, getLogRecordProcessorsFromConfiguration, getPropagatorFromConfiguration, getResourceDetectorsFromConfiguration, getResourceFromConfiguration, - setupPropagator, } from './utils'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; -import type { SDKOptions } from './types'; +import type { SDKComponents, SDKOptions } from './types'; import { LoggerProvider } from '@opentelemetry/sdk-logs'; import { logs } from '@opentelemetry/api-logs'; import { @@ -41,6 +45,11 @@ import { } from '@opentelemetry/resources'; import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import { ATTR_SERVICE_INSTANCE_ID } from './semconv'; +import { + CompositePropagator, + W3CBaggagePropagator, + W3CTraceContextPropagator, +} from '@opentelemetry/core'; /** * @experimental Function to start the OpenTelemetry Node SDK @@ -59,24 +68,23 @@ export function startNodeSDK(sdkOptions: SDKOptions): { if (config.log_level != null) { diag.setLogger(new DiagConsoleLogger(), { logLevel: config.log_level }); } - registerInstrumentations({ instrumentations: sdkOptions?.instrumentations?.flat() ?? [], }); - setupDefaultContextManager(); - setupPropagator( - sdkOptions?.textMapPropagator === null - ? null // null means don't set. - : (sdkOptions?.textMapPropagator ?? - getPropagatorFromConfiguration(config)) - ); - const resource = setupResource(config, sdkOptions); - const loggerProvider = setupLoggerProvider(config, sdkOptions, resource); + + const components = create(config, sdkOptions); + context.setGlobalContextManager(components.contextManager); + if (components.loggerProvider) { + logs.setGlobalLoggerProvider(components.loggerProvider); + } + if (components.propagator) { + propagation.setGlobalPropagator(components.propagator); + } const shutdownFn = async () => { const promises: Promise[] = []; - if (loggerProvider) { - promises.push(loggerProvider.shutdown()); + if (components.loggerProvider) { + promises.push(components.loggerProvider.shutdown()); } await Promise.all(promises); }; @@ -86,6 +94,48 @@ const NOOP_SDK = { shutdown: async () => {}, }; +/** + * Interpret configuration model and return SDK components. + */ +function create( + config: ConfigurationModel, + sdkOptions: SDKOptions +): SDKComponents { + const defaultContextManager = new AsyncLocalStorageContextManager(); + defaultContextManager.enable(); + const components: SDKComponents = { + contextManager: defaultContextManager, + }; + const resource = setupResource(config, sdkOptions); + + const propagator = + sdkOptions?.textMapPropagator === null + ? null // null means don't set. + : (sdkOptions?.textMapPropagator ?? + getPropagatorFromConfiguration(config)); + if (propagator) { + components.propagator = propagator; + } else if (propagator === undefined) { + components.propagator = new CompositePropagator({ + propagators: [ + new W3CTraceContextPropagator(), + new W3CBaggagePropagator(), + ], + }); + } + + const logProcessors = getLogRecordProcessorsFromConfiguration(config); + if (logProcessors) { + const loggerProvider = new LoggerProvider({ + resource: resource, + processors: logProcessors, + }); + components.loggerProvider = loggerProvider; + } + + return components; +} + export function setupResource( config: ConfigurationModel, sdkOptions: SDKOptions @@ -119,28 +169,3 @@ export function setupResource( return resource; } - -function setupDefaultContextManager() { - const defaultContextManager = new AsyncLocalStorageContextManager(); - defaultContextManager.enable(); - context.setGlobalContextManager(defaultContextManager); -} - -function setupLoggerProvider( - config: ConfigurationModel, - sdkOptions: SDKOptions, - resource: Resource | undefined -): LoggerProvider | undefined { - const logProcessors = getLogRecordProcessorsFromConfiguration(config); - - if (logProcessors) { - const loggerProvider = new LoggerProvider({ - resource: resource, - processors: logProcessors, - }); - - logs.setGlobalLoggerProvider(loggerProvider); - return loggerProvider; - } - return undefined; -} diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index 807ec4abc46..070c18d7514 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -18,8 +18,8 @@ import type { ContextManager } from '@opentelemetry/api'; import { TextMapPropagator } from '@opentelemetry/api'; import { Instrumentation } from '@opentelemetry/instrumentation'; import { Resource, ResourceDetector } from '@opentelemetry/resources'; -import { LogRecordProcessor } from '@opentelemetry/sdk-logs'; -import { IMetricReader, ViewOptions } from '@opentelemetry/sdk-metrics'; +import { LoggerProvider, LogRecordProcessor } from '@opentelemetry/sdk-logs'; +import { IMetricReader, MeterProvider, ViewOptions } from '@opentelemetry/sdk-metrics'; import { Sampler, SpanExporter, @@ -27,6 +27,7 @@ import { SpanProcessor, IdGenerator, } from '@opentelemetry/sdk-trace-base'; +import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; export interface NodeSDKConfiguration { autoDetectResources: boolean; @@ -59,3 +60,11 @@ export interface SDKOptions { resourceDetectors?: ResourceDetector[]; textMapPropagator?: TextMapPropagator | null; } + +export interface SDKComponents { + contextManager: ContextManager; + loggerProvider?: LoggerProvider; + meterProvider?: MeterProvider; + tracesProvider?: NodeTracerProvider; + propagator?: TextMapPropagator; +} From 651686fe27e263ea40e75cd395078d0f7678d118 Mon Sep 17 00:00:00 2001 From: maryliag Date: Thu, 27 Nov 2025 11:45:31 -0500 Subject: [PATCH 13/13] fix lint --- experimental/packages/opentelemetry-sdk-node/src/types.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index 070c18d7514..fc03e313ce2 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -19,7 +19,11 @@ import { TextMapPropagator } from '@opentelemetry/api'; import { Instrumentation } from '@opentelemetry/instrumentation'; import { Resource, ResourceDetector } from '@opentelemetry/resources'; import { LoggerProvider, LogRecordProcessor } from '@opentelemetry/sdk-logs'; -import { IMetricReader, MeterProvider, ViewOptions } from '@opentelemetry/sdk-metrics'; +import { + IMetricReader, + MeterProvider, + ViewOptions, +} from '@opentelemetry/sdk-metrics'; import { Sampler, SpanExporter,