Skip to content

Commit 6885278

Browse files
feat: add forceFlush-function to the BasicTracerProvider-class (#2191)
Co-authored-by: Weyert de Boer <[email protected]>
1 parent 1758fa6 commit 6885278

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed

packages/opentelemetry-tracing/src/BasicTracerProvider.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ import { BatchSpanProcessor } from './export/BatchSpanProcessor';
4141
export type PROPAGATOR_FACTORY = () => TextMapPropagator;
4242
export type EXPORTER_FACTORY = () => SpanExporter;
4343

44+
export enum ForceFlushState {
45+
'resolved',
46+
'timeout',
47+
'error',
48+
'unresolved',
49+
}
50+
4451
/**
4552
* This class represents a basic tracer provider which platform libraries can extend
4653
*/
@@ -140,6 +147,55 @@ export class BasicTracerProvider implements TracerProvider {
140147
}
141148
}
142149

150+
forceFlush(): Promise<void> {
151+
const timeout = this._config.forceFlushTimeoutMillis;
152+
const promises = this._registeredSpanProcessors.map(
153+
(spanProcessor: SpanProcessor) => {
154+
return new Promise(resolve => {
155+
let state: ForceFlushState;
156+
const timeoutInterval = setTimeout(() => {
157+
resolve(
158+
new Error(
159+
`Span processor did not completed within timeout period of ${timeout} ms`
160+
)
161+
);
162+
state = ForceFlushState.timeout;
163+
}, timeout);
164+
165+
spanProcessor
166+
.forceFlush()
167+
.then(() => {
168+
clearTimeout(timeoutInterval);
169+
if (state !== ForceFlushState.timeout) {
170+
state = ForceFlushState.resolved;
171+
resolve(state);
172+
}
173+
})
174+
.catch(error => {
175+
clearTimeout(timeoutInterval);
176+
state = ForceFlushState.error;
177+
resolve(error);
178+
});
179+
});
180+
}
181+
);
182+
183+
return new Promise<void>((resolve, reject) => {
184+
Promise.all(promises)
185+
.then(results => {
186+
const errors = results.filter(
187+
result => result !== ForceFlushState.resolved
188+
);
189+
if (errors.length > 0) {
190+
reject(errors);
191+
} else {
192+
resolve();
193+
}
194+
})
195+
.catch(error => reject([error]));
196+
});
197+
}
198+
143199
shutdown() {
144200
return this.activeSpanProcessor.shutdown();
145201
}

packages/opentelemetry-tracing/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const FALLBACK_OTEL_TRACES_SAMPLER = TracesSamplerValues.AlwaysOn;
3636
*/
3737
export const DEFAULT_CONFIG = {
3838
sampler: buildSamplerFromEnv(env),
39+
forceFlushTimeoutMillis: 30000,
3940
traceParams: {
4041
numberOfAttributesPerSpan: getEnv().OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT,
4142
numberOfLinksPerSpan: getEnv().OTEL_SPAN_LINK_COUNT_LIMIT,

packages/opentelemetry-tracing/src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ export interface TracerConfig {
4040
* The default idGenerator generates random ids
4141
*/
4242
idGenerator?: IdGenerator;
43+
44+
/**
45+
* How long the forceFlush can run before it is cancelled.
46+
* The default value is 30000ms
47+
*/
48+
forceFlushTimeoutMillis?: number;
4349
}
4450

4551
/**

packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,64 @@ describe('BasicTracerProvider', () => {
441441
});
442442
});
443443

444+
describe('.forceFlush()', () => {
445+
it('should call forceFlush on all registered span processors', done => {
446+
sinon.restore();
447+
const forceFlushStub = sinon.stub(
448+
NoopSpanProcessor.prototype,
449+
'forceFlush'
450+
);
451+
forceFlushStub.resolves();
452+
453+
const tracerProvider = new BasicTracerProvider();
454+
const spanProcessorOne = new NoopSpanProcessor();
455+
const spanProcessorTwo = new NoopSpanProcessor();
456+
457+
tracerProvider.addSpanProcessor(spanProcessorOne);
458+
tracerProvider.addSpanProcessor(spanProcessorTwo);
459+
460+
tracerProvider
461+
.forceFlush()
462+
.then(() => {
463+
sinon.restore();
464+
assert(forceFlushStub.calledTwice);
465+
done();
466+
})
467+
.catch(error => {
468+
sinon.restore();
469+
done(error);
470+
});
471+
});
472+
473+
it('should throw error when calling forceFlush on all registered span processors fails', done => {
474+
sinon.restore();
475+
476+
const forceFlushStub = sinon.stub(
477+
NoopSpanProcessor.prototype,
478+
'forceFlush'
479+
);
480+
forceFlushStub.returns(Promise.reject('Error'));
481+
482+
const tracerProvider = new BasicTracerProvider();
483+
const spanProcessorOne = new NoopSpanProcessor();
484+
const spanProcessorTwo = new NoopSpanProcessor();
485+
tracerProvider.addSpanProcessor(spanProcessorOne);
486+
tracerProvider.addSpanProcessor(spanProcessorTwo);
487+
488+
tracerProvider
489+
.forceFlush()
490+
.then(() => {
491+
sinon.restore();
492+
done(new Error('Successful forceFlush not expected'));
493+
})
494+
.catch(_error => {
495+
sinon.restore();
496+
sinon.assert.calledTwice(forceFlushStub);
497+
done();
498+
});
499+
});
500+
});
501+
444502
describe('.bind()', () => {
445503
it('should bind context with NoopContextManager context manager', done => {
446504
const tracer = new BasicTracerProvider().getTracer('default');

0 commit comments

Comments
 (0)