@depup/elastic-apm-node 4.15.0-depup.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/LICENSE +26 -0
- package/NOTICE.md +442 -0
- package/README.md +48 -0
- package/changes.json +78 -0
- package/index.d.ts +398 -0
- package/index.js +11 -0
- package/lib/InflightEventSet.js +53 -0
- package/lib/activation-method.js +119 -0
- package/lib/agent.js +941 -0
- package/lib/apm-client/apm-client.js +313 -0
- package/lib/apm-client/http-apm-client/CHANGELOG.md +271 -0
- package/lib/apm-client/http-apm-client/README.md +485 -0
- package/lib/apm-client/http-apm-client/central-config.js +41 -0
- package/lib/apm-client/http-apm-client/container-info.js +111 -0
- package/lib/apm-client/http-apm-client/detect-hostname.js +96 -0
- package/lib/apm-client/http-apm-client/index.js +1975 -0
- package/lib/apm-client/http-apm-client/logging.js +31 -0
- package/lib/apm-client/http-apm-client/ndjson.js +20 -0
- package/lib/apm-client/http-apm-client/truncate.js +434 -0
- package/lib/apm-client/noop-apm-client.js +73 -0
- package/lib/async-hooks-polyfill.js +58 -0
- package/lib/cloud-metadata/aws.js +175 -0
- package/lib/cloud-metadata/azure.js +123 -0
- package/lib/cloud-metadata/callback-coordination.js +159 -0
- package/lib/cloud-metadata/gcp.js +133 -0
- package/lib/cloud-metadata/index.js +175 -0
- package/lib/config/config.js +458 -0
- package/lib/config/normalizers.js +701 -0
- package/lib/config/schema.js +1007 -0
- package/lib/constants.js +35 -0
- package/lib/errors.js +303 -0
- package/lib/filters/sanitize-field-names.js +69 -0
- package/lib/http-request.js +249 -0
- package/lib/instrumentation/azure-functions.js +519 -0
- package/lib/instrumentation/context.js +56 -0
- package/lib/instrumentation/dropped-spans-stats.js +112 -0
- package/lib/instrumentation/elasticsearch-shared.js +63 -0
- package/lib/instrumentation/express-utils.js +91 -0
- package/lib/instrumentation/generic-span.js +322 -0
- package/lib/instrumentation/http-shared.js +424 -0
- package/lib/instrumentation/ids.js +39 -0
- package/lib/instrumentation/index.js +1127 -0
- package/lib/instrumentation/modules/@apollo/server.js +30 -0
- package/lib/instrumentation/modules/@aws-sdk/client-dynamodb.js +143 -0
- package/lib/instrumentation/modules/@aws-sdk/client-s3.js +230 -0
- package/lib/instrumentation/modules/@aws-sdk/client-sns.js +197 -0
- package/lib/instrumentation/modules/@aws-sdk/client-sqs.js +336 -0
- package/lib/instrumentation/modules/@elastic/elasticsearch.js +343 -0
- package/lib/instrumentation/modules/@hapi/hapi.js +221 -0
- package/lib/instrumentation/modules/@opentelemetry/api.js +86 -0
- package/lib/instrumentation/modules/@opentelemetry/sdk-metrics.js +79 -0
- package/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js +178 -0
- package/lib/instrumentation/modules/@redis/client/dist/lib/client/index.js +49 -0
- package/lib/instrumentation/modules/@smithy/smithy-client.js +198 -0
- package/lib/instrumentation/modules/_lambda-handler.js +40 -0
- package/lib/instrumentation/modules/apollo-server-core.js +49 -0
- package/lib/instrumentation/modules/aws-sdk/dynamodb.js +155 -0
- package/lib/instrumentation/modules/aws-sdk/s3.js +184 -0
- package/lib/instrumentation/modules/aws-sdk/sns.js +232 -0
- package/lib/instrumentation/modules/aws-sdk/sqs.js +361 -0
- package/lib/instrumentation/modules/aws-sdk.js +76 -0
- package/lib/instrumentation/modules/bluebird.js +93 -0
- package/lib/instrumentation/modules/cassandra-driver.js +280 -0
- package/lib/instrumentation/modules/elasticsearch.js +191 -0
- package/lib/instrumentation/modules/express-graphql.js +66 -0
- package/lib/instrumentation/modules/express-queue.js +28 -0
- package/lib/instrumentation/modules/express.js +162 -0
- package/lib/instrumentation/modules/fastify.js +172 -0
- package/lib/instrumentation/modules/finalhandler.js +41 -0
- package/lib/instrumentation/modules/generic-pool.js +85 -0
- package/lib/instrumentation/modules/graphql.js +256 -0
- package/lib/instrumentation/modules/handlebars.js +22 -0
- package/lib/instrumentation/modules/http.js +112 -0
- package/lib/instrumentation/modules/http2.js +320 -0
- package/lib/instrumentation/modules/https.js +68 -0
- package/lib/instrumentation/modules/ioredis.js +94 -0
- package/lib/instrumentation/modules/jade.js +18 -0
- package/lib/instrumentation/modules/kafkajs.js +476 -0
- package/lib/instrumentation/modules/knex.js +91 -0
- package/lib/instrumentation/modules/koa-router.js +74 -0
- package/lib/instrumentation/modules/koa.js +15 -0
- package/lib/instrumentation/modules/memcached.js +99 -0
- package/lib/instrumentation/modules/mimic-response.js +45 -0
- package/lib/instrumentation/modules/mongodb/lib/cmap/connection_pool.js +40 -0
- package/lib/instrumentation/modules/mongodb-core.js +206 -0
- package/lib/instrumentation/modules/mongodb.js +259 -0
- package/lib/instrumentation/modules/mysql.js +200 -0
- package/lib/instrumentation/modules/mysql2.js +140 -0
- package/lib/instrumentation/modules/pg.js +148 -0
- package/lib/instrumentation/modules/pug.js +18 -0
- package/lib/instrumentation/modules/redis.js +176 -0
- package/lib/instrumentation/modules/restify.js +52 -0
- package/lib/instrumentation/modules/tedious.js +159 -0
- package/lib/instrumentation/modules/undici.js +270 -0
- package/lib/instrumentation/modules/ws.js +59 -0
- package/lib/instrumentation/noop-transaction.js +81 -0
- package/lib/instrumentation/run-context/AbstractRunContextManager.js +215 -0
- package/lib/instrumentation/run-context/AsyncHooksRunContextManager.js +106 -0
- package/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js +73 -0
- package/lib/instrumentation/run-context/BasicRunContextManager.js +82 -0
- package/lib/instrumentation/run-context/RunContext.js +151 -0
- package/lib/instrumentation/run-context/index.js +23 -0
- package/lib/instrumentation/shimmer.js +123 -0
- package/lib/instrumentation/span-compression.js +239 -0
- package/lib/instrumentation/span.js +621 -0
- package/lib/instrumentation/template-shared.js +43 -0
- package/lib/instrumentation/timer.js +84 -0
- package/lib/instrumentation/transaction.js +571 -0
- package/lib/lambda.js +992 -0
- package/lib/load-source-map.js +100 -0
- package/lib/logging.js +212 -0
- package/lib/metrics/index.js +92 -0
- package/lib/metrics/platforms/generic/index.js +40 -0
- package/lib/metrics/platforms/generic/process-cpu.js +22 -0
- package/lib/metrics/platforms/generic/process-top.js +157 -0
- package/lib/metrics/platforms/generic/stats.js +34 -0
- package/lib/metrics/platforms/generic/system-cpu.js +51 -0
- package/lib/metrics/platforms/linux/index.js +19 -0
- package/lib/metrics/platforms/linux/stats.js +213 -0
- package/lib/metrics/queue.js +90 -0
- package/lib/metrics/registry.js +52 -0
- package/lib/metrics/reporter.js +119 -0
- package/lib/metrics/runtime.js +77 -0
- package/lib/middleware/connect.js +16 -0
- package/lib/opentelemetry-bridge/OTelBridgeNonRecordingSpan.js +150 -0
- package/lib/opentelemetry-bridge/OTelBridgeRunContext.js +124 -0
- package/lib/opentelemetry-bridge/OTelContextManager.js +82 -0
- package/lib/opentelemetry-bridge/OTelSpan.js +344 -0
- package/lib/opentelemetry-bridge/OTelTracer.js +201 -0
- package/lib/opentelemetry-bridge/OTelTracerProvider.js +25 -0
- package/lib/opentelemetry-bridge/README.md +244 -0
- package/lib/opentelemetry-bridge/index.js +15 -0
- package/lib/opentelemetry-bridge/oblog.js +23 -0
- package/lib/opentelemetry-bridge/opentelemetry-core-mini/README.md +3 -0
- package/lib/opentelemetry-bridge/opentelemetry-core-mini/internal/validators.js +52 -0
- package/lib/opentelemetry-bridge/opentelemetry-core-mini/trace/TraceState.js +109 -0
- package/lib/opentelemetry-bridge/otelutils.js +99 -0
- package/lib/opentelemetry-bridge/setup.js +76 -0
- package/lib/opentelemetry-metrics/ElasticApmMetricExporter.js +285 -0
- package/lib/opentelemetry-metrics/index.js +50 -0
- package/lib/parsers.js +225 -0
- package/lib/propwrap.js +147 -0
- package/lib/stacktraces.js +537 -0
- package/lib/symbols.js +15 -0
- package/lib/tracecontext/index.js +118 -0
- package/lib/tracecontext/traceparent.js +185 -0
- package/lib/tracecontext/tracestate.js +388 -0
- package/lib/wildcard-matcher.js +52 -0
- package/loader.mjs +7 -0
- package/package.json +299 -0
- package/start.d.ts +8 -0
- package/start.js +29 -0
- package/types/aws-lambda.d.ts +98 -0
- package/types/connect.d.ts +23 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Elasticsearch B.V. and other contributors where applicable.
|
|
3
|
+
* Licensed under the BSD 2-Clause License; you may not use this file except in
|
|
4
|
+
* compliance with the BSD 2-Clause License.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
var { URL, urlToHttpOptions } = require('url');
|
|
10
|
+
|
|
11
|
+
var endOfStream = require('end-of-stream');
|
|
12
|
+
const semver = require('semver');
|
|
13
|
+
|
|
14
|
+
var { getHTTPDestination } = require('./context');
|
|
15
|
+
|
|
16
|
+
const transactionForResponse = new WeakMap();
|
|
17
|
+
exports.transactionForResponse = transactionForResponse;
|
|
18
|
+
|
|
19
|
+
const nodeHttpRequestSupportsSeparateUrlArg = semver.gte(
|
|
20
|
+
process.version,
|
|
21
|
+
'10.9.0',
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* safeUrlToHttpOptions is a version of `urlToHttpOptions` -- available in
|
|
26
|
+
* later Node.js versions (https://nodejs.org/api/all.html#all_url_urlurltohttpoptionsurl)
|
|
27
|
+
* -- where the returned object is made "safe" to use as the `options` argument
|
|
28
|
+
* to `http.request()` and `https.request()`.
|
|
29
|
+
*
|
|
30
|
+
* By "safe" here we mean that it will not accidentally be considered a `url`
|
|
31
|
+
* argument. This matters in the instrumentation below because the following are
|
|
32
|
+
* handled differently:
|
|
33
|
+
* http.request(<options>, 'this is a bogus callback')
|
|
34
|
+
* http.request(<url>, 'this is a bogus callback')
|
|
35
|
+
*/
|
|
36
|
+
let safeUrlToHttpOptions;
|
|
37
|
+
if (!urlToHttpOptions) {
|
|
38
|
+
// Adapted from https://github.com/nodejs/node/blob/v18.13.0/lib/internal/url.js#L1408-L1431
|
|
39
|
+
// Added in: v15.7.0, v14.18.0.
|
|
40
|
+
safeUrlToHttpOptions = function (url) {
|
|
41
|
+
const options = {
|
|
42
|
+
protocol: url.protocol,
|
|
43
|
+
hostname:
|
|
44
|
+
typeof url.hostname === 'string' &&
|
|
45
|
+
String.prototype.startsWith(url.hostname, '[')
|
|
46
|
+
? String.prototype.slice(url.hostname, 1, -1)
|
|
47
|
+
: url.hostname,
|
|
48
|
+
hash: url.hash,
|
|
49
|
+
search: url.search,
|
|
50
|
+
pathname: url.pathname,
|
|
51
|
+
path: `${url.pathname || ''}${url.search || ''}`,
|
|
52
|
+
href: url.href,
|
|
53
|
+
};
|
|
54
|
+
if (url.port !== '') {
|
|
55
|
+
options.port = Number(url.port);
|
|
56
|
+
}
|
|
57
|
+
if (url.username || url.password) {
|
|
58
|
+
options.auth = `${decodeURIComponent(url.username)}:${decodeURIComponent(
|
|
59
|
+
url.password,
|
|
60
|
+
)}`;
|
|
61
|
+
}
|
|
62
|
+
return options;
|
|
63
|
+
};
|
|
64
|
+
} else if (
|
|
65
|
+
semver.satisfies(process.version, '>=19.9.0 <20') ||
|
|
66
|
+
semver.satisfies(process.version, '>=18.17.0 <19')
|
|
67
|
+
) {
|
|
68
|
+
// Starting in node v19.9.0 (as of https://github.com/nodejs/node/pull/46989)
|
|
69
|
+
// `urlToHttpOptions(url)` returns an object which is considered a `url`
|
|
70
|
+
// argument by `http.request()` -- because of the internal `isURL(url)` test.
|
|
71
|
+
// Starting with node v18.17.0, the same is true with the internal switch
|
|
72
|
+
// to the "Ada" lib for URL parsing.
|
|
73
|
+
safeUrlToHttpOptions = function (url) {
|
|
74
|
+
const options = urlToHttpOptions(url);
|
|
75
|
+
// Specifically we are dropping the `Symbol(context)` field.
|
|
76
|
+
Object.getOwnPropertySymbols(options).forEach((sym) => {
|
|
77
|
+
delete options[sym];
|
|
78
|
+
});
|
|
79
|
+
return options;
|
|
80
|
+
};
|
|
81
|
+
} else if (
|
|
82
|
+
semver.satisfies(process.version, '>=20', { includePrerelease: true })
|
|
83
|
+
) {
|
|
84
|
+
// This only works for versions of node v20 after
|
|
85
|
+
// https://github.com/nodejs/node/pull/47339 which changed the internal
|
|
86
|
+
// `isURL()` to duck-type test for the `href` field. `href` isn't an option
|
|
87
|
+
// to `http.request()` so there is no harm in dropping it.
|
|
88
|
+
safeUrlToHttpOptions = function (url) {
|
|
89
|
+
const options = urlToHttpOptions(url);
|
|
90
|
+
delete options.href;
|
|
91
|
+
return options;
|
|
92
|
+
};
|
|
93
|
+
} else {
|
|
94
|
+
safeUrlToHttpOptions = urlToHttpOptions;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
exports.instrumentRequest = function (agent, moduleName) {
|
|
98
|
+
var ins = agent._instrumentation;
|
|
99
|
+
return function (orig) {
|
|
100
|
+
return function (event, req, res) {
|
|
101
|
+
if (event === 'request') {
|
|
102
|
+
agent.logger.debug(
|
|
103
|
+
'intercepted request event call to %s.Server.prototype.emit for %s',
|
|
104
|
+
moduleName,
|
|
105
|
+
req.url,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
if (shouldIgnoreRequest(agent, req)) {
|
|
109
|
+
agent.logger.debug('ignoring request to %s', req.url);
|
|
110
|
+
// Don't leak previous transaction.
|
|
111
|
+
agent._instrumentation.supersedeWithEmptyRunContext();
|
|
112
|
+
} else {
|
|
113
|
+
// Decide whether to use trace-context headers, if any, for a
|
|
114
|
+
// distributed trace.
|
|
115
|
+
const traceparent =
|
|
116
|
+
req.headers.traceparent || req.headers['elastic-apm-traceparent'];
|
|
117
|
+
const tracestate = req.headers.tracestate;
|
|
118
|
+
const trans = agent.startTransaction(null, null, {
|
|
119
|
+
childOf: traceparent,
|
|
120
|
+
tracestate,
|
|
121
|
+
});
|
|
122
|
+
trans.type = 'request';
|
|
123
|
+
trans.req = req;
|
|
124
|
+
trans.res = res;
|
|
125
|
+
|
|
126
|
+
transactionForResponse.set(res, trans);
|
|
127
|
+
|
|
128
|
+
ins.bindEmitter(req);
|
|
129
|
+
ins.bindEmitter(res);
|
|
130
|
+
|
|
131
|
+
endOfStream(res, function (err) {
|
|
132
|
+
if (trans.ended) return;
|
|
133
|
+
if (!err) return trans.end();
|
|
134
|
+
|
|
135
|
+
if (agent._conf.errorOnAbortedRequests) {
|
|
136
|
+
var duration = trans._timer.elapsed();
|
|
137
|
+
if (duration > agent._conf.abortedErrorThreshold * 1000) {
|
|
138
|
+
agent.captureError(
|
|
139
|
+
'Socket closed with active HTTP request (>' +
|
|
140
|
+
agent._conf.abortedErrorThreshold +
|
|
141
|
+
' sec)',
|
|
142
|
+
{
|
|
143
|
+
request: req,
|
|
144
|
+
extra: { abortTime: duration },
|
|
145
|
+
},
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Handle case where res.end is called after an error occurred on the
|
|
151
|
+
// stream (e.g. if the underlying socket was prematurely closed)
|
|
152
|
+
const end = res.end;
|
|
153
|
+
res.end = function () {
|
|
154
|
+
const result = end.apply(this, arguments);
|
|
155
|
+
trans.end();
|
|
156
|
+
return result;
|
|
157
|
+
};
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return orig.apply(this, arguments);
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
function shouldIgnoreRequest(agent, req) {
|
|
168
|
+
var i;
|
|
169
|
+
|
|
170
|
+
for (i = 0; i < agent._conf.ignoreUrlStr.length; i++) {
|
|
171
|
+
if (agent._conf.ignoreUrlStr[i] === req.url) return true;
|
|
172
|
+
}
|
|
173
|
+
for (i = 0; i < agent._conf.ignoreUrlRegExp.length; i++) {
|
|
174
|
+
if (agent._conf.ignoreUrlRegExp[i].test(req.url)) return true;
|
|
175
|
+
}
|
|
176
|
+
for (i = 0; i < agent._conf.transactionIgnoreUrlRegExp.length; i++) {
|
|
177
|
+
if (agent._conf.transactionIgnoreUrlRegExp[i].test(req.url)) return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
var ua = req.headers['user-agent'];
|
|
181
|
+
if (!ua) return false;
|
|
182
|
+
|
|
183
|
+
for (i = 0; i < agent._conf.ignoreUserAgentStr.length; i++) {
|
|
184
|
+
if (ua.indexOf(agent._conf.ignoreUserAgentStr[i]) === 0) return true;
|
|
185
|
+
}
|
|
186
|
+
for (i = 0; i < agent._conf.ignoreUserAgentRegExp.length; i++) {
|
|
187
|
+
if (agent._conf.ignoreUserAgentRegExp[i].test(ua)) return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Safely get the Host header used in the given client request without incurring
|
|
195
|
+
* the core Node.js DEP0066 warning for using `req._headers`.
|
|
196
|
+
*
|
|
197
|
+
* @param {http.ClientRequest} req
|
|
198
|
+
* @returns {string}
|
|
199
|
+
*/
|
|
200
|
+
function getSafeHost(req) {
|
|
201
|
+
return req.getHeader ? req.getHeader('Host') : req._headers.host;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
exports.traceOutgoingRequest = function (agent, moduleName, method) {
|
|
205
|
+
var ins = agent._instrumentation;
|
|
206
|
+
|
|
207
|
+
return function wrapHttpRequest(orig) {
|
|
208
|
+
return function wrappedHttpRequest(input, options, cb) {
|
|
209
|
+
const parentRunContext = ins.currRunContext();
|
|
210
|
+
var span = ins.createSpan(null, 'external', 'http', { exitSpan: true });
|
|
211
|
+
var id = span && span.transaction.id;
|
|
212
|
+
agent.logger.debug('intercepted call to %s.%s %o', moduleName, method, {
|
|
213
|
+
id,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Reproduce the argument handling from node/lib/_http_client.js#ClientRequest().
|
|
217
|
+
//
|
|
218
|
+
// The `new URL(...)` calls in this block *could* throw INVALID_URL, but
|
|
219
|
+
// that would happen anyway when calling `orig(...)`. The only slight
|
|
220
|
+
// downside is that the Error stack won't originate inside "_http_client.js".
|
|
221
|
+
if (!nodeHttpRequestSupportsSeparateUrlArg) {
|
|
222
|
+
// Signature from node <10.9.0:
|
|
223
|
+
// http.request(options[, callback])
|
|
224
|
+
// options <Object> | <string> | <URL>
|
|
225
|
+
cb = options;
|
|
226
|
+
options = input;
|
|
227
|
+
if (typeof options === 'string') {
|
|
228
|
+
options = safeUrlToHttpOptions(new URL(options));
|
|
229
|
+
} else if (options instanceof URL) {
|
|
230
|
+
options = safeUrlToHttpOptions(options);
|
|
231
|
+
} else {
|
|
232
|
+
options = Object.assign({}, options);
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
// Signature from node >=10.9.0:
|
|
236
|
+
// http.request(options[, callback])
|
|
237
|
+
// http.request(url[, options][, callback])
|
|
238
|
+
// url <string> | <URL>
|
|
239
|
+
// options <Object>
|
|
240
|
+
if (typeof input === 'string') {
|
|
241
|
+
input = safeUrlToHttpOptions(new URL(input));
|
|
242
|
+
} else if (input instanceof URL) {
|
|
243
|
+
input = safeUrlToHttpOptions(input);
|
|
244
|
+
} else {
|
|
245
|
+
cb = options;
|
|
246
|
+
options = input;
|
|
247
|
+
input = null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (typeof options === 'function') {
|
|
251
|
+
cb = options;
|
|
252
|
+
options = input || {};
|
|
253
|
+
} else {
|
|
254
|
+
options = Object.assign(input || {}, options);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const newArgs = [options];
|
|
259
|
+
if (cb !== undefined) {
|
|
260
|
+
if (typeof cb === 'function') {
|
|
261
|
+
newArgs.push(ins.bindFunctionToRunContext(parentRunContext, cb));
|
|
262
|
+
} else {
|
|
263
|
+
newArgs.push(cb);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// W3C trace-context propagation.
|
|
268
|
+
// There are a number of reasons why `span` might be null: child of an
|
|
269
|
+
// exit span, `transactionMaxSpans` was hit, unsampled transaction, etc.
|
|
270
|
+
// If so, then fallback to the current run context's span or transaction,
|
|
271
|
+
// if any.
|
|
272
|
+
const parent =
|
|
273
|
+
span ||
|
|
274
|
+
parentRunContext.currSpan() ||
|
|
275
|
+
parentRunContext.currTransaction();
|
|
276
|
+
if (parent) {
|
|
277
|
+
const headers = Object.assign({}, options.headers);
|
|
278
|
+
parent.propagateTraceContextHeaders(
|
|
279
|
+
headers,
|
|
280
|
+
function (carrier, name, value) {
|
|
281
|
+
carrier[name] = value;
|
|
282
|
+
},
|
|
283
|
+
);
|
|
284
|
+
options.headers = headers;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (!span) {
|
|
288
|
+
return orig.apply(this, newArgs);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const spanRunContext = parentRunContext.enterSpan(span);
|
|
292
|
+
var req = ins.withRunContext(spanRunContext, orig, this, ...newArgs);
|
|
293
|
+
|
|
294
|
+
var protocol = req.agent && req.agent.protocol;
|
|
295
|
+
agent.logger.debug('request details: %o', {
|
|
296
|
+
protocol,
|
|
297
|
+
host: getSafeHost(req),
|
|
298
|
+
id,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
ins.bindEmitter(req);
|
|
302
|
+
|
|
303
|
+
span.action = req.method;
|
|
304
|
+
span.name = req.method + ' ' + getSafeHost(req);
|
|
305
|
+
|
|
306
|
+
// TODO: Research if it's possible to add this to the prototype instead.
|
|
307
|
+
// Or if it's somehow preferable to listen for when a `response` listener
|
|
308
|
+
// is added instead of when `response` is emitted.
|
|
309
|
+
const emit = req.emit;
|
|
310
|
+
req.emit = function wrappedEmit(type, res) {
|
|
311
|
+
if (type === 'response') onResponse(res);
|
|
312
|
+
if (type === 'abort') onAbort(type);
|
|
313
|
+
return emit.apply(req, arguments);
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const url = getUrlFromRequestAndOptions(req, options, moduleName + ':');
|
|
317
|
+
if (!url) {
|
|
318
|
+
agent.logger.warn('unable to identify http.ClientRequest url %o', {
|
|
319
|
+
id,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
let statusCode;
|
|
323
|
+
return req;
|
|
324
|
+
|
|
325
|
+
// In case the request is ended prematurely
|
|
326
|
+
function onAbort(type) {
|
|
327
|
+
if (span.ended) return;
|
|
328
|
+
agent.logger.debug('intercepted http.ClientRequest abort event %o', {
|
|
329
|
+
id,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
onEnd();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function onEnd() {
|
|
336
|
+
span.setHttpContext({
|
|
337
|
+
method: req.method,
|
|
338
|
+
status_code: statusCode,
|
|
339
|
+
url,
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Add destination info only when socket conn is established
|
|
343
|
+
if (url) {
|
|
344
|
+
// The `getHTTPDestination` function might throw in case an
|
|
345
|
+
// invalid URL is given to the `URL()` function. Until we can
|
|
346
|
+
// be 100% sure this doesn't happen, we better catch it here.
|
|
347
|
+
// For details, see:
|
|
348
|
+
// https://github.com/elastic/apm-agent-nodejs/issues/1769
|
|
349
|
+
try {
|
|
350
|
+
span._setDestinationContext(getHTTPDestination(url));
|
|
351
|
+
} catch (e) {
|
|
352
|
+
agent.logger.error(
|
|
353
|
+
'Could not set destination context: %s',
|
|
354
|
+
e.message,
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
span._setOutcomeFromHttpStatusCode(statusCode);
|
|
360
|
+
span.end();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function onResponse(res) {
|
|
364
|
+
agent.logger.debug('intercepted http.ClientRequest response event %o', {
|
|
365
|
+
id,
|
|
366
|
+
});
|
|
367
|
+
ins.bindEmitterToRunContext(parentRunContext, res);
|
|
368
|
+
statusCode = res.statusCode;
|
|
369
|
+
res.prependListener('end', function () {
|
|
370
|
+
agent.logger.debug('intercepted http.IncomingMessage end event %o', {
|
|
371
|
+
id,
|
|
372
|
+
});
|
|
373
|
+
onEnd();
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
};
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
// Creates a sanitized URL suitable for the span's HTTP context
|
|
381
|
+
//
|
|
382
|
+
// This function reconstructs a URL using the request object's properties
|
|
383
|
+
// where it can (node versions v14.5.0, v12.19.0 and later), and falling
|
|
384
|
+
// back to the options where it can not. This function also strips any
|
|
385
|
+
// authentication information provided with the hostname. In other words
|
|
386
|
+
//
|
|
387
|
+
// http://username:password@example.com/foo
|
|
388
|
+
//
|
|
389
|
+
// becomes http://example.com/foo
|
|
390
|
+
//
|
|
391
|
+
// NOTE: The options argument may not be the same options that are passed
|
|
392
|
+
// to http.request if the caller uses the the http.request(url,options,...)
|
|
393
|
+
// method signature. The agent normalizes the url and options into a single
|
|
394
|
+
// options object. This function expects those pre-normalized options.
|
|
395
|
+
//
|
|
396
|
+
// @param {ClientRequest} req
|
|
397
|
+
// @param {object} options
|
|
398
|
+
// @param {string} fallbackProtocol
|
|
399
|
+
// @return string|undefined
|
|
400
|
+
function getUrlFromRequestAndOptions(req, options, fallbackProtocol) {
|
|
401
|
+
if (!req) {
|
|
402
|
+
return undefined;
|
|
403
|
+
}
|
|
404
|
+
options = options || {};
|
|
405
|
+
req = req || {};
|
|
406
|
+
req.agent = req.agent || {};
|
|
407
|
+
|
|
408
|
+
if (isProxiedRequest(req)) {
|
|
409
|
+
return req.path;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const port = options.port ? `:${options.port}` : '';
|
|
413
|
+
// req.host and req.protocol are node versions v14.5.0/v12.19.0 and later
|
|
414
|
+
const host = req.host || options.hostname || options.host || 'localhost';
|
|
415
|
+
const protocol = req.protocol || req.agent.protocol || fallbackProtocol;
|
|
416
|
+
|
|
417
|
+
return `${protocol}//${host}${port}${req.path}`;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function isProxiedRequest(req) {
|
|
421
|
+
return req.path.indexOf('https:') === 0 || req.path.indexOf('http:') === 0;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
exports.getUrlFromRequestAndOptions = getUrlFromRequestAndOptions;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright Elasticsearch B.V. and other contributors where applicable.
|
|
3
|
+
* Licensed under the BSD 2-Clause License; you may not use this file except in
|
|
4
|
+
* compliance with the BSD 2-Clause License.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { stringify } = require('querystring');
|
|
10
|
+
|
|
11
|
+
class Ids {
|
|
12
|
+
toString() {
|
|
13
|
+
return stringify(this, ' ', '=');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class SpanIds extends Ids {
|
|
18
|
+
constructor(span) {
|
|
19
|
+
super();
|
|
20
|
+
this['trace.id'] = span.traceId;
|
|
21
|
+
this['span.id'] = span.id;
|
|
22
|
+
Object.freeze(this);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class TransactionIds extends Ids {
|
|
27
|
+
constructor(transaction) {
|
|
28
|
+
super();
|
|
29
|
+
this['trace.id'] = transaction.traceId;
|
|
30
|
+
this['transaction.id'] = transaction.id;
|
|
31
|
+
Object.freeze(this);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
Ids,
|
|
37
|
+
SpanIds,
|
|
38
|
+
TransactionIds,
|
|
39
|
+
};
|