Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tracing): allow to configure exporter by environment #1676 #2100

Merged
merged 6 commits into from
May 12, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -70,6 +70,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 @@ -105,6 +106,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
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';
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()
dyladan marked this conversation as resolved.
Show resolved Hide resolved
.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;
}
}
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';
59 changes: 54 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,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