@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.
Files changed (154) hide show
  1. package/LICENSE +26 -0
  2. package/NOTICE.md +442 -0
  3. package/README.md +48 -0
  4. package/changes.json +78 -0
  5. package/index.d.ts +398 -0
  6. package/index.js +11 -0
  7. package/lib/InflightEventSet.js +53 -0
  8. package/lib/activation-method.js +119 -0
  9. package/lib/agent.js +941 -0
  10. package/lib/apm-client/apm-client.js +313 -0
  11. package/lib/apm-client/http-apm-client/CHANGELOG.md +271 -0
  12. package/lib/apm-client/http-apm-client/README.md +485 -0
  13. package/lib/apm-client/http-apm-client/central-config.js +41 -0
  14. package/lib/apm-client/http-apm-client/container-info.js +111 -0
  15. package/lib/apm-client/http-apm-client/detect-hostname.js +96 -0
  16. package/lib/apm-client/http-apm-client/index.js +1975 -0
  17. package/lib/apm-client/http-apm-client/logging.js +31 -0
  18. package/lib/apm-client/http-apm-client/ndjson.js +20 -0
  19. package/lib/apm-client/http-apm-client/truncate.js +434 -0
  20. package/lib/apm-client/noop-apm-client.js +73 -0
  21. package/lib/async-hooks-polyfill.js +58 -0
  22. package/lib/cloud-metadata/aws.js +175 -0
  23. package/lib/cloud-metadata/azure.js +123 -0
  24. package/lib/cloud-metadata/callback-coordination.js +159 -0
  25. package/lib/cloud-metadata/gcp.js +133 -0
  26. package/lib/cloud-metadata/index.js +175 -0
  27. package/lib/config/config.js +458 -0
  28. package/lib/config/normalizers.js +701 -0
  29. package/lib/config/schema.js +1007 -0
  30. package/lib/constants.js +35 -0
  31. package/lib/errors.js +303 -0
  32. package/lib/filters/sanitize-field-names.js +69 -0
  33. package/lib/http-request.js +249 -0
  34. package/lib/instrumentation/azure-functions.js +519 -0
  35. package/lib/instrumentation/context.js +56 -0
  36. package/lib/instrumentation/dropped-spans-stats.js +112 -0
  37. package/lib/instrumentation/elasticsearch-shared.js +63 -0
  38. package/lib/instrumentation/express-utils.js +91 -0
  39. package/lib/instrumentation/generic-span.js +322 -0
  40. package/lib/instrumentation/http-shared.js +424 -0
  41. package/lib/instrumentation/ids.js +39 -0
  42. package/lib/instrumentation/index.js +1127 -0
  43. package/lib/instrumentation/modules/@apollo/server.js +30 -0
  44. package/lib/instrumentation/modules/@aws-sdk/client-dynamodb.js +143 -0
  45. package/lib/instrumentation/modules/@aws-sdk/client-s3.js +230 -0
  46. package/lib/instrumentation/modules/@aws-sdk/client-sns.js +197 -0
  47. package/lib/instrumentation/modules/@aws-sdk/client-sqs.js +336 -0
  48. package/lib/instrumentation/modules/@elastic/elasticsearch.js +343 -0
  49. package/lib/instrumentation/modules/@hapi/hapi.js +221 -0
  50. package/lib/instrumentation/modules/@opentelemetry/api.js +86 -0
  51. package/lib/instrumentation/modules/@opentelemetry/sdk-metrics.js +79 -0
  52. package/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js +178 -0
  53. package/lib/instrumentation/modules/@redis/client/dist/lib/client/index.js +49 -0
  54. package/lib/instrumentation/modules/@smithy/smithy-client.js +198 -0
  55. package/lib/instrumentation/modules/_lambda-handler.js +40 -0
  56. package/lib/instrumentation/modules/apollo-server-core.js +49 -0
  57. package/lib/instrumentation/modules/aws-sdk/dynamodb.js +155 -0
  58. package/lib/instrumentation/modules/aws-sdk/s3.js +184 -0
  59. package/lib/instrumentation/modules/aws-sdk/sns.js +232 -0
  60. package/lib/instrumentation/modules/aws-sdk/sqs.js +361 -0
  61. package/lib/instrumentation/modules/aws-sdk.js +76 -0
  62. package/lib/instrumentation/modules/bluebird.js +93 -0
  63. package/lib/instrumentation/modules/cassandra-driver.js +280 -0
  64. package/lib/instrumentation/modules/elasticsearch.js +191 -0
  65. package/lib/instrumentation/modules/express-graphql.js +66 -0
  66. package/lib/instrumentation/modules/express-queue.js +28 -0
  67. package/lib/instrumentation/modules/express.js +162 -0
  68. package/lib/instrumentation/modules/fastify.js +172 -0
  69. package/lib/instrumentation/modules/finalhandler.js +41 -0
  70. package/lib/instrumentation/modules/generic-pool.js +85 -0
  71. package/lib/instrumentation/modules/graphql.js +256 -0
  72. package/lib/instrumentation/modules/handlebars.js +22 -0
  73. package/lib/instrumentation/modules/http.js +112 -0
  74. package/lib/instrumentation/modules/http2.js +320 -0
  75. package/lib/instrumentation/modules/https.js +68 -0
  76. package/lib/instrumentation/modules/ioredis.js +94 -0
  77. package/lib/instrumentation/modules/jade.js +18 -0
  78. package/lib/instrumentation/modules/kafkajs.js +476 -0
  79. package/lib/instrumentation/modules/knex.js +91 -0
  80. package/lib/instrumentation/modules/koa-router.js +74 -0
  81. package/lib/instrumentation/modules/koa.js +15 -0
  82. package/lib/instrumentation/modules/memcached.js +99 -0
  83. package/lib/instrumentation/modules/mimic-response.js +45 -0
  84. package/lib/instrumentation/modules/mongodb/lib/cmap/connection_pool.js +40 -0
  85. package/lib/instrumentation/modules/mongodb-core.js +206 -0
  86. package/lib/instrumentation/modules/mongodb.js +259 -0
  87. package/lib/instrumentation/modules/mysql.js +200 -0
  88. package/lib/instrumentation/modules/mysql2.js +140 -0
  89. package/lib/instrumentation/modules/pg.js +148 -0
  90. package/lib/instrumentation/modules/pug.js +18 -0
  91. package/lib/instrumentation/modules/redis.js +176 -0
  92. package/lib/instrumentation/modules/restify.js +52 -0
  93. package/lib/instrumentation/modules/tedious.js +159 -0
  94. package/lib/instrumentation/modules/undici.js +270 -0
  95. package/lib/instrumentation/modules/ws.js +59 -0
  96. package/lib/instrumentation/noop-transaction.js +81 -0
  97. package/lib/instrumentation/run-context/AbstractRunContextManager.js +215 -0
  98. package/lib/instrumentation/run-context/AsyncHooksRunContextManager.js +106 -0
  99. package/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js +73 -0
  100. package/lib/instrumentation/run-context/BasicRunContextManager.js +82 -0
  101. package/lib/instrumentation/run-context/RunContext.js +151 -0
  102. package/lib/instrumentation/run-context/index.js +23 -0
  103. package/lib/instrumentation/shimmer.js +123 -0
  104. package/lib/instrumentation/span-compression.js +239 -0
  105. package/lib/instrumentation/span.js +621 -0
  106. package/lib/instrumentation/template-shared.js +43 -0
  107. package/lib/instrumentation/timer.js +84 -0
  108. package/lib/instrumentation/transaction.js +571 -0
  109. package/lib/lambda.js +992 -0
  110. package/lib/load-source-map.js +100 -0
  111. package/lib/logging.js +212 -0
  112. package/lib/metrics/index.js +92 -0
  113. package/lib/metrics/platforms/generic/index.js +40 -0
  114. package/lib/metrics/platforms/generic/process-cpu.js +22 -0
  115. package/lib/metrics/platforms/generic/process-top.js +157 -0
  116. package/lib/metrics/platforms/generic/stats.js +34 -0
  117. package/lib/metrics/platforms/generic/system-cpu.js +51 -0
  118. package/lib/metrics/platforms/linux/index.js +19 -0
  119. package/lib/metrics/platforms/linux/stats.js +213 -0
  120. package/lib/metrics/queue.js +90 -0
  121. package/lib/metrics/registry.js +52 -0
  122. package/lib/metrics/reporter.js +119 -0
  123. package/lib/metrics/runtime.js +77 -0
  124. package/lib/middleware/connect.js +16 -0
  125. package/lib/opentelemetry-bridge/OTelBridgeNonRecordingSpan.js +150 -0
  126. package/lib/opentelemetry-bridge/OTelBridgeRunContext.js +124 -0
  127. package/lib/opentelemetry-bridge/OTelContextManager.js +82 -0
  128. package/lib/opentelemetry-bridge/OTelSpan.js +344 -0
  129. package/lib/opentelemetry-bridge/OTelTracer.js +201 -0
  130. package/lib/opentelemetry-bridge/OTelTracerProvider.js +25 -0
  131. package/lib/opentelemetry-bridge/README.md +244 -0
  132. package/lib/opentelemetry-bridge/index.js +15 -0
  133. package/lib/opentelemetry-bridge/oblog.js +23 -0
  134. package/lib/opentelemetry-bridge/opentelemetry-core-mini/README.md +3 -0
  135. package/lib/opentelemetry-bridge/opentelemetry-core-mini/internal/validators.js +52 -0
  136. package/lib/opentelemetry-bridge/opentelemetry-core-mini/trace/TraceState.js +109 -0
  137. package/lib/opentelemetry-bridge/otelutils.js +99 -0
  138. package/lib/opentelemetry-bridge/setup.js +76 -0
  139. package/lib/opentelemetry-metrics/ElasticApmMetricExporter.js +285 -0
  140. package/lib/opentelemetry-metrics/index.js +50 -0
  141. package/lib/parsers.js +225 -0
  142. package/lib/propwrap.js +147 -0
  143. package/lib/stacktraces.js +537 -0
  144. package/lib/symbols.js +15 -0
  145. package/lib/tracecontext/index.js +118 -0
  146. package/lib/tracecontext/traceparent.js +185 -0
  147. package/lib/tracecontext/tracestate.js +388 -0
  148. package/lib/wildcard-matcher.js +52 -0
  149. package/loader.mjs +7 -0
  150. package/package.json +299 -0
  151. package/start.d.ts +8 -0
  152. package/start.js +29 -0
  153. package/types/aws-lambda.d.ts +98 -0
  154. package/types/connect.d.ts +23 -0
