opentelemetry-js/packages/opentelemetry-sdk-trace-base/test/common/MultiSpanProcessor.test.ts

196 lines
6.2 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 * as assert from 'assert';
import * as Sinon from 'sinon';
import {
BasicTracerProvider,
InMemorySpanExporter,
SimpleSpanProcessor,
Span,
SpanProcessor,
} from '../../src';
import {
setGlobalErrorHandler,
loggingErrorHandler,
} from '@opentelemetry/core';
import { MultiSpanProcessor } from '../../src/MultiSpanProcessor';
class TestProcessor implements SpanProcessor {
spans: Span[] = [];
onStart(span: Span): void {}
onEnd(span: Span): void {
this.spans.push(span);
}
shutdown(): Promise<void> {
this.spans = [];
return Promise.resolve();
}
forceFlush(): Promise<void> {
return Promise.resolve();
}
}
describe('MultiSpanProcessor', () => {
let removeEvent: (() => void) | undefined;
afterEach(() => {
if (removeEvent) {
removeEvent();
removeEvent = undefined;
}
});
it('should handle one span processor', () => {
const processor1 = new TestProcessor();
const tracerProvider = new BasicTracerProvider({
spanProcessors: [processor1],
});
const tracer = tracerProvider.getTracer('default');
const span = tracer.startSpan('one');
assert.strictEqual(processor1.spans.length, 0);
span.end();
assert.strictEqual(processor1.spans.length, 1);
tracerProvider['_activeSpanProcessor'].shutdown();
});
it('should handle two span processor', async () => {
const processor1 = new TestProcessor();
const processor2 = new TestProcessor();
const tracerProvider = new BasicTracerProvider({
spanProcessors: [processor1, processor2],
});
const tracer = tracerProvider.getTracer('default');
const span = tracer.startSpan('one');
assert.strictEqual(processor1.spans.length, 0);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
span.end();
assert.strictEqual(processor1.spans.length, 1);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
tracerProvider.shutdown().then(() => {
assert.strictEqual(processor1.spans.length, 0);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
});
});
it('should export spans on manual shutdown from two span processor', () => {
const processor1 = new TestProcessor();
const processor2 = new TestProcessor();
const tracerProvider = new BasicTracerProvider({
spanProcessors: [processor1, processor2],
});
const tracer = tracerProvider.getTracer('default');
const span = tracer.startSpan('one');
assert.strictEqual(processor1.spans.length, 0);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
span.end();
assert.strictEqual(processor1.spans.length, 1);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
tracerProvider.shutdown().then(() => {
assert.strictEqual(processor1.spans.length, 0);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
});
});
it('should export spans on manual shutdown from two span processor', () => {
const processor1 = new TestProcessor();
const processor2 = new TestProcessor();
const tracerProvider = new BasicTracerProvider({
spanProcessors: [processor1, processor2],
});
const tracer = tracerProvider.getTracer('default');
const span = tracer.startSpan('one');
assert.strictEqual(processor1.spans.length, 0);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
span.end();
assert.strictEqual(processor1.spans.length, 1);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
tracerProvider.shutdown().then(() => {
assert.strictEqual(processor1.spans.length, 0);
assert.strictEqual(processor1.spans.length, processor2.spans.length);
});
});
it('should force span processors to flush', () => {
let flushed = false;
const processor: SpanProcessor = {
forceFlush: () => {
flushed = true;
return Promise.resolve();
},
onStart: span => {},
onEnd: span => {},
shutdown: () => {
return Promise.resolve();
},
};
const multiSpanProcessor = new MultiSpanProcessor([processor]);
multiSpanProcessor.forceFlush();
assert.ok(flushed);
});
it('should wait for all span processors to finish flushing', done => {
let flushed = 0;
const processor1 = new SimpleSpanProcessor(new InMemorySpanExporter());
const processor2 = new SimpleSpanProcessor(new InMemorySpanExporter());
const spy1 = Sinon.stub(processor1, 'forceFlush').callsFake(() => {
flushed++;
return Promise.resolve();
});
const spy2 = Sinon.stub(processor2, 'forceFlush').callsFake(() => {
flushed++;
return Promise.resolve();
});
const multiSpanProcessor = new MultiSpanProcessor([processor1, processor2]);
multiSpanProcessor.forceFlush().then(() => {
Sinon.assert.calledOnce(spy1);
Sinon.assert.calledOnce(spy2);
assert.strictEqual(flushed, 2);
done();
});
});
it('should call globalErrorHandler in forceFlush', async () => {
const expectedError = new Error('whoops');
const testProcessor = new TestProcessor();
const forceFlush = Sinon.stub(testProcessor, 'forceFlush');
forceFlush.rejects(expectedError);
const multiSpanProcessor = new MultiSpanProcessor([testProcessor]);
const errorHandlerSpy = Sinon.spy();
setGlobalErrorHandler(errorHandlerSpy);
await multiSpanProcessor.forceFlush();
forceFlush.restore();
const [[error]] = errorHandlerSpy.args;
assert.strictEqual(error, expectedError);
assert.strictEqual(errorHandlerSpy.callCount, 1);
//reset global error handler
setGlobalErrorHandler(loggingErrorHandler());
});
});