Skip to content

Commit b4ab8a5

Browse files
dyladanmayurkale22
authored andcommitted
Jaeger no flush interval (#609)
* fix: remove flush timer from jaeger exporter * chore: remove deprecated flushInterval * feat: force flush on each export * chore: make export noop on empty span array * chore: do not flush empty batch span processor
1 parent 9a91434 commit b4ab8a5

File tree

12 files changed

+61
-53
lines changed

12 files changed

+61
-53
lines changed

examples/basic-tracer-node/multi_exporter.js

-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ const tracer = new BasicTracer();
99
const zipkinExporter = new ZipkinExporter({serviceName: 'basic-service'});
1010
const jaegerExporter = new JaegerExporter({
1111
serviceName: 'basic-service',
12-
// The default flush interval is 5 seconds.
13-
flushInterval: 2000
1412
});
1513
const collectorExporter = new CollectorExporter({serviceName: 'basic-service'});
1614

examples/dns/setup.js

-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ function setupTracerAndExporters(service) {
2727
} else {
2828
exporter = new JaegerExporter({
2929
serviceName: service,
30-
// The default flush interval is 5 seconds.
31-
flushInterval: 2000
3230
});
3331
}
3432

examples/grpc/setup.js

-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ function setupTracerAndExporters(service) {
2626
} else {
2727
exporter = new JaegerExporter({
2828
serviceName: service,
29-
// The default flush interval is 5 seconds.
30-
flushInterval: 2000
3129
});
3230
}
3331

examples/grpc_dynamic_codegen/setup.js

-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ function setupTracerAndExporters(service) {
2626
} else {
2727
exporter = new JaegerExporter({
2828
serviceName: service,
29-
// The default flush interval is 5 seconds.
30-
flushInterval: 2000
3129
});
3230
}
3331

examples/http/setup.js

-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ function setupTracerAndExporters(service) {
1818
} else {
1919
exporter = new JaegerExporter({
2020
serviceName: service,
21-
// The default flush interval is 5 seconds.
22-
flushInterval: 2000
2321
});
2422
}
2523

examples/https/setup.js

-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ function setupTracerAndExporters(service) {
1818
} else {
1919
exporter = new JaegerExporter({
2020
serviceName: service,
21-
// The default flush interval is 5 seconds.
22-
flushInterval: 2000
2321
});
2422
}
2523

examples/mysql/setup.js

-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ function setupTracerAndExporters(service) {
2525
})));
2626
tracer.addSpanProcessor(new SimpleSpanProcessor(new JaegerExporter({
2727
serviceName: service,
28-
// The default flush interval is 5 seconds.
29-
flushInterval: 2000
3028
})));
3129

3230
// Initialize the OpenTelemetry APIs to use the BasicTracer bindings

examples/redis/setup.js

-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ function setupTracerAndExporters(service) {
1818
} else {
1919
exporter = new JaegerExporter({
2020
serviceName: service,
21-
// The default flush interval is 5 seconds.
22-
flushInterval: 2000
2321
});
2422
}
2523

packages/opentelemetry-exporter-jaeger/src/jaeger.ts

+46-30
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import * as jaegerTypes from './types';
2020
import { NoopLogger } from '@opentelemetry/core';
2121
import * as types from '@opentelemetry/types';
2222
import { spanToThrift } from './transform';
23-
import { unrefTimer } from '@opentelemetry/core';
2423

2524
/**
2625
* Format and sends span information to Jaeger Exporter.
@@ -29,77 +28,94 @@ export class JaegerExporter implements SpanExporter {
2928
private readonly _logger: types.Logger;
3029
private readonly _process: jaegerTypes.ThriftProcess;
3130
private readonly _sender: typeof jaegerTypes.UDPSender;
32-
private readonly _forceFlush: boolean = true;
33-
private readonly _flushTimeout: number;
34-
private _timer: NodeJS.Timeout;
31+
private readonly _forceFlushOnShutdown: boolean = true;
32+
private readonly _onShutdownFlushTimeout: number;
3533

3634
constructor(config: jaegerTypes.ExporterConfig) {
3735
this._logger = config.logger || new NoopLogger();
3836
const tags: jaegerTypes.Tag[] = config.tags || [];
39-
if (config.forceFlush !== undefined) {
40-
this._forceFlush = config.forceFlush;
41-
}
42-
this._flushTimeout = config.flushTimeout || 2000;
37+
this._forceFlushOnShutdown =
38+
typeof config.forceFlush === 'boolean' ? config.forceFlush : true;
39+
this._onShutdownFlushTimeout =
40+
typeof config.flushTimeout === 'number' ? config.flushTimeout : 2000;
4341

4442
this._sender = new jaegerTypes.UDPSender(config);
4543
this._process = {
4644
serviceName: config.serviceName,
4745
tags: jaegerTypes.ThriftUtils.getThriftTags(tags),
4846
};
4947
this._sender.setProcess(this._process);
50-
51-
const flushInterval = config.flushInterval || 5000;
52-
this._timer = setInterval(this._flush.bind(this), flushInterval);
53-
unrefTimer(this._timer);
5448
}
5549

5650
/** Exports a list of spans to Jaeger. */
5751
export(
5852
spans: ReadableSpan[],
5953
resultCallback: (result: ExportResult) => void
6054
): void {
55+
if (spans.length === 0) {
56+
return resultCallback(ExportResult.SUCCESS);
57+
}
6158
this._logger.debug('Jaeger exporter export');
62-
return this._sendSpans(spans, resultCallback);
59+
this._sendSpans(spans, resultCallback).catch(err => {
60+
this._logger.error(`JaegerExporter failed to export: ${err}`);
61+
});
6362
}
6463

