From 28e727129b460370281b152864070ea5be9aa773 Mon Sep 17 00:00:00 2001 From: Ben Hughes Date: Tue, 12 Aug 2025 16:07:52 -0400 Subject: [PATCH] feat(sdk-trace-base): add tracerFactory option to TracerConfig Allows a different Tracer/Span implementation to be used by the TracerProvider and the SDKs in cases where behavior needs to be customized. --- .../opentelemetry-sdk-node/src/types.ts | 2 ++ .../src/BasicTracerProvider.ts | 19 ++++++++--- .../opentelemetry-sdk-trace-base/src/index.ts | 1 + .../opentelemetry-sdk-trace-base/src/types.ts | 15 ++++++++- .../test/common/BasicTracerProvider.test.ts | 32 +++++++++++++++++++ 5 files changed, 64 insertions(+), 5 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index ff400de8f21..58f7c9b97fc 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -26,6 +26,7 @@ import { SpanLimits, SpanProcessor, IdGenerator, + TracerFactory, } from '@opentelemetry/sdk-trace-base'; export interface NodeSDKConfiguration { @@ -48,4 +49,5 @@ export interface NodeSDKConfiguration { traceExporter: SpanExporter; spanLimits: SpanLimits; idGenerator: IdGenerator; + tracerFactory: TracerFactory; } diff --git a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts index 50a445e389a..27c189aede3 100644 --- a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts +++ b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts @@ -15,13 +15,13 @@ */ import { TracerProvider, Tracer as ApiTracer } from '@opentelemetry/api'; -import { merge } from '@opentelemetry/core'; +import { InstrumentationScope, merge } from '@opentelemetry/core'; import { defaultResource, Resource } from '@opentelemetry/resources'; import { SpanProcessor } from './SpanProcessor'; import { Tracer } from './Tracer'; import { loadDefaultConfig } from './config'; import { MultiSpanProcessor } from './MultiSpanProcessor'; -import { TracerConfig } from './types'; +import { TracerConfig, TracerFactory } from './types'; import { reconfigureLimits } from './utility'; export enum ForceFlushState { @@ -31,14 +31,24 @@ export enum ForceFlushState { 'unresolved', } +function defaultTracerFactory( + instrumentationScope: InstrumentationScope, + config: TracerConfig, + resource: Resource, + spanProcessor: SpanProcessor +) { + return new Tracer(instrumentationScope, config, resource, spanProcessor); +} + /** * This class represents a basic tracer provider which platform libraries can extend */ export class BasicTracerProvider implements TracerProvider { private readonly _config: TracerConfig; - private readonly _tracers: Map = new Map(); + private readonly _tracers: Map = new Map(); private readonly _resource: Resource; private readonly _activeSpanProcessor: MultiSpanProcessor; + private readonly _tracerFactory: TracerFactory; constructor(config: TracerConfig = {}) { const mergedConfig = merge( @@ -47,6 +57,7 @@ export class BasicTracerProvider implements TracerProvider { reconfigureLimits(config) ); this._resource = mergedConfig.resource ?? defaultResource(); + this._tracerFactory = mergedConfig.tracerFactory ?? defaultTracerFactory; this._config = Object.assign({}, mergedConfig, { resource: this._resource, @@ -70,7 +81,7 @@ export class BasicTracerProvider implements TracerProvider { if (!this._tracers.has(key)) { this._tracers.set( key, - new Tracer( + this._tracerFactory( { name, version, schemaUrl: options?.schemaUrl }, this._config, this._resource, diff --git a/packages/opentelemetry-sdk-trace-base/src/index.ts b/packages/opentelemetry-sdk-trace-base/src/index.ts index 65520e88c6a..5f242cc1994 100644 --- a/packages/opentelemetry-sdk-trace-base/src/index.ts +++ b/packages/opentelemetry-sdk-trace-base/src/index.ts @@ -38,5 +38,6 @@ export type { SDKRegistrationConfig, SpanLimits, TracerConfig, + TracerFactory, } from './types'; export type { IdGenerator } from './IdGenerator'; diff --git a/packages/opentelemetry-sdk-trace-base/src/types.ts b/packages/opentelemetry-sdk-trace-base/src/types.ts index 413a5caa1cc..6692f0df7bc 100644 --- a/packages/opentelemetry-sdk-trace-base/src/types.ts +++ b/packages/opentelemetry-sdk-trace-base/src/types.ts @@ -14,11 +14,12 @@ * limitations under the License. */ -import { ContextManager, TextMapPropagator } from '@opentelemetry/api'; +import { ContextManager, TextMapPropagator, Tracer } from '@opentelemetry/api'; import { Resource } from '@opentelemetry/resources'; import { IdGenerator } from './IdGenerator'; import { Sampler } from './Sampler'; import { SpanProcessor } from './SpanProcessor'; +import { InstrumentationScope } from '@opentelemetry/core'; /** * TracerConfig provides an interface for configuring a Basic Tracer. @@ -54,8 +55,20 @@ export interface TracerConfig { * List of SpanProcessor for the tracer */ spanProcessors?: SpanProcessor[]; + + /** + * Factory function for creating a tracer instance + */ + tracerFactory?: TracerFactory; } +export type TracerFactory = ( + instrumentationScope: InstrumentationScope, + config: TracerConfig, + resource: Resource, + spanProcessor: SpanProcessor +) => Tracer; + /** * Configuration options for registering the API with the SDK. * Undefined values may be substituted for defaults, and null diff --git a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts index 6a3e86efe99..6eb357f0118 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/BasicTracerProvider.test.ts @@ -104,6 +104,38 @@ describe('BasicTracerProvider', () => { }); }); + describe('when "tracerFactory" option defined', () => { + it('should use custom tracer factory when provided', () => { + const customTracerFactory = sinon + .stub() + .returns( + new Tracer( + { name: 'test', version: '1.0.0' }, + {}, + defaultResource(), + new NoopSpanProcessor() + ) + ); + + const tracerProvider = new BasicTracerProvider({ + tracerFactory: customTracerFactory, + }); + + const tracer = tracerProvider.getTracer('test-tracer'); + + sinon.assert.calledOnce(customTracerFactory); + + assert.ok(tracer instanceof Tracer); + }); + + it('should use default factory when tracerFactory is undefined', () => { + const tracerProvider = new BasicTracerProvider({}); + const tracer = tracerProvider.getTracer('default-tracer'); + + assert.ok(tracer instanceof Tracer); + }); + }); + describe('generalLimits', () => { describe('when not defined default values', () => { it('should have tracer with default values', () => {