3
3
const nsolidApi = internalBinding ( 'nsolid_api' ) ;
4
4
const {
5
5
nsolid_counts,
6
+ nsolid_span_id_s,
6
7
nsolid_tracer_s,
7
8
nsolid_consts,
8
9
} = nsolidApi ;
@@ -14,6 +15,7 @@ const {
14
15
} = require ( 'internal/otel/core' ) ;
15
16
16
17
const {
18
+ extractSpanContextFromHttpHeaders,
17
19
generateSpan,
18
20
nsolidTracer,
19
21
} = require ( 'internal/nsolid_trace' ) ;
@@ -28,21 +30,34 @@ const {
28
30
kSpanHttpClient,
29
31
kSpanHttpMethod,
30
32
kSpanHttpReqUrl,
33
+ kSpanHttpServer,
31
34
kSpanHttpStatusCode,
32
35
} = nsolid_consts ;
33
36
34
37
const undiciFetch = dc . tracingChannel ( 'undici:fetch' ) ;
38
+ const http2Client = dc . tracingChannel ( 'http2.client' ) ;
39
+ const http2Server = dc . tracingChannel ( 'http2.server' ) ;
35
40
36
41
// To lazy load the http2 constants
37
42
let http2Constants ;
38
43
39
44
let tracingEnabled = false ;
40
45
41
- const fetchSubscribeListener = ( message , name ) => { } ;
46
+ const subscribeListener = ( message , name ) => { } ;
42
47
43
48
function disableTracing ( ) {
44
49
undiciFetch . start . unbindStore ( ) ;
45
- dc . unsubscribe ( 'tracing:undici:fetch:start' , fetchSubscribeListener ) ;
50
+ dc . unsubscribe ( 'tracing:undici:fetch:start' , subscribeListener ) ;
51
+ http2Client . start . unbindStore ( ) ;
52
+ dc . unsubscribe ( 'tracing:http2.client:start' , subscribeListener ) ;
53
+ http2Server . start . unbindStore ( ) ;
54
+ dc . unsubscribe ( 'tracing:http2.server:start' , subscribeListener ) ;
55
+ }
56
+
57
+ function extractHttp2Url ( headers , http2Constants ) {
58
+ const { HTTP2_HEADER_SCHEME , HTTP2_HEADER_PATH } = http2Constants ;
59
+ const authority = require ( 'internal/http2/util' ) . getAuthority ( headers ) ;
60
+ return `${ headers [ HTTP2_HEADER_SCHEME ] } ://${ authority } ${ headers [ HTTP2_HEADER_PATH ] } ` ;
46
61
}
47
62
48
63
function enableTracing ( ) {
@@ -66,7 +81,52 @@ function enableTracing() {
66
81
return api . trace . setSpan ( api . context . active ( ) , span ) ;
67
82
} ) ;
68
83
69
- dc . subscribe ( 'tracing:undici:fetch:start' , fetchSubscribeListener ) ;
84
+ dc . subscribe ( 'tracing:http2.client:start' , subscribeListener ) ;
85
+
86
+ http2Client . start . bindStore ( contextManager . _getALS ( ) , ( data ) => {
87
+ const api = getApi ( ) ;
88
+ const tracer = api . trace . getTracer ( 'http2' ) ;
89
+ http2Constants ||= require ( 'internal/http2/core' ) . constants ;
90
+ const { headers } = data ;
91
+ const method = headers [ http2Constants . HTTP2_HEADER_METHOD ] ;
92
+ const url = extractHttp2Url ( headers , http2Constants ) ;
93
+ const span = tracer . startSpan ( `HTTP ${ method } ` ,
94
+ { internal : true ,
95
+ kind : api . SpanKind . CLIENT ,
96
+ type : kSpanHttpClient } ) ;
97
+ span . _pushSpanDataString ( kSpanHttpMethod , method ) ;
98
+ span . _pushSpanDataString ( kSpanHttpReqUrl , url ) ;
99
+ const { spanId, traceId } = span . spanContext ( ) ;
100
+ if ( span . _isSampled ( ) ) {
101
+ headers . traceparent = `00-${ traceId } -${ spanId } -01` ;
102
+ } else {
103
+ headers . traceparent = `00-${ traceId } -${ spanId } -00` ;
104
+ }
105
+
106
+ return api . trace . setSpan ( api . context . active ( ) , span ) ;
107
+ } ) ;
108
+
109
+ dc . subscribe ( 'tracing:http2.client:start' , subscribeListener ) ;
110
+
111
+ http2Server . start . bindStore ( contextManager . _getALS ( ) , ( data ) => {
112
+ const api = getApi ( ) ;
113
+ const tracer = api . trace . getTracer ( 'http2' ) ;
114
+ http2Constants ||= require ( 'internal/http2/core' ) . constants ;
115
+ const { headers } = data ;
116
+ const method = headers [ http2Constants . HTTP2_HEADER_METHOD ] ;
117
+ const url = extractHttp2Url ( headers , http2Constants ) ;
118
+ const ctxt = extractSpanContextFromHttpHeaders ( api . ROOT_CONTEXT , headers ) ;
119
+ const span = tracer . startSpan ( `HTTP ${ method } ` ,
120
+ { internal : true ,
121
+ kind : api . SpanKind . SERVER ,
122
+ type : kSpanHttpServer } ,
123
+ ctxt ) ;
124
+ span . _pushSpanDataString ( kSpanHttpMethod , method ) ;
125
+ span . _pushSpanDataString ( kSpanHttpReqUrl , url ) ;
126
+ return api . trace . setSpan ( api . context . active ( ) , span ) ;
127
+ } ) ;
128
+
129
+ dc . subscribe ( 'tracing:http2.server:start' , subscribeListener ) ;
70
130
}
71
131
72
132
nsolidTracer . on ( 'flagsUpdated' , ( ) => {
@@ -130,41 +190,119 @@ dc.subscribe('http2.client.stream.created', ({ stream }) => {
130
190
start : now ( ) ,
131
191
response : false ,
132
192
} ;
193
+
194
+ if ( generateSpan ( kSpanHttpClient ) ) {
195
+ const api = getApi ( ) ;
196
+ const span = api . trace . getSpan ( api . context . active ( ) ) ;
197
+ if ( span ) {
198
+ stream [ nsolid_span_id_s ] = span ;
199
+ }
200
+ }
133
201
} ) ;
134
202
135
- dc . subscribe ( 'http2.client.stream.finish' , ( { stream, flags } ) => {
203
+ dc . subscribe ( 'http2.client.stream.finish' , ( { stream, headers } ) => {
136
204
stream [ nsolid_tracer_s ] . response = true ;
205
+ http2Constants ||= require ( 'internal/http2/core' ) . constants ;
206
+ if ( generateSpan ( kSpanHttpClient ) ) {
207
+ const span = stream [ nsolid_span_id_s ] ;
208
+ if ( span ) {
209
+ const status = headers [ http2Constants . HTTP2_HEADER_STATUS ] ;
210
+ span . _pushSpanDataUint64 ( kSpanHttpStatusCode , status ) ;
211
+ if ( status >= 400 ) {
212
+ span . setStatus ( { code : getApi ( ) . SpanStatusCode . ERROR } ) ;
213
+ }
214
+ }
215
+ }
216
+ } ) ;
217
+
218
+ dc . subscribe ( 'http2.client.stream.error' , ( { stream, error } ) => {
219
+ if ( generateSpan ( kSpanHttpClient ) ) {
220
+ const span = stream [ nsolid_span_id_s ] ;
221
+ if ( span ) {
222
+ span . recordException ( error ) ;
223
+ span . setStatus ( {
224
+ code : getApi ( ) . SpanStatusCode . ERROR ,
225
+ message : error . message ,
226
+ } ) ;
227
+ span . end ( ) ;
228
+ }
229
+ }
137
230
} ) ;
138
231
139
232
dc . subscribe ( 'http2.client.stream.close' , ( { stream, code } ) => {
140
233
http2Constants ||= require ( 'internal/http2/core' ) . constants ;
141
234
const tracingInfo = stream [ nsolid_tracer_s ] ;
235
+ const span = stream [ nsolid_span_id_s ] ;
142
236
if ( code === http2Constants . NGHTTP2_NO_ERROR && tracingInfo . response ) {
143
237
nsolid_counts [ kHttpClientCount ] ++ ;
144
238
nsolidApi . pushClientBucket ( now ( ) - tracingInfo . start ) ;
145
239
} else {
146
240
nsolid_counts [ kHttpClientAbortCount ] ++ ;
241
+ if ( span ) {
242
+ span . setStatus ( {
243
+ code : getApi ( ) . SpanStatusCode . ERROR ,
244
+ } ) ;
245
+ }
147
246
}
247
+
248
+ span ?. end ( ) ;
148
249
} ) ;
149
250
150
- dc . subscribe ( 'http2.server.stream.start' , ( { stream } ) => {
251
+ dc . subscribe ( 'http2.server.stream.start' , ( { stream, headers } ) => {
151
252
stream [ nsolid_tracer_s ] = {
152
253
start : now ( ) ,
153
254
response : false ,
154
255
} ;
256
+
257
+ if ( generateSpan ( kSpanHttpServer ) ) {
258
+ const api = getApi ( ) ;
259
+ const span = api . trace . getSpan ( api . context . active ( ) ) ;
260
+ if ( span ) {
261
+ stream [ nsolid_span_id_s ] = span ;
262
+ }
263
+ }
155
264
} ) ;
156
265
157
- dc . subscribe ( 'http2.server.stream.finish' , ( { stream, flags } ) => {
266
+ dc . subscribe ( 'http2.server.stream.finish' , ( { stream, headers } ) => {
158
267
stream [ nsolid_tracer_s ] . response = true ;
159
268
} ) ;
160
269
270
+ dc . subscribe ( 'http2.server.stream.error' , ( { stream, error } ) => {
271
+ if ( generateSpan ( kSpanHttpServer ) ) {
272
+ const span = stream [ nsolid_span_id_s ] ;
273
+ if ( span ) {
274
+ span . recordException ( error ) ;
275
+ span . setStatus ( {
276
+ code : getApi ( ) . SpanStatusCode . ERROR ,
277
+ message : error . message ,
278
+ } ) ;
279
+ span . end ( ) ;
280
+ }
281
+ }
282
+ } ) ;
283
+
161
284
dc . subscribe ( 'http2.server.stream.close' , ( { stream, code } ) => {
162
285
http2Constants ||= require ( 'internal/http2/core' ) . constants ;
163
286
const tracingInfo = stream [ nsolid_tracer_s ] ;
287
+ const span = stream [ nsolid_span_id_s ] ;
164
288
if ( code === http2Constants . NGHTTP2_NO_ERROR && tracingInfo . response ) {
165
289
nsolid_counts [ kHttpServerCount ] ++ ;
166
290
nsolidApi . pushServerBucket ( now ( ) - tracingInfo . start ) ;
167
291
} else {
168
292
nsolid_counts [ kHttpServerAbortCount ] ++ ;
293
+ if ( span ) {
294
+ span . setStatus ( {
295
+ code : getApi ( ) . SpanStatusCode . ERROR ,
296
+ } ) ;
297
+ }
298
+ }
299
+
300
+ if ( span ) {
301
+ if ( stream . headersSent ) {
302
+ const status = stream . sentHeaders [ http2Constants . HTTP2_HEADER_STATUS ] ;
303
+ span . _pushSpanDataUint64 ( kSpanHttpStatusCode , status ) ;
304
+ }
305
+
306
+ span . end ( ) ;
169
307
}
170
308
} ) ;
0 commit comments