dd-trace 5.104.0 → 5.106.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-3rdparty.csv +90 -102
- package/index.d.ts +82 -3
- package/package.json +15 -15
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +16 -2
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +19 -0
- package/packages/datadog-instrumentations/src/cucumber.js +390 -157
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -62
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +360 -150
- package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
- package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +515 -292
- package/packages/datadog-instrumentations/src/router.js +76 -32
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +218 -4
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -13
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +33 -40
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +1 -1
- package/packages/dd-trace/src/appsec/reporter.js +5 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
- package/packages/dd-trace/src/config/supported-configurations.json +27 -8
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/id.js +15 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +92 -6
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +43 -21
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +0 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +22 -3
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +64 -77
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +50 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +43 -5
- package/packages/dd-trace/src/plugins/util/test.js +236 -13
- package/packages/dd-trace/src/plugins/util/web.js +79 -65
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/config.js +10 -23
- package/packages/dd-trace/src/profiling/exporters/agent.js +11 -10
- package/packages/dd-trace/src/profiling/profiler.js +21 -11
- package/packages/dd-trace/src/profiling/profilers/wall.js +12 -7
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
|
@@ -10,16 +10,14 @@ const kinds = require('../../../../../ext/kinds')
|
|
|
10
10
|
const { ERROR_MESSAGE } = require('../../constants')
|
|
11
11
|
const TracingPlugin = require('../tracing')
|
|
12
12
|
const { storage } = require('../../../../datadog-core')
|
|
13
|
+
const legacyStorage = storage('legacy')
|
|
13
14
|
const urlFilter = require('./urlfilter')
|
|
14
15
|
const { createInferredProxySpan, finishInferredProxySpan } = require('./inferred_proxy')
|
|
15
16
|
const { extractURL, obfuscateQs, calculateHttpEndpoint } = require('./url')
|
|
16
17
|
|
|
17
|
-
let extractIp
|
|
18
|
-
|
|
19
18
|
const WEB = types.WEB
|
|
20
19
|
const SERVER = kinds.SERVER
|
|
21
20
|
const RESOURCE_NAME = tags.RESOURCE_NAME
|
|
22
|
-
const SERVICE_NAME = tags.SERVICE_NAME
|
|
23
21
|
const SPAN_TYPE = tags.SPAN_TYPE
|
|
24
22
|
const SPAN_KIND = tags.SPAN_KIND
|
|
25
23
|
const ERROR = tags.ERROR
|
|
@@ -35,7 +33,6 @@ const HTTP_CLIENT_IP = tags.HTTP_CLIENT_IP
|
|
|
35
33
|
const MANUAL_DROP = tags.MANUAL_DROP
|
|
36
34
|
|
|
37
35
|
const contexts = new WeakMap()
|
|
38
|
-
const ends = new WeakMap()
|
|
39
36
|
|
|
40
37
|
// TODO: change this to no longer rely on creating a dummy plugin to be able to access startSpan
|
|
41
38
|
function createWebPlugin (tracer, config = {}) {
|
|
@@ -67,7 +64,9 @@ const web = {
|
|
|
67
64
|
const middleware = getMiddlewareSetting(config)
|
|
68
65
|
const queryStringObfuscation = getQsObfuscator(config)
|
|
69
66
|
|
|
70
|
-
extractIp = config.clientIpEnabled
|
|
67
|
+
const extractIp = config.clientIpEnabled
|
|
68
|
+
? require('./ip_extractor').extractIp
|
|
69
|
+
: undefined
|
|
71
70
|
|
|
72
71
|
return {
|
|
73
72
|
...config,
|
|
@@ -77,6 +76,7 @@ const web = {
|
|
|
77
76
|
filter,
|
|
78
77
|
middleware,
|
|
79
78
|
queryStringObfuscation,
|
|
79
|
+
extractIp,
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
|
|
@@ -87,7 +87,7 @@ const web = {
|
|
|
87
87
|
if (!span) return
|
|
88
88
|
|
|
89
89
|
span.context()._name = `${name}.request`
|
|
90
|
-
span.context().
|
|
90
|
+
span.context().setTag('component', name)
|
|
91
91
|
span._integrationName = name
|
|
92
92
|
|
|
93
93
|
web.setConfig(req, config)
|
|
@@ -105,7 +105,7 @@ const web = {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
if (config.service) {
|
|
108
|
-
|
|
108
|
+
web.plugin.setServiceName(span, config.service)
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
analyticsSampler.sample(span, config.measured, true)
|
|
@@ -126,7 +126,6 @@ const web = {
|
|
|
126
126
|
context.tracer = tracer
|
|
127
127
|
context.span = span
|
|
128
128
|
context.res = res
|
|
129
|
-
context.store = storage('legacy').getStore()
|
|
130
129
|
|
|
131
130
|
this.setConfig(req, config)
|
|
132
131
|
addRequestTags(context, this.TYPE)
|
|
@@ -204,7 +203,7 @@ const web = {
|
|
|
204
203
|
startServerlessSpanWithInferredProxy (tracer, config, name, req, traceCtx) {
|
|
205
204
|
const headers = req.headers
|
|
206
205
|
const reqCtx = contexts.get(req)
|
|
207
|
-
const store =
|
|
206
|
+
const store = legacyStorage.getStore()
|
|
208
207
|
const pubsubSpan = store?.span?._name === 'pubsub.push.receive' ? store.span : null
|
|
209
208
|
|
|
210
209
|
let childOf = pubsubSpan || tracer.extract(FORMAT_HTTP_HEADERS, headers)
|
|
@@ -225,9 +224,11 @@ const web = {
|
|
|
225
224
|
const context = contexts.get(req)
|
|
226
225
|
const { span, inferredProxySpan, error } = context
|
|
227
226
|
|
|
228
|
-
const
|
|
227
|
+
const spanContext = span.context()
|
|
228
|
+
const spanHasExistingError = spanContext.getTag('error') || spanContext.getTag(ERROR_MESSAGE)
|
|
229
229
|
const inferredSpanContext = inferredProxySpan?.context()
|
|
230
|
-
const inferredSpanHasExistingError = inferredSpanContext?.
|
|
230
|
+
const inferredSpanHasExistingError = inferredSpanContext?.getTag('error') ||
|
|
231
|
+
inferredSpanContext?.getTag(ERROR_MESSAGE)
|
|
231
232
|
|
|
232
233
|
const isValidStatusCode = context.config.validateStatus(statusCode)
|
|
233
234
|
|
|
@@ -266,7 +267,16 @@ const web = {
|
|
|
266
267
|
|
|
267
268
|
if (context.finished && !req.stream) return
|
|
268
269
|
|
|
270
|
+
// `addRequestTags` is idempotent: in the normal HTTP path it ran during
|
|
271
|
+
// `web.startSpan`. Serverless callers (e.g. Azure Functions) skip
|
|
272
|
+
// `web.startSpan` and rely on this call to do the request-side work.
|
|
269
273
|
addRequestTags(context, spanType)
|
|
274
|
+
// Configured-header tagging runs at finish time. Framework plugins
|
|
275
|
+
// (connect, express, ...) install their own config via `setFramework`
|
|
276
|
+
// after `web.startSpan` has already locked the http-plugin config in;
|
|
277
|
+
// tagging earlier would use the http-plugin's `headers` list and drop
|
|
278
|
+
// the framework's.
|
|
279
|
+
addRequestHeaders(context)
|
|
270
280
|
addResponseTags(context)
|
|
271
281
|
|
|
272
282
|
context.config.hooks.request(context.span, req, res)
|
|
@@ -293,11 +303,18 @@ const web = {
|
|
|
293
303
|
const writeHead = res.writeHead
|
|
294
304
|
|
|
295
305
|
return function (statusCode, statusMessage, headers) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
306
|
+
// CORS preflight tagging only matters for OPTIONS requests. Skip the
|
|
307
|
+
// getHeaders() spread + isOriginAllowed work entirely for the common
|
|
308
|
+
// GET / POST / etc. case. Node's http module passes `req.method`
|
|
309
|
+
// through unchanged, so all standard methods are uppercase; the
|
|
310
|
+
// `toLowerCase` fallback covers any non-standard caller.
|
|
311
|
+
if (req.method === 'OPTIONS' || req.method.toLowerCase() === 'options') {
|
|
312
|
+
headers = typeof statusMessage === 'string' ? headers : statusMessage
|
|
313
|
+
headers = { ...res.getHeaders(), ...headers }
|
|
314
|
+
|
|
315
|
+
if (isOriginAllowed(req, headers)) {
|
|
316
|
+
addAllowHeaders(req, res, headers)
|
|
317
|
+
}
|
|
301
318
|
}
|
|
302
319
|
|
|
303
320
|
return writeHead.apply(this, arguments)
|
|
@@ -306,34 +323,6 @@ const web = {
|
|
|
306
323
|
getContext (req) {
|
|
307
324
|
return contexts.get(req)
|
|
308
325
|
},
|
|
309
|
-
wrapRes (context, req, res, end) {
|
|
310
|
-
return function (...args) {
|
|
311
|
-
web.finishAll(context)
|
|
312
|
-
|
|
313
|
-
return end.apply(res, args)
|
|
314
|
-
}
|
|
315
|
-
},
|
|
316
|
-
wrapEnd (context) {
|
|
317
|
-
const req = context.req
|
|
318
|
-
const res = context.res
|
|
319
|
-
const end = res.end
|
|
320
|
-
|
|
321
|
-
res.writeHead = web.wrapWriteHead(context)
|
|
322
|
-
|
|
323
|
-
ends.set(res, this.wrapRes(context, req, res, end))
|
|
324
|
-
|
|
325
|
-
Object.defineProperty(res, 'end', {
|
|
326
|
-
configurable: true,
|
|
327
|
-
get () {
|
|
328
|
-
return ends.get(this)
|
|
329
|
-
},
|
|
330
|
-
set (value) {
|
|
331
|
-
ends.set(this, function (...args) {
|
|
332
|
-
return storage('legacy').run(context.store, value, ...args)
|
|
333
|
-
})
|
|
334
|
-
},
|
|
335
|
-
})
|
|
336
|
-
},
|
|
337
326
|
setRouteOrEndpointTag (req) {
|
|
338
327
|
const context = contexts.get(req)
|
|
339
328
|
|
|
@@ -379,6 +368,16 @@ function splitHeader (str) {
|
|
|
379
368
|
|
|
380
369
|
function addRequestTags (context, spanType) {
|
|
381
370
|
const { req, span, inferredProxySpan, config } = context
|
|
371
|
+
const spanContext = span.context()
|
|
372
|
+
|
|
373
|
+
// Idempotency guard. `addRequestTags` runs in `web.startSpan` for the
|
|
374
|
+
// normal HTTP path and again in `web.finishSpan`; without this guard the
|
|
375
|
+
// second call would re-extract the URL, re-obfuscate the query string,
|
|
376
|
+
// and re-publish five `tagsUpdateCh` events with the same values. The
|
|
377
|
+
// serverless path skips `startSpan` and lands here first, in which case
|
|
378
|
+
// HTTP_URL is unset and the work runs normally.
|
|
379
|
+
if (spanContext.hasTag(HTTP_URL)) return
|
|
380
|
+
|
|
382
381
|
const url = extractURL(req)
|
|
383
382
|
const type = spanType ?? WEB
|
|
384
383
|
|
|
@@ -391,8 +390,8 @@ function addRequestTags (context, spanType) {
|
|
|
391
390
|
})
|
|
392
391
|
|
|
393
392
|
// if client ip has already been set by appsec, no need to run it again
|
|
394
|
-
if (extractIp && !
|
|
395
|
-
const clientIp = extractIp(config, req)
|
|
393
|
+
if (config.extractIp && !spanContext.hasTag(HTTP_CLIENT_IP)) {
|
|
394
|
+
const clientIp = config.extractIp(config, req)
|
|
396
395
|
|
|
397
396
|
if (clientIp) {
|
|
398
397
|
span.setTag(HTTP_CLIENT_IP, clientIp)
|
|
@@ -410,8 +409,6 @@ function addRequestTags (context, spanType) {
|
|
|
410
409
|
if (securityTest !== undefined) {
|
|
411
410
|
span.setTag(`${HTTP_REQUEST_HEADERS}.x-datadog-security-test`, securityTest)
|
|
412
411
|
}
|
|
413
|
-
|
|
414
|
-
addHeaders(context)
|
|
415
412
|
}
|
|
416
413
|
|
|
417
414
|
function addResponseTags (context) {
|
|
@@ -426,14 +423,26 @@ function addResponseTags (context) {
|
|
|
426
423
|
[HTTP_STATUS_CODE]: res.statusCode,
|
|
427
424
|
})
|
|
428
425
|
|
|
426
|
+
addResponseHeaders(context)
|
|
427
|
+
|
|
429
428
|
web.addStatusError(req, res.statusCode)
|
|
430
429
|
}
|
|
431
430
|
|
|
432
431
|
function applyRouteOrEndpointTag (context) {
|
|
433
432
|
const { paths, span, config } = context
|
|
434
433
|
if (!span) return
|
|
435
|
-
const
|
|
436
|
-
|
|
434
|
+
const spanContext = span.context()
|
|
435
|
+
|
|
436
|
+
// AppSec calls `web.setRouteOrEndpointTag` from a pre-finish hook so the
|
|
437
|
+
// route/endpoint tags are available for API Security sampling, and the
|
|
438
|
+
// normal finish-time path runs this again. Either tag being present
|
|
439
|
+
// means the work has already been done; paths are stable between the
|
|
440
|
+
// two calls, so the second pass has nothing to add.
|
|
441
|
+
if (spanContext.hasTag(HTTP_ROUTE) || spanContext.hasTag(HTTP_ENDPOINT)) return
|
|
442
|
+
|
|
443
|
+
// Skip the `Array.prototype.join` builtin in the empty / single-segment
|
|
444
|
+
// cases; `paths[0]` covers both (`undefined` is falsy for the empty case).
|
|
445
|
+
const route = paths.length > 1 ? paths.join('') : paths[0]
|
|
437
446
|
|
|
438
447
|
if (route) {
|
|
439
448
|
// Use http.route from trusted framework instrumentation.
|
|
@@ -441,44 +450,49 @@ function applyRouteOrEndpointTag (context) {
|
|
|
441
450
|
return
|
|
442
451
|
}
|
|
443
452
|
|
|
444
|
-
if (!config.resourceRenamingEnabled
|
|
445
|
-
return
|
|
446
|
-
}
|
|
453
|
+
if (!config.resourceRenamingEnabled) return
|
|
447
454
|
|
|
448
455
|
// Route is unavailable, compute http.endpoint once.
|
|
449
|
-
const url =
|
|
456
|
+
const url = spanContext.getTag(HTTP_URL)
|
|
450
457
|
const endpoint = url ? calculateHttpEndpoint(url) : '/'
|
|
451
458
|
span.setTag(HTTP_ENDPOINT, endpoint)
|
|
452
459
|
}
|
|
453
460
|
|
|
454
461
|
function addResourceTag (context) {
|
|
455
462
|
const { req, span } = context
|
|
456
|
-
const
|
|
463
|
+
const spanContext = span.context()
|
|
457
464
|
|
|
458
|
-
if (
|
|
465
|
+
if (spanContext.getTag(RESOURCE_NAME)) return
|
|
459
466
|
|
|
460
|
-
const resource = [req.method,
|
|
467
|
+
const resource = [req.method, spanContext.getTag(HTTP_ROUTE)]
|
|
461
468
|
.filter(Boolean)
|
|
462
469
|
.join(' ')
|
|
463
470
|
|
|
464
471
|
span.setTag(RESOURCE_NAME, resource)
|
|
465
472
|
}
|
|
466
473
|
|
|
467
|
-
function
|
|
468
|
-
const { req,
|
|
474
|
+
function addRequestHeaders (context) {
|
|
475
|
+
const { req, config, span, inferredProxySpan } = context
|
|
469
476
|
|
|
470
477
|
for (const [key, tag] of config.headers) {
|
|
471
478
|
const reqHeader = req.headers[key]
|
|
472
|
-
const resHeader = res.getHeader(key)
|
|
473
|
-
|
|
474
479
|
if (reqHeader) {
|
|
475
|
-
|
|
476
|
-
|
|
480
|
+
const tagName = tag || `${HTTP_REQUEST_HEADERS}.${key}`
|
|
481
|
+
span.setTag(tagName, reqHeader)
|
|
482
|
+
inferredProxySpan?.setTag(tagName, reqHeader)
|
|
477
483
|
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function addResponseHeaders (context) {
|
|
488
|
+
const { res, config, span, inferredProxySpan } = context
|
|
478
489
|
|
|
490
|
+
for (const [key, tag] of config.headers) {
|
|
491
|
+
const resHeader = res.getHeader(key)
|
|
479
492
|
if (resHeader) {
|
|
480
|
-
|
|
481
|
-
|
|
493
|
+
const tagName = tag || `${HTTP_RESPONSE_HEADERS}.${key}`
|
|
494
|
+
span.setTag(tagName, resHeader)
|
|
495
|
+
inferredProxySpan?.setTag(tagName, resHeader)
|
|
482
496
|
}
|
|
483
497
|
}
|
|
484
498
|
}
|
|
@@ -125,7 +125,7 @@ class PrioritySampler {
|
|
|
125
125
|
|
|
126
126
|
log.trace(span, auto)
|
|
127
127
|
|
|
128
|
-
const tag = this._getPriorityFromTags(context.
|
|
128
|
+
const tag = this._getPriorityFromTags(context.getTags(), context)
|
|
129
129
|
|
|
130
130
|
if (this.validate(tag)) {
|
|
131
131
|
context._sampling.priority = tag
|
|
@@ -300,7 +300,7 @@ class PrioritySampler {
|
|
|
300
300
|
* @returns {SamplingPriority}
|
|
301
301
|
*/
|
|
302
302
|
#getPriorityByAgent (context) {
|
|
303
|
-
const key = `service:${context.
|
|
303
|
+
const key = `service:${context.getTag(SERVICE_NAME)},env:${this._env}`
|
|
304
304
|
// TODO: Change underscored properties to private ones.
|
|
305
305
|
const sampler = this._samplers[key] || this._samplers[DEFAULT_KEY]
|
|
306
306
|
|
|
@@ -5,6 +5,7 @@ const { pathToFileURL } = require('url')
|
|
|
5
5
|
|
|
6
6
|
const satisfies = require('../../../../vendor/dist/semifies')
|
|
7
7
|
const getGitMetadata = require('../git_metadata')
|
|
8
|
+
const log = require('../log')
|
|
8
9
|
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../plugins/util/tags')
|
|
9
10
|
const { getIsAzureFunction } = require('../serverless')
|
|
10
11
|
const { getAzureTagsFromMetadata, getAzureAppMetadata, getAzureFunctionMetadata } = require('../azure_metadata')
|
|
@@ -14,7 +15,6 @@ const { isACFActive } = require('../../../datadog-core/src/storage')
|
|
|
14
15
|
|
|
15
16
|
const { AgentExporter } = require('./exporters/agent')
|
|
16
17
|
const { FileExporter } = require('./exporters/file')
|
|
17
|
-
const { ConsoleLogger } = require('./loggers/console')
|
|
18
18
|
const WallProfiler = require('./profilers/wall')
|
|
19
19
|
const SpaceProfiler = require('./profilers/space')
|
|
20
20
|
const EventsProfiler = require('./profilers/events')
|
|
@@ -54,7 +54,6 @@ class Config {
|
|
|
54
54
|
this.pprofPrefix = options.DD_PROFILING_PPROF_PREFIX
|
|
55
55
|
this.v8ProfilerBugWorkaroundEnabled = options.DD_PROFILING_V8_PROFILER_BUG_WORKAROUND
|
|
56
56
|
|
|
57
|
-
this.logger = ensureLogger(options.logger)
|
|
58
57
|
this.url = getAgentUrl(options)
|
|
59
58
|
|
|
60
59
|
this.libraryInjected = !!options.DD_INJECTION_ENABLED
|
|
@@ -73,7 +72,7 @@ class Config {
|
|
|
73
72
|
const heapLimitExtensionSize = options.DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE
|
|
74
73
|
const maxHeapExtensionCount = options.DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT
|
|
75
74
|
const exportStrategies = oomMonitoringEnabled
|
|
76
|
-
? ensureOOMExportStrategies(options.DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES
|
|
75
|
+
? ensureOOMExportStrategies(options.DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES)
|
|
77
76
|
: []
|
|
78
77
|
const exportCommand = oomMonitoringEnabled ? buildExportCommand(this) : undefined
|
|
79
78
|
this.oomMonitoring = {
|
|
@@ -102,7 +101,7 @@ class Config {
|
|
|
102
101
|
if (level !== undefined) {
|
|
103
102
|
const maxLevel = { gzip: 9, zstd: 22 }[uploadCompression]
|
|
104
103
|
if (level > maxLevel) {
|
|
105
|
-
|
|
104
|
+
log.warn('Invalid compression level %d. Will use %d.', level, maxLevel)
|
|
106
105
|
level = maxLevel
|
|
107
106
|
}
|
|
108
107
|
}
|
|
@@ -119,8 +118,7 @@ class Config {
|
|
|
119
118
|
|
|
120
119
|
const that = this
|
|
121
120
|
function turnOffAsyncContextFrame (msg) {
|
|
122
|
-
|
|
123
|
-
`DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED was set ${msg}, it will have no effect.`)
|
|
121
|
+
log.warn('DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED was set %s, it will have no effect.', msg)
|
|
124
122
|
that.asyncContextFrameEnabled = false
|
|
125
123
|
}
|
|
126
124
|
|
|
@@ -215,18 +213,18 @@ function getProfilers ({
|
|
|
215
213
|
return profilersArray
|
|
216
214
|
}
|
|
217
215
|
|
|
218
|
-
function getExportStrategy (name
|
|
216
|
+
function getExportStrategy (name) {
|
|
219
217
|
const strategy = Object.values(oomExportStrategies).find(value => value === name)
|
|
220
218
|
if (strategy === undefined) {
|
|
221
|
-
|
|
219
|
+
log.error('Unknown oom export strategy "%s"', name)
|
|
222
220
|
}
|
|
223
221
|
return strategy
|
|
224
222
|
}
|
|
225
223
|
|
|
226
|
-
function ensureOOMExportStrategies (strategies
|
|
224
|
+
function ensureOOMExportStrategies (strategies) {
|
|
227
225
|
const set = new Set()
|
|
228
226
|
for (const strategy of strategies) {
|
|
229
|
-
set.add(getExportStrategy(strategy
|
|
227
|
+
set.add(getExportStrategy(strategy))
|
|
230
228
|
}
|
|
231
229
|
|
|
232
230
|
return [...set]
|
|
@@ -239,7 +237,7 @@ function getExporter (name, options) {
|
|
|
239
237
|
case 'file':
|
|
240
238
|
return new FileExporter(options)
|
|
241
239
|
default:
|
|
242
|
-
|
|
240
|
+
log.error('Unknown exporter "%s"', name)
|
|
243
241
|
}
|
|
244
242
|
}
|
|
245
243
|
|
|
@@ -255,7 +253,7 @@ function getProfiler (name, options) {
|
|
|
255
253
|
case 'space':
|
|
256
254
|
return new SpaceProfiler(options)
|
|
257
255
|
default:
|
|
258
|
-
|
|
256
|
+
log.error('Unknown profiler "%s"', name)
|
|
259
257
|
}
|
|
260
258
|
}
|
|
261
259
|
|
|
@@ -278,17 +276,6 @@ function ensureProfilers (profilers, options) {
|
|
|
278
276
|
return filteredProfilers
|
|
279
277
|
}
|
|
280
278
|
|
|
281
|
-
function ensureLogger (logger) {
|
|
282
|
-
if (typeof logger?.debug !== 'function' ||
|
|
283
|
-
typeof logger.info !== 'function' ||
|
|
284
|
-
typeof logger.warn !== 'function' ||
|
|
285
|
-
typeof logger.error !== 'function') {
|
|
286
|
-
return new ConsoleLogger()
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return logger
|
|
290
|
-
}
|
|
291
|
-
|
|
292
279
|
function buildExportCommand (options) {
|
|
293
280
|
const tags = [...Object.entries(options.tags),
|
|
294
281
|
['snapshot', snapshotKinds.ON_OUT_OF_MEMORY]].map(([key, value]) => `${key}:${value}`).join(',')
|
|
@@ -9,6 +9,7 @@ const retry = require('../../../../../vendor/dist/retry')
|
|
|
9
9
|
// TODO: avoid using dd-trace internals. Make this a separate module?
|
|
10
10
|
const docker = require('../../exporters/common/docker')
|
|
11
11
|
const FormData = require('../../exporters/common/form-data')
|
|
12
|
+
const log = require('../../log')
|
|
12
13
|
const { storage } = require('../../../../datadog-core')
|
|
13
14
|
const version = require('../../../../../package.json').version
|
|
14
15
|
const telemetryMetrics = require('../../telemetry/metrics')
|
|
@@ -89,9 +90,8 @@ function computeRetries (uploadTimeout) {
|
|
|
89
90
|
class AgentExporter extends EventSerializer {
|
|
90
91
|
constructor (config = {}) {
|
|
91
92
|
super(config)
|
|
92
|
-
const { url,
|
|
93
|
+
const { url, uploadTimeout } = config
|
|
93
94
|
this._url = url
|
|
94
|
-
this._logger = logger
|
|
95
95
|
|
|
96
96
|
const [backoffTries, backoffTime] = computeRetries(uploadTimeout)
|
|
97
97
|
|
|
@@ -109,12 +109,11 @@ class AgentExporter extends EventSerializer {
|
|
|
109
109
|
contentType: 'application/json',
|
|
110
110
|
}])
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
return `Building agent export report:\n${event}`
|
|
114
|
-
})
|
|
112
|
+
log.debug('Building agent export report:\n%s', event)
|
|
115
113
|
|
|
116
114
|
for (const [type, buffer] of Object.entries(profiles)) {
|
|
117
|
-
|
|
115
|
+
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
116
|
+
log.debug(() => {
|
|
118
117
|
const bytes = buffer.toString('hex').match(/../g).join(' ')
|
|
119
118
|
return `Adding ${type} profile to agent export: ` + bytes
|
|
120
119
|
})
|
|
@@ -163,7 +162,8 @@ class AgentExporter extends EventSerializer {
|
|
|
163
162
|
options.port = httpOptions.port
|
|
164
163
|
}
|
|
165
164
|
|
|
166
|
-
|
|
165
|
+
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
166
|
+
log.debug(() => {
|
|
167
167
|
return `Submitting profiler agent report attempt #${attempt} to: ${JSON.stringify(options)}`
|
|
168
168
|
})
|
|
169
169
|
|
|
@@ -171,7 +171,7 @@ class AgentExporter extends EventSerializer {
|
|
|
171
171
|
if (err) {
|
|
172
172
|
const { status } = err
|
|
173
173
|
if ((typeof status !== 'number' || status >= 500 || status === 429) && operation.retry(err)) {
|
|
174
|
-
|
|
174
|
+
log.warn('Error from the agent: %s', err.message)
|
|
175
175
|
} else {
|
|
176
176
|
reject(err)
|
|
177
177
|
}
|
|
@@ -180,9 +180,10 @@ class AgentExporter extends EventSerializer {
|
|
|
180
180
|
|
|
181
181
|
getBody(response, (err, body) => {
|
|
182
182
|
if (err) {
|
|
183
|
-
|
|
183
|
+
log.warn('Error reading agent response: %s', err.message)
|
|
184
184
|
} else {
|
|
185
|
-
|
|
185
|
+
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
186
|
+
log.debug(() => {
|
|
186
187
|
const bytes = (body.toString('hex').match(/../g) || []).join(' ')
|
|
187
188
|
return `Agent export response: ${bytes}`
|
|
188
189
|
})
|
|
@@ -17,7 +17,7 @@ function findWebSpan (startedSpans, spanId) {
|
|
|
17
17
|
const ispan = startedSpans[i]
|
|
18
18
|
const context = ispan.context()
|
|
19
19
|
if (context._spanId === spanId) {
|
|
20
|
-
if (isWebServerSpan(context.
|
|
20
|
+
if (isWebServerSpan(context.getTags())) {
|
|
21
21
|
return true
|
|
22
22
|
}
|
|
23
23
|
spanId = context._parentId
|
|
@@ -40,6 +40,16 @@ function processInfo (infos, info, type) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// Route pprof through the central log module so logLevel applies.
|
|
44
|
+
const pprofLogger = {
|
|
45
|
+
trace: (...args) => log.trace(...args),
|
|
46
|
+
debug: (...args) => log.debug(...args),
|
|
47
|
+
info: (...args) => log.info(...args),
|
|
48
|
+
warn: (...args) => log.warn(...args),
|
|
49
|
+
error: (...args) => log.error(...args),
|
|
50
|
+
fatal: (...args) => log.error(...args),
|
|
51
|
+
}
|
|
52
|
+
|
|
43
53
|
class Profiler extends EventEmitter {
|
|
44
54
|
#compressionFn
|
|
45
55
|
#compressionFnInitialized = false
|
|
@@ -49,7 +59,6 @@ class Profiler extends EventEmitter {
|
|
|
49
59
|
#enabled = false
|
|
50
60
|
#endpointCounts = new Map()
|
|
51
61
|
#lastStart
|
|
52
|
-
#logger
|
|
53
62
|
#profileSeq = 0
|
|
54
63
|
#spanFinishListener
|
|
55
64
|
#timer
|
|
@@ -159,14 +168,13 @@ class Profiler extends EventEmitter {
|
|
|
159
168
|
this.#enabled = true
|
|
160
169
|
|
|
161
170
|
const config = this.#config = new Config(options)
|
|
162
|
-
this.#logger = config.logger
|
|
163
171
|
|
|
164
172
|
this._setInterval()
|
|
165
173
|
// Log errors if the source map finder fails, but don't prevent the rest
|
|
166
174
|
// of the profiler from running without source maps.
|
|
167
175
|
let mapper
|
|
168
176
|
const { setLogger, SourceMapper } = require('@datadog/pprof')
|
|
169
|
-
setLogger(
|
|
177
|
+
setLogger(pprofLogger)
|
|
170
178
|
|
|
171
179
|
if (config.sourceMap) {
|
|
172
180
|
mapper = new SourceMapper(config.debugSourceMaps)
|
|
@@ -174,7 +182,8 @@ class Profiler extends EventEmitter {
|
|
|
174
182
|
.then(() => {
|
|
175
183
|
if (config.debugSourceMaps) {
|
|
176
184
|
const count = mapper.infoMap.size
|
|
177
|
-
|
|
185
|
+
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
186
|
+
log.debug(() => {
|
|
178
187
|
return count === 0
|
|
179
188
|
? 'Found no source maps'
|
|
180
189
|
: `Found source maps for following files: [${[...mapper.infoMap.keys()].join(', ')}]`
|
|
@@ -195,7 +204,7 @@ class Profiler extends EventEmitter {
|
|
|
195
204
|
mapper,
|
|
196
205
|
nearOOMCallback,
|
|
197
206
|
})
|
|
198
|
-
|
|
207
|
+
log.debug('Started %s profiler in %s thread', profiler.type, threadNamePrefix)
|
|
199
208
|
}
|
|
200
209
|
|
|
201
210
|
if (config.endpointCollectionEnabled) {
|
|
@@ -248,7 +257,7 @@ class Profiler extends EventEmitter {
|
|
|
248
257
|
|
|
249
258
|
for (const profiler of this.#config.profilers) {
|
|
250
259
|
profiler.stop()
|
|
251
|
-
|
|
260
|
+
log.debug('Stopped %s profiler in %s thread', profiler.type, threadNamePrefix)
|
|
252
261
|
}
|
|
253
262
|
|
|
254
263
|
clearTimeout(this.#timer)
|
|
@@ -268,7 +277,7 @@ class Profiler extends EventEmitter {
|
|
|
268
277
|
|
|
269
278
|
#onSpanFinish (span) {
|
|
270
279
|
const context = span.context()
|
|
271
|
-
const tags = context.
|
|
280
|
+
const tags = context.getTags()
|
|
272
281
|
if (!isWebServerSpan(tags)) return
|
|
273
282
|
|
|
274
283
|
const endpointName = endpointNameFromTags(tags)
|
|
@@ -312,7 +321,7 @@ class Profiler extends EventEmitter {
|
|
|
312
321
|
const info = profiler.getInfo()
|
|
313
322
|
const profile = profiler.profile(restart, startDate, endDate)
|
|
314
323
|
if (!restart) {
|
|
315
|
-
|
|
324
|
+
log.debug('Stopped %s profiler in %s thread', profiler.type, threadNamePrefix)
|
|
316
325
|
}
|
|
317
326
|
if (!profile) continue
|
|
318
327
|
profiles.push({ profiler, profile, info })
|
|
@@ -341,7 +350,8 @@ class Profiler extends EventEmitter {
|
|
|
341
350
|
infos.hasMissingSourceMaps = true
|
|
342
351
|
}
|
|
343
352
|
processInfo(infos, info, profiler.type)
|
|
344
|
-
|
|
353
|
+
// eslint-disable-next-line eslint-rules/eslint-log-printf-style
|
|
354
|
+
log.debug(() => {
|
|
345
355
|
const profileJson = JSON.stringify(profile, (_, value) => {
|
|
346
356
|
return typeof value === 'bigint' ? value.toString() : value
|
|
347
357
|
})
|
|
@@ -358,7 +368,7 @@ class Profiler extends EventEmitter {
|
|
|
358
368
|
if (hasEncoded) {
|
|
359
369
|
await this.#submit(encodedProfiles, infos, startDate, endDate, snapshotKind)
|
|
360
370
|
profileSubmittedChannel.publish()
|
|
361
|
-
|
|
371
|
+
log.debug('Submitted profiles')
|
|
362
372
|
}
|
|
363
373
|
} catch (error) {
|
|
364
374
|
log.error(error)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const dc = require('dc-polyfill')
|
|
4
4
|
|
|
5
5
|
const { storage } = require('../../../../datadog-core')
|
|
6
|
+
const log = require('../../log')
|
|
6
7
|
const runtimeMetrics = require('../../runtime_metrics')
|
|
7
8
|
const telemetryMetrics = require('../../telemetry/metrics')
|
|
8
9
|
const { isWebServerSpan, endpointNameFromTags, getStartedSpans } = require('../webspan-utils')
|
|
@@ -112,7 +113,6 @@ class NativeWallProfiler {
|
|
|
112
113
|
#customLabelKeys
|
|
113
114
|
#endpointCollectionEnabled = false
|
|
114
115
|
#flushIntervalMillis = 0
|
|
115
|
-
#logger
|
|
116
116
|
#mapper
|
|
117
117
|
#pprof
|
|
118
118
|
#samplingIntervalMicros = 0
|
|
@@ -136,7 +136,6 @@ class NativeWallProfiler {
|
|
|
136
136
|
this.#cpuProfilingEnabled = !!options.cpuProfilingEnabled
|
|
137
137
|
this.#endpointCollectionEnabled = !!options.endpointCollectionEnabled
|
|
138
138
|
this.#flushIntervalMillis = options.flushInterval || 60 * 1e3 // 60 seconds
|
|
139
|
-
this.#logger = options.logger
|
|
140
139
|
// TODO: Remove default value. It is only used in testing.
|
|
141
140
|
this.#samplingIntervalMicros = (options.samplingInterval || 1e3 / 99) * 1000
|
|
142
141
|
this.#telemetryHeartbeatIntervalMillis = options.heartbeatInterval || 60 * 1e3 // 60 seconds
|
|
@@ -247,6 +246,7 @@ class NativeWallProfiler {
|
|
|
247
246
|
// context -- we simply can't tell which one it might've been across all
|
|
248
247
|
// possible async context frames.
|
|
249
248
|
if (this.#asyncContextFrameEnabled) {
|
|
249
|
+
const current = this.#pprof.time.getContext()
|
|
250
250
|
if (this.#customLabelsActive) {
|
|
251
251
|
// Custom labels may be active in this async context. The current CPED
|
|
252
252
|
// context could be a 2-element array [profilingContext, customLabels].
|
|
@@ -254,7 +254,6 @@ class NativeWallProfiler {
|
|
|
254
254
|
// This flag is monotonic (once set, stays true) because async
|
|
255
255
|
// continuations from runWithLabels can fire at any time after the
|
|
256
256
|
// synchronous runWithLabels call has returned.
|
|
257
|
-
const current = this.#pprof.time.getContext()
|
|
258
257
|
if (Array.isArray(current)) {
|
|
259
258
|
if (current[0] !== sampleContext) {
|
|
260
259
|
this.#pprof.time.setContext([sampleContext, current[1]])
|
|
@@ -262,7 +261,13 @@ class NativeWallProfiler {
|
|
|
262
261
|
} else if (current !== sampleContext) {
|
|
263
262
|
this.#pprof.time.setContext(sampleContext)
|
|
264
263
|
}
|
|
265
|
-
|
|
264
|
+
// Every setContext() call in ACF mode allocates a fresh contextHolder
|
|
265
|
+
// (a node::ObjectWrap with its own v8::Global<v8::Value>) in the native
|
|
266
|
+
// profiler. Skip the call if the CPED already holds this sampleContext,
|
|
267
|
+
// which is the common case when the same span is repeatedly activated:
|
|
268
|
+
// #getProfilingContext caches profilingContext on span[ProfilingContext],
|
|
269
|
+
// so identity comparison short-circuits.
|
|
270
|
+
} else if (current !== sampleContext) {
|
|
266
271
|
this.#pprof.time.setContext(sampleContext)
|
|
267
272
|
}
|
|
268
273
|
} else {
|
|
@@ -294,7 +299,7 @@ class NativeWallProfiler {
|
|
|
294
299
|
|
|
295
300
|
let webTags
|
|
296
301
|
if (this.#endpointCollectionEnabled) {
|
|
297
|
-
const tags = context.
|
|
302
|
+
const tags = context.getTags()
|
|
298
303
|
if (isWebServerSpan(tags)) {
|
|
299
304
|
webTags = tags
|
|
300
305
|
} else {
|
|
@@ -333,7 +338,7 @@ class NativeWallProfiler {
|
|
|
333
338
|
if (!this.#started) return
|
|
334
339
|
const profilingContext = span[ProfilingContext]
|
|
335
340
|
if (profilingContext === undefined || profilingContext.webTags !== undefined) return
|
|
336
|
-
const tags = span.context().
|
|
341
|
+
const tags = span.context().getTags()
|
|
337
342
|
if (isWebServerSpan(tags)) {
|
|
338
343
|
profilingContext.webTags = tags
|
|
339
344
|
}
|
|
@@ -342,7 +347,7 @@ class NativeWallProfiler {
|
|
|
342
347
|
#reportV8bug (maybeBug) {
|
|
343
348
|
const tag = `v8_profiler_bug_workaround_enabled:${this.#v8ProfilerBugWorkaroundEnabled}`
|
|
344
349
|
const metric = `v8_cpu_profiler${maybeBug ? '_maybe' : ''}_stuck_event_loop`
|
|
345
|
-
|
|
350
|
+
log.warn('Wall profiler: %sv8 profiler stuck event loop detected.', maybeBug ? 'possible ' : '')
|
|
346
351
|
// report as runtime metric (can be removed in the future when telemetry is mature)
|
|
347
352
|
runtimeMetrics.increment(`runtime.node.profiler.${metric}`, tag, true)
|
|
348
353
|
// report as telemetry metric
|