@@ -0,0 +1,621 @@
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 { executionAsyncId } = require('async_hooks');
10
+ const { URL } = require('url');
11
+ var util = require('util');
12
+
13
+ var Value = require('async-value-promise');
14
+
15
+ const constants = require('../constants');
16
+ var GenericSpan = require('./generic-span');
17
+ var { SpanIds } = require('./ids');
18
+ const { gatherStackTrace } = require('../stacktraces');
19
+
20
+ const TEST = process.env.ELASTIC_APM_TEST;
21
+
22
+ module.exports = Span;
23
+
24
+ util.inherits(Span, GenericSpan);
25
+
26
+ // new Span(transaction)
27
+ // new Span(transaction, name?, opts?)
28
+ // new Span(transaction, name?, type?, opts?)
29
+ // new Span(transaction, name?, type?, subtype?, opts?)
30
+ // new Span(transaction, name?, type?, subtype?, action?, opts?)
31
+ function Span(transaction, ...args) {
32
+ const opts =
33
+ typeof args[args.length - 1] === 'object' ? args.pop() || {} : {};
34
+ const [name, ...tsaArgs] = args; // "tsa" === Type, Subtype, Action
35
+
36
+ if (opts.timer) {
37
+ // Before 4.x this option could be passed in. It was never publicly documented.
38
+ delete opts.timer;
39
+ }
40
+ if (!opts.childOf) {
41
+ const defaultChildOf =
42
+ transaction._agent._instrumentation.currSpan() || transaction;
43
+ opts.childOf = defaultChildOf;
44
+ opts.timer = defaultChildOf._timer;
45
+ } else if (opts.childOf._timer) {
46
+ opts.timer = opts.childOf._timer;
47
+ }
48
+
49
+ this._exitSpan = !!opts.exitSpan;
50
+ this.discardable = this._exitSpan;
51
+
52
+ delete opts.exitSpan;
53
+
54
+ this.type = null;
55
+ this.subtype = null;
56
+ this.action = null;
57
+ this.setType(...tsaArgs);
58
+
59
+ GenericSpan.call(this, transaction._agent, opts);
60
+
61
+ this._db = null;
62
+ this._http = null;
63
+ this._destination = null;
64
+ this._serviceTarget = null;
65
+ this._excludeServiceTarget = false;
66
+ this._message = null;
67
+ this._stackObj = null;
68
+ this._capturedStackTrace = null;
69
+ this.sync = true;
70
+ this._startXid = executionAsyncId();
71
+
72
+ this.transaction = transaction;
73
+ this.name = name || 'unnamed';
74
+
75
+ if (this._agent._conf.spanStackTraceMinDuration >= 0) {
76
+ this._recordStackTrace();
77
+ }
78
+
79
+ this._agent.logger.debug('start span %o', {
80
+ span: this.id,
81
+ parent: this.parentId,
82
+ trace: this.traceId,
83
+ name: this.name,
84
+ type: this.type,
85
+ subtype: this.subtype,
86
+ action: this.action,
87
+ });
88
+ }
89
+
90
+ Object.defineProperty(Span.prototype, 'ids', {
91
+ get() {
92
+ return this._ids === null ? (this._ids = new SpanIds(this)) : this._ids;
93
+ },
94
+ });
95
+
96
+ Span.prototype.setType = function (type = null, subtype = null, action = null) {
97
+ this.type = type || constants.DEFAULT_SPAN_TYPE;
98
+ this.subtype = subtype;
99
+ this.action = action;
100
+ };
101
+
102
+ /*
103
+ * A string representation of the span to help with internal debugging. This
104
+ * is not a promised interface.
105
+ */
106
+ Span.prototype.toString = function () {
107
+ return `Span(${this.id}, '${this.name}'${this.ended ? ', ended' : ''})`;
108
+ };
109
+
110
+ Span.prototype.customStackTrace = function (stackObj) {
111
+ this._agent.logger.debug('applying custom stack trace to span %o', {
112
+ span: this.id,
113
+ parent: this.parentId,
114
+ trace: this.traceId,
115
+ });
116
+ this._recordStackTrace(stackObj);
117
+ };
118
+
119
+ Span.prototype.end = function (endTime) {
120
+ if (this.ended) {
121
+ this._agent.logger.debug(
122
+ 'tried to call span.end() on already ended span %o',
123
+ {
124
+ span: this.id,
125
+ parent: this.parentId,
126
+ trace: this.traceId,
127
+ name: this.name,
128
+ type: this.type,
129
+ subtype: this.subtype,
130
+ action: this.action,
131
+ },
132
+ );
133
+ return;
134
+ }
135
+
136
+ this._timer.end(endTime);
137
+ this._endTimestamp = this._timer.endTimestamp;
138
+ this._duration = this._timer.duration;
139
+ if (executionAsyncId() !== this._startXid) {
140
+ this.sync = false;
141
+ }
142
+
143
+ this._setOutcomeFromSpanEnd();
144
+
145
+ this._inferServiceTargetAndDestinationService();
146
+
147
+ this.ended = true;
148
+ this._agent.logger.debug('ended span %o', {
149
+ span: this.id,
150
+ parent: this.parentId,
151
+ trace: this.traceId,
152
+ name: this.name,
153
+ type: this.type,
154
+ subtype: this.subtype,
155
+ action: this.action,
156
+ });
157
+
158
+ if (
159
+ this._capturedStackTrace !== null &&
160
+ this._agent._conf.spanStackTraceMinDuration >= 0 &&
161
+ this._duration / 1000 >= this._agent._conf.spanStackTraceMinDuration
162
+ ) {
163
+ // NOTE: This uses a promise-like thing and not a *real* promise
164
+ // because passing error stacks into a promise context makes it
165
+ // uncollectable by the garbage collector.
166
+ this._stackObj = new Value();
167
+ var self = this;
168
+ gatherStackTrace(
169
+ this._agent.logger,
170
+ this._capturedStackTrace,
171
+ this._agent._conf.sourceLinesSpanAppFrames,
172
+ this._agent._conf.sourceLinesSpanLibraryFrames,
173
+ TEST ? null : filterCallSite,
174
+ function (_err, stacktrace) {
175
+ // _err from gatherStackTrace is always null.
176
+ self._stackObj.resolve(stacktrace);
177
+ },
178
+ );
179
+ }
180
+
181
+ this._agent._instrumentation.addEndedSpan(this);
182
+ this.transaction._captureBreakdown(this);
183
+ };
184
+
185
+ Span.prototype._inferServiceTargetAndDestinationService = function () {
186
+ // `context.service.target.*` must be set for exit spans. There is a public
187
+ // `span.setServiceTarget(...)` for users to manually set this, but typically
188
+ // it is inferred from other span fields here.
189
+ // https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-service-target.md#field-values
190
+ if (this._excludeServiceTarget || !this._exitSpan) {
191
+ this._serviceTarget = null;
192
+ } else {
193
+ if (!this._serviceTarget) {
194
+ this._serviceTarget = {};
195
+ }
196
+ if (!('type' in this._serviceTarget)) {
197
+ this._serviceTarget.type =
198
+ this.subtype || this.type || constants.DEFAULT_SPAN_TYPE;
199
+ }
200
+ if (!('name' in this._serviceTarget)) {
201
+ if (this._db) {
202
+ if (this._db.instance) {
203
+ this._serviceTarget.name = this._db.instance;
204
+ }
205
+ } else if (this._message) {
206
+ if (this._message.queue && this._message.queue.name) {
207
+ this._serviceTarget.name = this._message.queue.name;
208
+ }
209
+ } else if (this._http && this._http.url) {
210
+ try {
211
+ const defaultPorts = { 'https:': '443', 'http:': '80' };
212
+ const url = new URL(this._http.url);
213
+ if (!url.port && defaultPorts[url.protocol]) {
214
+ this._serviceTarget.name = `${url.host}:${
215
+ defaultPorts[url.protocol]
216
+ }`;
217
+ } else {
218
+ this._serviceTarget.name = url.host;
219
+ }
220
+ } catch (invalidUrlErr) {
221
+ this._agent.logger.debug(
222
+ 'cannot set "service.target.name": %s (ignoring)',
223
+ invalidUrlErr,
224
+ );
225
+ }
226
+ }
227
+ }
228
+
229
+ // `destination.service.*` is deprecated, but still required for older
230
+ // APM servers.
231
+ if (!this._destination) {
232
+ this._destination = {};
233
+ }
234
+ if (!this._destination.service) {
235
+ this._destination.service = {};
236
+ }
237
+ // - `destination.service.{type,name}` could be skipped if the upstream APM server is known to be >=7.14.
238
+ this._destination.service.type = '';
239
+ this._destination.service.name = '';
240
+ // - Infer the now deprecated `context.destination.service.resource` value.
241
+ // https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-destination.md#destination-resource
242
+ if (!this._destination.service.resource) {
243
+ if (!this._serviceTarget.name) {
244
+ // If we only have `.type`, then use that.
245
+ this._destination.service.resource = this._serviceTarget.type;
246
+ } else if (!this._serviceTarget.type) {
247
+ // If we only have `.name`, then use that.
248
+ this._destination.service.resource = this._serviceTarget.name;
249
+ } else if (this.type === 'external') {
250
+ // Typically the "resource" value would now be "$type/$name", e.g.
251
+ // "mysql/customers". However, we want a special case for some spans (to
252
+ // have the same value as historically?) where we do NOT use the
253
+ // "$type/" prefix. One example is HTTP spans. Another is gRPC spans
254
+ // and, I infer from otel_bridge.feature, any OTel "rpc.system"-usage
255
+ // spans as well
256
+ // (https://opentelemetry.io/docs/reference/specification/trace/semantic_conventions/rpc/).
257
+ // Options to infer this from other span data:
258
+ // - Use the presence of "http" context, but without "db" and "message"
259
+ // context. This is a little brittle, and requires more complete OTel
260
+ // bridge compatibility mapping of OTel attributes than is currently
261
+ // being done.
262
+ // } else if (!this._db && !this._message && this._http && this._http.url) {
263
+ // - Use `span.subtype`: "http", "grpc", ... add others if/when they are
264
+ // used.
265
+ // - Use `span.type === "external"`. This, at least currently corresponds.
266
+ // Let's use this one.
267
+ this._destination.service.resource = this._serviceTarget.name;
268
+ } else {
269
+ this._destination.service.resource = `${this._serviceTarget.type}/${this._serviceTarget.name}`;
270
+ }
271
+ }
272
+ }
273
+ };
274
+
275
+ Span.prototype.setDbContext = function (context) {
276
+ if (!context) return;
277
+ this._db = Object.assign(this._db || {}, context);
278
+ };
279
+
280
+ Span.prototype.setHttpContext = function (context) {
281
+ if (!context) return;
282
+ this._http = Object.assign(this._http || {}, context);
283
+ };
284
+
285
+ /**
286
+ * This is deprecated and will be dropped in a future version. This was always
287
+ * an internal method, but possibly used by enterprising users of manual
288
+ * instrumentation.
289
+ *
290
+ * @deprecated Users should use the public `setServiceTarget()`.
291
+ * Internal APM agent code should use `_setDestinationContext()`.
292
+ */
293
+ Span.prototype.setDestinationContext = function (destCtx) {
294
+ process.emitWarning(
295
+ '<span>.setDestinationContext() was never a public API and will be removed, use <span>.setServiceTarget().',
296
+ 'DeprecationWarning',
297
+ 'ELASTIC_APM_SET_DESTINATION_CONTEXT',
298
+ );
299
+
300
+ if (destCtx.service && destCtx.service.resource) {
301
+ this.setServiceTarget('', destCtx.service.resource);
302
+ }
303
+ const destCtxWithoutService = Object.assign({}, destCtx);
304
+ delete destCtxWithoutService.service;
305
+ this._setDestinationContext(destCtxWithoutService);
306
+ };
307
+
308
+ /**
309
+ * The internal method for setting "destination" context.
310
+ *
311
+ * "destination.service.resource" should only ever be included for special
312
+ * cases. It is typically inferred from other fields via a general algorithm.
313
+ */
314
+ Span.prototype._setDestinationContext = function (destCtx) {
315
+ this._destination = Object.assign(this._destination || {}, destCtx);
316
+ };
317
+
318
+ /**
319
+ * Manually set the `service.target.type` and `service.target.name` fields that
320
+ * are used for service maps and the identification of downstream services. The
321
+ * values are only used for "exit" spans -- spans representing outgoing
322
+ * communication, marked with `exitSpan: true` at span creation.
323
+ *
324
+ * If false-y values (e.g. `null`) are given for both `type` and `name`, then
325
+ * `service.target` will explicitly be excluded from this span. This may impact
326
+ * Service Maps and other Kibana APM app reporting for this service.
327
+ *
328
+ * If this method is not called, values are inferred from other span fields per
329
+ * https://github.com/elastic/apm/blob/main/specs/agents/tracing-spans-service-target.md#field-values
330
+ *
331
+ * `service.target.*` fields are ignored for APM Server before v8.3.
332
+ *
333
+ * @param {string | null} type - service target type, usually same value as
334
+ * `span.subtype`
335
+ * @param {string | null} name - service target name: value depends on type,
336
+ * for databases it's usually the database name
337
+ */
338
+ Span.prototype.setServiceTarget = function (type, name) {
339
+ if (!type && !name) {
340
+ this._excludeServiceTarget = true;
341
+ this._serviceTarget = null;
342
+ return;
343
+ }
344
+
345
+ if (typeof type === 'string') {
346
+ this._excludeServiceTarget = false;
347
+ if (this._serviceTarget === null) {
348
+ this._serviceTarget = { type };
349
+ } else {
350
+ this._serviceTarget.type = type;
351
+ }
352
+ } else if (type != null) {
353
+ this._agent.logger.warn(
354
+ '"type" argument to Span#setServiceTarget must be of type "string", got type "%s": ignoring',
355
+ typeof type,
356
+ );
357
+ }
358
+ if (typeof name === 'string') {
359
+ this._excludeServiceTarget = false;
360
+ if (this._serviceTarget === null) {
361
+ this._serviceTarget = { name };
362
+ } else {
363
+ this._serviceTarget.name = name;
364
+ }
365
+ } else if (name != null) {
366
+ this._agent.logger.warn(
367
+ '"name" argument to Span#setServiceTarget must be of type "string", got type "%s": ignoring',
368
+ typeof name,
369
+ );
370
+ }
371
+ };
372
+
373
+ Span.prototype.setMessageContext = function (context) {
374
+ this._message = Object.assign(this._message || {}, context);
375
+ };
376
+
377
+ Span.prototype.setOutcome = function (outcome) {
378
+ if (!this._isValidOutcome(outcome)) {
379
+ this._agent.logger.trace(
380
+ 'Unknown outcome [%s] seen in Span.setOutcome, ignoring',
381
+ outcome,
382
+ );
383
+ return;
384
+ }
385
+
386
+ if (this.ended) {
387
+ this._agent.logger.debug(
388
+ 'tried to call Span.setOutcome() on already ended span %o',
389
+ {
390
+ span: this.id,
391
+ parent: this.parentId,
392
+ trace: this.traceId,
393
+ name: this.name,
394
+ type: this.type,
395
+ subtype: this.subtype,
396
+ action: this.action,
397
+ },
398
+ );
399
+ return;
400
+ }
401
+ this._freezeOutcome();
402
+ this._setOutcome(outcome);
403
+ };
404
+
405
+ Span.prototype._setOutcomeFromErrorCapture = function (outcome) {
406
+ if (this._isOutcomeFrozen) {
407
+ return;
408
+ }
409
+ this._setOutcome(outcome);
410
+ };
411
+
412
+ Span.prototype._setOutcomeFromHttpStatusCode = function (statusCode) {
413
+ if (this._isOutcomeFrozen) {
414
+ return;
415
+ }
416
+ /**
417
+ * The statusCode could be undefined for example if,
418
+ * the request is aborted before socket, in that case
419
+ * we keep the default 'unknown' value.
420
+ */
421
+ if (typeof statusCode !== 'undefined') {
422
+ if (statusCode >= 400) {
423
+ this._setOutcome(constants.OUTCOME_FAILURE);
424
+ } else {
425
+ this._setOutcome(constants.OUTCOME_SUCCESS);
426
+ }
427
+ }
428
+
429
+ this._freezeOutcome();
430
+ };
431
+
432
+ Span.prototype._setOutcomeFromSpanEnd = function () {
433
+ if (this.outcome === constants.OUTCOME_UNKNOWN && !this._isOutcomeFrozen) {
434
+ this._setOutcome(constants.OUTCOME_SUCCESS);
435
+ }
436
+ };
437
+
438
+ /**
439
+ * Central setting for outcome
440
+ *
441
+ * Enables "when outcome does X, Y should also happen" behaviors
442
+ */
443
+ Span.prototype._setOutcome = function (outcome) {
444
+ this.outcome = outcome;
445
+ if (outcome !== constants.OUTCOME_SUCCESS) {
446
+ this.discardable = false;
447
+ }
448
+ };
449
+
450
+ Span.prototype._recordStackTrace = function (obj) {
451
+ if (!obj) {
452
+ obj = {};
453
+ Error.captureStackTrace(obj, Span);
454
+ }
455
+ this._capturedStackTrace = obj;
456
+ };
457
+
458
+ Span.prototype._encode = function (cb) {
459
+ var self = this;
460
+
461
+ if (!this.ended) {
462
+ return cb(new Error('cannot encode un-ended span'));
463
+ }
464
+
465
+ const payload = {
466
+ id: self.id,
467
+ transaction_id: self.transaction.id,
468
+ parent_id: self.parentId,
469
+ trace_id: self.traceId,
470
+ name: self.name,
471
+ type: self.type || constants.DEFAULT_SPAN_TYPE,
472
+ subtype: self.subtype,
473
+ action: self.action,
474
+ timestamp: self.timestamp,
475
+ duration: self._duration,
476
+ context: undefined,
477
+ stacktrace: undefined,
478
+ sync: self.sync,
479
+ outcome: self.outcome,
480
+ };
481
+
482
+ // if a valid sample rate is set (truthy or zero), set the property
483
+ const sampleRate = self.sampleRate;
484
+ if (sampleRate !== null) {
485
+ payload.sample_rate = sampleRate;
486
+ }
487
+
488
+ let haveContext = false;
489
+ const context = {};
490
+ if (self._serviceTarget) {
491
+ context.service = { target: self._serviceTarget };
492
+ haveContext = true;
493
+ }
494
+ if (self._destination) {
495
+ context.destination = self._destination;
496
+ haveContext = true;
497
+ }
498
+ if (self._db) {
499
+ context.db = self._db;
500
+ haveContext = true;
501
+ }
502
+ if (self._message) {
503
+ context.message = self._message;
504
+ haveContext = true;
505
+ }
506
+ if (self._http) {
507
+ context.http = self._http;
508
+ haveContext = true;
509
+ }
510
+ if (self._labels) {
511
+ context.tags = self._labels;
512
+ haveContext = true;
513
+ }
514
+ if (haveContext) {
515
+ payload.context = context;
516
+ }
517
+
518
+ if (self.isComposite()) {
519
+ payload.composite = self._compression.encode();
520
+ payload.timestamp = self._compression.timestamp;
521
+ payload.duration = self._compression.duration;
522
+ }
523
+
524
+ this._serializeOTel(payload);
525
+
526
+ if (this._links.length > 0) {
527
+ payload.links = this._links;
528
+ }
529
+
530
+ if (this._stackObj) {
531
+ this._stackObj.then(
532
+ (value) => done(null, value),
533
+ (error) => done(error),
534
+ );
535
+ } else {
536
+ process.nextTick(done);
537
+ }
538
+
539
+ function done(err, frames) {
540
+ if (err) {
541
+ self._agent.logger.debug('could not capture stack trace for span %o', {
542
+ span: self.id,
543
+ parent: self.parentId,
544
+ trace: self.traceId,
545
+ name: self.name,
546
+ type: self.type,
547
+ subtype: self.subtype,
548
+ action: self.action,
549
+ err: err.message,
550
+ });
551
+ } else if (frames) {
552
+ payload.stacktrace = frames;
553
+ }
554
+
555
+ // Reduce this span's memory usage by dropping references once they're
556
+ // no longer needed. We also keep fields required to support
557
+ // `interface Span`.
558
+ // Span fields:
559
+ self._db = null;
560
+ self._http = null;
561
+ self._message = null;
562
+ self._capturedStackTrace = null;
563
+ // GenericSpan fields:
564
+ // - Cannot drop `this._context` because it is used for traceparent and ids.
565
+ self._timer = null;
566
+ self._labels = null;
567
+
568
+ cb(null, payload);
569
+ }
570
+ };
571
+
572
+ Span.prototype.isCompressionEligible = function () {
573
+ if (!this.getParentSpan()) {
574
+ return false;
575
+ }
576
+
577
+ if (
578
+ this.outcome !== constants.OUTCOME_UNKNOWN &&
579
+ this.outcome !== constants.OUTCOME_SUCCESS
580
+ ) {
581
+ return false;
582
+ }
583
+
584
+ if (!this._exitSpan) {
585
+ return false;
586
+ }
587
+
588
+ if (this._hasPropagatedTraceContext) {
589
+ return false;
590
+ }
591
+
592
+ return true;
593
+ };
594
+
595
+ Span.prototype.tryToCompress = function (spanToCompress) {
596
+ return this._compression.tryToCompress(this, spanToCompress);
597
+ };
598
+
599
+ Span.prototype.isRecorded = function () {
600
+ return this._context.isRecorded();
601
+ };
602
+
603
+ Span.prototype.setRecorded = function (value) {
604
+ return this._context.setRecorded(value);
605
+ };
606
+
607
+ Span.prototype.propagateTraceContextHeaders = function (carrier, setter) {
608
+ this.discardable = false;
609
+ return GenericSpan.prototype.propagateTraceContextHeaders.call(
610
+ this,
611
+ carrier,
612
+ setter,
613
+ );
614
+ };
615
+
616
+ function filterCallSite(callsite) {
617
+ var filename = callsite.getFileName();
618
+ return filename
619
+ ? filename.indexOf('/node_modules/elastic-apm-node/') === -1
620
+ : true;
621
+ }
@@ -0,0 +1,43 @@
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
+ exports.wrapCompile = function (agent, moduleName) {
10
+ function wrapTemplate(original) {
11
+ return function wrappedTemplate(data) {
12
+ var span = agent.startSpan(moduleName, 'template', moduleName, 'render');
13
+ var id = span && span.transaction.id;
14
+
15
+ agent.logger.debug('intercepted call to %s render %o', moduleName, {
16
+ id,
17
+ data,
18
+ });
19
+
20
+ var ret = original.apply(this, arguments);
21
+ if (span) span.end();
22
+
23
+ return ret;
24
+ };
25
+ }
26
+
27
+ return function wrappedCompile(original) {
28
+ return function wrappedCompile(input) {
29
+ var span = agent.startSpan(moduleName, 'template', moduleName, 'compile');
30
+ var id = span && span.transaction.id;
31
+
32
+ agent.logger.debug('intercepted call to %s compile %o', moduleName, {
33
+ id,
34
+ input,
35
+ });
36
+
37
+ var ret = original.apply(this, arguments);
38
+ if (span) span.end();
39
+
40
+ return typeof ret === 'function' ? wrapTemplate(ret) : ret;
41
+ };
42
+ };
43
+ };