dd-trace 5.103.0 → 5.105.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 +107 -6
- package/package.json +18 -17
- 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 +15 -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/cassandra-driver.js +5 -2
- package/packages/datadog-instrumentations/src/cucumber.js +181 -35
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -67
- package/packages/datadog-instrumentations/src/grpc/client.js +48 -32
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- 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/kafka.js +17 -0
- 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/compiler.js +3 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +19 -6
- 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 +31 -229
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/client.js +2 -2
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/ioredis.js +3 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +390 -183
- package/packages/datadog-instrumentations/src/kafkajs.js +140 -17
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/memcached.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +399 -107
- package/packages/datadog-instrumentations/src/mocha/utils.js +48 -8
- package/packages/datadog-instrumentations/src/mongodb-core.js +1 -1
- package/packages/datadog-instrumentations/src/mongoose.js +10 -12
- package/packages/datadog-instrumentations/src/mysql.js +2 -2
- package/packages/datadog-instrumentations/src/mysql2.js +1 -1
- 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/pg.js +1 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +537 -297
- package/packages/datadog-instrumentations/src/router.js +80 -34
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +246 -149
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- 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 +223 -45
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-elasticsearch/src/index.js +28 -8
- 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-graphql/src/utils.js +4 -1
- 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 +35 -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 +311 -35
- 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-redis/src/index.js +37 -2
- 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-undici/src/index.js +19 -0
- package/packages/datadog-plugin-vitest/src/index.js +24 -20
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +49 -21
- 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/blocking.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +11 -4
- package/packages/dd-trace/src/appsec/reporter.js +24 -11
- 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/requests/request.js +3 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +5 -3
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -2
- package/packages/dd-trace/src/config/supported-configurations.json +36 -8
- package/packages/dd-trace/src/crashtracking/crashtracker.js +15 -3
- package/packages/dd-trace/src/datastreams/context.js +4 -2
- 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 +57 -42
- 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/exporters/common/agents.js +3 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -1
- package/packages/dd-trace/src/id.js +17 -4
- package/packages/dd-trace/src/lambda/handler.js +2 -4
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- 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 +10 -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/log/writer.js +3 -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/noop/span.js +3 -1
- 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/openfeature/writers/exposures.js +51 -20
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- 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/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +49 -0
- package/packages/dd-trace/src/plugins/apollo.js +3 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +23 -33
- 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 -46
- 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 +48 -8
- package/packages/dd-trace/src/plugins/util/git.js +3 -1
- package/packages/dd-trace/src/plugins/util/test.js +318 -13
- package/packages/dd-trace/src/plugins/util/web.js +89 -64
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/scope.js +7 -5
- package/packages/dd-trace/src/service-naming/extra-services.js +14 -0
- 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
- package/vendor/dist/opentracing/LICENSE +0 -201
- package/vendor/dist/opentracing/binary_carrier.d.ts +0 -11
- package/vendor/dist/opentracing/constants.d.ts +0 -61
- package/vendor/dist/opentracing/examples/demo/demo.d.ts +0 -2
- package/vendor/dist/opentracing/ext/tags.d.ts +0 -90
- package/vendor/dist/opentracing/functions.d.ts +0 -20
- package/vendor/dist/opentracing/global_tracer.d.ts +0 -14
- package/vendor/dist/opentracing/index.d.ts +0 -12
- package/vendor/dist/opentracing/index.js +0 -1
- package/vendor/dist/opentracing/mock_tracer/index.d.ts +0 -5
- package/vendor/dist/opentracing/mock_tracer/mock_context.d.ts +0 -13
- package/vendor/dist/opentracing/mock_tracer/mock_report.d.ts +0 -16
- package/vendor/dist/opentracing/mock_tracer/mock_span.d.ts +0 -50
- package/vendor/dist/opentracing/mock_tracer/mock_tracer.d.ts +0 -26
- package/vendor/dist/opentracing/noop.d.ts +0 -8
- package/vendor/dist/opentracing/reference.d.ts +0 -33
- package/vendor/dist/opentracing/span.d.ts +0 -147
- package/vendor/dist/opentracing/span_context.d.ts +0 -26
- package/vendor/dist/opentracing/test/api_compatibility.d.ts +0 -16
- package/vendor/dist/opentracing/test/mocktracer_implemenation.d.ts +0 -3
- package/vendor/dist/opentracing/test/noop_implementation.d.ts +0 -4
- package/vendor/dist/opentracing/test/opentracing_api.d.ts +0 -3
- package/vendor/dist/opentracing/test/unittest.d.ts +0 -2
- package/vendor/dist/opentracing/tracer.d.ts +0 -127
|
@@ -11,6 +11,7 @@ const {
|
|
|
11
11
|
TEST_PARAMETERS,
|
|
12
12
|
finishAllTraceSpans,
|
|
13
13
|
getTestSuitePath,
|
|
14
|
+
getRelativeCoverageFiles,
|
|
14
15
|
getTestParametersString,
|
|
15
16
|
getTestSuiteCommonTags,
|
|
16
17
|
addIntelligentTestRunnerSpanTags,
|
|
@@ -73,8 +74,10 @@ class MochaPlugin extends CiPlugin {
|
|
|
73
74
|
this.telemetry.count(TELEMETRY_CODE_COVERAGE_EMPTY)
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
const relativeCoverageFiles = [
|
|
77
|
-
|
|
77
|
+
const relativeCoverageFiles = [
|
|
78
|
+
...getRelativeCoverageFiles(coverageFiles, this.repositoryRoot || this.sourceRoot),
|
|
79
|
+
getTestSuitePath(suiteFile, this.repositoryRoot || this.sourceRoot),
|
|
80
|
+
]
|
|
78
81
|
|
|
79
82
|
const { _traceId, _spanId } = testSuiteSpan.context()
|
|
80
83
|
|
|
@@ -152,7 +155,7 @@ class MochaPlugin extends CiPlugin {
|
|
|
152
155
|
this.addSub('ci:mocha:test-suite:finish', ({ testSuiteSpan, status }) => {
|
|
153
156
|
if (testSuiteSpan) {
|
|
154
157
|
// the test status of the suite may have been set in ci:mocha:test-suite:error already
|
|
155
|
-
if (!testSuiteSpan.context().
|
|
158
|
+
if (!testSuiteSpan.context().getTag(TEST_STATUS)) {
|
|
156
159
|
testSuiteSpan.setTag(TEST_STATUS, status)
|
|
157
160
|
}
|
|
158
161
|
testSuiteSpan.finish()
|
|
@@ -352,6 +355,7 @@ class MochaPlugin extends CiPlugin {
|
|
|
352
355
|
status,
|
|
353
356
|
isSuitesSkipped,
|
|
354
357
|
testCodeCoverageLinesTotal,
|
|
358
|
+
testSessionCoverageFiles,
|
|
355
359
|
numSkippedSuites,
|
|
356
360
|
hasForcedToRunSuites,
|
|
357
361
|
hasUnskippableSuites,
|
|
@@ -362,7 +366,11 @@ class MochaPlugin extends CiPlugin {
|
|
|
362
366
|
isParallel,
|
|
363
367
|
}) => {
|
|
364
368
|
if (this.testSessionSpan) {
|
|
365
|
-
const {
|
|
369
|
+
const {
|
|
370
|
+
isSuitesSkippingEnabled,
|
|
371
|
+
isCodeCoverageEnabled,
|
|
372
|
+
isCoverageReportUploadEnabled,
|
|
373
|
+
} = this.libraryConfig || {}
|
|
366
374
|
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
367
375
|
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
368
376
|
|
|
@@ -394,6 +402,13 @@ class MochaPlugin extends CiPlugin {
|
|
|
394
402
|
}
|
|
395
403
|
)
|
|
396
404
|
|
|
405
|
+
if (testSessionCoverageFiles?.length && isCoverageReportUploadEnabled) {
|
|
406
|
+
this.tracer._exporter.exportCoverage({
|
|
407
|
+
sessionId: this.testSessionSpan.context()._traceId,
|
|
408
|
+
files: testSessionCoverageFiles,
|
|
409
|
+
})
|
|
410
|
+
}
|
|
411
|
+
|
|
397
412
|
if (isEarlyFlakeDetectionEnabled) {
|
|
398
413
|
this.testSessionSpan.setTag(TEST_EARLY_FLAKE_ENABLED, 'true')
|
|
399
414
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { isMap, isRegExp } = require('node:util').types
|
|
4
|
+
|
|
3
5
|
const DatabasePlugin = require('../../dd-trace/src/plugins/database')
|
|
4
6
|
|
|
5
7
|
class MongodbCorePlugin extends DatabasePlugin {
|
|
@@ -20,6 +22,9 @@ class MongodbCorePlugin extends DatabasePlugin {
|
|
|
20
22
|
|
|
21
23
|
this.config.heartbeatEnabled = config.heartbeatEnabled ??
|
|
22
24
|
this._tracerConfig.DD_TRACE_MONGODB_HEARTBEAT_ENABLED
|
|
25
|
+
this.config.obfuscateQuery = normaliseObfuscateQuery(
|
|
26
|
+
config.obfuscateQuery ?? this._tracerConfig.DD_TRACE_MONGODB_OBFUSCATE_QUERY
|
|
27
|
+
)
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
bindStart (ctx) {
|
|
@@ -28,7 +33,7 @@ class MongodbCorePlugin extends DatabasePlugin {
|
|
|
28
33
|
if (!this.config.heartbeatEnabled && isHeartbeat(ops, this.config)) {
|
|
29
34
|
return
|
|
30
35
|
}
|
|
31
|
-
const query = getQuery(ops)
|
|
36
|
+
const query = getQuery(ops, this.config.obfuscateQuery)
|
|
32
37
|
const resource = truncate(getResource(this, ns, query, name))
|
|
33
38
|
const serviceResult = this.serviceName({ pluginConfig: this.config })
|
|
34
39
|
const span = this.startSpan(this.operationName(), {
|
|
@@ -106,15 +111,19 @@ function extractQuery (statements) {
|
|
|
106
111
|
return extractedQueries
|
|
107
112
|
}
|
|
108
113
|
|
|
109
|
-
|
|
114
|
+
/**
|
|
115
|
+
* @param {Record<string, unknown> | unknown[] | undefined} cmd
|
|
116
|
+
* @param {'none' | 'types' | 'redact'} mode
|
|
117
|
+
*/
|
|
118
|
+
function getQuery (cmd, mode) {
|
|
110
119
|
if (!cmd || (typeof cmd !== 'object' && !Array.isArray(cmd))) return
|
|
111
120
|
|
|
112
|
-
if (Array.isArray(cmd)) return sanitiseAndStringify(extractQuery(cmd))
|
|
113
|
-
if (cmd.query) return sanitiseAndStringify(cmd.query)
|
|
114
|
-
if (cmd.filter) return sanitiseAndStringify(cmd.filter)
|
|
115
|
-
if (cmd.pipeline) return sanitiseAndStringify(cmd.pipeline)
|
|
116
|
-
if (cmd.deletes) return sanitiseAndStringify(extractQuery(cmd.deletes))
|
|
117
|
-
if (cmd.updates) return sanitiseAndStringify(extractQuery(cmd.updates))
|
|
121
|
+
if (Array.isArray(cmd)) return sanitiseAndStringify(extractQuery(cmd), mode)
|
|
122
|
+
if (cmd.query) return sanitiseAndStringify(cmd.query, mode)
|
|
123
|
+
if (cmd.filter) return sanitiseAndStringify(cmd.filter, mode)
|
|
124
|
+
if (cmd.pipeline) return sanitiseAndStringify(cmd.pipeline, mode)
|
|
125
|
+
if (cmd.deletes) return sanitiseAndStringify(extractQuery(cmd.deletes), mode)
|
|
126
|
+
if (cmd.updates) return sanitiseAndStringify(extractQuery(cmd.updates), mode)
|
|
118
127
|
}
|
|
119
128
|
|
|
120
129
|
function getResource (plugin, ns, query, operationName) {
|
|
@@ -131,37 +140,304 @@ function truncate (input) {
|
|
|
131
140
|
return input.length > MAX_QUERY_LENGTH ? input.slice(0, MAX_QUERY_LENGTH) : input
|
|
132
141
|
}
|
|
133
142
|
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
143
|
+
// Depth doubles as the cycle bound: a cycle pushes past MAX_DEPTH and bails,
|
|
144
|
+
// after which the slow path catches it via its ancestor stack.
|
|
145
|
+
/** @param {unknown} input */
|
|
146
|
+
function canStringifyDirect (input) {
|
|
147
|
+
if (input === null ||
|
|
148
|
+
typeof input !== 'object' ||
|
|
149
|
+
ArrayBuffer.isView(input) ||
|
|
150
|
+
input._bsontype !== undefined ||
|
|
151
|
+
isRegExp(input) ||
|
|
152
|
+
isMap(input) ||
|
|
153
|
+
typeof input.toJSON === 'function') {
|
|
154
|
+
return false
|
|
155
|
+
}
|
|
156
|
+
return canStringifyDirectWalk(input, 1)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @param {Record<string, unknown> | unknown[]} value
|
|
161
|
+
* @param {number} depth
|
|
162
|
+
*/
|
|
163
|
+
function canStringifyDirectWalk (value, depth) {
|
|
164
|
+
if (depth > MAX_DEPTH) return false
|
|
165
|
+
const children = Array.isArray(value) ? value : Object.values(value)
|
|
166
|
+
for (const child of children) {
|
|
167
|
+
if (child === null ||
|
|
168
|
+
typeof child === 'string' ||
|
|
169
|
+
typeof child === 'number' ||
|
|
170
|
+
typeof child === 'boolean') {
|
|
171
|
+
continue
|
|
172
|
+
}
|
|
173
|
+
if (typeof child !== 'object' ||
|
|
174
|
+
ArrayBuffer.isView(child) ||
|
|
175
|
+
child._bsontype !== undefined ||
|
|
176
|
+
isRegExp(child) ||
|
|
177
|
+
isMap(child) ||
|
|
178
|
+
typeof child.toJSON === 'function') {
|
|
179
|
+
return false
|
|
180
|
+
}
|
|
181
|
+
if (!canStringifyDirectWalk(child, depth + 1)) return false
|
|
182
|
+
}
|
|
183
|
+
return true
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @param {Record<string, unknown> | unknown[]} input
|
|
188
|
+
* @param {'none' | 'types' | 'redact'} mode
|
|
189
|
+
*/
|
|
190
|
+
function sanitiseAndStringify (input, mode) {
|
|
191
|
+
if (mode === 'none') {
|
|
192
|
+
if (canStringifyDirect(input)) return JSON.stringify(input)
|
|
193
|
+
return buildNone(input, [])
|
|
194
|
+
}
|
|
195
|
+
if (mode === 'redact') return buildRedact(input, [])
|
|
196
|
+
return buildTypes(input, [])
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const REDACT_LEAF = '"?"'
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* @param {RegExp} value
|
|
203
|
+
* @returns {string}
|
|
204
|
+
*/
|
|
205
|
+
function stringifyRegExp (value) {
|
|
206
|
+
return `{"$regex":${JSON.stringify(value.source)},"$options":${JSON.stringify(value.flags)}}`
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* @param {Record<string, unknown> | unknown[]} value
|
|
211
|
+
* @param {object[]} ancestors
|
|
212
|
+
* @returns {string | undefined}
|
|
213
|
+
*/
|
|
214
|
+
function buildNone (value, ancestors) {
|
|
215
|
+
// ArrayBuffer views (Buffer, every TypedArray, DataView) and Binary BSON
|
|
216
|
+
// wrappers redact at the leaf; the walker neither recurses into the bytes
|
|
217
|
+
// nor invokes any custom conversion.
|
|
218
|
+
const bsontype = value._bsontype
|
|
219
|
+
if (ArrayBuffer.isView(value) || bsontype === 'Binary' ||
|
|
220
|
+
ancestors.length >= MAX_DEPTH || ancestors.includes(value)) {
|
|
221
|
+
return REDACT_LEAF
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (isRegExp(value)) return stringifyRegExp(value)
|
|
225
|
+
|
|
226
|
+
// Mirror JSON.stringify's contract: when `toJSON` is present, walk its
|
|
227
|
+
// result (wrappers like Timestamp / Decimal128 expand to a small object,
|
|
228
|
+
// ObjectId / Date flatten to a primitive).
|
|
229
|
+
if (typeof value.toJSON === 'function') {
|
|
230
|
+
const json = value.toJSON()
|
|
231
|
+
if (json === value) return REDACT_LEAF
|
|
232
|
+
// JSON.stringify keeps a null result as null (an invalid Date's toJSON
|
|
233
|
+
// returns null); only function / symbol / undefined results drop the key.
|
|
234
|
+
if (json === null) return 'null'
|
|
235
|
+
if (typeof json !== 'object') return classifyLeafForNone(json)
|
|
236
|
+
// A wrapper that exposes binary state through toJSON (Buffer-backed
|
|
237
|
+
// class with WeakMap state, etc.) returns a TypedArray here. Re-screen
|
|
238
|
+
// before the per-key walk would expand it element by element.
|
|
239
|
+
if (ArrayBuffer.isView(json) || json._bsontype === 'Binary') return REDACT_LEAF
|
|
240
|
+
value = json
|
|
241
|
+
} else if (bsontype !== undefined) {
|
|
242
|
+
return REDACT_LEAF
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// The driver serializes a Map via its entries; mirror that as a document so
|
|
246
|
+
// the tag matches the wire shape.
|
|
247
|
+
if (isMap(value)) value = Object.fromEntries(value)
|
|
248
|
+
|
|
249
|
+
ancestors.push(value)
|
|
250
|
+
|
|
251
|
+
let result
|
|
252
|
+
if (Array.isArray(value)) {
|
|
253
|
+
result = '['
|
|
254
|
+
let sep = ''
|
|
255
|
+
for (let i = 0; i < value.length; i++) {
|
|
256
|
+
// JSON.stringify renders unsupported leaves (function, symbol, undefined) as null in arrays.
|
|
257
|
+
result += sep + (classifyForNone(value[i], ancestors) ?? 'null')
|
|
258
|
+
sep = ','
|
|
259
|
+
}
|
|
260
|
+
result += ']'
|
|
261
|
+
} else {
|
|
262
|
+
result = '{'
|
|
263
|
+
let sep = ''
|
|
264
|
+
for (const key of Object.keys(value)) {
|
|
265
|
+
const childResult = classifyForNone(value[key], ancestors)
|
|
266
|
+
if (childResult === undefined) continue
|
|
267
|
+
result += sep + JSON.stringify(key) + ':' + childResult
|
|
268
|
+
sep = ','
|
|
269
|
+
}
|
|
270
|
+
result += '}'
|
|
271
|
+
}
|
|
272
|
+
ancestors.pop()
|
|
273
|
+
return result
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* @param {unknown} child
|
|
278
|
+
* @param {object[]} ancestors
|
|
279
|
+
* @returns {string | undefined}
|
|
280
|
+
*/
|
|
281
|
+
function classifyForNone (child, ancestors) {
|
|
282
|
+
if (typeof child !== 'object') return classifyLeafForNone(child)
|
|
283
|
+
if (child === null) return 'null'
|
|
284
|
+
return buildNone(child, ancestors)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* @param {unknown} leaf
|
|
289
|
+
* @returns {string | undefined}
|
|
290
|
+
*/
|
|
291
|
+
function classifyLeafForNone (leaf) {
|
|
292
|
+
// Implicit `undefined` for function / symbol / undefined matches the
|
|
293
|
+
// contract callers rely on: JSON.stringify drops those property values
|
|
294
|
+
// inside objects and writes `null` in arrays.
|
|
295
|
+
switch (typeof leaf) {
|
|
296
|
+
case 'string': return JSON.stringify(leaf)
|
|
297
|
+
case 'number': return Number.isFinite(leaf) ? String(leaf) : 'null'
|
|
298
|
+
case 'boolean': return leaf ? 'true' : 'false'
|
|
299
|
+
case 'bigint': return `"${String(leaf)}"`
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @param {Record<string, unknown> | unknown[]} value
|
|
305
|
+
* @param {object[]} ancestors
|
|
306
|
+
*/
|
|
307
|
+
function buildRedact (value, ancestors) {
|
|
308
|
+
const bsontype = value._bsontype
|
|
309
|
+
if (ArrayBuffer.isView(value) || bsontype === 'Binary' || isRegExp(value) ||
|
|
310
|
+
ancestors.length >= MAX_DEPTH || ancestors.includes(value)) {
|
|
311
|
+
return REDACT_LEAF
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Mirror JSON.stringify: when `toJSON` is present, walk its result (which
|
|
315
|
+
// wrappers like Timestamp / Decimal128 expand to `{$timestamp: "..."}` etc).
|
|
316
|
+
// A primitive, null, or self-reference collapses to the sentinel — master's
|
|
317
|
+
// `value === original` short-circuit.
|
|
318
|
+
if (typeof value.toJSON === 'function') {
|
|
319
|
+
const json = value.toJSON()
|
|
320
|
+
if (typeof json !== 'object' || json === null || json === value) return REDACT_LEAF
|
|
321
|
+
// Re-screen: toJSON can return a TypedArray or Binary BSON wrapper.
|
|
322
|
+
if (ArrayBuffer.isView(json) || json._bsontype === 'Binary') return REDACT_LEAF
|
|
323
|
+
value = json
|
|
324
|
+
} else if (bsontype !== undefined) {
|
|
325
|
+
return REDACT_LEAF
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (isMap(value)) value = Object.fromEntries(value)
|
|
329
|
+
|
|
330
|
+
ancestors.push(value)
|
|
331
|
+
|
|
332
|
+
let result
|
|
333
|
+
if (Array.isArray(value)) {
|
|
334
|
+
result = '['
|
|
335
|
+
let sep = ''
|
|
336
|
+
for (let i = 0; i < value.length; i++) {
|
|
337
|
+
result += sep + classifyForRedact(value[i], ancestors)
|
|
338
|
+
sep = ','
|
|
155
339
|
}
|
|
340
|
+
result += ']'
|
|
341
|
+
} else {
|
|
342
|
+
result = '{'
|
|
343
|
+
let sep = ''
|
|
344
|
+
for (const key of Object.keys(value)) {
|
|
345
|
+
result += sep + JSON.stringify(key) + ':' + classifyForRedact(value[key], ancestors)
|
|
346
|
+
sep = ','
|
|
347
|
+
}
|
|
348
|
+
result += '}'
|
|
349
|
+
}
|
|
350
|
+
ancestors.pop()
|
|
351
|
+
return result
|
|
352
|
+
}
|
|
156
353
|
|
|
157
|
-
|
|
354
|
+
/**
|
|
355
|
+
* @param {unknown} child
|
|
356
|
+
* @param {object[]} ancestors
|
|
357
|
+
*/
|
|
358
|
+
function classifyForRedact (child, ancestors) {
|
|
359
|
+
if (typeof child !== 'object' || child === null) return REDACT_LEAF
|
|
360
|
+
return buildRedact(child, ancestors)
|
|
361
|
+
}
|
|
158
362
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
363
|
+
const TYPE_OBJECT = '"object"'
|
|
364
|
+
const TYPE_NULL = '"null"'
|
|
365
|
+
const TYPE_BY_TYPEOF = {
|
|
366
|
+
string: '"string"',
|
|
367
|
+
number: '"number"',
|
|
368
|
+
boolean: '"boolean"',
|
|
369
|
+
bigint: '"bigint"',
|
|
370
|
+
undefined: '"undefined"',
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* @param {Record<string, unknown> | unknown[]} value
|
|
375
|
+
* @param {object[]} ancestors
|
|
376
|
+
*/
|
|
377
|
+
function buildTypes (value, ancestors) {
|
|
378
|
+
const bsontype = value._bsontype
|
|
379
|
+
if (ArrayBuffer.isView(value) || bsontype === 'Binary' || isRegExp(value) ||
|
|
380
|
+
ancestors.length >= MAX_DEPTH || ancestors.includes(value)) {
|
|
381
|
+
return TYPE_OBJECT
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (typeof value.toJSON === 'function') {
|
|
385
|
+
const json = value.toJSON()
|
|
386
|
+
if (typeof json !== 'object' ||
|
|
387
|
+
json === null ||
|
|
388
|
+
json === value ||
|
|
389
|
+
ArrayBuffer.isView(json) ||
|
|
390
|
+
json._bsontype === 'Binary') {
|
|
391
|
+
return TYPE_OBJECT
|
|
392
|
+
}
|
|
393
|
+
value = json
|
|
394
|
+
} else if (bsontype !== undefined) {
|
|
395
|
+
return TYPE_OBJECT
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (isMap(value)) value = Object.fromEntries(value)
|
|
399
|
+
|
|
400
|
+
ancestors.push(value)
|
|
401
|
+
|
|
402
|
+
let result
|
|
403
|
+
if (Array.isArray(value)) {
|
|
404
|
+
result = '['
|
|
405
|
+
let sep = ''
|
|
406
|
+
for (let i = 0; i < value.length; i++) {
|
|
407
|
+
// JSON.stringify renders unsupported leaves (function, symbol) as null in arrays.
|
|
408
|
+
result += sep + (classifyForTypes(value[i], ancestors) ?? 'null')
|
|
409
|
+
sep = ','
|
|
410
|
+
}
|
|
411
|
+
result += ']'
|
|
412
|
+
} else {
|
|
413
|
+
result = '{'
|
|
414
|
+
let sep = ''
|
|
415
|
+
for (const key of Object.keys(value)) {
|
|
416
|
+
const childResult = classifyForTypes(value[key], ancestors)
|
|
417
|
+
if (childResult === undefined) continue
|
|
418
|
+
result += sep + JSON.stringify(key) + ':' + childResult
|
|
419
|
+
sep = ','
|
|
420
|
+
}
|
|
421
|
+
result += '}'
|
|
422
|
+
}
|
|
423
|
+
ancestors.pop()
|
|
424
|
+
return result
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* @param {unknown} child
|
|
429
|
+
* @param {object[]} ancestors
|
|
430
|
+
*/
|
|
431
|
+
function classifyForTypes (child, ancestors) {
|
|
432
|
+
if (typeof child !== 'object') return TYPE_BY_TYPEOF[typeof child]
|
|
433
|
+
if (child === null) return TYPE_NULL
|
|
434
|
+
return buildTypes(child, ancestors)
|
|
435
|
+
}
|
|
162
436
|
|
|
163
|
-
|
|
164
|
-
|
|
437
|
+
/** @param {unknown} value */
|
|
438
|
+
function normaliseObfuscateQuery (value) {
|
|
439
|
+
if (value === 'types' || value === 'redact') return value
|
|
440
|
+
return 'none'
|
|
165
441
|
}
|
|
166
442
|
|
|
167
443
|
function isHeartbeat (ops, config) {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { TEXT_MAP } = require('../../../ext/formats')
|
|
4
|
+
const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
|
|
5
|
+
const { headersToTextMap } = require('./util')
|
|
6
|
+
|
|
7
|
+
const MESSAGING_DESTINATION_KEY = 'messaging.destination.name'
|
|
8
|
+
|
|
9
|
+
class NatsConsumerPlugin extends ConsumerPlugin {
|
|
10
|
+
static id = 'nats'
|
|
11
|
+
static operation = 'consume'
|
|
12
|
+
|
|
13
|
+
bindStart (ctx) {
|
|
14
|
+
const { subject: filter, message } = ctx
|
|
15
|
+
// For wildcard subscriptions (e.g. `orders.*`), `filter` is the subscription
|
|
16
|
+
// pattern but `message.subject` is the actual delivered subject. Prefer the
|
|
17
|
+
// delivered one for resource/destination so spans aren't all collapsed under
|
|
18
|
+
// the wildcard pattern. Fall back to the filter if the message is missing it.
|
|
19
|
+
const subject = typeof message?.subject === 'string' ? message.subject : filter
|
|
20
|
+
const carrier = headersToTextMap(message?.headers)
|
|
21
|
+
const childOf = carrier ? this.tracer.extract(TEXT_MAP, carrier) : null
|
|
22
|
+
|
|
23
|
+
const meta = {
|
|
24
|
+
component: 'nats',
|
|
25
|
+
'nats.subject': subject,
|
|
26
|
+
[MESSAGING_DESTINATION_KEY]: subject,
|
|
27
|
+
}
|
|
28
|
+
if (filter && filter !== subject) {
|
|
29
|
+
meta['nats.subscription.subject'] = filter
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
this.startSpan({
|
|
33
|
+
childOf,
|
|
34
|
+
resource: subject,
|
|
35
|
+
type: 'worker',
|
|
36
|
+
meta,
|
|
37
|
+
}, ctx)
|
|
38
|
+
|
|
39
|
+
return ctx.currentStore
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = NatsConsumerPlugin
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
4
|
+
const ProducerPlugin = require('./producer')
|
|
5
|
+
const ConsumerPlugin = require('./consumer')
|
|
6
|
+
|
|
7
|
+
class NatsPlugin extends CompositePlugin {
|
|
8
|
+
static id = 'nats'
|
|
9
|
+
// Disabled by default — users must opt in via DD_TRACE_NATS_ENABLED=true
|
|
10
|
+
// or `tracer.use('nats')`. Matches the feature parity dashboard policy.
|
|
11
|
+
static experimental = true
|
|
12
|
+
static get plugins () {
|
|
13
|
+
return {
|
|
14
|
+
producer: ProducerPlugin,
|
|
15
|
+
consumer: ConsumerPlugin,
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = NatsPlugin
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { TEXT_MAP } = require('../../../ext/formats')
|
|
4
|
+
const { CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
|
|
5
|
+
const ProducerPlugin = require('../../dd-trace/src/plugins/producer')
|
|
6
|
+
const { getOperationName } = require('./util')
|
|
7
|
+
|
|
8
|
+
const MESSAGING_DESTINATION_KEY = 'messaging.destination.name'
|
|
9
|
+
|
|
10
|
+
class NatsProducerPlugin extends ProducerPlugin {
|
|
11
|
+
static id = 'nats'
|
|
12
|
+
static operation = 'publish'
|
|
13
|
+
static peerServicePrecursors = [MESSAGING_DESTINATION_KEY]
|
|
14
|
+
|
|
15
|
+
bindStart (ctx) {
|
|
16
|
+
const { subject, options, connection, type, createHeaders } = ctx
|
|
17
|
+
const server = connection?.protocol?.servers?.getCurrent?.() ??
|
|
18
|
+
connection?.protocol?.servers?.getCurrentServer?.()
|
|
19
|
+
const operation = getOperationName(type)
|
|
20
|
+
|
|
21
|
+
const span = this.startSpan({
|
|
22
|
+
resource: subject,
|
|
23
|
+
meta: {
|
|
24
|
+
component: 'nats',
|
|
25
|
+
'nats.subject': subject,
|
|
26
|
+
'nats.operation': operation,
|
|
27
|
+
[MESSAGING_DESTINATION_KEY]: subject,
|
|
28
|
+
'out.host': server?.hostname,
|
|
29
|
+
},
|
|
30
|
+
}, ctx)
|
|
31
|
+
|
|
32
|
+
if (server?.port) {
|
|
33
|
+
span.setTag(CLIENT_PORT_KEY, server.port)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (this.serverSupportsHeaders(connection)) {
|
|
37
|
+
let headers = options.headers
|
|
38
|
+
if (!headers && typeof createHeaders === 'function') {
|
|
39
|
+
headers = createHeaders()
|
|
40
|
+
options.headers = headers
|
|
41
|
+
}
|
|
42
|
+
if (headers && typeof headers.set === 'function') {
|
|
43
|
+
const carrier = {}
|
|
44
|
+
this.tracer.inject(span, TEXT_MAP, carrier)
|
|
45
|
+
for (const key of Object.keys(carrier)) {
|
|
46
|
+
headers.set(key, carrier[key])
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return ctx.currentStore
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
serverSupportsHeaders (connection) {
|
|
55
|
+
const info = connection?.protocol?.info
|
|
56
|
+
// If info isn't available yet (e.g. publish before INFO), assume supported — modern NATS does.
|
|
57
|
+
if (!info) return true
|
|
58
|
+
return info.headers !== false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = NatsProducerPlugin
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function headersToTextMap (msgHdrs) {
|
|
4
|
+
if (!msgHdrs || typeof msgHdrs[Symbol.iterator] !== 'function') return null
|
|
5
|
+
const textMap = {}
|
|
6
|
+
for (const [key, values] of msgHdrs) {
|
|
7
|
+
if (!Array.isArray(values) || values.length === 0) continue
|
|
8
|
+
// Trace headers are single-valued (injected via `set`, not `append`), so
|
|
9
|
+
// the first element is always the authoritative value.
|
|
10
|
+
textMap[key] = values[0]
|
|
11
|
+
}
|
|
12
|
+
return textMap
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getOperationName (type) {
|
|
16
|
+
switch (type) {
|
|
17
|
+
case 'publish':
|
|
18
|
+
return 'publish'
|
|
19
|
+
case 'request':
|
|
20
|
+
case 'requestMany':
|
|
21
|
+
return 'request'
|
|
22
|
+
default:
|
|
23
|
+
// Surface unrecognized operations explicitly rather than silently
|
|
24
|
+
// collapsing them into 'publish' — if NATS adds a new outbound API,
|
|
25
|
+
// this lets us see it in traces and fix the mapping deliberately.
|
|
26
|
+
return 'unknown'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
headersToTextMap,
|
|
32
|
+
getOperationName,
|
|
33
|
+
}
|
|
@@ -33,11 +33,13 @@ class NextPlugin extends ServerPlugin {
|
|
|
33
33
|
'span.type': 'web',
|
|
34
34
|
'span.kind': 'server',
|
|
35
35
|
'http.method': req.method,
|
|
36
|
-
...(serviceSource === undefined ?
|
|
36
|
+
...(serviceSource === undefined ? undefined : { [SVC_SRC_KEY]: serviceSource }),
|
|
37
37
|
},
|
|
38
38
|
integrationName: this.constructor.id,
|
|
39
39
|
})
|
|
40
40
|
|
|
41
|
+
this.stampIntegrationService(span, serviceName)
|
|
42
|
+
|
|
41
43
|
analyticsSampler.sample(span, this.config.measured, true)
|
|
42
44
|
|
|
43
45
|
return { ...store, span, req }
|
|
@@ -60,7 +62,7 @@ class NextPlugin extends ServerPlugin {
|
|
|
60
62
|
if (!store) return
|
|
61
63
|
|
|
62
64
|
const span = store.span
|
|
63
|
-
const error = span.context().
|
|
65
|
+
const error = span.context().getTag('error')
|
|
64
66
|
const requestError = req.error || nextRequest.error
|
|
65
67
|
|
|
66
68
|
if (requestError) {
|
|
@@ -97,7 +99,7 @@ class NextPlugin extends ServerPlugin {
|
|
|
97
99
|
if (!req) return
|
|
98
100
|
|
|
99
101
|
// Only use error page names if there's not already a name
|
|
100
|
-
const current = span.context().
|
|
102
|
+
const current = span.context().getTag('next.page')
|
|
101
103
|
const isErrorPage = errorPages.has(page)
|
|
102
104
|
|
|
103
105
|
if (current && isErrorPage) {
|
|
@@ -8,6 +8,7 @@ const Sampler = require('../../dd-trace/src/sampler')
|
|
|
8
8
|
const { MEASURED } = require('../../../ext/tags')
|
|
9
9
|
|
|
10
10
|
const { DD_MAJOR } = require('../../../version')
|
|
11
|
+
const { ERROR_TYPE } = require('../../dd-trace/src/constants')
|
|
11
12
|
const {
|
|
12
13
|
convertBuffersToObjects,
|
|
13
14
|
constructCompletionResponseFromStreamedChunks,
|
|
@@ -157,7 +158,7 @@ class OpenAiTracingPlugin extends TracingPlugin {
|
|
|
157
158
|
const span = store?.span
|
|
158
159
|
if (!span) return
|
|
159
160
|
|
|
160
|
-
const error = !!span.context().
|
|
161
|
+
const error = !!span.context().getTag('error')
|
|
161
162
|
|
|
162
163
|
let headers, body, method, path
|
|
163
164
|
if (!error) {
|
|
@@ -171,7 +172,7 @@ class OpenAiTracingPlugin extends TracingPlugin {
|
|
|
171
172
|
headers = Object.fromEntries(headers)
|
|
172
173
|
}
|
|
173
174
|
|
|
174
|
-
const resource = span.
|
|
175
|
+
const resource = span.context().getTag('resource.name')
|
|
175
176
|
const normalizedMethodName = store.normalizedMethodName
|
|
176
177
|
|
|
177
178
|
body = coerceResponseBody(body, normalizedMethodName)
|
|
@@ -211,6 +212,18 @@ class OpenAiTracingPlugin extends TracingPlugin {
|
|
|
211
212
|
this.sendMetrics(headers, body, endpoint, span._duration, error, tags)
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
error (ctx) {
|
|
216
|
+
const span = ctx.currentStore?.span
|
|
217
|
+
if (!span) return
|
|
218
|
+
|
|
219
|
+
super.error(ctx) // add normal error tag
|
|
220
|
+
|
|
221
|
+
const errorType = ctx.error?.type
|
|
222
|
+
if (errorType) {
|
|
223
|
+
span.setTag(ERROR_TYPE, errorType)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
214
227
|
sendMetrics (headers, body, endpoint, duration, error, spanTags) {
|
|
215
228
|
const tags = [`error:${Number(!!error)}`]
|
|
216
229
|
if (error) {
|