@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,84 @@
|
|
|
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 microtime = require('relative-microtime');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Return `time`, if given and valid, or the current time (calculated using
|
|
13
|
+
* the given `timer`).
|
|
14
|
+
*
|
|
15
|
+
* @param {Timer} timer
|
|
16
|
+
* @param {Number} [time] - An optional float number of milliseconds since
|
|
17
|
+
* the epoch (i.e. the same as provided by `Date.now()`).
|
|
18
|
+
* @returns {Number} A time in *microseconds* since the Epoch.
|
|
19
|
+
*/
|
|
20
|
+
function maybeTime(timer, time) {
|
|
21
|
+
if (time >= 0) {
|
|
22
|
+
return time * 1000;
|
|
23
|
+
} else {
|
|
24
|
+
return timer._timer();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = class Timer {
|
|
29
|
+
// `startTime`: millisecond float
|
|
30
|
+
constructor(parentTimer, startTime) {
|
|
31
|
+
this._parent = parentTimer;
|
|
32
|
+
this._timer = parentTimer ? parentTimer._timer : microtime();
|
|
33
|
+
this.start = maybeTime(this, startTime); // microsecond integer (note: might not be an integer)
|
|
34
|
+
this.endTimestamp = null;
|
|
35
|
+
this.duration = null; // millisecond float
|
|
36
|
+
this.selfTime = null; // millisecond float
|
|
37
|
+
|
|
38
|
+
// Track child timings to produce self-time
|
|
39
|
+
this.activeChildren = 0;
|
|
40
|
+
this.childStart = 0;
|
|
41
|
+
this.childDuration = 0;
|
|
42
|
+
|
|
43
|
+
if (this._parent) {
|
|
44
|
+
this._parent.startChild(startTime);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
startChild(startTime) {
|
|
49
|
+
if (++this.activeChildren === 1) {
|
|
50
|
+
this.childStart = maybeTime(this, startTime);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
endChild(endTime) {
|
|
55
|
+
if (--this.activeChildren === 0) {
|
|
56
|
+
this.incrementChildDuration(endTime);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
incrementChildDuration(endTime) {
|
|
61
|
+
this.childDuration += (maybeTime(this, endTime) - this.childStart) / 1000;
|
|
62
|
+
this.childStart = 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// `endTime`: millisecond float
|
|
66
|
+
end(endTime) {
|
|
67
|
+
if (this.duration !== null) return;
|
|
68
|
+
this.duration = this.elapsed(endTime);
|
|
69
|
+
if (this.activeChildren) {
|
|
70
|
+
this.incrementChildDuration(endTime);
|
|
71
|
+
}
|
|
72
|
+
this.selfTime = this.duration - this.childDuration;
|
|
73
|
+
if (this._parent) {
|
|
74
|
+
this._parent.endChild(endTime);
|
|
75
|
+
}
|
|
76
|
+
this.endTimestamp = this._timer();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// `endTime`: millisecond float
|
|
80
|
+
// returns: millisecond float
|
|
81
|
+
elapsed(endTime) {
|
|
82
|
+
return (maybeTime(this, endTime) - this.start) / 1000;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
@@ -0,0 +1,571 @@
|
|
|
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 util = require('util');
|
|
10
|
+
|
|
11
|
+
var ObjectIdentityMap = require('object-identity-map');
|
|
12
|
+
|
|
13
|
+
const constants = require('../constants');
|
|
14
|
+
const { DroppedSpansStats } = require('./dropped-spans-stats');
|
|
15
|
+
var getPathFromRequest = require('./express-utils').getPathFromRequest;
|
|
16
|
+
var GenericSpan = require('./generic-span');
|
|
17
|
+
var parsers = require('../parsers');
|
|
18
|
+
var Span = require('./span');
|
|
19
|
+
var symbols = require('../symbols');
|
|
20
|
+
const {
|
|
21
|
+
TRACE_CONTINUATION_STRATEGY_CONTINUE,
|
|
22
|
+
TRACE_CONTINUATION_STRATEGY_RESTART,
|
|
23
|
+
TRACE_CONTINUATION_STRATEGY_RESTART_EXTERNAL,
|
|
24
|
+
} = require('../constants');
|
|
25
|
+
var { TransactionIds } = require('./ids');
|
|
26
|
+
const TraceState = require('../tracecontext/tracestate');
|
|
27
|
+
|
|
28
|
+
module.exports = Transaction;
|
|
29
|
+
util.inherits(Transaction, GenericSpan);
|
|
30
|
+
|
|
31
|
+
// Usage:
|
|
32
|
+
// new Transaction(agent)
|
|
33
|
+
// new Transaction(agent, name, opts?)
|
|
34
|
+
// new Transaction(agent, name, type?, opts?)
|
|
35
|
+
//
|
|
36
|
+
// @param {Agent} agent
|
|
37
|
+
// @param {string} [name]
|
|
38
|
+
// @param {string} [type] - Defaults to 'custom' when serialized.
|
|
39
|
+
// @param {Object} [opts]
|
|
40
|
+
// - opts.childOf - Used to determine the W3C trace-context trace id, parent
|
|
41
|
+
// id, and sampling information for this new transaction. This currently
|
|
42
|
+
// accepts a Transaction instance, Span instance, TraceParent instance, or
|
|
43
|
+
// a traceparent string. (Arguably any but the latter two are non-sensical
|
|
44
|
+
// for a new transaction.)
|
|
45
|
+
// - opts.tracestate - A W3C trace-context tracestate string.
|
|
46
|
+
// - Any other options supported by GenericSpan ...
|
|
47
|
+
function Transaction(agent, name, ...args) {
|
|
48
|
+
const opts =
|
|
49
|
+
typeof args[args.length - 1] === 'object' ? args.pop() || {} : {};
|
|
50
|
+
|
|
51
|
+
if (opts.timer) {
|
|
52
|
+
// Before 4.x this option could be passed in. It was never publicly documented.
|
|
53
|
+
delete opts.timer;
|
|
54
|
+
}
|
|
55
|
+
if (opts.tracestate) {
|
|
56
|
+
opts.tracestate = TraceState.fromStringFormatString(opts.tracestate);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (opts.childOf) {
|
|
60
|
+
// Possibly restart the trace, depending on `traceContinuationStrategy`.
|
|
61
|
+
// Spec: https://github.com/elastic/apm/blob/main/specs/agents/trace-continuation.md
|
|
62
|
+
let traceContinuationStrategy = agent._conf.traceContinuationStrategy;
|
|
63
|
+
if (
|
|
64
|
+
traceContinuationStrategy === TRACE_CONTINUATION_STRATEGY_RESTART_EXTERNAL
|
|
65
|
+
) {
|
|
66
|
+
traceContinuationStrategy = TRACE_CONTINUATION_STRATEGY_RESTART;
|
|
67
|
+
if (opts.tracestate && opts.tracestate.toMap().has('es')) {
|
|
68
|
+
traceContinuationStrategy = TRACE_CONTINUATION_STRATEGY_CONTINUE;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (traceContinuationStrategy === TRACE_CONTINUATION_STRATEGY_RESTART) {
|
|
72
|
+
if (!opts.links || !Array.isArray(opts.links)) {
|
|
73
|
+
opts.links = [];
|
|
74
|
+
}
|
|
75
|
+
opts.links.push({ context: opts.childOf });
|
|
76
|
+
delete opts.childOf; // restart the trace
|
|
77
|
+
delete opts.tracestate;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.type = null;
|
|
82
|
+
this.setType(...args);
|
|
83
|
+
|
|
84
|
+
GenericSpan.call(this, agent, opts);
|
|
85
|
+
|
|
86
|
+
const verb = this.parentId ? 'continue' : 'start';
|
|
87
|
+
agent.logger.debug('%s trace %o', verb, {
|
|
88
|
+
trans: this.id,
|
|
89
|
+
parent: this.parentId,
|
|
90
|
+
trace: this.traceId,
|
|
91
|
+
sampled: this.sampled,
|
|
92
|
+
name: this.name,
|
|
93
|
+
type: this.type,
|
|
94
|
+
traceparent: this.traceparent,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
this._defaultName = name || '';
|
|
98
|
+
this._customName = '';
|
|
99
|
+
this._user = null;
|
|
100
|
+
this._custom = null;
|
|
101
|
+
this._result = constants.RESULT_SUCCESS;
|
|
102
|
+
this._builtSpans = 0;
|
|
103
|
+
this._droppedSpans = 0;
|
|
104
|
+
this._breakdownTimings = new ObjectIdentityMap();
|
|
105
|
+
this._faas = undefined;
|
|
106
|
+
this._service = undefined;
|
|
107
|
+
this._message = undefined;
|
|
108
|
+
this._cloud = undefined;
|
|
109
|
+
this._droppedSpansStats = new DroppedSpansStats();
|
|
110
|
+
this.outcome = constants.OUTCOME_UNKNOWN;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
Object.defineProperty(Transaction.prototype, 'name', {
|
|
114
|
+
configurable: true,
|
|
115
|
+
enumerable: true,
|
|
116
|
+
get() {
|
|
117
|
+
// Fall back to a somewhat useful name in case no _defaultName is set.
|
|
118
|
+
// This might happen if res.writeHead wasn't called.
|
|
119
|
+
return (
|
|
120
|
+
this._customName ||
|
|
121
|
+
this._defaultName ||
|
|
122
|
+
(this.req ? this.req.method + ' unknown route (unnamed)' : 'unnamed')
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
set(name) {
|
|
126
|
+
if (this.ended) {
|
|
127
|
+
this._agent.logger.debug(
|
|
128
|
+
'tried to set transaction.name on already ended transaction %o',
|
|
129
|
+
{ trans: this.id, parent: this.parentId, trace: this.traceId },
|
|
130
|
+
);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
this._agent.logger.debug('setting transaction name %o', {
|
|
134
|
+
trans: this.id,
|
|
135
|
+
parent: this.parentId,
|
|
136
|
+
trace: this.traceId,
|
|
137
|
+
name,
|
|
138
|
+
});
|
|
139
|
+
this._customName = name;
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
Object.defineProperty(Transaction.prototype, 'result', {
|
|
144
|
+
configurable: true,
|
|
145
|
+
enumerable: true,
|
|
146
|
+
get() {
|
|
147
|
+
return this._result;
|
|
148
|
+
},
|
|
149
|
+
set(result) {
|
|
150
|
+
if (this.ended) {
|
|
151
|
+
this._agent.logger.debug(
|
|
152
|
+
'tried to set transaction.result on already ended transaction %o',
|
|
153
|
+
{ trans: this.id, parent: this.parentId, trace: this.traceId },
|
|
154
|
+
);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this._agent.logger.debug('setting transaction result %o', {
|
|
158
|
+
trans: this.id,
|
|
159
|
+
parent: this.parentId,
|
|
160
|
+
trace: this.traceId,
|
|
161
|
+
result,
|
|
162
|
+
});
|
|
163
|
+
this._result = result;
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
Object.defineProperty(Transaction.prototype, 'ids', {
|
|
168
|
+
get() {
|
|
169
|
+
return this._ids === null
|
|
170
|
+
? (this._ids = new TransactionIds(this))
|
|
171
|
+
: this._ids;
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
Transaction.prototype.setType = function (type = null) {
|
|
176
|
+
this.type = type || constants.DEFAULT_SPAN_TYPE;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* A string representation of the transaction to help with internal debugging.
|
|
181
|
+
* This is not a promised interface.
|
|
182
|
+
*/
|
|
183
|
+
Transaction.prototype.toString = function () {
|
|
184
|
+
return `Transaction(${this.id}, '${this.name}'${
|
|
185
|
+
this.ended ? ', ended' : ''
|
|
186
|
+
})`;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
Transaction.prototype.setUserContext = function (context) {
|
|
190
|
+
if (!context) return;
|
|
191
|
+
this._user = Object.assign(this._user || {}, context);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
Transaction.prototype.setServiceContext = function (serviceContext) {
|
|
195
|
+
if (!serviceContext) return;
|
|
196
|
+
this._service = Object.assign(this._service || {}, serviceContext);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
Transaction.prototype.setMessageContext = function (messageContext) {
|
|
200
|
+
if (!messageContext) return;
|
|
201
|
+
this._message = Object.assign(this._message || {}, messageContext);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
Transaction.prototype.setFaas = function (faasFields) {
|
|
205
|
+
if (!faasFields) return;
|
|
206
|
+
this._faas = Object.assign(this._faas || {}, faasFields);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
Transaction.prototype.setCustomContext = function (context) {
|
|
210
|
+
if (!context) return;
|
|
211
|
+
this._custom = Object.assign(this._custom || {}, context);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
Transaction.prototype.setCloudContext = function (cloudContext) {
|
|
215
|
+
if (!cloudContext) return;
|
|
216
|
+
this._cloud = Object.assign(this._cloud || {}, cloudContext);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Create a span on this transaction and make it the current span.
|
|
220
|
+
Transaction.prototype.startSpan = function (...args) {
|
|
221
|
+
const span = this.createSpan(...args);
|
|
222
|
+
if (span) {
|
|
223
|
+
this._agent._instrumentation.supersedeWithSpanRunContext(span);
|
|
224
|
+
}
|
|
225
|
+
return span;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Create a span on this transaction.
|
|
229
|
+
//
|
|
230
|
+
// This does *not* replace the current run context to make this span the
|
|
231
|
+
// "current" one. This allows instrumentations to avoid impacting the run
|
|
232
|
+
// context of the calling code. Compare to `startSpan`.
|
|
233
|
+
Transaction.prototype.createSpan = function (...args) {
|
|
234
|
+
if (!this.sampled) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Exit spans must not have child spans (unless of the same type and subtype).
|
|
239
|
+
// https://github.com/elastic/apm/blob/master/specs/agents/tracing-spans.md#child-spans-of-exit-spans
|
|
240
|
+
const opts =
|
|
241
|
+
typeof args[args.length - 1] === 'object' ? args.pop() || {} : {};
|
|
242
|
+
const [_name, type, subtype] = args; // eslint-disable-line no-unused-vars
|
|
243
|
+
opts.childOf =
|
|
244
|
+
opts.childOf || this._agent._instrumentation.currSpan() || this;
|
|
245
|
+
const childOf = opts.childOf;
|
|
246
|
+
if (
|
|
247
|
+
childOf instanceof Span &&
|
|
248
|
+
childOf._exitSpan &&
|
|
249
|
+
!(childOf.type === type && childOf.subtype === subtype)
|
|
250
|
+
) {
|
|
251
|
+
this._agent.logger.trace(
|
|
252
|
+
{ exitSpanId: childOf.id, newSpanArgs: args },
|
|
253
|
+
'createSpan: drop child span of exit span',
|
|
254
|
+
);
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const span = new Span(this, ...args, opts);
|
|
259
|
+
|
|
260
|
+
if (this._builtSpans >= this._agent._conf.transactionMaxSpans) {
|
|
261
|
+
this._droppedSpans++;
|
|
262
|
+
span.setRecorded(false);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
this._builtSpans++;
|
|
266
|
+
return span;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Note that this only returns a complete result when called *during* the call
|
|
270
|
+
// to `transaction.end()`.
|
|
271
|
+
Transaction.prototype.toJSON = function () {
|
|
272
|
+
var payload = {
|
|
273
|
+
id: this.id,
|
|
274
|
+
trace_id: this.traceId,
|
|
275
|
+
parent_id: this.parentId,
|
|
276
|
+
name: this.name,
|
|
277
|
+
type: this.type || constants.DEFAULT_SPAN_TYPE,
|
|
278
|
+
duration: this._duration,
|
|
279
|
+
timestamp: this.timestamp,
|
|
280
|
+
result: String(this.result),
|
|
281
|
+
sampled: this.sampled,
|
|
282
|
+
context: undefined,
|
|
283
|
+
span_count: {
|
|
284
|
+
started: this._builtSpans - this._droppedSpans,
|
|
285
|
+
},
|
|
286
|
+
outcome: this.outcome,
|
|
287
|
+
faas: this._faas,
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
if (this.sampled) {
|
|
291
|
+
payload.context = {
|
|
292
|
+
user: Object.assign(
|
|
293
|
+
{},
|
|
294
|
+
this.req && parsers.getUserContextFromRequest(this.req),
|
|
295
|
+
this._user,
|
|
296
|
+
),
|
|
297
|
+
tags: this._labels || {},
|
|
298
|
+
custom: this._custom || {},
|
|
299
|
+
service: this._service || {},
|
|
300
|
+
cloud: this._cloud || {},
|
|
301
|
+
message: this._message || {},
|
|
302
|
+
};
|
|
303
|
+
// Only include dropped count when spans have been dropped.
|
|
304
|
+
if (this._droppedSpans > 0) {
|
|
305
|
+
payload.span_count.dropped = this._droppedSpans;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
var conf = this._agent._conf;
|
|
309
|
+
if (this.req) {
|
|
310
|
+
payload.context.request = parsers.getContextFromRequest(
|
|
311
|
+
this.req,
|
|
312
|
+
conf,
|
|
313
|
+
'transactions',
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
if (this.res) {
|
|
317
|
+
payload.context.response = parsers.getContextFromResponse(this.res, conf);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// add sample_rate to transaction
|
|
322
|
+
// https://github.com/elastic/apm/blob/main/specs/agents/tracing-sampling.md
|
|
323
|
+
// Only set sample_rate on transaction payload if a valid trace state
|
|
324
|
+
// variable is set.
|
|
325
|
+
//
|
|
326
|
+
// "If there is no tracestate or no valid es entry with an s attribute,
|
|
327
|
+
// then the agent must omit sample_rate from non-root transactions and
|
|
328
|
+
// their spans."
|
|
329
|
+
const sampleRate = this.sampleRate;
|
|
330
|
+
if (sampleRate !== null) {
|
|
331
|
+
payload.sample_rate = sampleRate;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
this._serializeOTel(payload);
|
|
335
|
+
|
|
336
|
+
if (this._links.length > 0) {
|
|
337
|
+
payload.links = this._links;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (this._droppedSpansStats.size() > 0) {
|
|
341
|
+
payload.dropped_spans_stats = this._droppedSpansStats.encode();
|
|
342
|
+
}
|
|
343
|
+
return payload;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// Note that this only returns a complete result when called *during* the call
|
|
347
|
+
// to `transaction.end()`.
|
|
348
|
+
Transaction.prototype._encode = function () {
|
|
349
|
+
if (!this.ended) {
|
|
350
|
+
this._agent.logger.error('cannot encode un-ended transaction: %o', {
|
|
351
|
+
trans: this.id,
|
|
352
|
+
parent: this.parentId,
|
|
353
|
+
trace: this.traceId,
|
|
354
|
+
});
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return this.toJSON();
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
Transaction.prototype.setDefaultName = function (name) {
|
|
362
|
+
this._agent.logger.debug('setting default transaction name: %s %o', name, {
|
|
363
|
+
trans: this.id,
|
|
364
|
+
parent: this.parentId,
|
|
365
|
+
trace: this.traceId,
|
|
366
|
+
});
|
|
367
|
+
this._defaultName = name;
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
Transaction.prototype.setDefaultNameFromRequest = function () {
|
|
371
|
+
var req = this.req;
|
|
372
|
+
var path = getPathFromRequest(
|
|
373
|
+
req,
|
|
374
|
+
false,
|
|
375
|
+
this._agent._conf.usePathAsTransactionName,
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
if (!path) {
|
|
379
|
+
this._agent.logger.debug('could not extract route name from request %o', {
|
|
380
|
+
url: req.url,
|
|
381
|
+
type: typeof path,
|
|
382
|
+
null: path === null, // because typeof null === 'object'
|
|
383
|
+
route: !!req.route,
|
|
384
|
+
regex: req.route ? !!req.route.regexp : false,
|
|
385
|
+
mountstack: req[symbols.expressMountStack]
|
|
386
|
+
? req[symbols.expressMountStack].length
|
|
387
|
+
: false,
|
|
388
|
+
trans: this.id,
|
|
389
|
+
parent: this.parentId,
|
|
390
|
+
trace: this.traceId,
|
|
391
|
+
});
|
|
392
|
+
path = 'unknown route';
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
this.setDefaultName(req.method + ' ' + path);
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
Transaction.prototype.ensureParentId = function () {
|
|
399
|
+
return this._context.ensureParentId();
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
Transaction.prototype.end = function (result, endTime) {
|
|
403
|
+
if (this.ended) {
|
|
404
|
+
this._agent.logger.debug(
|
|
405
|
+
'tried to call transaction.end() on already ended transaction %o',
|
|
406
|
+
{ trans: this.id, parent: this.parentId, trace: this.traceId },
|
|
407
|
+
);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (result !== undefined && result !== null) {
|
|
412
|
+
this.result = result;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!this._defaultName && this.req) this.setDefaultNameFromRequest();
|
|
416
|
+
|
|
417
|
+
this._timer.end(endTime);
|
|
418
|
+
this._duration = this._timer.duration;
|
|
419
|
+
this._captureBreakdown(this);
|
|
420
|
+
this.ended = true;
|
|
421
|
+
|
|
422
|
+
this._agent._instrumentation.addEndedTransaction(this);
|
|
423
|
+
this._agent.logger.debug(
|
|
424
|
+
{
|
|
425
|
+
trans: this.id,
|
|
426
|
+
name: this.name,
|
|
427
|
+
parent: this.parentId,
|
|
428
|
+
trace: this.traceId,
|
|
429
|
+
type: this.type,
|
|
430
|
+
result: this.result,
|
|
431
|
+
duration: this._duration,
|
|
432
|
+
},
|
|
433
|
+
'ended transaction',
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
// Reduce this transaction's memory usage by dropping references except to
|
|
437
|
+
// fields required to support `interface Transaction`.
|
|
438
|
+
// Transaction fields:
|
|
439
|
+
this._customName = this.name; // Short-circuit the `name` getter.
|
|
440
|
+
this._defaultName = '';
|
|
441
|
+
this.req = null;
|
|
442
|
+
this.res = null;
|
|
443
|
+
this._user = null;
|
|
444
|
+
this._custom = null;
|
|
445
|
+
this._breakdownTimings = null;
|
|
446
|
+
this._faas = undefined;
|
|
447
|
+
this._service = undefined;
|
|
448
|
+
this._message = undefined;
|
|
449
|
+
this._cloud = undefined;
|
|
450
|
+
// GenericSpan fields:
|
|
451
|
+
// - Cannot drop `this._context` because it is used for `traceparent`, `ids`,
|
|
452
|
+
// and `.sampled` (when capturing breakdown metrics for child spans).
|
|
453
|
+
this._timer = null;
|
|
454
|
+
this._labels = null;
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
Transaction.prototype.setOutcome = function (outcome) {
|
|
458
|
+
if (!this._isValidOutcome(outcome)) {
|
|
459
|
+
this._agent.logger.trace(
|
|
460
|
+
'Unknown outcome [%s] seen in Transaction.setOutcome, ignoring',
|
|
461
|
+
outcome,
|
|
462
|
+
);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (this.ended) {
|
|
467
|
+
this._agent.logger.debug(
|
|
468
|
+
'tried to call Transaction.setOutcome() on already ended transaction %o',
|
|
469
|
+
{ trans: this.id, parent: this.parentId, trace: this.traceId },
|
|
470
|
+
);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
this._freezeOutcome();
|
|
475
|
+
this.outcome = outcome;
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
Transaction.prototype._setOutcomeFromHttpStatusCode = function (statusCode) {
|
|
479
|
+
// if an outcome's been set from the API we
|
|
480
|
+
// honor its value
|
|
481
|
+
if (this._isOutcomeFrozen) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (statusCode >= 500) {
|
|
486
|
+
this.outcome = constants.OUTCOME_FAILURE;
|
|
487
|
+
} else {
|
|
488
|
+
this.outcome = constants.OUTCOME_SUCCESS;
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
Transaction.prototype._captureBreakdown = function (span) {
|
|
493
|
+
if (this.ended) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const agent = this._agent;
|
|
498
|
+
const metrics = agent._metrics;
|
|
499
|
+
const conf = agent._conf;
|
|
500
|
+
|
|
501
|
+
// Avoid unneeded breakdown metrics processing if only propagating trace context.
|
|
502
|
+
if (conf.contextPropagationOnly) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Record span data
|
|
507
|
+
if (this.sampled && conf.breakdownMetrics) {
|
|
508
|
+
captureBreakdown(
|
|
509
|
+
this,
|
|
510
|
+
{
|
|
511
|
+
transaction: transactionBreakdownDetails(this),
|
|
512
|
+
span: spanBreakdownDetails(span),
|
|
513
|
+
},
|
|
514
|
+
span._timer.selfTime,
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Record transaction data
|
|
519
|
+
if (span instanceof Transaction) {
|
|
520
|
+
for (const { labels, time, count } of this._breakdownTimings.values()) {
|
|
521
|
+
const flattenedLabels = flattenBreakdown(labels);
|
|
522
|
+
metrics.incrementCounter('span.self_time.count', flattenedLabels, count);
|
|
523
|
+
metrics.incrementCounter('span.self_time.sum.us', flattenedLabels, time);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
Transaction.prototype.captureDroppedSpan = function (span) {
|
|
529
|
+
return this._droppedSpansStats.captureDroppedSpan(span);
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
function transactionBreakdownDetails({ name, type } = {}) {
|
|
533
|
+
return {
|
|
534
|
+
name,
|
|
535
|
+
type,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function spanBreakdownDetails(span) {
|
|
540
|
+
if (span instanceof Transaction) {
|
|
541
|
+
return {
|
|
542
|
+
type: 'app',
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const { type, subtype } = span;
|
|
547
|
+
return {
|
|
548
|
+
type,
|
|
549
|
+
subtype,
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function captureBreakdown(transaction, labels, time) {
|
|
554
|
+
const build = () => ({ labels, count: 0, time: 0 });
|
|
555
|
+
const counter = transaction._breakdownTimings.ensure(labels, build);
|
|
556
|
+
counter.time += time;
|
|
557
|
+
counter.count++;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function flattenBreakdown(source, target = {}, prefix = '') {
|
|
561
|
+
for (const [key, value] of Object.entries(source)) {
|
|
562
|
+
if (typeof value === 'undefined' || value === null) continue;
|
|
563
|
+
if (typeof value === 'object') {
|
|
564
|
+
flattenBreakdown(value, target, `${prefix}${key}::`);
|
|
565
|
+
} else {
|
|
566
|
+
target[`${prefix}${key}`] = value;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return target;
|
|
571
|
+
}
|