247 lines
8.3 KiB
TypeScript
247 lines
8.3 KiB
TypeScript
/*
|
|
* Copyright The OpenTelemetry Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import {
|
|
context,
|
|
TraceFlags,
|
|
propagation, trace,
|
|
} from '@opentelemetry/api';
|
|
import { AlwaysOnSampler, AlwaysOffSampler } from '@opentelemetry/core';
|
|
import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks';
|
|
import { Span } from '@opentelemetry/tracing';
|
|
import { Resource } from '@opentelemetry/resources';
|
|
import { ResourceAttributes } from '@opentelemetry/semantic-conventions';
|
|
import * as assert from 'assert';
|
|
import * as path from 'path';
|
|
import { ContextManager, ROOT_CONTEXT } from '@opentelemetry/api';
|
|
import { NodeTracerProvider } from '../src/NodeTracerProvider';
|
|
|
|
const sleep = (time: number) =>
|
|
new Promise(resolve => {
|
|
return setTimeout(resolve, time);
|
|
});
|
|
|
|
const INSTALLED_PLUGINS_PATH = path.join(
|
|
__dirname,
|
|
'instrumentation',
|
|
'node_modules'
|
|
);
|
|
|
|
describe('NodeTracerProvider', () => {
|
|
let provider: NodeTracerProvider;
|
|
let contextManager: ContextManager;
|
|
before(() => {
|
|
module.paths.push(INSTALLED_PLUGINS_PATH);
|
|
});
|
|
|
|
beforeEach(() => {
|
|
contextManager = new AsyncHooksContextManager();
|
|
context.setGlobalContextManager(contextManager.enable());
|
|
});
|
|
|
|
afterEach(() => {
|
|
// clear require cache
|
|
Object.keys(require.cache).forEach(key => delete require.cache[key]);
|
|
contextManager.disable();
|
|
context.disable();
|
|
});
|
|
|
|
describe('constructor', () => {
|
|
it('should construct an instance with required only options', () => {
|
|
provider = new NodeTracerProvider();
|
|
assert.ok(provider instanceof NodeTracerProvider);
|
|
});
|
|
|
|
it('should construct an instance with logger', () => {
|
|
provider = new NodeTracerProvider();
|
|
assert.ok(provider instanceof NodeTracerProvider);
|
|
});
|
|
|
|
it('should construct an instance with sampler', () => {
|
|
provider = new NodeTracerProvider({
|
|
sampler: new AlwaysOnSampler(),
|
|
});
|
|
assert.ok(provider instanceof NodeTracerProvider);
|
|
});
|
|
});
|
|
|
|
describe('.startSpan()', () => {
|
|
it('should start a span with name only', () => {
|
|
provider = new NodeTracerProvider();
|
|
const span = provider.getTracer('default').startSpan('my-span');
|
|
assert.ok(span);
|
|
});
|
|
|
|
it('should start a span with name and options', () => {
|
|
provider = new NodeTracerProvider();
|
|
const span = provider.getTracer('default').startSpan('my-span', {});
|
|
assert.ok(span);
|
|
});
|
|
|
|
it('should return a default span with no sampling (AlwaysOffSampler)', () => {
|
|
provider = new NodeTracerProvider({
|
|
sampler: new AlwaysOffSampler(),
|
|
});
|
|
const span = provider.getTracer('default').startSpan('my-span');
|
|
assert.strictEqual(span.spanContext().traceFlags, TraceFlags.NONE);
|
|
assert.strictEqual(span.isRecording(), false);
|
|
});
|
|
|
|
it('should start a recording span with always sampling (AlwaysOnSampler)', () => {
|
|
provider = new NodeTracerProvider({
|
|
sampler: new AlwaysOnSampler(),
|
|
});
|
|
const span = provider.getTracer('default').startSpan('my-span');
|
|
assert.ok(span instanceof Span);
|
|
assert.strictEqual(span.spanContext().traceFlags, TraceFlags.SAMPLED);
|
|
assert.strictEqual(span.isRecording(), true);
|
|
});
|
|
|
|
it('should sample with AlwaysOnSampler if parent was not sampled', () => {
|
|
provider = new NodeTracerProvider({
|
|
sampler: new AlwaysOnSampler(),
|
|
});
|
|
|
|
const sampledParent = provider.getTracer('default').startSpan(
|
|
'not-sampled-span',
|
|
{},
|
|
trace.setSpanContext(ROOT_CONTEXT, {
|
|
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
|
|
spanId: '6e0c63257de34c92',
|
|
traceFlags: TraceFlags.NONE,
|
|
})
|
|
);
|
|
assert.ok(sampledParent instanceof Span);
|
|
assert.strictEqual(
|
|
sampledParent.spanContext().traceFlags,
|
|
TraceFlags.SAMPLED
|
|
);
|
|
assert.strictEqual(sampledParent.isRecording(), true);
|
|
|
|
const span = provider
|
|
.getTracer('default')
|
|
.startSpan('child-span', {}, trace.setSpan(ROOT_CONTEXT, sampledParent));
|
|
assert.ok(span instanceof Span);
|
|
assert.strictEqual(span.spanContext().traceFlags, TraceFlags.SAMPLED);
|
|
assert.strictEqual(span.isRecording(), true);
|
|
});
|
|
|
|
it('should assign resource to span', () => {
|
|
provider = new NodeTracerProvider();
|
|
const span = provider.getTracer('default').startSpan('my-span') as Span;
|
|
assert.ok(span);
|
|
assert.ok(span.resource instanceof Resource);
|
|
assert.equal(
|
|
span.resource.attributes[ResourceAttributes.TELEMETRY_SDK_LANGUAGE],
|
|
'nodejs'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('.withSpan()', () => {
|
|
it('should run context with AsyncHooksContextManager context manager', done => {
|
|
provider = new NodeTracerProvider({});
|
|
const span = provider.getTracer('default').startSpan('my-span');
|
|
context.with(trace.setSpan(context.active(), span), () => {
|
|
assert.deepStrictEqual(trace.getSpan(context.active()), span);
|
|
return done();
|
|
});
|
|
assert.deepStrictEqual(trace.getSpan(context.active()), undefined);
|
|
});
|
|
|
|
it('should run context with AsyncHooksContextManager context manager with multiple spans', done => {
|
|
provider = new NodeTracerProvider({});
|
|
const span = provider.getTracer('default').startSpan('my-span');
|
|
context.with(trace.setSpan(context.active(), span), () => {
|
|
assert.deepStrictEqual(trace.getSpan(context.active()), span);
|
|
|
|
const span1 = provider.getTracer('default').startSpan('my-span1');
|
|
|
|
context.with(trace.setSpan(context.active(), span1), () => {
|
|
assert.deepStrictEqual(trace.getSpan(context.active()), span1);
|
|
assert.deepStrictEqual(
|
|
span1.spanContext().traceId,
|
|
span.spanContext().traceId
|
|
);
|
|
return done();
|
|
});
|
|
});
|
|
// when span ended.
|
|
// @todo: below check is not running.
|
|
assert.deepStrictEqual(trace.getSpan(context.active()), undefined);
|
|
});
|
|
|
|
it('should find correct context with promises', async () => {
|
|
provider = new NodeTracerProvider();
|
|
const span = provider.getTracer('default').startSpan('my-span');
|
|
await context.with(trace.setSpan(context.active(), span), async () => {
|
|
for (let i = 0; i < 3; i++) {
|
|
await sleep(5).then(() => {
|
|
assert.deepStrictEqual(trace.getSpan(context.active()), span);
|
|
});
|
|
}
|
|
});
|
|
assert.deepStrictEqual(trace.getSpan(context.active()), undefined);
|
|
});
|
|
});
|
|
|
|
describe('.bind()', () => {
|
|
it('should bind context with AsyncHooksContextManager context manager', done => {
|
|
const provider = new NodeTracerProvider({});
|
|
const span = provider.getTracer('default').startSpan('my-span');
|
|
const fn = () => {
|
|
assert.deepStrictEqual(trace.getSpan(context.active()), span);
|
|
return done();
|
|
};
|
|
const patchedFn = context.bind(fn, trace.setSpan(context.active(), span));
|
|
return patchedFn();
|
|
});
|
|
});
|
|
|
|
describe('.register()', () => {
|
|
let originalPropagators: string | number | undefined | string[];
|
|
beforeEach(() => {
|
|
originalPropagators = process.env.OTEL_PROPAGATORS;
|
|
});
|
|
|
|
afterEach(() => {
|
|
// otherwise we may assign 'undefined' (a string)
|
|
if (originalPropagators !== undefined) {
|
|
(process.env as any).OTEL_PROPAGATORS = originalPropagators;
|
|
} else {
|
|
delete (process.env as any).OTEL_PROPAGATORS;
|
|
}
|
|
});
|
|
|
|
it('should allow propagators as per the specification', () => {
|
|
(process.env as any).OTEL_PROPAGATORS = 'b3,b3multi,jaeger';
|
|
|
|
const provider = new NodeTracerProvider();
|
|
provider.register();
|
|
|
|
assert.deepStrictEqual(propagation.fields(), [
|
|
'b3',
|
|
'x-b3-traceid',
|
|
'x-b3-spanid',
|
|
'x-b3-flags',
|
|
'x-b3-sampled',
|
|
'x-b3-parentspanid',
|
|
'uber-trace-id',
|
|
]);
|
|
});
|
|
});
|
|
});
|