Skip to content

Commit

Permalink
feat(tracing): allow to configure exporter by environment #1676
Browse files Browse the repository at this point in the history
  • Loading branch information
vmarchaud committed Apr 11, 2021
1 parent 9fc1b10 commit 9288511
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 13 deletions.
2 changes: 2 additions & 0 deletions packages/opentelemetry-core/src/utils/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export type ENVIRONMENT = {
OTEL_EXPORTER_JAEGER_USER?: string;
OTEL_LOG_LEVEL?: DiagLogLevel;
OTEL_RESOURCE_ATTRIBUTES?: string;
OTEL_TRACES_EXPORTER?: string;
} & ENVIRONMENT_NUMBERS &
ENVIRONMENT_LISTS;

Expand Down Expand Up @@ -102,6 +103,7 @@ export const DEFAULT_ENVIRONMENT: Required<ENVIRONMENT> = {
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: 1000,
OTEL_SPAN_EVENT_COUNT_LIMIT: 1000,
OTEL_SPAN_LINK_COUNT_LIMIT: 1000,
OTEL_TRACES_EXPORTER: 'none',
};

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/opentelemetry-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@
"dependencies": {
"@opentelemetry/context-async-hooks": "^0.18.2",
"@opentelemetry/core": "^0.18.2",
"@opentelemetry/tracing": "^0.18.2",
"@opentelemetry/exporter-collector": "^0.18.2",
"@opentelemetry/propagator-b3": "^0.18.0",
"@opentelemetry/propagator-jaeger": "^0.18.0",
"@opentelemetry/tracing": "^0.18.2",
"semver": "^7.1.3"
}
}
15 changes: 15 additions & 0 deletions packages/opentelemetry-node/src/NodeTracerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ import { B3Propagator, B3InjectEncoding } from '@opentelemetry/propagator-b3';
import {
BasicTracerProvider,
PROPAGATOR_FACTORY,
EXPORTER_FACTORY,
SDKRegistrationConfig,
SpanExporter,
} from '@opentelemetry/tracing';
import * as semver from 'semver';
import { NodeTracerConfig } from './config';
import { JaegerHttpTracePropagator } from '@opentelemetry/propagator-jaeger';
import { CollectorTraceExporter } from '@opentelemetry/exporter-collector';

