@@ -38,8 +38,7 @@ import * as http from 'http';
3838import * as nock from 'nock' ;
3939import * as shimmer from 'shimmer' ;
4040import * as url from 'url' ;
41-
42- import { HttpPlugin , plugin } from '../src/' ;
41+ import { HttpPlugin , plugin } from '../src/' ;
4342import * as stats from '../src/http-stats' ;
4443
4544function doNock (
@@ -181,13 +180,18 @@ function assertCustomAttribute(
181180}
182181
183182function assertClientStats (
184- testExporter : TestExporter ,
185- httpStatusCode : number ,
186- httpMethod : string
187- ) {
183+ testExporter : TestExporter , httpStatusCode : number , httpMethod : string ,
184+ tagCtx ?: TagMap ) {
188185 const tags = new TagMap ( ) ;
189- tags . set ( stats . HTTP_CLIENT_METHOD , { value : httpMethod } ) ;
190- tags . set ( stats . HTTP_CLIENT_STATUS , { value : `${ httpStatusCode } ` } ) ;
186+ tags . set ( stats . HTTP_CLIENT_METHOD , { value : httpMethod } ) ;
187+ tags . set ( stats . HTTP_CLIENT_STATUS , { value : `${ httpStatusCode } ` } ) ;
188+
189+ if ( tagCtx ) {
190+ tagCtx . tags . forEach ( ( tagValue : TagValue , tagKey : TagKey ) => {
191+ tags . set ( tagKey , tagValue ) ;
192+ } ) ;
193+ }
194+
191195 assert . strictEqual ( testExporter . registeredViews . length , 8 ) ;
192196 assert . strictEqual ( testExporter . recordedMeasurements . length , 1 ) ;
193197 assert . strictEqual (
@@ -199,15 +203,19 @@ function assertClientStats(
199203}
200204
201205function assertServerStats (
202- testExporter : TestExporter ,
203- httpStatusCode : number ,
204- httpMethod : string ,
205- path : string
206- ) {
206+ testExporter : TestExporter , httpStatusCode : number , httpMethod : string ,
207+ path : string , tagCtx ?: TagMap ) {
207208 const tags = new TagMap ( ) ;
208- tags . set ( stats . HTTP_SERVER_METHOD , { value : httpMethod } ) ;
209- tags . set ( stats . HTTP_SERVER_STATUS , { value : `${ httpStatusCode } ` } ) ;
210- tags . set ( stats . HTTP_SERVER_ROUTE , { value : path } ) ;
209+ tags . set ( stats . HTTP_SERVER_METHOD , { value : httpMethod } ) ;
210+ tags . set ( stats . HTTP_SERVER_STATUS , { value : `${ httpStatusCode } ` } ) ;
211+ tags . set ( stats . HTTP_SERVER_ROUTE , { value : path } ) ;
212+
213+ if ( tagCtx ) {
214+ tagCtx . tags . forEach ( ( tagValue : TagValue , tagKey : TagKey ) => {
215+ tags . set ( tagKey , tagValue ) ;
216+ } ) ;
217+ }
218+
211219 assert . strictEqual ( testExporter . registeredViews . length , 8 ) ;
212220 assert . strictEqual ( testExporter . recordedMeasurements . length , 1 ) ;
213221 assert . strictEqual (
@@ -357,6 +365,60 @@ describe('HttpPlugin', () => {
357365 } ) ;
358366 } ) ;
359367
368+ it ( 'should create a child span for GET requests with tag context' , ( ) => {
369+ const testPath = '/outgoing/rootSpan/childs/1' ;
370+ doNock ( urlHost , testPath , 200 , 'Ok' ) ;
371+ const tags = new TagMap ( ) ;
372+ tags . set ( { name : 'testKey1' } , { value : 'value1' } ) ;
373+ tags . set ( { name : 'testKey2' } , { value : 'value2' } ) ;
374+ return globalStats . withTagContext ( tags , async ( ) => {
375+ return tracer . startRootSpan (
376+ { name : 'TestRootSpan' } , async ( root : Span ) => {
377+ await httpRequest . get ( `${ urlHost } ${ testPath } ` ) . then ( ( result ) => {
378+ assert . ok ( root . name . indexOf ( 'TestRootSpan' ) >= 0 ) ;
379+ assert . strictEqual ( root . spans . length , 1 ) ;
380+ const [ span ] = root . spans ;
381+ assert . ok ( span . name . indexOf ( testPath ) >= 0 ) ;
382+ assert . strictEqual ( root . traceId , span . traceId ) ;
383+ assertSpanAttributes ( span , 200 , 'GET' , hostName , testPath ) ;
384+ assert . strictEqual ( span . messageEvents . length , 1 ) ;
385+ const [ messageEvent ] = span . messageEvents ;
386+ assert . strictEqual ( messageEvent . type , MessageEventType . SENT ) ;
387+ assert . strictEqual ( messageEvent . id , 1 ) ;
388+ assertClientStats ( testExporter , 200 , 'GET' , tags ) ;
389+ } ) ;
390+ } ) ;
391+ } ) ;
392+ } ) ;
393+
394+ it ( 'should create a child span for GET requests with empty tag context' ,
395+ ( ) => {
396+ const testPath = '/outgoing/rootSpan/childs/1' ;
397+ doNock ( urlHost , testPath , 200 , 'Ok' ) ;
398+ const tags = new TagMap ( ) ;
399+ return globalStats . withTagContext ( tags , async ( ) => {
400+ return tracer . startRootSpan (
401+ { name : 'TestRootSpan' } , async ( root : Span ) => {
402+ await httpRequest . get ( `${ urlHost } ${ testPath } ` )
403+ . then ( ( result ) => {
404+ assert . ok ( root . name . indexOf ( 'TestRootSpan' ) >= 0 ) ;
405+ assert . strictEqual ( root . spans . length , 1 ) ;
406+ const [ span ] = root . spans ;
407+ assert . ok ( span . name . indexOf ( testPath ) >= 0 ) ;
408+ assert . strictEqual ( root . traceId , span . traceId ) ;
409+ assertSpanAttributes (
410+ span , 200 , 'GET' , hostName , testPath ) ;
411+ assert . strictEqual ( span . messageEvents . length , 1 ) ;
412+ const [ messageEvent ] = span . messageEvents ;
413+ assert . strictEqual (
414+ messageEvent . type , MessageEventType . SENT ) ;
415+ assert . strictEqual ( messageEvent . id , 1 ) ;
416+ assertClientStats ( testExporter , 200 , 'GET' ) ;
417+ } ) ;
418+ } ) ;
419+ } ) ;
420+ } ) ;
421+
360422 for ( let i = 0 ; i < httpErrorCodes . length ; i ++ ) {
361423 it ( `should test a child spans for GET requests with http error ${
362424 httpErrorCodes [ i ]
@@ -563,6 +625,66 @@ describe('HttpPlugin', () => {
563625 ) ;
564626 } ) ;
565627 } ) ;
628+ it ( 'should create a root span for incoming requests with Correlation Context header' ,
629+ async ( ) => {
630+ const testPath = '/incoming/rootSpan/' ;
631+ const options = {
632+ host : 'localhost' ,
633+ path : testPath ,
634+ port : serverPort ,
635+ headers :
636+ { 'User-Agent' : 'Android' , 'Correlation-Context' : 'k1=v1,k2=v2' }
637+ } ;
638+
639+ const expectedTagsFromHeaders = new TagMap ( ) ;
640+ expectedTagsFromHeaders . set ( { name : 'k1' } , { value : 'v1' } ) ;
641+ expectedTagsFromHeaders . set ( { name : 'k2' } , { value : 'v2' } ) ;
642+
643+ shimmer . unwrap ( http , 'get' ) ;
644+ shimmer . unwrap ( http , 'request' ) ;
645+ nock . enableNetConnect ( ) ;
646+
647+ assert . strictEqual ( spanVerifier . endedSpans . length , 0 ) ;
648+
649+ await httpRequest . get ( options ) . then ( ( result ) => {
650+ assert . ok ( spanVerifier . endedSpans [ 0 ] . name . indexOf ( testPath ) >= 0 ) ;
651+ assert . strictEqual ( spanVerifier . endedSpans . length , 1 ) ;
652+ const [ span ] = spanVerifier . endedSpans ;
653+ assertSpanAttributes (
654+ span , 200 , 'GET' , 'localhost' , testPath , 'Android' ) ;
655+ assertServerStats (
656+ testExporter , 200 , 'GET' , testPath , expectedTagsFromHeaders ) ;
657+ } ) ;
658+ } ) ;
659+
660+ it ( 'should handle incoming requests with long request url path' ,
661+ async ( ) => {
662+ const testPath = '/test&code=' +
663+ 'a' . repeat ( 300 ) ;
664+ const options = {
665+ host : 'localhost' ,
666+ path : testPath ,
667+ port : serverPort ,
668+ headers : { 'User-Agent' : 'Android' }
669+ } ;
670+ shimmer . unwrap ( http , 'get' ) ;
671+ shimmer . unwrap ( http , 'request' ) ;
672+ nock . enableNetConnect ( ) ;
673+
674+ assert . strictEqual ( spanVerifier . endedSpans . length , 0 ) ;
675+
676+ await httpRequest . get ( options ) . then ( ( result ) => {
677+ assert . strictEqual ( spanVerifier . endedSpans . length , 1 ) ;
678+ assert . ok ( spanVerifier . endedSpans [ 0 ] . name . indexOf ( testPath ) >= 0 ) ;
679+ const [ span ] = spanVerifier . endedSpans ;
680+ assertSpanAttributes (
681+ span , 200 , 'GET' , 'localhost' , testPath , 'Android' ) ;
682+ assertServerStats (
683+ testExporter , 200 , 'GET' ,
684+ '/test&code=' +
685+ 'a' . repeat ( 244 ) ) ;
686+ } ) ;
687+ } ) ;
566688
567689 it ( 'custom attributes should show up on server spans' , async ( ) => {
568690 const testPath = '/incoming/rootSpan/' ;
0 commit comments