Skip to content

Commit

Permalink
feat(tracing): allow to configure exporter by environment #1676 (#2100)
Browse files Browse the repository at this point in the history
Co-authored-by: Bartlomiej Obecny <bobecny@gmail.com>
Co-authored-by: Daniel Dyla <dyladan@users.noreply.github.com>
  • Loading branch information
3 people committed May 12, 2021
1 parent 02239b5 commit 1758fa6
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 10 deletions.
2 changes: 2 additions & 0 deletions packages/opentelemetry-core/src/utils/environment.ts
Expand Up @@ -76,6 +76,7 @@ export type ENVIRONMENT = {
OTEL_EXPORTER_ZIPKIN_ENDPOINT?: string;
OTEL_LOG_LEVEL?: DiagLogLevel;
OTEL_RESOURCE_ATTRIBUTES?: string;
OTEL_TRACES_EXPORTER?: string;
OTEL_TRACES_SAMPLER_ARG?: string;
OTEL_TRACES_SAMPLER?: string;
} & ENVIRONMENT_NUMBERS &
Expand Down Expand Up @@ -117,6 +118,7 @@ export const DEFAULT_ENVIRONMENT: Required<ENVIRONMENT> = {
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: 128,
OTEL_SPAN_EVENT_COUNT_LIMIT: 128,
OTEL_SPAN_LINK_COUNT_LIMIT: 128,
OTEL_TRACES_EXPORTER: 'none',
OTEL_TRACES_SAMPLER: TracesSamplerValues.ParentBasedAlwaysOn,
OTEL_TRACES_SAMPLER_ARG: '',
};
Expand Down
48 changes: 46 additions & 2 deletions packages/opentelemetry-tracing/src/BasicTracerProvider.ts
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';
const 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 HttpBaggagePropagator()],
]);

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,18 @@ 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()
.catch(err =>
diag.error(
'Error while trying to shutdown current span processor',
err
)
);
}
this._registeredSpanProcessors.push(spanProcessor);
this.activeSpanProcessor = new MultiSpanProcessor(
this._registeredSpanProcessors
Expand Down Expand Up @@ -120,6 +148,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 = Array.from(
Expand Down Expand Up @@ -156,4 +188,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.error(
`Exporter "${exporterName}" requested through environment variable is unavailable.`
);
}
return exporter;
}
}
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
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 './TimedEvent';
Expand Down
59 changes: 54 additions & 5 deletions packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts
Expand Up @@ -38,10 +38,20 @@ 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,
InMemorySpanExporter,
SpanExporter,
BatchSpanProcessor,
} 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 +130,14 @@ 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);
});
});

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

describe('propagator', () => {
class DummyPropagator implements TextMapPropagator {
inject(
Expand Down Expand Up @@ -213,6 +224,44 @@ describe('BasicTracerProvider', () => {
warnStub.restore();
});
});

describe('exporter', () => {
class CustomTracerProvider extends BasicTracerProvider {
protected _getSpanExporter(name: string): SpanExporter | undefined {
return name === 'memory'
? new InMemorySpanExporter()
: BasicTracerProvider._registeredExporters.get(name)?.();
}
}

afterEach(() => {
delete envSource.OTEL_TRACES_EXPORTER;
});

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

envSource.OTEL_TRACES_EXPORTER = 'missing-exporter';
const provider = new BasicTracerProvider({});
provider.register();
assert.ok(
errorStub.getCall(0).args[0] ===
'Exporter "missing-exporter" requested through environment variable is unavailable.'
);
errorStub.restore();
});

it('registers trace exporter from environment variable', () => {
envSource.OTEL_TRACES_EXPORTER = 'memory';
const provider = new CustomTracerProvider({});
provider.register();
const processor = provider.getActiveSpanProcessor();
assert(processor instanceof BatchSpanProcessor);
// @ts-expect-error access configured to verify its the correct one
const exporter = processor._exporter;
assert(exporter instanceof InMemorySpanExporter);
});
});
});

describe('.startSpan()', () => {
Expand Down

0 comments on commit 1758fa6

Please sign in to comment.