/**
* Register this TracerProvider for use with the OpenTelemetry API.
Expand All @@ -52,6 +55,11 @@ export class NodeTracerProvider extends BasicTracerProvider {
['jaeger', () => new JaegerHttpTracePropagator()],
]);

protected static readonly _registeredExporters = new Map<
string,
EXPORTER_FACTORY
>([['otlp', () => new CollectorTraceExporter()]]);

constructor(config: NodeTracerConfig = {}) {
super(config);
}
Expand All @@ -74,4 +82,11 @@ export class NodeTracerProvider extends BasicTracerProvider {
NodeTracerProvider._registeredPropagators.get(name)?.()
);
}

protected _getSpanExporter(name: string): SpanExporter | undefined {
return (
super._getSpanExporter(name) ||
NodeTracerProvider._registeredExporters.get(name)?.()
);
}
}
22 changes: 21 additions & 1 deletion packages/opentelemetry-node/test/NodeTracerProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ import {
} from '@opentelemetry/api';
import { AlwaysOnSampler, AlwaysOffSampler } from '@opentelemetry/core';
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks';
import { Span } from '@opentelemetry/tracing';
import {
Span,
NoopSpanProcessor,
BatchSpanProcessor,
} from '@opentelemetry/tracing';
import { Resource, TELEMETRY_SDK_RESOURCE } from '@opentelemetry/resources';
import * as assert from 'assert';
import * as path from 'path';
import { ContextManager, ROOT_CONTEXT } from '@opentelemetry/api';
import { NodeTracerProvider } from '../src/NodeTracerProvider';
import { CollectorTraceExporter } from '@opentelemetry/exporter-collector';

const sleep = (time: number) =>
new Promise(resolve => {
Expand Down Expand Up @@ -78,6 +83,21 @@ describe('NodeTracerProvider', () => {
});
assert.ok(provider instanceof NodeTracerProvider);
});

it('should register noon span processor by default', () => {
provider = new NodeTracerProvider();
assert.ok(provider.activeSpanProcessor instanceof NoopSpanProcessor);
});

it('should register batch span processor when configuring otlp via env', () => {
process.env.OTEL_TRACES_EXPORTER = 'otlp';
provider = new NodeTracerProvider();
assert.ok(provider.activeSpanProcessor instanceof BatchSpanProcessor);
// @ts-expect-error Access actual exporter for tests
const exporter = provider.activeSpanProcessor._exporter;
assert.ok(exporter instanceof CollectorTraceExporter);
process.env.OTEL_TRACES_EXPORTER = 'none';
});
});

describe('.startSpan()', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/opentelemetry-tracing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
},
"dependencies": {
"@opentelemetry/core": "^0.18.2",
"@opentelemetry/exporter-collector": "^0.18.2",
"@opentelemetry/resources": "^0.18.2",
"@opentelemetry/semantic-conventions": "^0.18.2",
"lodash.merge": "^4.6.2"
Expand Down
41 changes: 39 additions & 2 deletions packages/opentelemetry-tracing/src/BasicTracerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ import { Resource } from '@opentelemetry/resources';
import { SpanProcessor, Tracer } from '.';
import { DEFAULT_CONFIG } from './config';
import { MultiSpanProcessor } from './MultiSpanProcessor';
import { NoopSpanProcessor } from './NoopSpanProcessor';
import { NoopSpanProcessor } from './export/NoopSpanProcessor';
import { SDKRegistrationConfig, TracerConfig } from './types';
import merge = require('lodash.merge');
import { SpanExporter } from './export/SpanExporter';
import { BatchSpanProcessor } from './export/BatchSpanProcessor';

export type PROPAGATOR_FACTORY = () => TextMapPropagator;
export type EXPORTER_FACTORY = () => SpanExporter;

/**
* This class represents a basic tracer provider which platform libraries can extend
Expand All @@ -50,11 +53,16 @@ export class BasicTracerProvider implements TracerProvider {
['baggage', () => new HttpBaggage()],
]);

protected static readonly _registeredExporters = new Map<
string,
EXPORTER_FACTORY
>();

private readonly _config: TracerConfig;
private readonly _registeredSpanProcessors: SpanProcessor[] = [];
private readonly _tracers: Map<string, Tracer> = new Map();

activeSpanProcessor: SpanProcessor = new NoopSpanProcessor();
activeSpanProcessor: SpanProcessor;
readonly resource: Resource;

constructor(config: TracerConfig = {}) {
Expand All @@ -64,6 +72,14 @@ export class BasicTracerProvider implements TracerProvider {
this._config = Object.assign({}, mergedConfig, {
resource: this.resource,
});

const defaultExporter = this._buildExporterFromEnv();
if (defaultExporter !== undefined) {
const batchProcessor = new BatchSpanProcessor(defaultExporter);
this.activeSpanProcessor = batchProcessor;
} else {
this.activeSpanProcessor = new NoopSpanProcessor();
}
}

getTracer(name: string, version?: string): Tracer {
Expand All @@ -80,6 +96,11 @@ export class BasicTracerProvider implements TracerProvider {
* @param spanProcessor the new SpanProcessor to be added.
*/
addSpanProcessor(spanProcessor: SpanProcessor): void {
if (this._registeredSpanProcessors.length === 0) {
// since we might have enabled by default a batchProcessor, we disable it
// before adding the new one
this.activeSpanProcessor.shutdown();
}
this._registeredSpanProcessors.push(spanProcessor);
this.activeSpanProcessor = new MultiSpanProcessor(
this._registeredSpanProcessors
Expand Down Expand Up @@ -120,6 +141,10 @@ export class BasicTracerProvider implements TracerProvider {
return BasicTracerProvider._registeredPropagators.get(name)?.();
}

protected _getSpanExporter(name: string): SpanExporter | undefined {
return BasicTracerProvider._registeredExporters.get(name)?.();
}

protected _buildPropagatorFromEnv(): TextMapPropagator | undefined {
// per spec, propagators from env must be deduplicated
const uniquePropagatorNames = [...new Set(getEnv().OTEL_PROPAGATORS)];
Expand Down Expand Up @@ -154,4 +179,16 @@ export class BasicTracerProvider implements TracerProvider {
});
}
}

