Skip to content

Commit 081469f

Browse files
markwolffmayurkale22
authored andcommitted
add GlobalTracer API (open-telemetry#118)
* add GlobalTracer * remove extra tslint rule * update format types * refactor to add globaltracer-utils * rename: GlobalTracer to GlobalTracerDelegate * remove 1st arg from Delegate constructor * rename GlobalTracerDelegate to TracerDelegate * refactor TracerDelegate tracer as runtime readonly * refactor globaltracer-utils * fix new lint issues * add missing linter fix * move no-any disabler * delegate: add start/stop to use fallback * core: reorder exports * delegate: use constructor initializers
1 parent a15ccb9 commit 081469f

File tree

5 files changed

+337
-0
lines changed

5 files changed

+337
-0
lines changed

packages/opentelemetry-core/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ export * from './context/propagation/BinaryTraceContext';
1919
export * from './context/propagation/HttpTraceContext';
2020
export * from './platform';
2121
export * from './resources/Resource';
22+
export * from './trace/globaltracer-utils';
2223
export * from './trace/instrumentation/BasePlugin';
2324
export * from './trace/NoopSpan';
2425
export * from './trace/NoopTracer';
2526
export * from './trace/sampler/ProbabilitySampler';
2627
export * from './trace/spancontext-utils';
28+
export * from './trace/TracerDelegate';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* Copyright 2019, OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as types from '@opentelemetry/types';
18+
import { NoopTracer } from './NoopTracer';
19+
20+
// Acts a bridge to the global tracer that can be safely called before the
21+
// global tracer is initialized. The purpose of the delegation is to avoid the
22+
// sometimes nearly intractible initialization order problems that can arise in
23+
// applications with a complex set of dependencies. Also allows for the tracer
24+
// to be changed/disabled during runtime without needing to change reference
25+
// to the global tracer
26+
export class TracerDelegate implements types.Tracer {
27+
private _currentTracer: types.Tracer;
28+
29+
// Wrap a tracer with a TracerDelegate. Provided tracer becomes the default
30+
// fallback tracer for when a global tracer has not been initialized
31+
constructor(
32+
private readonly tracer: types.Tracer | null = null,
33+
private readonly fallbackTracer: types.Tracer = new NoopTracer()
34+
) {
35+
this._currentTracer = tracer || fallbackTracer; // equivalent to this.start()
36+
}
37+
38+
// Begin using the user provided tracer. Stop always falling back to fallback tracer
39+
start(): void {
40+
this._currentTracer = this.tracer || this.fallbackTracer;
41+
}
42+
43+
// Stop the delegate from using the provided tracer. Begin to use the fallback tracer
44+
stop(): void {
45+
this._currentTracer = this.fallbackTracer;
46+
}
47+
48+
// -- Tracer interface implementation below -- //
49+
50+
getCurrentSpan(): types.Span {
51+
return this._currentTracer.getCurrentSpan.apply(
52+
this._currentTracer,
53+
// tslint:disable-next-line:no-any
54+
arguments as any
55+
);
56+
}
57+
58+
startSpan(name: string, options?: types.SpanOptions | undefined): types.Span {
59+
return this._currentTracer.startSpan.apply(
60+
this._currentTracer,
61+
// tslint:disable-next-line:no-any
62+
arguments as any
63+
);
64+
}
65+
66+
withSpan<T extends (...args: unknown[]) => unknown>(
67+
span: types.Span,
68+
fn: T
69+
): ReturnType<T> {
70+
return this._currentTracer.withSpan.apply(
71+
this._currentTracer,
72+
// tslint:disable-next-line:no-any
73+
arguments as any
74+
) as ReturnType<T>;
75+
}
76+
77+
recordSpanData(span: types.Span): void {
78+
return this._currentTracer.recordSpanData.apply(
79+
this._currentTracer,
80+
// tslint:disable-next-line:no-any
81+
arguments as any
82+
);
83+
}
84+
85+
getBinaryFormat(): types.BinaryFormat {
86+
return this._currentTracer.getBinaryFormat.apply(
87+
this._currentTracer,
88+
// tslint:disable-next-line:no-any
89+
arguments as any
90+
);
91+
}
92+
93+
getHttpTextFormat(): types.HttpTextFormat {
94+
return this._currentTracer.getHttpTextFormat.apply(
95+
this._currentTracer,
96+
// tslint:disable-next-line:no-any
97+
arguments as any
98+
);
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Copyright 2019, OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as types from '@opentelemetry/types';
18+
import { TracerDelegate } from './TracerDelegate';
19+
20+
let globalTracerDelegate = new TracerDelegate();
21+
22+
/**
23+
* Set the current global tracer. Returns the initialized global tracer
24+
*/
25+
export function initGlobalTracer(tracer: types.Tracer): types.Tracer {
26+
return (globalTracerDelegate = new TracerDelegate(tracer));
27+
}
28+
29+
/**
30+
* Returns the global tracer
31+
*/
32+
export function getTracer(): types.Tracer {
33+
// Return the global tracer delegate
34+
return globalTracerDelegate;
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* Copyright 2019, OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as assert from 'assert';
18+
import * as types from '@opentelemetry/types';
19+
import { TracerDelegate } from '../../src/trace/TracerDelegate';
20+
import { NoopTracer, NoopSpan } from '../../src';
21+
import { TraceOptions } from '@opentelemetry/types';
22+
23+
describe('TracerDelegate', () => {
24+
const functions = [
25+
'getCurrentSpan',
26+
'startSpan',
27+
'withSpan',
28+
'recordSpanData',
29+
'getBinaryFormat',
30+
'getHttpTextFormat',
31+
];
32+
const spanContext = {
33+
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
34+
spanId: '6e0c63257de34c92',
35+
traceOptions: TraceOptions.UNSAMPLED,
36+
};
37+
38+
describe('#constructor(...)', () => {
39+
it('should not crash with default constructor', () => {
40+
functions.forEach(fn => {
41+
const tracer = new TracerDelegate();
42+
try {
43+
((tracer as unknown) as { [fn: string]: Function })[fn](); // Try to run the function
44+
assert.ok(true, fn);
45+
} catch (err) {
46+
if (err.message !== 'Method not implemented.') {
47+
assert.ok(false, fn);
48+
}
49+
}
50+
});
51+
});
52+
53+
it('should allow fallback tracer to be set', () => {
54+
const dummyTracer = new DummyTracer();
55+
const tracerDelegate = new TracerDelegate(dummyTracer);
56+
57+
tracerDelegate.startSpan('foo');
58+
assert.deepStrictEqual(dummyTracer.spyCounter, 1);
59+
});
60+
61+
it('should use user provided tracer if provided', () => {
62+
const dummyTracer = new DummyTracer();
63+
const tracerDelegate = new TracerDelegate(dummyTracer);
64+
65+
tracerDelegate.startSpan('foo');
66+
assert.deepStrictEqual(dummyTracer.spyCounter, 1);
67+
});
68+
69+
describe('#start/stop()', () => {
70+
it('should use the fallback tracer when stop is called', () => {
71+
const dummyTracerUser = new DummyTracer();
72+
const dummyTracerFallback = new DummyTracer();
73+
const tracerDelegate = new TracerDelegate(
74+
dummyTracerUser,
75+
dummyTracerFallback
76+
);
77+
78+
tracerDelegate.stop();
79+
tracerDelegate.startSpan('fallback');
80+
assert.deepStrictEqual(dummyTracerUser.spyCounter, 0);
81+
assert.deepStrictEqual(dummyTracerFallback.spyCounter, 1);
82+
});
83+
84+
it('should use the user tracer when start is called', () => {
85+
const dummyTracerUser = new DummyTracer();
86+
const dummyTracerFallback = new DummyTracer();
87+
const tracerDelegate = new TracerDelegate(
88+
dummyTracerUser,
89+
dummyTracerFallback
90+
);
91+
92+
tracerDelegate.stop();
93+
tracerDelegate.startSpan('fallback');
94+
assert.deepStrictEqual(dummyTracerUser.spyCounter, 0);
95+
assert.deepStrictEqual(dummyTracerFallback.spyCounter, 1);
96+
97+
tracerDelegate.start();
98+
tracerDelegate.startSpan('user');
99+
assert.deepStrictEqual(dummyTracerUser.spyCounter, 1);
100+
assert.deepStrictEqual(
101+
dummyTracerFallback.spyCounter,
102+
1,
103+
'Only user tracer counter is incremented'
104+
);
105+
});
106+
});
107+
});
108+
109+
class DummyTracer extends NoopTracer {
110+
spyCounter = 0;
111+
112+
startSpan(name: string, options?: types.SpanOptions | undefined) {
113+
this.spyCounter = this.spyCounter + 1;
114+
return new NoopSpan(spanContext);
115+
}
116+
}
117+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Copyright 2019, OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as assert from 'assert';
18+
import * as types from '@opentelemetry/types';
19+
import {
20+
getTracer,
21+
initGlobalTracer,
22+
} from '../../src/trace/globaltracer-utils';
23+
import { NoopTracer, NoopSpan } from '../../src';
24+
import { TraceOptions } from '@opentelemetry/types';
25+
26+
describe('globaltracer-utils', () => {
27+
const functions = [
28+
'getCurrentSpan',
29+
'startSpan',
30+
'withSpan',
31+
'recordSpanData',
32+
'getBinaryFormat',
33+
'getHttpTextFormat',
34+
];
35+
36+
it('should expose a tracer via getTracer', () => {
37+
const tracer = getTracer();
38+
assert.ok(tracer);
39+
assert.strictEqual(typeof tracer, 'object');
40+
});
41+
42+
describe('GlobalTracer', () => {
43+
const spanContext = {
44+
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
45+
spanId: '6e0c63257de34c92',
46+
traceOptions: TraceOptions.UNSAMPLED,
47+
};
48+
const dummySpan = new NoopSpan(spanContext);
49+
50+
afterEach(() => {
51+
initGlobalTracer(new NoopTracer());
52+
});
53+
54+
it('should not crash', () => {
55+
functions.forEach(fn => {
56+
const tracer = getTracer();
57+
try {
58+
((tracer as unknown) as { [fn: string]: Function })[fn](); // Try to run the function
59+
assert.ok(true, fn);
60+
} catch (err) {
61+
if (err.message !== 'Method not implemented.') {
62+
assert.ok(false, fn);
63+
}
64+
}
65+
});
66+
});
67+
68+
it('should use the global tracer', () => {
69+
const tracer = initGlobalTracer(new TestTracer());
70+
const span = tracer.startSpan('test');
71+
assert.deepStrictEqual(span, dummySpan);
72+
});
73+
74+
class TestTracer extends NoopTracer {
75+
startSpan(
76+
name: string,
77+
options?: types.SpanOptions | undefined
78+
): types.Span {
79+
return dummySpan;
80+
}
81+
}
82+
});
83+
});

0 commit comments

Comments
 (0)