14
14
* limitations under the License.
15
15
*/
16
16
17
- import { BasePlugin , CanonicalCode , Func , HeaderGetter , HeaderSetter , MessageEventType , RootSpan , Span , SpanKind , TraceOptions } from '@opencensus/core' ;
17
+ import { BasePlugin , CanonicalCode , Func , HeaderGetter , HeaderSetter , MessageEventType , Span , SpanKind , TagMap , TraceOptions } from '@opencensus/core' ;
18
18
import * as httpModule from 'http' ;
19
19
import * as semver from 'semver' ;
20
20
import * as shimmer from 'shimmer' ;
21
21
import * as url from 'url' ;
22
22
import * as uuid from 'uuid' ;
23
- import { HttpPluginConfig , IgnoreMatcher } from './types' ;
23
+ import * as stats from './http-stats' ;
24
+ import { IgnoreMatcher } from './types' ;
24
25
25
26
export type HttpGetCallback = ( res : httpModule . IncomingMessage ) => void ;
26
27
export type HttpModule = typeof httpModule ;
27
28
export type RequestFunction = typeof httpModule . request ;
28
29
30
+ // tslint:disable-next-line:no-any
31
+ function isOpenCensusRequest ( options : any ) {
32
+ return options && options . headers &&
33
+ ! ! options . headers [ 'x-opencensus-outgoing-request' ] ;
34
+ }
35
+
29
36
/** Http instrumentation plugin for Opencensus */
30
37
export class HttpPlugin extends BasePlugin {
31
38
/**
@@ -149,7 +156,6 @@ export class HttpPlugin extends BasePlugin {
149
156
}
150
157
}
151
158
152
-
153
159
/**
154
160
* Creates spans for incoming requests, restoring spans' context if applied.
155
161
*/
@@ -164,10 +170,11 @@ export class HttpPlugin extends BasePlugin {
164
170
if ( event !== 'request' ) {
165
171
return original . apply ( this , arguments ) ;
166
172
}
167
-
173
+ const startTime = Date . now ( ) ;
168
174
const request : httpModule . IncomingMessage = args [ 0 ] ;
169
175
const response : httpModule . ServerResponse = args [ 1 ] ;
170
176
const path = request . url ? url . parse ( request . url ) . pathname || '' : '' ;
177
+ const method = request . method || 'GET' ;
171
178
plugin . logger . debug ( '%s plugin incomingRequest' , plugin . moduleName ) ;
172
179
173
180
if ( plugin . isIgnored (
@@ -209,6 +216,7 @@ export class HttpPlugin extends BasePlugin {
209
216
const host = headers . host || 'localhost' ;
210
217
const userAgent =
211
218
( headers [ 'user-agent' ] || headers [ 'User-Agent' ] ) as string ;
219
+ const tags = new TagMap ( ) ;
212
220
213
221
rootSpan . addAttribute (
214
222
HttpPlugin . ATTRIBUTE_HTTP_HOST ,
@@ -217,21 +225,18 @@ export class HttpPlugin extends BasePlugin {
217
225
'$1' ,
218
226
) ) ;
219
227
220
- rootSpan . addAttribute (
221
- HttpPlugin . ATTRIBUTE_HTTP_METHOD , request . method || 'GET' ) ;
222
-
228
+ rootSpan . addAttribute ( HttpPlugin . ATTRIBUTE_HTTP_METHOD , method ) ;
223
229
if ( requestUrl ) {
224
230
rootSpan . addAttribute (
225
231
HttpPlugin . ATTRIBUTE_HTTP_PATH , requestUrl . pathname || '' ) ;
226
232
rootSpan . addAttribute (
227
233
HttpPlugin . ATTRIBUTE_HTTP_ROUTE , requestUrl . path || '' ) ;
234
+ tags . set ( stats . HTTP_SERVER_ROUTE , { value : requestUrl . path || '' } ) ;
228
235
}
229
-
230
236
if ( userAgent ) {
231
237
rootSpan . addAttribute (
232
238
HttpPlugin . ATTRIBUTE_HTTP_USER_AGENT , userAgent ) ;
233
239
}
234
-
235
240
rootSpan . addAttribute (
236
241
HttpPlugin . ATTRIBUTE_HTTP_STATUS_CODE ,
237
242
response . statusCode . toString ( ) ) ;
@@ -243,6 +248,12 @@ export class HttpPlugin extends BasePlugin {
243
248
rootSpan . addMessageEvent (
244
249
MessageEventType . RECEIVED , uuid . v4 ( ) . split ( '-' ) . join ( '' ) ) ;
245
250
251
+ tags . set ( stats . HTTP_SERVER_METHOD , { value : method } ) ;
252
+ tags . set (
253
+ stats . HTTP_SERVER_STATUS ,
254
+ { value : response . statusCode . toString ( ) } ) ;
255
+ HttpPlugin . recordStats ( rootSpan . kind , tags , Date . now ( ) - startTime ) ;
256
+
246
257
rootSpan . end ( ) ;
247
258
return returned ;
248
259
} ;
@@ -266,7 +277,14 @@ export class HttpPlugin extends BasePlugin {
266
277
options : httpModule . RequestOptions | string ,
267
278
callback ) : httpModule . ClientRequest {
268
279
if ( ! options ) {
269
- return original . apply ( this , arguments ) ;
280
+ return original . apply ( this , [ options , callback ] ) ;
281
+ }
282
+
283
+ // Do not trace ourselves
284
+ if ( isOpenCensusRequest ( options ) ) {
285
+ plugin . logger . debug (
286
+ 'header with "x-opencensus-outgoing-request" - do not trace' ) ;
287
+ return original . apply ( this , [ options , callback ] ) ;
270
288
}
271
289
272
290
// Makes sure the url is an url object
@@ -279,27 +297,19 @@ export class HttpPlugin extends BasePlugin {
279
297
pathname = parsedUrl . pathname || '' ;
280
298
origin = `${ parsedUrl . protocol || 'http:' } //${ parsedUrl . host } ` ;
281
299
} else {
282
- // Do not trace ourselves
283
- if ( options . headers &&
284
- options . headers [ 'x-opencensus-outgoing-request' ] ) {
285
- plugin . logger . debug (
286
- 'header with "x-opencensus-outgoing-request" - do not trace' ) ;
287
- return original . apply ( this , arguments ) ;
288
- }
289
-
290
300
try {
291
301
pathname = ( options as url . URL ) . pathname ;
292
302
if ( ! pathname ) {
293
303
pathname = options . path ? url . parse ( options . path ) . pathname : '' ;
294
304
}
295
305
method = options . method || 'GET' ;
296
306
origin = `${ options . protocol || 'http:' } //${ options . host } ` ;
297
- } catch ( e ) {
307
+ } catch ( ignore ) {
298
308
}
299
309
}
300
310
301
311
const request : httpModule . ClientRequest =
302
- original . apply ( this , arguments ) ;
312
+ original . apply ( this , [ options , callback ] ) ;
303
313
304
314
if ( plugin . isIgnored (
305
315
origin + pathname , request ,
@@ -343,10 +353,10 @@ export class HttpPlugin extends BasePlugin {
343
353
* @param options The arguments to the original function.
344
354
*/
345
355
private getMakeRequestTraceFunction (
346
- // tslint:disable-next-line:no-any
347
356
request : httpModule . ClientRequest , options : httpModule . RequestOptions ,
348
357
plugin : HttpPlugin ) : Func < httpModule . ClientRequest > {
349
358
return ( span : Span ) : httpModule . ClientRequest => {
359
+ const startTime = Date . now ( ) ;
350
360
plugin . logger . debug ( 'makeRequestTrace' ) ;
351
361
352
362
if ( ! span ) {
@@ -368,14 +378,16 @@ export class HttpPlugin extends BasePlugin {
368
378
request . on ( 'response' , ( response : httpModule . ClientResponse ) => {
369
379
plugin . tracer . wrapEmitter ( response ) ;
370
380
plugin . logger . debug ( 'outgoingRequest on response()' ) ;
371
-
372
381
response . on ( 'end' , ( ) => {
373
382
plugin . logger . debug ( 'outgoingRequest on end()' ) ;
374
383
const method = response . method ? response . method : 'GET' ;
375
384
const headers = options . headers ;
376
385
const userAgent =
377
386
headers ? ( headers [ 'user-agent' ] || headers [ 'User-Agent' ] ) : null ;
378
387
388
+ const tags = new TagMap ( ) ;
389
+ tags . set ( stats . HTTP_CLIENT_METHOD , { value : method } ) ;
390
+
379
391
if ( options . hostname ) {
380
392
span . addAttribute ( HttpPlugin . ATTRIBUTE_HTTP_HOST , options . hostname ) ;
381
393
}
@@ -394,12 +406,16 @@ export class HttpPlugin extends BasePlugin {
394
406
HttpPlugin . ATTRIBUTE_HTTP_STATUS_CODE ,
395
407
response . statusCode . toString ( ) ) ;
396
408
span . setStatus ( HttpPlugin . parseResponseStatus ( response . statusCode ) ) ;
409
+ tags . set (
410
+ stats . HTTP_CLIENT_STATUS ,
411
+ { value : response . statusCode . toString ( ) } ) ;
397
412
}
398
413
399
414
// Message Event ID is not defined
400
415
span . addMessageEvent (
401
416
MessageEventType . SENT , uuid . v4 ( ) . split ( '-' ) . join ( '' ) ) ;
402
417
418
+ HttpPlugin . recordStats ( span . kind , tags , Date . now ( ) - startTime ) ;
403
419
span . end ( ) ;
404
420
} ) ;
405
421
@@ -457,6 +473,30 @@ export class HttpPlugin extends BasePlugin {
457
473
}
458
474
}
459
475
}
476
+
477
+ /** Method to record stats for client and server. */
478
+ static recordStats ( kind : SpanKind , tags : TagMap , ms : number ) {
479
+ if ( ! plugin . stats ) {
480
+ return ;
481
+ }
482
+
483
+ try {
484
+ const measureList = [ ] ;
485
+ switch ( kind ) {
486
+ case SpanKind . CLIENT :
487
+ measureList . push (
488
+ { measure : stats . HTTP_CLIENT_ROUNDTRIP_LATENCY , value : ms } ) ;
489
+ break ;
490
+ case SpanKind . SERVER :
491
+ measureList . push ( { measure : stats . HTTP_SERVER_LATENCY , value : ms } ) ;
492
+ break ;
493
+ default :
494
+ break ;
495
+ }
496
+ plugin . stats . record ( measureList , tags ) ;
497
+ } catch ( ignore ) {
498
+ }
499
+ }
460
500
}
461
501
462
502
const plugin = new HttpPlugin ( 'http' ) ;
0 commit comments