protected _buildExporterFromEnv(): SpanExporter | undefined {
const exporterName = getEnv().OTEL_TRACES_EXPORTER;
if (exporterName === 'none') return;
const exporter = this._getSpanExporter(exporterName);
if (!exporter) {
diag.warn(
`Exporter "${exporterName}" requested through environment variable is unavailable.`
);
}
return exporter;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
*/

import { Context } from '@opentelemetry/api';
import { ReadableSpan } from './export/ReadableSpan';
import { Span } from './Span';
import { SpanProcessor } from './SpanProcessor';
import { ReadableSpan } from './ReadableSpan';
import { Span } from '../Span';
import { SpanProcessor } from '../SpanProcessor';

/** No-op implementation of SpanProcessor */
export class NoopSpanProcessor implements SpanProcessor {
Expand Down
1 change: 1 addition & 0 deletions packages/opentelemetry-tracing/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export * from './export/InMemorySpanExporter';
export * from './export/ReadableSpan';
export * from './export/SimpleSpanProcessor';
export * from './export/SpanExporter';
export * from './export/NoopSpanProcessor';
export * from './Span';
export * from './SpanProcessor';
export * from './types';
30 changes: 25 additions & 5 deletions packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@ import {
import { Resource } from '@opentelemetry/resources';
import * as assert from 'assert';
import * as sinon from 'sinon';
import { BasicTracerProvider, Span } from '../src';
import { BasicTracerProvider, NoopSpanProcessor, Span } from '../src';

describe('BasicTracerProvider', () => {
let removeEvent: Function | undefined;
const envSource = (typeof window !== 'undefined'
? window
: process.env) as any;

beforeEach(() => {
context.disable();
Expand Down Expand Up @@ -120,13 +123,30 @@ describe('BasicTracerProvider', () => {
const tracer = new BasicTracerProvider();
assert.ok(tracer instanceof BasicTracerProvider);
});

it('should use noop span processor by default', () => {
const tracer = new BasicTracerProvider();
assert.ok(tracer.activeSpanProcessor instanceof NoopSpanProcessor);
});

it('warns if there is no exporter registered with a given name', () => {
const warnStub = sinon.spy(diag, 'warn');

envSource.OTEL_TRACES_EXPORTER = 'missing-exporter';
const provider = new BasicTracerProvider({});
provider.register();

assert.ok(
warnStub.calledOnceWithExactly(
'Exporter "missing-exporter" requested through environment variable is unavailable.'
)
);
warnStub.restore();
envSource.OTEL_TRACES_EXPORTER = 'none';
});
});

describe('.register()', () => {
const envSource = (typeof window !== 'undefined'
? window
: process.env) as any;

describe('propagator', () => {
class DummyPropagator implements TextMapPropagator {
inject(
Expand Down
1 change: 1 addition & 0 deletions packages/opentelemetry-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
},
"dependencies": {
"@opentelemetry/core": "^0.18.2",
"@opentelemetry/exporter-collector": "^0.18.2",
"@opentelemetry/semantic-conventions": "^0.18.2",
"@opentelemetry/tracing": "^0.18.2"
}
Expand Down
15 changes: 15 additions & 0 deletions packages/opentelemetry-web/src/WebTracerProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
import {
BasicTracerProvider,
SDKRegistrationConfig,
SpanExporter,
TracerConfig,
EXPORTER_FACTORY,
} from '@opentelemetry/tracing';
import { StackContextManager } from './StackContextManager';
import { CollectorTraceExporter } from '@opentelemetry/exporter-collector';

/**
* WebTracerConfig provides an interface for configuring a Web Tracer.
Expand All @@ -30,6 +33,11 @@ export type WebTracerConfig = TracerConfig;
* This class represents a web tracer with {@link StackContextManager}
*/
export class WebTracerProvider extends BasicTracerProvider {
protected static readonly _registeredExporters = new Map<
string,
EXPORTER_FACTORY
>([['otlp', () => new CollectorTraceExporter()]]);

/**
* Constructs a new Tracer instance.
* @param config Web Tracer config
Expand Down Expand Up @@ -65,4 +73,11 @@ export class WebTracerProvider extends BasicTracerProvider {

super.register(config);
}

protected _getSpanExporter(name: string): SpanExporter | undefined {
return (
super._getSpanExporter(name) ||
WebTracerProvider._registeredExporters.get(name)?.()
);
}
}
23 changes: 22 additions & 1 deletion packages/opentelemetry-web/test/WebTracerProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@

import { context, getSpan, setSpan, ContextManager } from '@opentelemetry/api';
import { ZoneContextManager } from '@opentelemetry/context-zone';
import { CollectorTraceExporter } from '@opentelemetry/exporter-collector';
import { B3Propagator } from '@opentelemetry/propagator-b3';
import { Resource, TELEMETRY_SDK_RESOURCE } from '@opentelemetry/resources';
import { Span, Tracer } from '@opentelemetry/tracing';
import {
BatchSpanProcessor,
NoopSpanProcessor,
Span,
Tracer,
} from '@opentelemetry/tracing';
import * as assert from 'assert';
import { WebTracerConfig } from '../src';
import { WebTracerProvider } from '../src/WebTracerProvider';
Expand Down Expand Up @@ -136,5 +142,20 @@ describe('WebTracerProvider', () => {
);
});
});

it('should register noon span processor by default', () => {
const provider = new WebTracerProvider();
assert.ok(provider.activeSpanProcessor instanceof NoopSpanProcessor);
});

it('should register batch span processor when configuring otlp via env', () => {
(window as any).OTEL_TRACES_EXPORTER = 'otlp';
const provider = new WebTracerProvider();
assert.ok(provider.activeSpanProcessor instanceof BatchSpanProcessor);
// @ts-expect-error Access actual exporter for tests
const exporter = provider.activeSpanProcessor._exporter;
assert.ok(exporter instanceof CollectorTraceExporter);
(window as any).OTEL_TRACES_EXPORTER = 'none';
});
});
});

0 comments on commit 9288511

Please sign in to comment.