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 ;
9
10
10
11
const { now } = require ( 'internal/perf/utils' ) ;
12
+ const { contextManager } = require ( 'internal/otel/context' ) ;
13
+ const {
14
+ getApi,
15
+ } = require ( 'internal/otel/core' ) ;
16
+
17
+ const {
18
+ extractSpanContextFromHttpHeaders,
19
+ generateSpan,
20
+ nsolidTracer,
21
+ } = require ( 'internal/nsolid_trace' ) ;
11
22
12
23
const dc = require ( 'diagnostics_channel' ) ;
13
24
@@ -16,11 +27,96 @@ const {
16
27
kHttpClientCount,
17
28
kHttpServerAbortCount,
18
29
kHttpServerCount,
30
+ kSpanHttpClient,
31
+ kSpanHttpMethod,
32
+ kSpanHttpReqUrl,
33
+ kSpanHttpServer,
34
+ kSpanHttpStatusCode,
19
35
} = nsolid_consts ;
20
36
37
+ const http2Client = dc . tracingChannel ( 'http2.client' ) ;
38
+ const http2Server = dc . tracingChannel ( 'http2.server' ) ;
39
+
21
40
// To lazy load the http2 constants
22
41
let http2Constants ;
23
42
43
+ let tracingEnabled = false ;
44
+
45
+ const subscribeListener = ( message , name ) => { } ;
46
+
47
+ function disableTracing ( ) {
48
+ http2Client . start . unbindStore ( ) ;
49
+ dc . unsubscribe ( 'tracing:http2.client:start' , subscribeListener ) ;
50
+ http2Server . start . unbindStore ( ) ;
51
+ dc . unsubscribe ( 'tracing:http2.server:start' , subscribeListener ) ;
52
+ }
53
+
54
+ function extractHttp2Url ( headers , http2Constants ) {
55
+ const { HTTP2_HEADER_SCHEME , HTTP2_HEADER_PATH } = http2Constants ;
56
+ const authority = require ( 'internal/http2/util' ) . getAuthority ( headers ) ;
57
+ return `${ headers [ HTTP2_HEADER_SCHEME ] } ://${ authority } ${ headers [ HTTP2_HEADER_PATH ] } ` ;
58
+ }
59
+
60
+ function enableTracing ( ) {
61
+ dc . subscribe ( 'tracing:http2.client:start' , subscribeListener ) ;
62
+
63
+ http2Client . start . bindStore ( contextManager . _getALS ( ) , ( data ) => {
64
+ const api = getApi ( ) ;
65
+ const tracer = api . trace . getTracer ( 'http2' ) ;
66
+ http2Constants ||= require ( 'internal/http2/core' ) . constants ;
67
+ const { headers } = data ;
68
+ const method = headers [ http2Constants . HTTP2_HEADER_METHOD ] ;
69
+ const url = extractHttp2Url ( headers , http2Constants ) ;
70
+ const span = tracer . startSpan ( `HTTP ${ method } ` ,
71
+ { internal : true ,
72
+ kind : api . SpanKind . CLIENT ,
73
+ type : kSpanHttpClient } ) ;
74
+ span . _pushSpanDataString ( kSpanHttpMethod , method ) ;
75
+ span . _pushSpanDataString ( kSpanHttpReqUrl , url ) ;
76
+ const { spanId, traceId } = span . spanContext ( ) ;
77
+ if ( span . _isSampled ( ) ) {
78
+ headers . traceparent = `00-${ traceId } -${ spanId } -01` ;
79
+ } else {
80
+ headers . traceparent = `00-${ traceId } -${ spanId } -00` ;
81
+ }
82
+
83
+ return api . trace . setSpan ( api . context . active ( ) , span ) ;
84
+ } ) ;
85
+
86
+ dc . subscribe ( 'tracing:http2.client:start' , subscribeListener ) ;
87
+
88
+ http2Server . start . bindStore ( contextManager . _getALS ( ) , ( data ) => {
89
+ const api = getApi ( ) ;
90
+ const tracer = api . trace . getTracer ( 'http2' ) ;
91
+ http2Constants ||= require ( 'internal/http2/core' ) . constants ;
92
+ const { headers } = data ;
93
+ const method = headers [ http2Constants . HTTP2_HEADER_METHOD ] ;
94
+ const url = extractHttp2Url ( headers , http2Constants ) ;
95
+ const ctxt = extractSpanContextFromHttpHeaders ( api . ROOT_CONTEXT , headers ) ;
96
+ const span = tracer . startSpan ( `HTTP ${ method } ` ,
97
+ { internal : true ,
98
+ kind : api . SpanKind . SERVER ,
99
+ type : kSpanHttpServer } ,
100
+ ctxt ) ;
101
+ span . _pushSpanDataString ( kSpanHttpMethod , method ) ;
102
+ span . _pushSpanDataString ( kSpanHttpReqUrl , url ) ;
103
+ return api . trace . setSpan ( api . context . active ( ) , span ) ;
104
+ } ) ;
105
+
106
+ dc . subscribe ( 'tracing:http2.server:start' , subscribeListener ) ;
107
+ }
108
+
109
+ nsolidTracer . on ( 'flagsUpdated' , ( ) => {
110
+ const next = generateSpan ( kSpanHttpClient ) ;
111
+ if ( next && ! tracingEnabled ) {
112
+ enableTracing ( ) ;
113
+ tracingEnabled = true ;
114
+ } else if ( ! next && tracingEnabled ) {
115
+ disableTracing ( ) ;
116
+ tracingEnabled = false ;
117
+ }
118
+ } ) ;
119
+
24
120
dc . subscribe ( 'undici:request:create' , ( { request } ) => {
25
121
request [ nsolid_tracer_s ] = now ( ) ;
26
122
} ) ;
@@ -39,41 +135,119 @@ dc.subscribe('http2.client.stream.created', ({ stream }) => {
39
135
start : now ( ) ,
40
136
response : false ,
41
137
} ;
138
+
139
+ if ( generateSpan ( kSpanHttpClient ) ) {
140
+ const api = getApi ( ) ;
141
+ const span = api . trace . getSpan ( api . context . active ( ) ) ;
142
+ if ( span ) {
143
+ stream [ nsolid_span_id_s ] = span ;
144
+ }
145
+ }
42
146
} ) ;
43
147
44
- dc . subscribe ( 'http2.client.stream.finish' , ( { stream, flags } ) => {
148
+ dc . subscribe ( 'http2.client.stream.finish' , ( { stream, headers } ) => {
45
149
stream [ nsolid_tracer_s ] . response = true ;
150
+ http2Constants ||= require ( 'internal/http2/core' ) . constants ;
151
+ if ( generateSpan ( kSpanHttpClient ) ) {
152
+ const span = stream [ nsolid_span_id_s ] ;
153
+ if ( span ) {
154
+ const status = headers [ http2Constants . HTTP2_HEADER_STATUS ] ;
155
+ span . _pushSpanDataUint64 ( kSpanHttpStatusCode , status ) ;
156
+ if ( status >= 400 ) {
157
+ span . setStatus ( { code : getApi ( ) . SpanStatusCode . ERROR } ) ;
158
+ }
159
+ }
160
+ }
161
+ } ) ;
162
+
163
+ dc . subscribe ( 'http2.client.stream.error' , ( { stream, error } ) => {
164
+ if ( generateSpan ( kSpanHttpClient ) ) {
165
+ const span = stream [ nsolid_span_id_s ] ;
166
+ if ( span ) {
167
+ span . recordException ( error ) ;
168
+ span . setStatus ( {
169
+ code : getApi ( ) . SpanStatusCode . ERROR ,
170
+ message : error . message ,
171
+ } ) ;
172
+ span . end ( ) ;
173
+ }
174
+ }
46
175
} ) ;
47
176
48
177
dc . subscribe ( 'http2.client.stream.close' , ( { stream, code } ) => {
49
178
http2Constants ||= require ( 'internal/http2/core' ) . constants ;
50
179
const tracingInfo = stream [ nsolid_tracer_s ] ;
180
+ const span = stream [ nsolid_span_id_s ] ;
51
181
if ( code === http2Constants . NGHTTP2_NO_ERROR && tracingInfo . response ) {
52
182
nsolid_counts [ kHttpClientCount ] ++ ;
53
183
nsolidApi . pushClientBucket ( now ( ) - tracingInfo . start ) ;
54
184
} else {
55
185
nsolid_counts [ kHttpClientAbortCount ] ++ ;
186
+ if ( span ) {
187
+ span . setStatus ( {
188
+ code : getApi ( ) . SpanStatusCode . ERROR ,
189
+ } ) ;
190
+ }
56
191
}
192
+
193
+ span ?. end ( ) ;
57
194
} ) ;
58
195
59
- dc . subscribe ( 'http2.server.stream.start' , ( { stream } ) => {
196
+ dc . subscribe ( 'http2.server.stream.start' , ( { stream, headers } ) => {
60
197
stream [ nsolid_tracer_s ] = {
61
198
start : now ( ) ,
62
199
response : false ,
63
200
} ;
201
+
202
+ if ( generateSpan ( kSpanHttpServer ) ) {
203
+ const api = getApi ( ) ;
204
+ const span = api . trace . getSpan ( api . context . active ( ) ) ;
205
+ if ( span ) {
206
+ stream [ nsolid_span_id_s ] = span ;
207
+ }
208
+ }
64
209
} ) ;
65
210
66
- dc . subscribe ( 'http2.server.stream.finish' , ( { stream, flags } ) => {
211
+ dc . subscribe ( 'http2.server.stream.finish' , ( { stream, headers } ) => {
67
212
stream [ nsolid_tracer_s ] . response = true ;
68
213
} ) ;
69
214
215
+ dc . subscribe ( 'http2.server.stream.error' , ( { stream, error } ) => {
216
+ if ( generateSpan ( kSpanHttpServer ) ) {
217
+ const span = stream [ nsolid_span_id_s ] ;
218
+ if ( span ) {
219
+ span . recordException ( error ) ;
220
+ span . setStatus ( {
221
+ code : getApi ( ) . SpanStatusCode . ERROR ,
222
+ message : error . message ,
223
+ } ) ;
224
+ span . end ( ) ;
225
+ }
226
+ }
227
+ } ) ;
228
+
70
229
dc . subscribe ( 'http2.server.stream.close' , ( { stream, code } ) => {
71
230
http2Constants ||= require ( 'internal/http2/core' ) . constants ;
72
231
const tracingInfo = stream [ nsolid_tracer_s ] ;
232
+ const span = stream [ nsolid_span_id_s ] ;
73
233
if ( code === http2Constants . NGHTTP2_NO_ERROR && tracingInfo . response ) {
74
234
nsolid_counts [ kHttpServerCount ] ++ ;
75
235
nsolidApi . pushServerBucket ( now ( ) - tracingInfo . start ) ;
76
236
} else {
77
237
nsolid_counts [ kHttpServerAbortCount ] ++ ;
238
+ if ( span ) {
239
+ span . setStatus ( {
240
+ code : getApi ( ) . SpanStatusCode . ERROR ,
241
+ } ) ;
242
+ }
243
+ }
244
+
245
+ if ( span ) {
246
+ if ( stream . headersSent ) {
247
+ const status = stream . sentHeaders [ http2Constants . HTTP2_HEADER_STATUS ] ;
248
+ span . _pushSpanDataUint64 ( kSpanHttpStatusCode , status ) ;
249
+ }
250
+
251
+ span . end ( ) ;
78
252
}
79
253
} ) ;
0 commit comments