@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,198 @@
|
|
|
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 semver = require('semver');
|
|
10
|
+
const shimmer = require('../../shimmer');
|
|
11
|
+
const elasticAPMMiddlewares = Symbol('elasticAPMMiddlewares');
|
|
12
|
+
const {
|
|
13
|
+
DYNAMODB_NAME,
|
|
14
|
+
DYNAMODB_TYPE,
|
|
15
|
+
DYNAMODB_SUBTYPE,
|
|
16
|
+
dynamoDBMiddlewareFactory,
|
|
17
|
+
dynamoDBShouldIgnoreCommand,
|
|
18
|
+
} = require('../@aws-sdk/client-dynamodb');
|
|
19
|
+
const {
|
|
20
|
+
S3_NAME,
|
|
21
|
+
S3_TYPE,
|
|
22
|
+
S3_SUBTYPE,
|
|
23
|
+
s3MiddlewareFactory,
|
|
24
|
+
s3ShouldIgnoreCommand,
|
|
25
|
+
} = require('../@aws-sdk/client-s3');
|
|
26
|
+
const {
|
|
27
|
+
SNS_NAME,
|
|
28
|
+
SNS_TYPE,
|
|
29
|
+
SNS_SUBTYPE,
|
|
30
|
+
snsMiddlewareFactory,
|
|
31
|
+
snsShouldIgnoreCommand,
|
|
32
|
+
} = require('../@aws-sdk/client-sns');
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
SQS_NAME,
|
|
36
|
+
SQS_TYPE,
|
|
37
|
+
SQS_SUBTYPE,
|
|
38
|
+
sqsMiddlewareFactory,
|
|
39
|
+
sqsShouldIgnoreCommand,
|
|
40
|
+
} = require('../@aws-sdk/client-sqs');
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* We do alias them to a local type
|
|
44
|
+
* @typedef {import('@aws-sdk/types').InitializeMiddleware} InitializeMiddleware
|
|
45
|
+
* @typedef {import('@aws-sdk/types').FinalizeRequestMiddleware } FinalizeRequestMiddleware
|
|
46
|
+
* @typedef {import('@aws-sdk/types').InitializeHandlerOptions} InitializeHandlerOptions
|
|
47
|
+
* @typedef {import('@aws-sdk/types').FinalizeRequestHandlerOptions } FinalizeRequestHandlerOptions
|
|
48
|
+
*
|
|
49
|
+
* Then create our types
|
|
50
|
+
* @typedef {InitializeMiddleware | FinalizeRequestMiddleware} AWSMiddleware
|
|
51
|
+
* @typedef {InitializeHandlerOptions | FinalizeRequestHandlerOptions} AWSMiddlewareOptions
|
|
52
|
+
|
|
53
|
+
* @typedef {object} AWSMiddlewareEntry
|
|
54
|
+
* @property {AWSMiddleware} middleware
|
|
55
|
+
* @property {AWSMiddlewareOptions} options
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
const COMMAND_NAME_RE = /^(\w+)Command$/;
|
|
59
|
+
/**
|
|
60
|
+
* TODO: this method may be shared with other instrumentations
|
|
61
|
+
* For a HeadObject API call, `context.commandName === 'HeadObjectCommand'`.
|
|
62
|
+
*
|
|
63
|
+
* @param {String} commandName
|
|
64
|
+
* @returns {String}
|
|
65
|
+
*/
|
|
66
|
+
function opNameFromCommandName(commandName) {
|
|
67
|
+
const match = COMMAND_NAME_RE.exec(commandName);
|
|
68
|
+
if (match) {
|
|
69
|
+
return match[1];
|
|
70
|
+
} else {
|
|
71
|
+
return '<unknown command>';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const clientsConfig = {
|
|
76
|
+
DynamoDBClient: {
|
|
77
|
+
NAME: DYNAMODB_NAME,
|
|
78
|
+
TYPE: DYNAMODB_TYPE,
|
|
79
|
+
SUBTYPE: DYNAMODB_SUBTYPE,
|
|
80
|
+
factory: dynamoDBMiddlewareFactory,
|
|
81
|
+
shouldIgnoreCommand: dynamoDBShouldIgnoreCommand,
|
|
82
|
+
},
|
|
83
|
+
S3Client: {
|
|
84
|
+
NAME: S3_NAME,
|
|
85
|
+
TYPE: S3_TYPE,
|
|
86
|
+
SUBTYPE: S3_SUBTYPE,
|
|
87
|
+
factory: s3MiddlewareFactory,
|
|
88
|
+
shouldIgnoreCommand: s3ShouldIgnoreCommand,
|
|
89
|
+
},
|
|
90
|
+
SNSClient: {
|
|
91
|
+
NAME: SNS_NAME,
|
|
92
|
+
TYPE: SNS_TYPE,
|
|
93
|
+
SUBTYPE: SNS_SUBTYPE,
|
|
94
|
+
factory: snsMiddlewareFactory,
|
|
95
|
+
shouldIgnoreCommand: snsShouldIgnoreCommand,
|
|
96
|
+
},
|
|
97
|
+
SQSClient: {
|
|
98
|
+
NAME: SQS_NAME,
|
|
99
|
+
TYPE: SQS_TYPE,
|
|
100
|
+
SUBTYPE: SQS_SUBTYPE,
|
|
101
|
+
factory: sqsMiddlewareFactory,
|
|
102
|
+
shouldIgnoreCommand: sqsShouldIgnoreCommand,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
module.exports = function (mod, agent, { name, version, enabled }) {
|
|
107
|
+
if (!enabled) return mod;
|
|
108
|
+
|
|
109
|
+
// As of `@aws-sdk/*@3.363.0` the underlying smithy-client is under the
|
|
110
|
+
// `@smithy/` npm org.
|
|
111
|
+
if (
|
|
112
|
+
name === '@smithy/smithy-client' &&
|
|
113
|
+
!semver.satisfies(version, '>=1 <5')
|
|
114
|
+
) {
|
|
115
|
+
agent.logger.debug(
|
|
116
|
+
'cannot instrument @aws-sdk/client-*: @smithy/smithy-client version %s not supported',
|
|
117
|
+
version,
|
|
118
|
+
);
|
|
119
|
+
return mod;
|
|
120
|
+
} else if (
|
|
121
|
+
name === '@aws-sdk/smithy-client' &&
|
|
122
|
+
!semver.satisfies(version, '>=3 <4')
|
|
123
|
+
) {
|
|
124
|
+
agent.logger.debug(
|
|
125
|
+
'cannot instrument @aws-sdk/client-*: @aws-sdk/smithy-client version %s not supported',
|
|
126
|
+
version,
|
|
127
|
+
);
|
|
128
|
+
return mod;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
shimmer.wrap(mod.Client.prototype, 'send', function (orig) {
|
|
132
|
+
return function _wrappedSmithyClientSend() {
|
|
133
|
+
const clientName = this.constructor && this.constructor.name;
|
|
134
|
+
const clientConfig = clientsConfig[clientName];
|
|
135
|
+
|
|
136
|
+
if (!clientConfig) {
|
|
137
|
+
return orig.apply(this, arguments);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!this[elasticAPMMiddlewares]) {
|
|
141
|
+
const factory = clientConfig && clientConfig.factory;
|
|
142
|
+
const middlewares =
|
|
143
|
+
typeof factory === 'function' ? factory(this, agent) : [];
|
|
144
|
+
|
|
145
|
+
// We do the instrumentation by leveraging the middleware mechanism provided by the
|
|
146
|
+
// middlewareStack property of the Client instance. We add the instrumentation middlewares
|
|
147
|
+
// once at the client level so they persist for the whole life of the client instance
|
|
148
|
+
// https://github.com/aws/aws-sdk-js-v3/tree/main/packages/middleware-stack
|
|
149
|
+
this[elasticAPMMiddlewares] = middlewares;
|
|
150
|
+
for (const item of this[elasticAPMMiddlewares]) {
|
|
151
|
+
this.middlewareStack.add(item.middleware, item.options);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const command = arguments[0];
|
|
156
|
+
|
|
157
|
+
if (clientConfig.shouldIgnoreCommand(command, agent._conf)) {
|
|
158
|
+
return orig.apply(this, arguments);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const opName = opNameFromCommandName(command.constructor.name);
|
|
162
|
+
const name = clientConfig.NAME + ' ' + opName;
|
|
163
|
+
|
|
164
|
+
const ins = agent._instrumentation;
|
|
165
|
+
const span = ins.createSpan(
|
|
166
|
+
name,
|
|
167
|
+
clientConfig.TYPE,
|
|
168
|
+
clientConfig.SUBTYPE,
|
|
169
|
+
opName,
|
|
170
|
+
{ exitSpan: true },
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
if (!span) {
|
|
174
|
+
return orig.apply(this, arguments);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Run context notes: The `orig` should run in the context of the S3 span,
|
|
178
|
+
// because that is the point. The user's callback `cb` should run outside of
|
|
179
|
+
// the S3 span.
|
|
180
|
+
const parentRunContext = ins.currRunContext();
|
|
181
|
+
const spanRunContext = parentRunContext.enterSpan(span);
|
|
182
|
+
|
|
183
|
+
// Although the client consumer may use the Promise API `S3Client.send(command).then(...)`
|
|
184
|
+
// the clients may make use of the callback parameter on the super class method (SmithyClient)
|
|
185
|
+
// therefore we need to have this check
|
|
186
|
+
const cb = arguments[arguments.length - 1];
|
|
187
|
+
if (typeof cb === 'function') {
|
|
188
|
+
arguments[arguments.length - 1] = ins.bindFunctionToRunContext(
|
|
189
|
+
parentRunContext,
|
|
190
|
+
cb,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return ins.withRunContext(spanRunContext, orig, this, ...arguments);
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
return mod;
|
|
198
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
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 propwrap = require('../../propwrap');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Return a patch handler, `function (module, agent, options)`, that will patch
|
|
13
|
+
* the Lambda handler function at the given property path.
|
|
14
|
+
*
|
|
15
|
+
* For example, a Lambda _HANDLER=index.handler indicates that a file "index.js"
|
|
16
|
+
* has a `handler` export that is the Lambda handler function. In this case
|
|
17
|
+
* `module` will be the imported "index.js" module and `propPath` will be
|
|
18
|
+
* "handler".
|
|
19
|
+
*/
|
|
20
|
+
function createLambdaPatcher(propPath) {
|
|
21
|
+
return function lambdaHandlerPatcher(module, agent, { enabled }) {
|
|
22
|
+
if (!enabled) {
|
|
23
|
+
return module;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const newMod = propwrap.wrap(module, propPath, (orig) => {
|
|
28
|
+
return agent.lambda(orig);
|
|
29
|
+
});
|
|
30
|
+
return newMod;
|
|
31
|
+
} catch (wrapErr) {
|
|
32
|
+
agent.logger.warn('could not wrap lambda handler: %s', wrapErr);
|
|
33
|
+
return module;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = {
|
|
39
|
+
createLambdaPatcher,
|
|
40
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
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 semver = require('semver');
|
|
10
|
+
const shimmer = require('../shimmer');
|
|
11
|
+
const clone = require('shallow-clone-shim');
|
|
12
|
+
|
|
13
|
+
module.exports = function (apolloServerCore, agent, { version, enabled }) {
|
|
14
|
+
if (!enabled) return apolloServerCore;
|
|
15
|
+
|
|
16
|
+
if (!semver.satisfies(version, '^2.0.2 || ^3.0.0')) {
|
|
17
|
+
agent.logger.debug(
|
|
18
|
+
'apollo-server-core version %s not supported - aborting...',
|
|
19
|
+
version,
|
|
20
|
+
);
|
|
21
|
+
return apolloServerCore;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function wrapRunHttpQuery(orig) {
|
|
25
|
+
return function wrappedRunHttpQuery() {
|
|
26
|
+
var trans = agent._instrumentation.currTransaction();
|
|
27
|
+
if (trans) trans._graphqlRoute = true;
|
|
28
|
+
return orig.apply(this, arguments);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (semver.satisfies(version, '<2.14')) {
|
|
33
|
+
shimmer.wrap(apolloServerCore, 'runHttpQuery', wrapRunHttpQuery);
|
|
34
|
+
return apolloServerCore;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// apollo-server-core >= 2.14 does not allow overriding the exports object
|
|
38
|
+
return clone({}, apolloServerCore, {
|
|
39
|
+
runHttpQuery(descriptor) {
|
|
40
|
+
const getter = descriptor.get;
|
|
41
|
+
if (getter) {
|
|
42
|
+
descriptor.get = function get() {
|
|
43
|
+
return wrapRunHttpQuery(getter());
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return descriptor;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
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 TYPE = 'db';
|
|
10
|
+
const SUBTYPE = 'dynamodb';
|
|
11
|
+
const ACTION = 'query';
|
|
12
|
+
|
|
13
|
+
function getRegionFromRequest(request) {
|
|
14
|
+
return (
|
|
15
|
+
request &&
|
|
16
|
+
request.service &&
|
|
17
|
+
request.service.config &&
|
|
18
|
+
request.service.config.region
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getPortFromRequest(request) {
|
|
23
|
+
return (
|
|
24
|
+
request &&
|
|
25
|
+
request.service &&
|
|
26
|
+
request.service.endpoint &&
|
|
27
|
+
request.service.endpoint.port
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getMethodFromRequest(request) {
|
|
32
|
+
const method = request && request.operation;
|
|
33
|
+
if (method) {
|
|
34
|
+
return method[0].toUpperCase() + method.slice(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getStatementFromRequest(request) {
|
|
39
|
+
const method = getMethodFromRequest(request);
|
|
40
|
+
if (
|
|
41
|
+
method === 'Query' &&
|
|
42
|
+
request &&
|
|
43
|
+
request.params &&
|
|
44
|
+
request.params.KeyConditionExpression
|
|
45
|
+
) {
|
|
46
|
+
return request.params.KeyConditionExpression;
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getAddressFromRequest(request) {
|
|
52
|
+
return (
|
|
53
|
+
request &&
|
|
54
|
+
request.service &&
|
|
55
|
+
request.service.endpoint &&
|
|
56
|
+
request.service.endpoint.hostname
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getTableFromRequest(request) {
|
|
61
|
+
const table = request && request.params && request.params.TableName;
|
|
62
|
+
if (!table) {
|
|
63
|
+
return '';
|
|
64
|
+
}
|
|
65
|
+
return ` ${table}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Creates the span name from request information
|
|
69
|
+
function getSpanNameFromRequest(request) {
|
|
70
|
+
const method = getMethodFromRequest(request);
|
|
71
|
+
const table = getTableFromRequest(request);
|
|
72
|
+
const name = `DynamoDB ${method}${table}`;
|
|
73
|
+
return name;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function shouldIgnoreRequest(request, agent) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Main entrypoint for SQS instrumentation
|
|
81
|
+
//
|
|
82
|
+
// Must call (or one of its function calls must call) the
|
|
83
|
+
// `orig` function/method
|
|
84
|
+
function instrumentationDynamoDb(
|
|
85
|
+
orig,
|
|
86
|
+
origArguments,
|
|
87
|
+
request,
|
|
88
|
+
AWS,
|
|
89
|
+
agent,
|
|
90
|
+
{ version, enabled },
|
|
91
|
+
) {
|
|
92
|
+
if (shouldIgnoreRequest(request, agent)) {
|
|
93
|
+
return orig.apply(request, origArguments);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const ins = agent._instrumentation;
|
|
97
|
+
const name = getSpanNameFromRequest(request);
|
|
98
|
+
const span = ins.createSpan(name, TYPE, SUBTYPE, ACTION, { exitSpan: true });
|
|
99
|
+
if (!span) {
|
|
100
|
+
return orig.apply(request, origArguments);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const region = getRegionFromRequest(request);
|
|
104
|
+
const dbContext = {
|
|
105
|
+
type: SUBTYPE,
|
|
106
|
+
instance: region,
|
|
107
|
+
};
|
|
108
|
+
const dbStatement = getStatementFromRequest(request);
|
|
109
|
+
if (dbStatement) {
|
|
110
|
+
dbContext.statement = dbStatement;
|
|
111
|
+
}
|
|
112
|
+
span.setDbContext(dbContext);
|
|
113
|
+
span._setDestinationContext({
|
|
114
|
+
address: getAddressFromRequest(request),
|
|
115
|
+
port: getPortFromRequest(request),
|
|
116
|
+
cloud: {
|
|
117
|
+
region,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const onComplete = function (response) {
|
|
122
|
+
if (response && response.error) {
|
|
123
|
+
agent.captureError(response.error);
|
|
124
|
+
}
|
|
125
|
+
span.end();
|
|
126
|
+
};
|
|
127
|
+
// Bind onComplete to the span's run context so that `captureError` picks
|
|
128
|
+
// up the correct currentSpan.
|
|
129
|
+
const parentRunContext = ins.currRunContext();
|
|
130
|
+
const spanRunContext = parentRunContext.enterSpan(span);
|
|
131
|
+
request.on(
|
|
132
|
+
'complete',
|
|
133
|
+
ins.bindFunctionToRunContext(spanRunContext, onComplete),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const cb = origArguments[origArguments.length - 1];
|
|
137
|
+
if (typeof cb === 'function') {
|
|
138
|
+
origArguments[origArguments.length - 1] = ins.bindFunctionToRunContext(
|
|
139
|
+
parentRunContext,
|
|
140
|
+
cb,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
return ins.withRunContext(spanRunContext, orig, request, ...origArguments);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = {
|
|
147
|
+
instrumentationDynamoDb,
|
|
148
|
+
|
|
149
|
+
// exported for testing
|
|
150
|
+
getRegionFromRequest,
|
|
151
|
+
getPortFromRequest,
|
|
152
|
+
getStatementFromRequest,
|
|
153
|
+
getAddressFromRequest,
|
|
154
|
+
getMethodFromRequest,
|
|
155
|
+
};
|
|
@@ -0,0 +1,184 @@
|
|
|
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
|
+
// Instrument AWS S3 operations via the 'aws-sdk' package.
|
|
10
|
+
|
|
11
|
+
const constants = require('../../../constants');
|
|
12
|
+
|
|
13
|
+
const TYPE = 'storage';
|
|
14
|
+
const SUBTYPE = 's3';
|
|
15
|
+
|
|
16
|
+
// Return the PascalCase operation name from `request.operation` by undoing to
|
|
17
|
+
// `lowerFirst()` from
|
|
18
|
+
// https://github.com/aws/aws-sdk-js/blob/c0c44b8a4e607aae521686898f39a3e359f727e4/lib/model/api.js#L63-L65
|
|
19
|
+
//
|
|
20
|
+
// For example: 'headBucket' -> 'HeadBucket'
|
|
21
|
+
function opNameFromOperation(operation) {
|
|
22
|
+
return operation[0].toUpperCase() + operation.slice(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Return an APM "resource" string for the bucket, Access Point ARN, or Outpost
|
|
26
|
+
// ARN. ARNs are normalized to a shorter resource name.
|
|
27
|
+
//
|
|
28
|
+
// Known ARN patterns:
|
|
29
|
+
// - arn:aws:s3:<region>:<account-id>:accesspoint/<accesspoint-name>
|
|
30
|
+
// - arn:aws:s3-outposts:<region>:<account>:outpost/<outpost-id>/bucket/<bucket-name>
|
|
31
|
+
// - arn:aws:s3-outposts:<region>:<account>:outpost/<outpost-id>/accesspoint/<accesspoint-name>
|
|
32
|
+
//
|
|
33
|
+
// In general that is:
|
|
34
|
+
// arn:$partition:$service:$region:$accountId:$resource
|
|
35
|
+
//
|
|
36
|
+
// This parses using the same "split on colon" used by the JavaScript AWS SDK v3.
|
|
37
|
+
// https://github.com/aws/aws-sdk-js-v3/blob/v3.18.0/packages/util-arn-parser/src/index.ts#L14-L37
|
|
38
|
+
function resourceFromBucket(bucket) {
|
|
39
|
+
let resource = null;
|
|
40
|
+
if (bucket) {
|
|
41
|
+
resource = bucket;
|
|
42
|
+
if (resource.startsWith('arn:')) {
|
|
43
|
+
resource = bucket.split(':').slice(5).join(':');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return resource;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Instrument an awk-sdk@2.x operation (i.e. a AWS.Request.send or
|
|
50
|
+
// AWS.Request.promise).
|
|
51
|
+
//
|
|
52
|
+
// @param {AWS.Request} request https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Request.html
|
|
53
|
+
function instrumentationS3(
|
|
54
|
+
orig,
|
|
55
|
+
origArguments,
|
|
56
|
+
request,
|
|
57
|
+
AWS,
|
|
58
|
+
agent,
|
|
59
|
+
{ version, enabled },
|
|
60
|
+
) {
|
|
61
|
+
const opName = opNameFromOperation(request.operation);
|
|
62
|
+
const params = request.params;
|
|
63
|
+
const bucket = params && params.Bucket;
|
|
64
|
+
const resource = resourceFromBucket(bucket);
|
|
65
|
+
let name = 'S3 ' + opName;
|
|
66
|
+
if (resource) {
|
|
67
|
+
name += ' ' + resource;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const ins = agent._instrumentation;
|
|
71
|
+
|
|
72
|
+
const span = ins.createSpan(name, TYPE, SUBTYPE, opName, { exitSpan: true });
|
|
73
|
+
if (!span) {
|
|
74
|
+
return orig.apply(request, origArguments);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// As for now OTel spec defines attributes for operations that require a Bucket
|
|
78
|
+
// if that changes we should review this guard
|
|
79
|
+
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/semantic_conventions/trace/instrumentation/aws-sdk.yml#L435
|
|
80
|
+
if (bucket) {
|
|
81
|
+
const otelAttrs = span._getOTelAttributes();
|
|
82
|
+
|
|
83
|
+
otelAttrs['aws.s3.bucket'] = bucket;
|
|
84
|
+
|
|
85
|
+
if (params.Key) {
|
|
86
|
+
otelAttrs['aws.s3.key'] = params.Key;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const onComplete = function (response) {
|
|
91
|
+
// `response` is an AWS.Response
|
|
92
|
+
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Response.html
|
|
93
|
+
|
|
94
|
+
// Determining the bucket's region.
|
|
95
|
+
// `request.httpRequest.region` isn't documented, but the aws-sdk@2
|
|
96
|
+
// lib/services/s3.js will set it to the bucket's determined region.
|
|
97
|
+
// This can be asynchronously determined -- e.g. if it differs from the
|
|
98
|
+
// configured service endpoint region -- so this won't be set until
|
|
99
|
+
// 'complete'.
|
|
100
|
+
const httpRequest = request.httpRequest;
|
|
101
|
+
const region = httpRequest && httpRequest.region;
|
|
102
|
+
|
|
103
|
+
span.setServiceTarget('s3', resource);
|
|
104
|
+
const destContext = {};
|
|
105
|
+
// '.httpRequest.endpoint' might differ from '.service.endpoint' if
|
|
106
|
+
// the bucket is in a different region.
|
|
107
|
+
const endpoint = httpRequest && httpRequest.endpoint;
|
|
108
|
+
if (endpoint) {
|
|
109
|
+
destContext.address = endpoint.hostname;
|
|
110
|
+
destContext.port = endpoint.port;
|
|
111
|
+
}
|
|
112
|
+
if (region) {
|
|
113
|
+
destContext.cloud = { region };
|
|
114
|
+
}
|
|
115
|
+
span._setDestinationContext(destContext);
|
|
116
|
+
|
|
117
|
+
if (response) {
|
|
118
|
+
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/HttpResponse.html
|
|
119
|
+
const httpResponse = response.httpResponse;
|
|
120
|
+
let statusCode;
|
|
121
|
+
if (httpResponse) {
|
|
122
|
+
statusCode = httpResponse.statusCode;
|
|
123
|
+
|
|
124
|
+
// Set HTTP context. Some context not being set, though it is available:
|
|
125
|
+
// - method: Not that helpful.
|
|
126
|
+
// - url: Mostly redundant with context.destination.address.
|
|
127
|
+
// - response.headers: A lot of added size for uncertain utility. The
|
|
128
|
+
// inclusion of Amazon's request ID headers might be worth it.
|
|
129
|
+
const httpContext = {
|
|
130
|
+
status_code: statusCode,
|
|
131
|
+
};
|
|
132
|
+
const encodedBodySize =
|
|
133
|
+
Buffer.isBuffer(httpResponse.body) && httpResponse.body.byteLength;
|
|
134
|
+
if (encodedBodySize) {
|
|
135
|
+
// I'm not actually sure if this might be decoded_body_size.
|
|
136
|
+
httpContext.response = { encoded_body_size: encodedBodySize };
|
|
137
|
+
}
|
|
138
|
+
span.setHttpContext(httpContext);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Follow the spec for HTTP client span outcome.
|
|
142
|
+
// https://github.com/elastic/apm/blob/main/specs/agents/tracing-instrumentation-http.md#outcome
|
|
143
|
+
//
|
|
144
|
+
// For example, a S3 GetObject conditional request (e.g. using the
|
|
145
|
+
// IfNoneMatch param) will respond with response.error=NotModifed and
|
|
146
|
+
// statusCode=304. This is a *successful* outcome.
|
|
147
|
+
if (statusCode) {
|
|
148
|
+
span._setOutcomeFromHttpStatusCode(statusCode);
|
|
149
|
+
} else {
|
|
150
|
+
// `statusCode` will be undefined for errors before sending a request, e.g.:
|
|
151
|
+
// InvalidConfiguration: Custom endpoint is not compatible with access point ARN
|
|
152
|
+
span._setOutcomeFromErrorCapture(constants.OUTCOME_FAILURE);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (response.error && (!statusCode || statusCode >= 400)) {
|
|
156
|
+
agent.captureError(response.error, { skipOutcome: true });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
span.end();
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Run context notes: The `orig` should run in the context of the S3 span,
|
|
164
|
+
// because that is the point. The user's callback `cb` should run outside of
|
|
165
|
+
// the S3 span.
|
|
166
|
+
const parentRunContext = ins.currRunContext();
|
|
167
|
+
const spanRunContext = parentRunContext.enterSpan(span);
|
|
168
|
+
const cb = origArguments[origArguments.length - 1];
|
|
169
|
+
if (typeof cb === 'function') {
|
|
170
|
+
origArguments[origArguments.length - 1] = ins.bindFunctionToRunContext(
|
|
171
|
+
parentRunContext,
|
|
172
|
+
cb,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
request.on(
|
|
176
|
+
'complete',
|
|
177
|
+
ins.bindFunctionToRunContext(spanRunContext, onComplete),
|
|
178
|
+
);
|
|
179
|
+
return ins.withRunContext(spanRunContext, orig, request, ...origArguments);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = {
|
|
183
|
+
instrumentationS3,
|
|
184
|
+
};
|