@opentelemetry/instrumentation-http 0.53.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -6
- package/build/src/http.d.ts +10 -4
- package/build/src/http.js +163 -66
- package/build/src/http.js.map +1 -1
- package/build/src/index.d.ts +1 -1
- package/build/src/index.js +1 -2
- package/build/src/index.js.map +1 -1
- package/build/src/types.d.ts +17 -13
- package/build/src/types.js.map +1 -1
- package/build/src/utils.d.ts +39 -35
- package/build/src/utils.js +287 -79
- package/build/src/utils.js.map +1 -1
- package/build/src/version.d.ts +1 -1
- package/build/src/version.js +1 -1
- package/build/src/version.js.map +1 -1
- package/package.json +12 -13
package/README.md
CHANGED
|
@@ -68,15 +68,49 @@ Http instrumentation has few options available to choose from. You can set the f
|
|
|
68
68
|
| [`requireParentforIncomingSpans`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-http/src/types.ts#L105) | Boolean | Require that is a parent span to create new span for incoming requests. |
|
|
69
69
|
| [`headersToSpanAttributes`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-http/src/types.ts#L107) | `object` | List of case insensitive HTTP headers to convert to span attributes. Client (outgoing requests, incoming responses) and server (incoming requests, outgoing responses) headers will be converted to span attributes in the form of `http.{request\|response}.header.header_name`, e.g. `http.response.header.content_length` |
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
## Semantic Conventions
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
| ------- | ---- | ----------- |
|
|
75
|
-
| `ignoreIncomingPaths` | `IgnoreMatcher[]` | Http instrumentation will not trace all incoming requests that match paths |
|
|
73
|
+
Prior to version `0.54`, this instrumentation created spans targeting an experimental semantic convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md).
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
This package is capable of emitting both Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md) and [Version 1.27.0](https://github.com/open-telemetry/semantic-conventions/blob/v1.27.0/docs/http/http-spans.md).
|
|
76
|
+
It is controlled using the environment variable `OTEL_SEMCONV_STABILITY_OPT_IN`, which is a comma separated list of values.
|
|
77
|
+
The values `http` and `http/dup` control this instrumentation.
|
|
78
|
+
See details for the behavior of each of these values below.
|
|
79
|
+
If neither `http` or `http/dup` is included in `OTEL_SEMCONV_STABILITY_OPT_IN`, the old experimental semantic conventions will be used by default.
|
|
80
|
+
|
|
81
|
+
### Stable Semantic Conventions 1.27
|
|
82
|
+
|
|
83
|
+
Enabled when `OTEL_SEMCONV_STABILITY_OPT_IN` contains `http` OR `http/dup`.
|
|
84
|
+
This is the recommended configuration, and will soon become the default behavior.
|
|
85
|
+
|
|
86
|
+
Follow all requirements and recommendations of HTTP Client and Server Semantic Conventions Version 1.27.0 for [spans](https://github.com/open-telemetry/semantic-conventions/blob/v1.27.0/docs/http/http-spans.md) and [metrics](https://github.com/open-telemetry/semantic-conventions/blob/v1.27.0/docs/http/http-metrics.md), including all required and recommended attributes.
|
|
87
|
+
|
|
88
|
+
Metrics Exported:
|
|
89
|
+
|
|
90
|
+
- [`http.server.request.duration`](https://github.com/open-telemetry/semantic-conventions/blob/v1.27.0/docs/http/http-metrics.md#metric-httpserverrequestduration)
|
|
91
|
+
- [`http.client.request.duration`](https://github.com/open-telemetry/semantic-conventions/blob/v1.27.0/docs/http/http-metrics.md#metric-httpclientrequestduration)
|
|
92
|
+
|
|
93
|
+
### Upgrading Semantic Conventions
|
|
94
|
+
|
|
95
|
+
When upgrading to the new semantic conventions, it is recommended to do so in the following order:
|
|
96
|
+
|
|
97
|
+
1. Upgrade `@opentelemetry/instrumentation-http` to the latest version
|
|
98
|
+
2. Set `OTEL_SEMCONV_STABILITY_OPT_IN=http/dup` to emit both old and new semantic conventions
|
|
99
|
+
3. Modify alerts, dashboards, metrics, and other processes to expect the new semantic conventions
|
|
100
|
+
4. Set `OTEL_SEMCONV_STABILITY_OPT_IN=http` to emit only the new semantic conventions
|
|
101
|
+
|
|
102
|
+
This will cause both the old and new semantic conventions to be emitted during the transition period.
|
|
103
|
+
|
|
104
|
+
### Legacy Behavior (default)
|
|
105
|
+
|
|
106
|
+
Enabled when `OTEL_SEMCONV_STABILITY_OPT_IN` contains `http/dup` or DOES NOT CONTAIN `http`.
|
|
107
|
+
This is the current default behavior.
|
|
108
|
+
|
|
109
|
+
Create HTTP client spans which implement Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md).
|
|
110
|
+
|
|
111
|
+
#### Server Spans (legacy)
|
|
78
112
|
|
|
79
|
-
|
|
113
|
+
When `OTEL_SEMCONV_STABILITY_OPT_IN` is not set or includes `http/dup`, this module implements Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md).
|
|
80
114
|
|
|
81
115
|
Attributes collected:
|
|
82
116
|
|
package/build/src/http.d.ts
CHANGED
|
@@ -4,16 +4,21 @@ import * as url from 'url';
|
|
|
4
4
|
import { Func, HttpInstrumentationConfig, HttpRequestArgs } from './types';
|
|
5
5
|
import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation';
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* `node:http` and `node:https` instrumentation for OpenTelemetry
|
|
8
8
|
*/
|
|
9
9
|
export declare class HttpInstrumentation extends InstrumentationBase<HttpInstrumentationConfig> {
|
|
10
10
|
/** keep track on spans not ended */
|
|
11
11
|
private readonly _spanNotEnded;
|
|
12
12
|
private _headerCapture;
|
|
13
|
-
private
|
|
14
|
-
private
|
|
13
|
+
private _oldHttpServerDurationHistogram;
|
|
14
|
+
private _stableHttpServerDurationHistogram;
|
|
15
|
+
private _oldHttpClientDurationHistogram;
|
|
16
|
+
private _stableHttpClientDurationHistogram;
|
|
17
|
+
private _semconvStability;
|
|
15
18
|
constructor(config?: HttpInstrumentationConfig);
|
|
16
19
|
protected _updateMetricInstruments(): void;
|
|
20
|
+
private _recordServerDuration;
|
|
21
|
+
private _recordClientDuration;
|
|
17
22
|
setConfig(config?: HttpInstrumentationConfig): void;
|
|
18
23
|
init(): [
|
|
19
24
|
InstrumentationNodeModuleDefinition,
|
|
@@ -42,7 +47,8 @@ export declare class HttpInstrumentation extends InstrumentationBase<HttpInstrum
|
|
|
42
47
|
* @param request The original request object.
|
|
43
48
|
* @param span representing the current operation
|
|
44
49
|
* @param startTime representing the start time of the request to calculate duration in Metric
|
|
45
|
-
* @param
|
|
50
|
+
* @param oldMetricAttributes metric attributes for old semantic conventions
|
|
51
|
+
* @param stableMetricAttributes metric attributes for new semantic conventions
|
|
46
52
|
*/
|
|
47
53
|
private _traceClientRequest;
|
|
48
54
|
private _incomingRequestFunction;
|
package/build/src/http.js
CHANGED
|
@@ -20,33 +20,90 @@ const api_1 = require("@opentelemetry/api");
|
|
|
20
20
|
const core_1 = require("@opentelemetry/core");
|
|
21
21
|
const semver = require("semver");
|
|
22
22
|
const url = require("url");
|
|
23
|
-
const utils = require("./utils");
|
|
24
23
|
const version_1 = require("./version");
|
|
25
24
|
const instrumentation_1 = require("@opentelemetry/instrumentation");
|
|
26
25
|
const core_2 = require("@opentelemetry/core");
|
|
27
26
|
const events_1 = require("events");
|
|
28
27
|
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
28
|
+
const utils_1 = require("./utils");
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* `node:http` and `node:https` instrumentation for OpenTelemetry
|
|
31
31
|
*/
|
|
32
32
|
class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
33
33
|
constructor(config = {}) {
|
|
34
34
|
super('@opentelemetry/instrumentation-http', version_1.VERSION, config);
|
|
35
35
|
/** keep track on spans not ended */
|
|
36
36
|
this._spanNotEnded = new WeakSet();
|
|
37
|
+
this._semconvStability = 2 /* OLD */;
|
|
37
38
|
this._headerCapture = this._createHeaderCapture();
|
|
39
|
+
for (const entry in (0, core_2.getEnv)().OTEL_SEMCONV_STABILITY_OPT_IN) {
|
|
40
|
+
if (entry.toLowerCase() === 'http/dup') {
|
|
41
|
+
// http/dup takes highest precedence. If it is found, there is no need to read the rest of the list
|
|
42
|
+
this._semconvStability = 3 /* DUPLICATE */;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
else if (entry.toLowerCase() === 'http') {
|
|
46
|
+
this._semconvStability = 1 /* STABLE */;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
38
49
|
}
|
|
39
50
|
_updateMetricInstruments() {
|
|
40
|
-
this.
|
|
51
|
+
this._oldHttpServerDurationHistogram = this.meter.createHistogram('http.server.duration', {
|
|
41
52
|
description: 'Measures the duration of inbound HTTP requests.',
|
|
42
53
|
unit: 'ms',
|
|
43
54
|
valueType: api_1.ValueType.DOUBLE,
|
|
44
55
|
});
|
|
45
|
-
this.
|
|
56
|
+
this._oldHttpClientDurationHistogram = this.meter.createHistogram('http.client.duration', {
|
|
46
57
|
description: 'Measures the duration of outbound HTTP requests.',
|
|
47
58
|
unit: 'ms',
|
|
48
59
|
valueType: api_1.ValueType.DOUBLE,
|
|
49
60
|
});
|
|
61
|
+
this._stableHttpServerDurationHistogram = this.meter.createHistogram(semantic_conventions_1.METRIC_HTTP_SERVER_REQUEST_DURATION, {
|
|
62
|
+
description: 'Duration of HTTP server requests.',
|
|
63
|
+
unit: 's',
|
|
64
|
+
valueType: api_1.ValueType.DOUBLE,
|
|
65
|
+
advice: {
|
|
66
|
+
explicitBucketBoundaries: [
|
|
67
|
+
0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5,
|
|
68
|
+
7.5, 10,
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
this._stableHttpClientDurationHistogram = this.meter.createHistogram(semantic_conventions_1.METRIC_HTTP_CLIENT_REQUEST_DURATION, {
|
|
73
|
+
description: 'Duration of HTTP client requests.',
|
|
74
|
+
unit: 's',
|
|
75
|
+
valueType: api_1.ValueType.DOUBLE,
|
|
76
|
+
advice: {
|
|
77
|
+
explicitBucketBoundaries: [
|
|
78
|
+
0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5,
|
|
79
|
+
7.5, 10,
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
_recordServerDuration(durationMs, oldAttributes, stableAttributes) {
|
|
85
|
+
if ((this._semconvStability & 2 /* OLD */) ===
|
|
86
|
+
2 /* OLD */) {
|
|
87
|
+
// old histogram is counted in MS
|
|
88
|
+
this._oldHttpServerDurationHistogram.record(durationMs, oldAttributes);
|
|
89
|
+
}
|
|
90
|
+
if ((this._semconvStability & 1 /* STABLE */) ===
|
|
91
|
+
1 /* STABLE */) {
|
|
92
|
+
// stable histogram is counted in S
|
|
93
|
+
this._stableHttpServerDurationHistogram.record(durationMs / 1000, stableAttributes);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
_recordClientDuration(durationMs, oldAttributes, stableAttributes) {
|
|
97
|
+
if ((this._semconvStability & 2 /* OLD */) ===
|
|
98
|
+
2 /* OLD */) {
|
|
99
|
+
// old histogram is counted in MS
|
|
100
|
+
this._oldHttpClientDurationHistogram.record(durationMs, oldAttributes);
|
|
101
|
+
}
|
|
102
|
+
if ((this._semconvStability & 1 /* STABLE */) ===
|
|
103
|
+
1 /* STABLE */) {
|
|
104
|
+
// stable histogram is counted in S
|
|
105
|
+
this._stableHttpClientDurationHistogram.record(durationMs / 1000, stableAttributes);
|
|
106
|
+
}
|
|
50
107
|
}
|
|
51
108
|
setConfig(config = {}) {
|
|
52
109
|
super.setConfig(config);
|
|
@@ -57,9 +114,16 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
57
114
|
}
|
|
58
115
|
_getHttpInstrumentation() {
|
|
59
116
|
return new instrumentation_1.InstrumentationNodeModuleDefinition('http', ['*'], (moduleExports) => {
|
|
117
|
+
const isESM = moduleExports[Symbol.toStringTag] === 'Module';
|
|
60
118
|
if (!this.getConfig().disableOutgoingRequestInstrumentation) {
|
|
61
119
|
const patchedRequest = this._wrap(moduleExports, 'request', this._getPatchOutgoingRequestFunction('http'));
|
|
62
|
-
this._wrap(moduleExports, 'get', this._getPatchOutgoingGetFunction(patchedRequest));
|
|
120
|
+
const patchedGet = this._wrap(moduleExports, 'get', this._getPatchOutgoingGetFunction(patchedRequest));
|
|
121
|
+
if (isESM) {
|
|
122
|
+
// To handle `import http from 'http'`, which returns the default
|
|
123
|
+
// export, we need to set `module.default.*`.
|
|
124
|
+
moduleExports.default.request = patchedRequest;
|
|
125
|
+
moduleExports.default.get = patchedGet;
|
|
126
|
+
}
|
|
63
127
|
}
|
|
64
128
|
if (!this.getConfig().disableIncomingRequestInstrumentation) {
|
|
65
129
|
this._wrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction('http'));
|
|
@@ -79,9 +143,16 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
79
143
|
}
|
|
80
144
|
_getHttpsInstrumentation() {
|
|
81
145
|
return new instrumentation_1.InstrumentationNodeModuleDefinition('https', ['*'], (moduleExports) => {
|
|
146
|
+
const isESM = moduleExports[Symbol.toStringTag] === 'Module';
|
|
82
147
|
if (!this.getConfig().disableOutgoingRequestInstrumentation) {
|
|
83
148
|
const patchedRequest = this._wrap(moduleExports, 'request', this._getPatchHttpsOutgoingRequestFunction('https'));
|
|
84
|
-
this._wrap(moduleExports, 'get', this._getPatchHttpsOutgoingGetFunction(patchedRequest));
|
|
149
|
+
const patchedGet = this._wrap(moduleExports, 'get', this._getPatchHttpsOutgoingGetFunction(patchedRequest));
|
|
150
|
+
if (isESM) {
|
|
151
|
+
// To handle `import https from 'https'`, which returns the default
|
|
152
|
+
// export, we need to set `module.default.*`.
|
|
153
|
+
moduleExports.default.request = patchedRequest;
|
|
154
|
+
moduleExports.default.get = patchedGet;
|
|
155
|
+
}
|
|
85
156
|
}
|
|
86
157
|
if (!this.getConfig().disableIncomingRequestInstrumentation) {
|
|
87
158
|
this._wrap(moduleExports.Server.prototype, 'emit', this._getPatchIncomingRequestFunction('https'));
|
|
@@ -175,9 +246,10 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
175
246
|
* @param request The original request object.
|
|
176
247
|
* @param span representing the current operation
|
|
177
248
|
* @param startTime representing the start time of the request to calculate duration in Metric
|
|
178
|
-
* @param
|
|
249
|
+
* @param oldMetricAttributes metric attributes for old semantic conventions
|
|
250
|
+
* @param stableMetricAttributes metric attributes for new semantic conventions
|
|
179
251
|
*/
|
|
180
|
-
_traceClientRequest(request, span, startTime,
|
|
252
|
+
_traceClientRequest(request, span, startTime, oldMetricAttributes, stableMetricAttributes) {
|
|
181
253
|
if (this.getConfig().requestHook) {
|
|
182
254
|
this._callRequestHook(span, request);
|
|
183
255
|
}
|
|
@@ -195,9 +267,9 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
195
267
|
if (request.listenerCount('response') <= 1) {
|
|
196
268
|
response.resume();
|
|
197
269
|
}
|
|
198
|
-
const responseAttributes =
|
|
270
|
+
const responseAttributes = (0, utils_1.getOutgoingRequestAttributesOnResponse)(response, this._semconvStability);
|
|
199
271
|
span.setAttributes(responseAttributes);
|
|
200
|
-
|
|
272
|
+
oldMetricAttributes = Object.assign(oldMetricAttributes, (0, utils_1.getOutgoingRequestMetricAttributesOnResponse)(responseAttributes));
|
|
201
273
|
if (this.getConfig().responseHook) {
|
|
202
274
|
this._callResponseHook(span, response);
|
|
203
275
|
}
|
|
@@ -215,15 +287,16 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
215
287
|
status = { code: api_1.SpanStatusCode.ERROR };
|
|
216
288
|
}
|
|
217
289
|
else {
|
|
290
|
+
// behaves same for new and old semconv
|
|
218
291
|
status = {
|
|
219
|
-
code:
|
|
292
|
+
code: (0, utils_1.parseResponseStatus)(api_1.SpanKind.CLIENT, response.statusCode),
|
|
220
293
|
};
|
|
221
294
|
}
|
|
222
295
|
span.setStatus(status);
|
|
223
296
|
if (this.getConfig().applyCustomAttributesOnSpan) {
|
|
224
297
|
(0, instrumentation_1.safeExecuteInTheMiddle)(() => this.getConfig().applyCustomAttributesOnSpan(span, request, response), () => { }, true);
|
|
225
298
|
}
|
|
226
|
-
this._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime,
|
|
299
|
+
this._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
227
300
|
};
|
|
228
301
|
response.on('end', endHandler);
|
|
229
302
|
// See https://github.com/open-telemetry/opentelemetry-js/pull/3625#issuecomment-1475673533
|
|
@@ -236,12 +309,12 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
236
309
|
return;
|
|
237
310
|
}
|
|
238
311
|
responseFinished = true;
|
|
239
|
-
|
|
312
|
+
(0, utils_1.setSpanWithError)(span, error, this._semconvStability);
|
|
240
313
|
span.setStatus({
|
|
241
314
|
code: api_1.SpanStatusCode.ERROR,
|
|
242
315
|
message: error.message,
|
|
243
316
|
});
|
|
244
|
-
this._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime,
|
|
317
|
+
this._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
245
318
|
});
|
|
246
319
|
});
|
|
247
320
|
request.on('close', () => {
|
|
@@ -250,7 +323,7 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
250
323
|
return;
|
|
251
324
|
}
|
|
252
325
|
responseFinished = true;
|
|
253
|
-
this._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime,
|
|
326
|
+
this._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
254
327
|
});
|
|
255
328
|
request.on(events_1.errorMonitor, (error) => {
|
|
256
329
|
this._diag.debug('outgoingRequest on request error()', error);
|
|
@@ -258,8 +331,8 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
258
331
|
return;
|
|
259
332
|
}
|
|
260
333
|
responseFinished = true;
|
|
261
|
-
|
|
262
|
-
this._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime,
|
|
334
|
+
(0, utils_1.setSpanWithError)(span, error, this._semconvStability);
|
|
335
|
+
this._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
263
336
|
});
|
|
264
337
|
this._diag.debug('http.ClientRequest return request');
|
|
265
338
|
return request;
|
|
@@ -273,17 +346,13 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
273
346
|
}
|
|
274
347
|
const request = args[0];
|
|
275
348
|
const response = args[1];
|
|
276
|
-
const pathname = request.url
|
|
277
|
-
? url.parse(request.url).pathname || '/'
|
|
278
|
-
: '/';
|
|
279
349
|
const method = request.method || 'GET';
|
|
280
350
|
instrumentation._diag.debug(`${component} instrumentation incomingRequest`);
|
|
281
|
-
if (
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}, true)) {
|
|
351
|
+
if ((0, instrumentation_1.safeExecuteInTheMiddle)(() => { var _a, _b; return (_b = (_a = instrumentation.getConfig()).ignoreIncomingRequestHook) === null || _b === void 0 ? void 0 : _b.call(_a, request); }, (e) => {
|
|
352
|
+
if (e != null) {
|
|
353
|
+
instrumentation._diag.error('caught ignoreIncomingRequestHook error: ', e);
|
|
354
|
+
}
|
|
355
|
+
}, true)) {
|
|
287
356
|
return api_1.context.with((0, core_1.suppressTracing)(api_1.context.active()), () => {
|
|
288
357
|
api_1.context.bind(api_1.context.active(), request);
|
|
289
358
|
api_1.context.bind(api_1.context.active(), response);
|
|
@@ -291,17 +360,28 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
291
360
|
});
|
|
292
361
|
}
|
|
293
362
|
const headers = request.headers;
|
|
294
|
-
const spanAttributes =
|
|
363
|
+
const spanAttributes = (0, utils_1.getIncomingRequestAttributes)(request, {
|
|
295
364
|
component: component,
|
|
296
365
|
serverName: instrumentation.getConfig().serverName,
|
|
297
366
|
hookAttributes: instrumentation._callStartSpanHook(request, instrumentation.getConfig().startIncomingSpanHook),
|
|
367
|
+
semconvStability: instrumentation._semconvStability,
|
|
298
368
|
});
|
|
299
369
|
const spanOptions = {
|
|
300
370
|
kind: api_1.SpanKind.SERVER,
|
|
301
371
|
attributes: spanAttributes,
|
|
302
372
|
};
|
|
303
373
|
const startTime = (0, core_1.hrTime)();
|
|
304
|
-
const
|
|
374
|
+
const oldMetricAttributes = (0, utils_1.getIncomingRequestMetricAttributes)(spanAttributes);
|
|
375
|
+
// request method and url.scheme are both required span attributes
|
|
376
|
+
const stableMetricAttributes = {
|
|
377
|
+
[semantic_conventions_1.ATTR_HTTP_REQUEST_METHOD]: spanAttributes[semantic_conventions_1.ATTR_HTTP_REQUEST_METHOD],
|
|
378
|
+
[semantic_conventions_1.ATTR_URL_SCHEME]: spanAttributes[semantic_conventions_1.ATTR_URL_SCHEME],
|
|
379
|
+
};
|
|
380
|
+
// recommended if and only if one was sent, same as span recommendation
|
|
381
|
+
if (spanAttributes[semantic_conventions_1.ATTR_NETWORK_PROTOCOL_VERSION]) {
|
|
382
|
+
stableMetricAttributes[semantic_conventions_1.ATTR_NETWORK_PROTOCOL_VERSION] =
|
|
383
|
+
spanAttributes[semantic_conventions_1.ATTR_NETWORK_PROTOCOL_VERSION];
|
|
384
|
+
}
|
|
305
385
|
const ctx = api_1.propagation.extract(api_1.ROOT_CONTEXT, headers);
|
|
306
386
|
const span = instrumentation._startHttpSpan(method, spanOptions, ctx);
|
|
307
387
|
const rpcMetadata = {
|
|
@@ -324,16 +404,16 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
324
404
|
if (hasError) {
|
|
325
405
|
return;
|
|
326
406
|
}
|
|
327
|
-
instrumentation._onServerResponseFinish(request, response, span,
|
|
407
|
+
instrumentation._onServerResponseFinish(request, response, span, oldMetricAttributes, stableMetricAttributes, startTime);
|
|
328
408
|
});
|
|
329
409
|
response.on(events_1.errorMonitor, (err) => {
|
|
330
410
|
hasError = true;
|
|
331
|
-
instrumentation._onServerResponseError(span,
|
|
411
|
+
instrumentation._onServerResponseError(span, oldMetricAttributes, stableMetricAttributes, startTime, err);
|
|
332
412
|
});
|
|
333
413
|
return (0, instrumentation_1.safeExecuteInTheMiddle)(() => original.apply(this, [event, ...args]), error => {
|
|
334
414
|
if (error) {
|
|
335
|
-
|
|
336
|
-
instrumentation._closeHttpSpan(span, api_1.SpanKind.SERVER, startTime,
|
|
415
|
+
(0, utils_1.setSpanWithError)(span, error, instrumentation._semconvStability);
|
|
416
|
+
instrumentation._closeHttpSpan(span, api_1.SpanKind.SERVER, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
337
417
|
throw error;
|
|
338
418
|
}
|
|
339
419
|
});
|
|
@@ -343,14 +423,14 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
343
423
|
_outgoingRequestFunction(component, original) {
|
|
344
424
|
const instrumentation = this;
|
|
345
425
|
return function outgoingRequest(options, ...args) {
|
|
346
|
-
if (!
|
|
426
|
+
if (!(0, utils_1.isValidOptionsType)(options)) {
|
|
347
427
|
return original.apply(this, [options, ...args]);
|
|
348
428
|
}
|
|
349
429
|
const extraOptions = typeof args[0] === 'object' &&
|
|
350
430
|
(typeof options === 'string' || options instanceof url.URL)
|
|
351
431
|
? args.shift()
|
|
352
432
|
: undefined;
|
|
353
|
-
const {
|
|
433
|
+
const { method, optionsParsed } = (0, utils_1.getRequestInfo)(options, extraOptions);
|
|
354
434
|
/**
|
|
355
435
|
* Node 8's https module directly call the http one so to avoid creating
|
|
356
436
|
* 2 span for the same request we need to check that the protocol is correct
|
|
@@ -361,27 +441,42 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
361
441
|
optionsParsed.protocol === 'https:') {
|
|
362
442
|
return original.apply(this, [optionsParsed, ...args]);
|
|
363
443
|
}
|
|
364
|
-
if (
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}, true)) {
|
|
444
|
+
if ((0, instrumentation_1.safeExecuteInTheMiddle)(() => {
|
|
445
|
+
var _a, _b;
|
|
446
|
+
return (_b = (_a = instrumentation
|
|
447
|
+
.getConfig()).ignoreOutgoingRequestHook) === null || _b === void 0 ? void 0 : _b.call(_a, optionsParsed);
|
|
448
|
+
}, (e) => {
|
|
449
|
+
if (e != null) {
|
|
450
|
+
instrumentation._diag.error('caught ignoreOutgoingRequestHook error: ', e);
|
|
451
|
+
}
|
|
452
|
+
}, true)) {
|
|
374
453
|
return original.apply(this, [optionsParsed, ...args]);
|
|
375
454
|
}
|
|
376
|
-
const { hostname, port } =
|
|
377
|
-
const attributes =
|
|
455
|
+
const { hostname, port } = (0, utils_1.extractHostnameAndPort)(optionsParsed);
|
|
456
|
+
const attributes = (0, utils_1.getOutgoingRequestAttributes)(optionsParsed, {
|
|
378
457
|
component,
|
|
379
458
|
port,
|
|
380
459
|
hostname,
|
|
381
460
|
hookAttributes: instrumentation._callStartSpanHook(optionsParsed, instrumentation.getConfig().startOutgoingSpanHook),
|
|
382
|
-
});
|
|
461
|
+
}, instrumentation._semconvStability);
|
|
383
462
|
const startTime = (0, core_1.hrTime)();
|
|
384
|
-
const
|
|
463
|
+
const oldMetricAttributes = (0, utils_1.getOutgoingRequestMetricAttributes)(attributes);
|
|
464
|
+
// request method, server address, and server port are both required span attributes
|
|
465
|
+
const stableMetricAttributes = {
|
|
466
|
+
[semantic_conventions_1.ATTR_HTTP_REQUEST_METHOD]: attributes[semantic_conventions_1.ATTR_HTTP_REQUEST_METHOD],
|
|
467
|
+
[semantic_conventions_1.ATTR_SERVER_ADDRESS]: attributes[semantic_conventions_1.ATTR_SERVER_ADDRESS],
|
|
468
|
+
[semantic_conventions_1.ATTR_SERVER_PORT]: attributes[semantic_conventions_1.ATTR_SERVER_PORT],
|
|
469
|
+
};
|
|
470
|
+
// required if and only if one was sent, same as span requirement
|
|
471
|
+
if (attributes[semantic_conventions_1.ATTR_HTTP_RESPONSE_STATUS_CODE]) {
|
|
472
|
+
stableMetricAttributes[semantic_conventions_1.ATTR_HTTP_RESPONSE_STATUS_CODE] =
|
|
473
|
+
attributes[semantic_conventions_1.ATTR_HTTP_RESPONSE_STATUS_CODE];
|
|
474
|
+
}
|
|
475
|
+
// recommended if and only if one was sent, same as span recommendation
|
|
476
|
+
if (attributes[semantic_conventions_1.ATTR_NETWORK_PROTOCOL_VERSION]) {
|
|
477
|
+
stableMetricAttributes[semantic_conventions_1.ATTR_NETWORK_PROTOCOL_VERSION] =
|
|
478
|
+
attributes[semantic_conventions_1.ATTR_NETWORK_PROTOCOL_VERSION];
|
|
479
|
+
}
|
|
385
480
|
const spanOptions = {
|
|
386
481
|
kind: api_1.SpanKind.CLIENT,
|
|
387
482
|
attributes,
|
|
@@ -409,23 +504,24 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
409
504
|
}
|
|
410
505
|
const request = (0, instrumentation_1.safeExecuteInTheMiddle)(() => original.apply(this, [optionsParsed, ...args]), error => {
|
|
411
506
|
if (error) {
|
|
412
|
-
|
|
413
|
-
instrumentation._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime,
|
|
507
|
+
(0, utils_1.setSpanWithError)(span, error, instrumentation._semconvStability);
|
|
508
|
+
instrumentation._closeHttpSpan(span, api_1.SpanKind.CLIENT, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
414
509
|
throw error;
|
|
415
510
|
}
|
|
416
511
|
});
|
|
417
512
|
instrumentation._diag.debug(`${component} instrumentation outgoingRequest`);
|
|
418
513
|
api_1.context.bind(parentContext, request);
|
|
419
|
-
return instrumentation._traceClientRequest(request, span, startTime,
|
|
514
|
+
return instrumentation._traceClientRequest(request, span, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
420
515
|
});
|
|
421
516
|
};
|
|
422
517
|
}
|
|
423
|
-
_onServerResponseFinish(request, response, span,
|
|
424
|
-
const attributes =
|
|
425
|
-
|
|
518
|
+
_onServerResponseFinish(request, response, span, oldMetricAttributes, stableMetricAttributes, startTime) {
|
|
519
|
+
const attributes = (0, utils_1.getIncomingRequestAttributesOnResponse)(request, response, this._semconvStability);
|
|
520
|
+
oldMetricAttributes = Object.assign(oldMetricAttributes, (0, utils_1.getIncomingRequestMetricAttributesOnResponse)(attributes));
|
|
521
|
+
stableMetricAttributes = Object.assign(stableMetricAttributes, (0, utils_1.getIncomingStableRequestMetricAttributesOnResponse)(attributes));
|
|
426
522
|
this._headerCapture.server.captureResponseHeaders(span, header => response.getHeader(header));
|
|
427
523
|
span.setAttributes(attributes).setStatus({
|
|
428
|
-
code:
|
|
524
|
+
code: (0, utils_1.parseResponseStatus)(api_1.SpanKind.SERVER, response.statusCode),
|
|
429
525
|
});
|
|
430
526
|
const route = attributes[semantic_conventions_1.SEMATTRS_HTTP_ROUTE];
|
|
431
527
|
if (route) {
|
|
@@ -434,11 +530,12 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
434
530
|
if (this.getConfig().applyCustomAttributesOnSpan) {
|
|
435
531
|
(0, instrumentation_1.safeExecuteInTheMiddle)(() => this.getConfig().applyCustomAttributesOnSpan(span, request, response), () => { }, true);
|
|
436
532
|
}
|
|
437
|
-
this._closeHttpSpan(span, api_1.SpanKind.SERVER, startTime,
|
|
533
|
+
this._closeHttpSpan(span, api_1.SpanKind.SERVER, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
438
534
|
}
|
|
439
|
-
_onServerResponseError(span,
|
|
440
|
-
|
|
441
|
-
|
|
535
|
+
_onServerResponseError(span, oldMetricAttributes, stableMetricAttributes, startTime, error) {
|
|
536
|
+
(0, utils_1.setSpanWithError)(span, error, this._semconvStability);
|
|
537
|
+
// TODO get error attributes for metrics
|
|
538
|
+
this._closeHttpSpan(span, api_1.SpanKind.SERVER, startTime, oldMetricAttributes, stableMetricAttributes);
|
|
442
539
|
}
|
|
443
540
|
_startHttpSpan(name, options, ctx = api_1.context.active()) {
|
|
444
541
|
/*
|
|
@@ -462,7 +559,7 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
462
559
|
this._spanNotEnded.add(span);
|
|
463
560
|
return span;
|
|
464
561
|
}
|
|
465
|
-
_closeHttpSpan(span, spanKind, startTime,
|
|
562
|
+
_closeHttpSpan(span, spanKind, startTime, oldMetricAttributes, stableMetricAttributes) {
|
|
466
563
|
if (!this._spanNotEnded.has(span)) {
|
|
467
564
|
return;
|
|
468
565
|
}
|
|
@@ -471,10 +568,10 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
471
568
|
// Record metrics
|
|
472
569
|
const duration = (0, core_1.hrTimeToMilliseconds)((0, core_1.hrTimeDuration)(startTime, (0, core_1.hrTime)()));
|
|
473
570
|
if (spanKind === api_1.SpanKind.SERVER) {
|
|
474
|
-
this.
|
|
571
|
+
this._recordServerDuration(duration, oldMetricAttributes, stableMetricAttributes);
|
|
475
572
|
}
|
|
476
573
|
else if (spanKind === api_1.SpanKind.CLIENT) {
|
|
477
|
-
this.
|
|
574
|
+
this._recordClientDuration(duration, oldMetricAttributes, stableMetricAttributes);
|
|
478
575
|
}
|
|
479
576
|
}
|
|
480
577
|
_callResponseHook(span, response) {
|
|
@@ -493,12 +590,12 @@ class HttpInstrumentation extends instrumentation_1.InstrumentationBase {
|
|
|
493
590
|
const config = this.getConfig();
|
|
494
591
|
return {
|
|
495
592
|
client: {
|
|
496
|
-
captureRequestHeaders:
|
|
497
|
-
captureResponseHeaders:
|
|
593
|
+
captureRequestHeaders: (0, utils_1.headerCapture)('request', (_c = (_b = (_a = config.headersToSpanAttributes) === null || _a === void 0 ? void 0 : _a.client) === null || _b === void 0 ? void 0 : _b.requestHeaders) !== null && _c !== void 0 ? _c : []),
|
|
594
|
+
captureResponseHeaders: (0, utils_1.headerCapture)('response', (_f = (_e = (_d = config.headersToSpanAttributes) === null || _d === void 0 ? void 0 : _d.client) === null || _e === void 0 ? void 0 : _e.responseHeaders) !== null && _f !== void 0 ? _f : []),
|
|
498
595
|
},
|
|
499
596
|
server: {
|
|
500
|
-
captureRequestHeaders:
|
|
501
|
-
captureResponseHeaders:
|
|
597
|
+
captureRequestHeaders: (0, utils_1.headerCapture)('request', (_j = (_h = (_g = config.headersToSpanAttributes) === null || _g === void 0 ? void 0 : _g.server) === null || _h === void 0 ? void 0 : _h.requestHeaders) !== null && _j !== void 0 ? _j : []),
|
|
598
|
+
captureResponseHeaders: (0, utils_1.headerCapture)('response', (_m = (_l = (_k = config.headersToSpanAttributes) === null || _k === void 0 ? void 0 : _k.server) === null || _l === void 0 ? void 0 : _l.responseHeaders) !== null && _m !== void 0 ? _m : []),
|
|
502
599
|
},
|
|
503
600
|
};
|
|
504
601
|
}
|