@@ -5,10 +5,14 @@ const log = require('../../dd-trace/src/log')
55const tags = require ( '../../../ext/tags' )
66const kinds = require ( '../../../ext/kinds' )
77const formats = require ( '../../../ext/formats' )
8- const urlFilter = require ( '../../dd-trace/src/plugins/util/urlfilter' )
98const analyticsSampler = require ( '../../dd-trace/src/analytics_sampler' )
109const { AsyncResource, AsyncLocalStorage } = require ( 'async_hooks' )
11- const { addErrorToSpan, getServiceName, hasAmazonSignature, client : { normalizeConfig } } = require ( '../../dd-trace/src/plugins/util/web' )
10+ const {
11+ addErrorToSpan,
12+ getServiceName,
13+ hasAmazonSignature,
14+ client : { normalizeConfig }
15+ } = require ( '../../dd-trace/src/plugins/util/web' )
1216
1317const HTTP_HEADERS = formats . HTTP_HEADERS
1418const HTTP_STATUS_CODE = tags . HTTP_STATUS_CODE
@@ -58,7 +62,6 @@ function diagnostics (tracer, config) {
5862 )
5963 return ( ) => { }
6064 }
61- config = normalizeConfig ( config )
6265
6366 channels . requestChannel = diagnosticsChannel . channel ( 'undici:request:create' )
6467 channels . headersChannel = diagnosticsChannel . channel (
@@ -90,9 +93,17 @@ function diagnostics (tracer, config) {
9093 requestSpansMap . set ( request , span )
9194 }
9295
93- const headers = typeof request . headers == 'string' ? parseHeaders ( request . headers ) : request . headers ;
94-
95- if ( ! ( hasAmazonSignature ( { ...request , headers } ) || ! config . propagationFilter ( uri ) ) ) {
96+ const headers =
97+ typeof request . headers === 'string'
98+ ? parseHeaders ( request . headers )
99+ : request . headers
100+
101+ if (
102+ ! (
103+ hasAmazonSignature ( { ...request , headers } ) ||
104+ ! config . propagationFilter ( uri )
105+ )
106+ ) {
96107 const injectedHeaders = { }
97108 tracer . inject ( span , HTTP_HEADERS , injectedHeaders )
98109 Object . entries ( injectedHeaders ) . forEach ( ( [ key , value ] ) => {
@@ -106,12 +117,15 @@ function diagnostics (tracer, config) {
106117 function handleRequestError ( { request, error } ) {
107118 const span = requestSpansMap . get ( request )
108119 addErrorToSpan ( span , error )
109- finish ( request , null , span , config )
120+ addRequestHeaders ( request , span , config )
121+ span . finish ( )
110122 }
111123
112124 function handleRequestHeaders ( { request, response } ) {
113125 const span = requestSpansMap . get ( request )
114- finish ( request , response , span , config )
126+ addRequestHeaders ( request , span , config )
127+ setStatusCode ( response , span , config )
128+ config . hooks . request ( span , request , response )
115129 }
116130
117131 return function unsubscribe ( ) {
@@ -149,37 +163,38 @@ function addRequestHeaders (req, span, config) {
149163 }
150164}
151165
152- function addResponseHeaders ( res , span , config ) {
153- const resHeader = res . headers . map ( ( x ) => x . toString ( ) )
154- while ( resHeader . length ) {
155- const key = resHeader . shift ( )
156- const value = resHeader . shift ( )
157- span . setTag ( `${ HTTP_RESPONSE_HEADERS } .${ key } ` , value )
166+ function setStatusCode ( res , span , config ) {
167+ // fetch has status set on `status` rather than statusCode
168+ const statusCode = res . status || res . statusCode
169+ span . setTag ( HTTP_STATUS_CODE , statusCode )
170+
171+ if ( ! config . validateStatus ( statusCode ) ) {
172+ span . setTag ( 'error' , 1 )
158173 }
159174}
160175
161- function finish ( req , res , span , config ) {
162- if ( res ) {
163- span . setTag ( HTTP_STATUS_CODE , res . statusCode )
176+ function addResponseHeaders ( res , span , config ) {
177+ config . headers . forEach ( ( key ) => {
178+ const value = res . headers [ key ]
164179
165- if ( ! config . validateStatus ( res . statusCode ) ) {
166- span . setTag ( 'error' , 1 )
180+ if ( value ) {
181+ span . setTag ( ` ${ HTTP_RESPONSE_HEADERS } . ${ key } ` , value )
167182 }
183+ } )
184+ }
168185
186+ function finishSpan ( res , span , error , config ) {
187+ if ( res ) {
188+ setStatusCode ( res , span , config )
169189 addResponseHeaders ( res , span , config )
190+ span . finish ( )
170191 } else {
171192 span . setTag ( 'error' , 1 )
172193 }
173-
174- addRequestHeaders ( req , span , config )
175-
176- config . hooks . request ( span , req , res )
177-
178- span . finish ( )
179194}
180195
181196function patch ( undici , methodName , tracer , config ) {
182- this . wrap ( undici , methodName , fn => makeRequestTrace ( fn ) )
197+ this . wrap ( undici , methodName , ( fn ) => makeRequestTrace ( fn ) )
183198
184199 function makeRequestTrace ( request ) {
185200 return function requestTrace ( ) {
@@ -195,28 +210,78 @@ function patch (undici, methodName, tracer, config) {
195210 [ SPAN_KIND ] : CLIENT
196211 }
197212 } )
198-
199- return asyncLocalStorage . run ( span , ( ) => {
200- return request . apply ( this , arguments )
213+ const result = asyncLocalStorage . run ( span , ( ) => {
214+ return tracer . scope ( ) . activate ( span , ( ) => {
215+ return request . apply ( this , arguments )
216+ } )
201217 } )
218+
219+ if ( methodName === 'pipeline' ) {
220+ result . on ( 'end' , ( ) => {
221+ span . finish ( )
222+ } ) . on ( 'error' , ( ) => {
223+ span . finish ( )
224+ } )
225+ return result
226+ }
227+
228+ return wrapPromise ( result , span , config )
202229 }
203230 }
204231}
205232
233+ function wrapPromise ( promise , span , config ) {
234+ if ( ! promise ) {
235+ finishSpan ( null , span , null , config )
236+ return promise
237+ }
238+
239+ return promise
240+ . then (
241+ ( res ) => finishSpan ( res , span , null , config ) ,
242+ ( e ) => finishSpan ( null , span , e , config )
243+ )
244+ . then ( ( ) => promise )
245+ }
246+
206247module . exports = [
207248 {
208249 name : 'undici' ,
209250 versions : [ '>=4.7.1' ] ,
210251 patch : function ( undici , tracer , config ) {
252+ config = normalizeConfig ( config )
253+
211254 patch . call ( this , undici , 'request' , tracer , config )
212255 patch . call ( this , undici , 'upgrade' , tracer , config )
213256 patch . call ( this , undici , 'connect' , tracer , config )
214257 patch . call ( this , undici , 'fetch' , tracer , config )
215258 patch . call ( this , undici , 'pipeline' , tracer , config )
216259 patch . call ( this , undici , 'stream' , tracer , config )
217- patch . call ( this , undici . Client . prototype , 'request' , tracer , config )
218260
219- this . unpatch = diagnostics . call ( this , tracer , config )
261+ patch . call ( this , undici . Client . prototype , 'request' , tracer , config )
262+ patch . call ( this , undici . Client . prototype , 'pipeline' , tracer , config )
263+ patch . call ( this , undici . Client . prototype , 'upgrade' , tracer , config )
264+ patch . call ( this , undici . Client . prototype , 'connect' , tracer , config )
265+ patch . call ( this , undici . Client . prototype , 'stream' , tracer , config )
266+
267+ const unpatchDiagnostics = diagnostics . call ( this , tracer , config )
268+
269+ this . unpatch = ( ) => {
270+ this . unwrap ( undici , 'request' )
271+ this . unwrap ( undici , 'upgrade' )
272+ this . unwrap ( undici , 'connect' )
273+ this . unwrap ( undici , 'fetch' )
274+ this . unwrap ( undici , 'pipeline' )
275+ this . unwrap ( undici , 'stream' )
276+
277+ this . unwrap ( undici . Client . prototype , 'request' )
278+ this . unwrap ( undici . Client . prototype , 'pipeline' )
279+ this . unwrap ( undici . Client . prototype , 'upgrade' )
280+ this . unwrap ( undici . Client . prototype , 'connect' )
281+ this . unwrap ( undici . Client . prototype , 'stream' )
282+
283+ unpatchDiagnostics ( )
284+ }
220285 }
221286 }
222287]
0 commit comments