@@ -20,7 +20,6 @@ import * as jaegerTypes from './types';
20
20
import { NoopLogger } from '@opentelemetry/core' ;
21
21
import * as types from '@opentelemetry/types' ;
22
22
import { spanToThrift } from './transform' ;
23
- import { unrefTimer } from '@opentelemetry/core' ;
24
23
25
24
/**
26
25
* Format and sends span information to Jaeger Exporter.
@@ -29,77 +28,94 @@ export class JaegerExporter implements SpanExporter {
29
28
private readonly _logger : types . Logger ;
30
29
private readonly _process : jaegerTypes . ThriftProcess ;
31
30
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 ;
35
33
36
34
constructor ( config : jaegerTypes . ExporterConfig ) {
37
35
this . _logger = config . logger || new NoopLogger ( ) ;
38
36
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 ;
43
41
44
42
this . _sender = new jaegerTypes . UDPSender ( config ) ;
45
43
this . _process = {
46
44
serviceName : config . serviceName ,
47
45
tags : jaegerTypes . ThriftUtils . getThriftTags ( tags ) ,
48
46
} ;
49
47
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 ) ;
54
48
}
55
49
56
50
/** Exports a list of spans to Jaeger. */
57
51
export (
58
52
spans : ReadableSpan [ ] ,
59
53
resultCallback : ( result : ExportResult ) => void
60
54
) : void {
55
+ if ( spans . length === 0 ) {
56
+ return resultCallback ( ExportResult . SUCCESS ) ;
57
+ }
61
58
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
+ } ) ;
63
62
}
64
63
65
64
/** Shutdown exporter. */
66
65
shutdown ( ) : void {
67
- if ( ! this . _forceFlush ) return ;
66
+ if ( ! this . _forceFlushOnShutdown ) return ;
68
67
// Make an optimistic flush.
69
68
this . _flush ( ) ;
70
69
// Sleeping x seconds before closing the sender's connection to ensure
71
70
// all spans are flushed.
72
71
setTimeout ( ( ) => {
73
72
this . _sender . close ( ) ;
74
- } , this . _flushTimeout ) ;
73
+ } , this . _onShutdownFlushTimeout ) ;
75
74
}
76
75
77
76
/** Transform spans and sends to Jaeger service. */
78
- private _sendSpans (
77
+ private async _sendSpans (
79
78
spans : ReadableSpan [ ] ,
80
79
done ?: ( result : ExportResult ) => void
81
80
) {
82
81
const thriftSpan = spans . map ( span => spanToThrift ( span ) ) ;
83
82
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
+ }
91
90
}
92
- // @todo : We should wait for all the callbacks of the append calls to
93
- // complete before it calls done with success.
94
91
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
+
95
96
if ( done ) return done ( ExportResult . SUCCESS ) ;
96
97
}
97
98
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
+ } ) ;
103
119
} ) ;
104
120
}
105
121
}
0 commit comments