6564
/** Shutdown exporter. */
6665
shutdown(): void {
67-
if (!this._forceFlush) return;
66+
if (!this._forceFlushOnShutdown) return;
6867
// Make an optimistic flush.
6968
this._flush();
7069
// Sleeping x seconds before closing the sender's connection to ensure
7170
// all spans are flushed.
7271
setTimeout(() => {
7372
this._sender.close();
74-
}, this._flushTimeout);
73+
}, this._onShutdownFlushTimeout);
7574
}
7675

7776
/** Transform spans and sends to Jaeger service. */
78-
private _sendSpans(
77+
private async _sendSpans(
7978
spans: ReadableSpan[],
8079
done?: (result: ExportResult) => void
8180
) {
8281
const thriftSpan = spans.map(span => spanToThrift(span));
8382
for (const span of thriftSpan) {
84-
this._sender.append(span, (numSpans: number, err?: string) => {
85-
if (err) {
86-
// @todo: decide whether to break out the loop on first error.
87-
this._logger.error(`failed to append span: ${err}`);
88-
if (done) return done(ExportResult.FAILED_NOT_RETRYABLE);
89-
}
90-
});
83+
try {
84+
await this._append(span);
85+
} catch (err) {
86+
this._logger.error(`failed to append span: ${err}`);
87+
// TODO right now we break out on first error, is that desirable?
88+
if (done) return done(ExportResult.FAILED_NOT_RETRYABLE);
89+
}
9190
}
92-
// @todo: We should wait for all the callbacks of the append calls to
93-
// complete before it calls done with success.
9491
this._logger.debug('successful append for : %s', thriftSpan.length);
92+
93+
// Flush all spans on each export. No-op if span buffer is empty
94+
await this._flush();
95+
9596
if (done) return done(ExportResult.SUCCESS);
9697
}
9798

98-
private _flush(): void {
99-
this._sender.flush((numSpans: number, err?: string) => {
100-
if (err) {
101-
this._logger.error(`failed to flush ${numSpans} spans: ${err}`);
102-
}
99+
private async _append(span: jaegerTypes.ThriftSpan): Promise<number> {
100+
return new Promise((resolve, reject) => {
101+
this._sender.append(span, (count: number, err?: string) => {
102+
if (err) {
103+
return reject(new Error(err));
104+
}
105+
resolve(count);
106+
});
107+
});
108+
}
109+
110+
private async _flush(): Promise<void> {
111+
await new Promise((resolve, reject) => {
112+
this._sender.flush((_count: number, err?: string) => {
113+
if (err) {
114+
return reject(new Error(err));
115+
}
116+
this._logger.debug('successful flush for %s spans', _count);
117+
resolve();
118+
});
103119
});
104120
}
105121
}

packages/opentelemetry-exporter-jaeger/src/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ export interface ExporterConfig {
2626
host?: string; // default: 'localhost'
2727
port?: number; // default: 6832
2828
maxPacketSize?: number; // default: 65000
29+
/** Force a flush on shutdown */
2930
forceFlush?: boolean; // default: true
31+
/** Time to wait for an onShutdown flush to finish before closing the sender */
3032
flushTimeout?: number; // default: 2000
31-
flushInterval?: number; // default(ms): 5000
3233
}
3334

3435
// Below require is needed as jaeger-client types does not expose the thrift,

packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ describe('JaegerExporter', () => {
6161
assert.ok(typeof exporter.export === 'function');
6262
assert.ok(typeof exporter.shutdown === 'function');
6363

64-
assert.ok(exporter['_forceFlush']);
65-
assert.strictEqual(exporter['_flushTimeout'], 5000);
64+
assert.ok(exporter['_forceFlushOnShutdown']);
65+
assert.strictEqual(exporter['_onShutdownFlushTimeout'], 5000);
6666
});
6767

6868
it('should construct an exporter without forceFlush and flushTimeout', () => {
@@ -72,8 +72,8 @@ describe('JaegerExporter', () => {
7272
assert.ok(typeof exporter.export === 'function');
7373
assert.ok(typeof exporter.shutdown === 'function');
7474

75-
assert.ok(exporter['_forceFlush']);
76-
assert.strictEqual(exporter['_flushTimeout'], 2000);
75+
assert.ok(exporter['_forceFlushOnShutdown']);
76+
assert.strictEqual(exporter['_onShutdownFlushTimeout'], 2000);
7777
});
7878

7979
it('should construct an exporter with forceFlush = false', () => {
@@ -84,7 +84,7 @@ describe('JaegerExporter', () => {
8484
assert.ok(typeof exporter.export === 'function');
8585
assert.ok(typeof exporter.shutdown === 'function');
8686

87-
assert.ok(!exporter['_forceFlush']);
87+
assert.ok(!exporter['_forceFlushOnShutdown']);
8888
});
8989
});
9090

packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export class BatchSpanProcessor implements SpanProcessor {
4545
: DEFAULT_BUFFER_TIMEOUT_MS;
4646

4747
this._timer = setInterval(() => {
48-
if (Date.now() - this._lastSpanFlush >= this._bufferTimeout) {
48+
if (this._shouldFlush()) {
4949
this._flush();
5050
}
5151
}, this._bufferTimeout);
@@ -73,6 +73,13 @@ export class BatchSpanProcessor implements SpanProcessor {
7373
}
7474
}
7575

76+
private _shouldFlush(): boolean {
77+
return (
78+
this._finishedSpans.length >= 0 &&
79+
Date.now() - this._lastSpanFlush >= this._bufferTimeout
80+
);
81+
}
82+
7683
/** Send the span data list to exporter */
7784
private _flush() {
7885
this._exporter.export(this._finishedSpans, () => {});

0 commit comments

Comments
 (0)