dd-trace 6.9.0 → 6.11.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/README.md +0 -17
- package/ci/vitest-no-worker-init-setup.mjs +112 -10
- package/index.d.ts +150 -3
- package/initialize.mjs +28 -17
- package/openfeature.js +2 -2
- package/package.json +14 -10
- package/packages/datadog-esbuild/index.js +0 -34
- package/packages/datadog-instrumentations/src/anthropic.js +210 -15
- package/packages/datadog-instrumentations/src/aws-sdk.js +9 -1
- package/packages/datadog-instrumentations/src/browser-bunyan.js +11 -0
- package/packages/datadog-instrumentations/src/bunyan.js +3 -16
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
- package/packages/datadog-instrumentations/src/cucumber.js +26 -11
- package/packages/datadog-instrumentations/src/cypress-config.js +182 -16
- package/packages/datadog-instrumentations/src/cypress-legacy-finalizers.js +30 -0
- package/packages/datadog-instrumentations/src/cypress.js +2 -0
- package/packages/datadog-instrumentations/src/fastify.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +22 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +634 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -8
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +81 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
- package/packages/datadog-instrumentations/src/jest.js +26 -18
- package/packages/datadog-instrumentations/src/mariadb.js +278 -21
- package/packages/datadog-instrumentations/src/mocha/main.js +540 -56
- package/packages/datadog-instrumentations/src/mocha/utils.js +132 -25
- package/packages/datadog-instrumentations/src/mysql.js +45 -15
- package/packages/datadog-instrumentations/src/mysql2.js +119 -18
- package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
- package/packages/datadog-instrumentations/src/pg.js +116 -92
- package/packages/datadog-instrumentations/src/playwright-reporter.js +99 -0
- package/packages/datadog-instrumentations/src/playwright.js +149 -2
- package/packages/datadog-instrumentations/src/router.js +2 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -4
- package/packages/datadog-instrumentations/src/vitest-main.js +180 -20
- package/packages/datadog-instrumentations/src/vitest-util.js +64 -5
- package/packages/datadog-instrumentations/src/vitest-worker.js +150 -25
- package/packages/datadog-instrumentations/src/webdriverio.js +31 -17
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
- package/packages/datadog-plugin-aws-sdk/src/base.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +163 -44
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -13
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-browser-bunyan/src/index.js +9 -0
- package/packages/datadog-plugin-bunyan/src/index.js +5 -8
- package/packages/datadog-plugin-cucumber/src/index.js +11 -0
- package/packages/datadog-plugin-cypress/src/after-run.js +5 -1
- package/packages/datadog-plugin-cypress/src/after-spec.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +82 -30
- package/packages/datadog-plugin-cypress/src/finalization.js +76 -0
- package/packages/datadog-plugin-cypress/src/index.js +12 -6
- package/packages/datadog-plugin-cypress/src/plugin.js +16 -3
- package/packages/datadog-plugin-dd-trace-api/src/index.js +4 -0
- package/packages/datadog-plugin-electron/src/index.js +2 -0
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
- package/packages/datadog-plugin-jest/src/index.js +11 -4
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -2
- package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
- package/packages/datadog-plugin-mocha/src/index.js +606 -40
- package/packages/datadog-plugin-mysql/src/index.js +37 -0
- package/packages/datadog-plugin-nats/src/index.js +1 -1
- package/packages/datadog-plugin-next/src/index.js +1 -19
- package/packages/datadog-plugin-openai/src/tracing.js +41 -30
- package/packages/datadog-plugin-openai-agents/src/integration.js +279 -69
- package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
- package/packages/datadog-plugin-pg/src/index.js +1 -0
- package/packages/datadog-plugin-playwright/src/index.js +42 -13
- package/packages/datadog-plugin-vitest/src/index.js +14 -20
- package/packages/datadog-plugin-ws/src/util.js +2 -1
- package/packages/datadog-webpack/index.js +0 -11
- package/packages/dd-trace/index.js +0 -1
- package/packages/dd-trace/src/agent/info.js +6 -5
- package/packages/dd-trace/src/aiguard/client.js +100 -1
- package/packages/dd-trace/src/aiguard/errors.js +41 -0
- package/packages/dd-trace/src/aiguard/evaluation.js +357 -0
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +70 -0
- package/packages/dd-trace/src/aiguard/integrations/index.js +4 -0
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +423 -0
- package/packages/dd-trace/src/aiguard/messages/openai.js +1 -24
- package/packages/dd-trace/src/aiguard/messages/utils.js +28 -0
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +1 -11
- package/packages/dd-trace/src/aiguard/sdk.js +22 -278
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +13 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -12
- package/packages/dd-trace/src/carrier.js +356 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +1 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +27 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +21 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +164 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +365 -32
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +201 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +5 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -5
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +39 -0
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -6
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +6 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -0
- package/packages/dd-trace/src/config/index.js +13 -2
- package/packages/dd-trace/src/config/major-overrides.js +7 -0
- package/packages/dd-trace/src/config/supported-configurations.json +24 -0
- package/packages/dd-trace/src/datastreams/context.js +6 -1
- package/packages/dd-trace/src/datastreams/index.js +2 -0
- package/packages/dd-trace/src/datastreams/manager.js +14 -3
- package/packages/dd-trace/src/datastreams/pathway.js +23 -22
- package/packages/dd-trace/src/datastreams/processor.js +16 -13
- package/packages/dd-trace/src/datastreams/size.js +5 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +3 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +49 -9
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +6 -4
- package/packages/dd-trace/src/exporters/common/writer.js +11 -6
- package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +163 -5
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +241 -87
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +280 -20
- package/packages/dd-trace/src/llmobs/experiments/index.js +58 -59
- package/packages/dd-trace/src/llmobs/experiments/noop.js +71 -3
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +41 -5
- package/packages/dd-trace/src/llmobs/index.js +34 -2
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -3
- package/packages/dd-trace/src/llmobs/plugins/base.js +4 -2
- package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
- package/packages/dd-trace/src/llmobs/tagger.js +96 -0
- package/packages/dd-trace/src/llmobs/util.js +78 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -4
- package/packages/dd-trace/src/openfeature/flagging_provider.js +18 -2
- package/packages/dd-trace/src/openfeature/remote_config.js +1 -1
- package/packages/dd-trace/src/opentelemetry/context_manager.js +7 -7
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +2 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +67 -11
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +14 -3
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +25 -12
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +2 -5
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +96 -43
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
- package/packages/dd-trace/src/opentracing/tracer.js +5 -2
- package/packages/dd-trace/src/otel-thread-ctx.js +387 -0
- package/packages/dd-trace/src/plugin_manager.js +5 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +5 -65
- package/packages/dd-trace/src/plugins/util/test.js +93 -14
- package/packages/dd-trace/src/plugins/util/web.js +56 -2
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +37 -90
- package/packages/dd-trace/src/profiling/webspan-utils.js +45 -0
- package/packages/dd-trace/src/proxy.js +38 -29
- package/packages/dd-trace/src/ritm.js +9 -2
- package/packages/dd-trace/src/serverless.js +37 -0
- package/packages/dd-trace/src/span_format.js +1 -0
- package/packages/dd-trace/src/span_stats.js +30 -3
- package/packages/dd-trace/src/storage-channels.js +86 -0
- package/packages/dd-trace/src/tracer.js +9 -2
- package/packages/dd-trace/src/tracer_metadata.js +14 -1
- package/packages/dd-trace/src/web-tags-cache.js +132 -0
- package/vendor/dist/@datadog/openfeature-node-server/LICENSE +201 -0
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +0 -65
- package/packages/datadog-webpack/src/optional-peer-loader.js +0 -17
- package/packages/dd-trace/src/feature-registry.js +0 -29
- package/packages/dd-trace/src/openfeature/register.js +0 -35
- package/packages/dd-trace/src/openfeature/require-provider.js +0 -18
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { features } = require('../feature-registry')
|
|
4
3
|
const NoopAppsecSdk = require('../appsec/sdk/noop')
|
|
5
4
|
const NoopLLMObsSDK = require('../llmobs/noop')
|
|
6
5
|
const NoopAIGuardSDK = require('../aiguard/noop')
|
|
6
|
+
const NoopFlaggingProvider = require('../openfeature/noop')
|
|
7
7
|
const NoopDogStatsDClient = require('./dogstatsd')
|
|
8
8
|
const NoopTracer = require('./tracer')
|
|
9
9
|
|
|
@@ -12,6 +12,7 @@ const noopAppsec = new NoopAppsecSdk()
|
|
|
12
12
|
const noopDogStatsDClient = new NoopDogStatsDClient()
|
|
13
13
|
const noopLLMObs = new NoopLLMObsSDK(noop)
|
|
14
14
|
const noopAIGuard = new NoopAIGuardSDK()
|
|
15
|
+
const noopFlaggingProviderInstance = new NoopFlaggingProvider()
|
|
15
16
|
const noopProfiling = {
|
|
16
17
|
setCustomLabelKeys () {},
|
|
17
18
|
runWithLabels (labels, fn) { return fn() },
|
|
@@ -25,9 +26,7 @@ class NoopProxy {
|
|
|
25
26
|
this.dogstatsd = noopDogStatsDClient
|
|
26
27
|
this.llmobs = noopLLMObs
|
|
27
28
|
this.aiguard = noopAIGuard
|
|
28
|
-
|
|
29
|
-
this[name] = noop
|
|
30
|
-
}
|
|
29
|
+
this.openfeature = noopFlaggingProviderInstance
|
|
31
30
|
this.setBaggageItem = (key, value) => {}
|
|
32
31
|
this.getBaggageItem = (key) => {}
|
|
33
32
|
this.getAllBaggageItems = () => {}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { channel } = require('dc-polyfill')
|
|
4
|
+
|
|
5
|
+
const { DatadogNodeServerProvider } = require('../../../../vendor/dist/@datadog/openfeature-node-server')
|
|
4
6
|
const log = require('../log')
|
|
5
7
|
const configurationSource = require('./configuration_source')
|
|
6
8
|
const { EXPOSURE_CHANNEL } = require('./constants/constants')
|
|
7
9
|
const EvalMetricsHook = require('./eval-metrics-hook')
|
|
8
10
|
const SpanEnrichmentHook = require('./span-enrichment-hook')
|
|
9
11
|
|
|
10
|
-
const { DatadogNodeServerProvider } = require('./require-provider')
|
|
11
|
-
|
|
12
12
|
/**
|
|
13
13
|
* OpenFeature provider that integrates with Datadog's feature flagging system.
|
|
14
14
|
* Extends DatadogNodeServerProvider to add tracer integration and configuration management.
|
|
@@ -48,6 +48,22 @@ class FlaggingProvider extends DatadogNodeServerProvider {
|
|
|
48
48
|
this.#configurationSource?.start()
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @param {import('@openfeature/core').EvaluationContext} [context]
|
|
53
|
+
* @returns {Promise<void>}
|
|
54
|
+
*/
|
|
55
|
+
initialize (context) {
|
|
56
|
+
const promise = super.initialize(context)
|
|
57
|
+
|
|
58
|
+
// `DatadogNodeServerProvider#initialize` starts a timer that is never unref'd, which would
|
|
59
|
+
// otherwise keep an idle process (a short script, a serverless handler) alive for up to
|
|
60
|
+
// `initializationTimeoutMs` while waiting for configuration to arrive.
|
|
61
|
+
// TODO: remove once `@datadog/openfeature-node-server` unrefs this timer itself.
|
|
62
|
+
this.initController?.timeoutId?.unref?.()
|
|
63
|
+
|
|
64
|
+
return promise
|
|
65
|
+
}
|
|
66
|
+
|
|
51
67
|
/**
|
|
52
68
|
* Called when the provider is shut down.
|
|
53
69
|
* Cleans up resources including channel subscriptions.
|
|
@@ -6,7 +6,7 @@ const RemoteConfigCapabilities = require('../remote_config/capabilities')
|
|
|
6
6
|
* Configures remote config handlers for openfeature feature flagging
|
|
7
7
|
*
|
|
8
8
|
* @param {import('../remote_config')} rc - RemoteConfig instance
|
|
9
|
-
* @param {() => import('./flagging_provider')} getOpenfeatureProxy
|
|
9
|
+
* @param {() => InstanceType<ReturnType<typeof import('./flagging_provider')>>} getOpenfeatureProxy
|
|
10
10
|
* @param {boolean} subscribe - Whether Agent Remote Config owns UFC delivery
|
|
11
11
|
*/
|
|
12
12
|
function enable (rc, getOpenfeatureProxy, subscribe) {
|
|
@@ -21,14 +21,14 @@ class ContextManager {
|
|
|
21
21
|
const storedSpan = store ? trace.getSpan(store) : null
|
|
22
22
|
|
|
23
23
|
// Convert DD baggage to OTel format
|
|
24
|
-
|
|
25
|
-
const
|
|
24
|
+
let entries
|
|
25
|
+
for (const [key, value] of Object.entries(getAllBaggageItems())) {
|
|
26
|
+
entries ??= {}
|
|
27
|
+
entries[key] = { value }
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
let otelBaggages
|
|
27
|
-
if (
|
|
28
|
-
const entries = {}
|
|
29
|
-
for (const [key, value] of Object.entries(baggages)) {
|
|
30
|
-
entries[key] = { value }
|
|
31
|
-
}
|
|
31
|
+
if (entries !== undefined) {
|
|
32
32
|
otelBaggages = propagation.createBaggage(entries)
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -42,7 +42,8 @@ class BatchLogRecordProcessor {
|
|
|
42
42
|
*/
|
|
43
43
|
onEmit (logRecord, instrumentationScope) {
|
|
44
44
|
// Store the log record (already enriched by Logger.emit)
|
|
45
|
-
|
|
45
|
+
logRecord.instrumentationScope = instrumentationScope
|
|
46
|
+
this.#logRecords.push(logRecord)
|
|
46
47
|
|
|
47
48
|
if (this.#logRecords.length >= this.#maxExportBatchSize) {
|
|
48
49
|
this.#export()
|
|
@@ -1,8 +1,65 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { context } = require('@opentelemetry/api')
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
millisToHrTime,
|
|
6
|
+
sanitizeAttributes,
|
|
7
|
+
timeInputToHrTime,
|
|
8
|
+
} = require('../../../../../vendor/dist/@opentelemetry/core')
|
|
5
9
|
const { VERSION: packageVersion } = require('../../../../../version')
|
|
10
|
+
const log = require('../../log')
|
|
11
|
+
|
|
12
|
+
const MAX_DATE_MILLISECONDS = 8.64e15
|
|
13
|
+
const NANOSECONDS_PER_SECOND = 1e9
|
|
14
|
+
const MAX_UINT64_SECONDS = 18_446_744_073
|
|
15
|
+
const MAX_UINT64_NANOSECONDS = 709_551_615
|
|
16
|
+
let invalidTimestampWarningLogged = false
|
|
17
|
+
|
|
18
|
+
function isValidHrTime (hrTime) {
|
|
19
|
+
return Array.isArray(hrTime) &&
|
|
20
|
+
hrTime.length === 2 &&
|
|
21
|
+
Number.isInteger(hrTime[0]) &&
|
|
22
|
+
Number.isInteger(hrTime[1]) &&
|
|
23
|
+
hrTime[0] >= 0 &&
|
|
24
|
+
hrTime[1] >= 0 &&
|
|
25
|
+
hrTime[1] < NANOSECONDS_PER_SECOND &&
|
|
26
|
+
(hrTime[0] < MAX_UINT64_SECONDS ||
|
|
27
|
+
(hrTime[0] === MAX_UINT64_SECONDS && hrTime[1] <= MAX_UINT64_NANOSECONDS))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function toHrTime (timestamp) {
|
|
31
|
+
if (typeof timestamp === 'number') {
|
|
32
|
+
if (!Number.isFinite(timestamp)) return
|
|
33
|
+
|
|
34
|
+
// Older versions documented numeric timestamps as Unix nanoseconds.
|
|
35
|
+
if (Math.abs(timestamp) > MAX_DATE_MILLISECONDS) {
|
|
36
|
+
const seconds = Math.trunc(timestamp / NANOSECONDS_PER_SECOND)
|
|
37
|
+
const hrTime = [seconds, timestamp - seconds * NANOSECONDS_PER_SECOND]
|
|
38
|
+
return isValidHrTime(hrTime) ? hrTime : undefined
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const hrTime = timeInputToHrTime(timestamp)
|
|
44
|
+
return isValidHrTime(hrTime) ? hrTime : undefined
|
|
45
|
+
} catch {
|
|
46
|
+
// Invalid timestamps fall back to the current time in normalizeTimestamp.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function normalizeTimestamp (timestamp) {
|
|
51
|
+
if (timestamp !== undefined) {
|
|
52
|
+
const hrTime = toHrTime(timestamp)
|
|
53
|
+
if (hrTime) return hrTime
|
|
54
|
+
|
|
55
|
+
if (!invalidTimestampWarningLogged) {
|
|
56
|
+
invalidTimestampWarningLogged = true
|
|
57
|
+
log.warn('Invalid OpenTelemetry log timestamp; using the current time instead')
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return millisToHrTime(Date.now())
|
|
62
|
+
}
|
|
6
63
|
|
|
7
64
|
/**
|
|
8
65
|
* @typedef {import('@opentelemetry/api-logs').LogRecord} LogRecord
|
|
@@ -62,21 +119,20 @@ class Logger {
|
|
|
62
119
|
return
|
|
63
120
|
}
|
|
64
121
|
|
|
65
|
-
|
|
66
|
-
logRecord
|
|
122
|
+
const record = {
|
|
123
|
+
...logRecord,
|
|
124
|
+
timestamp: normalizeTimestamp(logRecord.timestamp),
|
|
125
|
+
context: logRecord.context || context.active(),
|
|
67
126
|
}
|
|
68
127
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
logRecord.timestamp = Number(process.hrtime.bigint())
|
|
128
|
+
if (logRecord.observedTimestamp !== undefined) {
|
|
129
|
+
record.observedTimestamp = normalizeTimestamp(logRecord.observedTimestamp)
|
|
72
130
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// Store span context in the log record context for trace correlation
|
|
76
|
-
logRecord.context = context.active()
|
|
131
|
+
if (logRecord.attributes) {
|
|
132
|
+
record.attributes = sanitizeAttributes(logRecord.attributes)
|
|
77
133
|
}
|
|
78
134
|
|
|
79
|
-
this.loggerProvider.processor.onEmit(
|
|
135
|
+
this.loggerProvider.processor.onEmit(record, this.#instrumentationScope)
|
|
80
136
|
}
|
|
81
137
|
}
|
|
82
138
|
|
|
@@ -38,6 +38,17 @@ const SEVERITY_MAP = {
|
|
|
38
38
|
[SeverityNumber.FATAL4]: 'SEVERITY_NUMBER_FATAL4',
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
const NANOSECONDS_PER_SECOND = 1_000_000_000n
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Converts an OpenTelemetry HrTime to an exact OTLP uint64 decimal string.
|
|
45
|
+
* @param {import('@opentelemetry/api').HrTime} hrTime
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
function encodeHrTime (hrTime) {
|
|
49
|
+
return (BigInt(hrTime[0]) * NANOSECONDS_PER_SECOND + BigInt(hrTime[1])).toString()
|
|
50
|
+
}
|
|
51
|
+
|
|
41
52
|
/**
|
|
42
53
|
* OtlpTransformer transforms log records to OTLP format.
|
|
43
54
|
*
|
|
@@ -138,13 +149,13 @@ class OtlpTransformer extends OtlpTransformerBase {
|
|
|
138
149
|
const spanContext = this.#extractSpanContext(logRecord.context)
|
|
139
150
|
|
|
140
151
|
const result = {
|
|
141
|
-
timeUnixNano: logRecord.timestamp,
|
|
152
|
+
timeUnixNano: encodeHrTime(logRecord.timestamp),
|
|
142
153
|
body: this.#transformBody(logRecord.body),
|
|
143
154
|
}
|
|
144
155
|
|
|
145
156
|
// Add optional fields only if they are set
|
|
146
|
-
if (logRecord.observedTimestamp) {
|
|
147
|
-
result.observedTimeUnixNano = logRecord.observedTimestamp
|
|
157
|
+
if (logRecord.observedTimestamp !== undefined) {
|
|
158
|
+
result.observedTimeUnixNano = encodeHrTime(logRecord.observedTimestamp)
|
|
148
159
|
}
|
|
149
160
|
|
|
150
161
|
if (logRecord.severityNumber !== undefined) {
|
|
@@ -10,6 +10,8 @@ const MeterProvider = require('./meter_provider')
|
|
|
10
10
|
const PeriodicMetricReader = require('./periodic_metric_reader')
|
|
11
11
|
const OtlpHttpMetricExporter = require('./otlp_http_metric_exporter')
|
|
12
12
|
|
|
13
|
+
const RESERVED_TRACER_TAGS = new Set(['service', 'env', 'version', 'runtime_id', 'runtime-id'])
|
|
14
|
+
|
|
13
15
|
/**
|
|
14
16
|
* @typedef {import('../../config')} Config
|
|
15
17
|
*/
|
|
@@ -78,7 +80,16 @@ function initializeOpenTelemetryMetrics (config) {
|
|
|
78
80
|
metrics.setGlobalMeterProvider(meterProvider)
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
|
|
83
|
+
/**
|
|
84
|
+
* @param {Record<string, unknown>} tags
|
|
85
|
+
* @param {object} [options]
|
|
86
|
+
* @param {boolean} [options.reportHostname]
|
|
87
|
+
* @param {string} [options.service]
|
|
88
|
+
* @param {string} [options.env]
|
|
89
|
+
* @param {string} [options.serviceVersion]
|
|
90
|
+
* @returns {import('@opentelemetry/api').Attributes}
|
|
91
|
+
*/
|
|
92
|
+
function buildResourceAttributes (tags, { reportHostname, service, env, serviceVersion } = {}) {
|
|
82
93
|
const attrs = {
|
|
83
94
|
'telemetry.sdk.name': 'datadog',
|
|
84
95
|
'telemetry.sdk.language': 'nodejs',
|
|
@@ -89,14 +100,19 @@ function buildResourceAttributes (tags, { reportHostname, otelSemanticsEnabled,
|
|
|
89
100
|
if (env) attrs['deployment.environment.name'] = env
|
|
90
101
|
if (reportHostname) attrs['host.name'] = os.hostname()
|
|
91
102
|
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
if (tags['runtime-id']) attrs['datadog.runtime_id'] = tags['runtime-id']
|
|
104
|
+
const tracerTags = []
|
|
105
|
+
for (const [key, value] of Object.entries(tags)) {
|
|
106
|
+
const valueType = typeof value
|
|
107
|
+
const supported = valueType === 'string' || valueType === 'boolean' ||
|
|
108
|
+
(valueType === 'number' && Number.isFinite(value))
|
|
109
|
+
if (!RESERVED_TRACER_TAGS.has(key) && supported) tracerTags.push(`${key}:${value}`)
|
|
110
|
+
}
|
|
111
|
+
if (tracerTags.length) attrs['datadog.tracer_tags'] = tracerTags
|
|
112
|
+
// Mirrors the legacy v0.6/stats ProcessTags shape (buildProcessTags().tagsArray); keep both in sync.
|
|
113
|
+
const processTagsArray = processTags.tagsArray
|
|
114
|
+
if (processTagsArray.length) {
|
|
115
|
+
attrs['datadog.process_tags'] = processTagsArray
|
|
100
116
|
}
|
|
101
117
|
return attrs
|
|
102
118
|
}
|
|
@@ -106,7 +122,6 @@ function createOtlpSpanStatsExporter (config) {
|
|
|
106
122
|
const protocol = config.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL || 'http/json'
|
|
107
123
|
const resourceAttributes = buildResourceAttributes(config.tags, {
|
|
108
124
|
reportHostname: config.reportHostname,
|
|
109
|
-
otelSemanticsEnabled: config.DD_TRACE_OTEL_SEMANTICS_ENABLED,
|
|
110
125
|
service: config.service,
|
|
111
126
|
env: config.env,
|
|
112
127
|
serviceVersion: config.version,
|
|
@@ -115,8 +130,6 @@ function createOtlpSpanStatsExporter (config) {
|
|
|
115
130
|
config.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
|
|
116
131
|
protocol,
|
|
117
132
|
resourceAttributes,
|
|
118
|
-
config.DD_TRACE_OTEL_SEMANTICS_ENABLED,
|
|
119
|
-
config.service,
|
|
120
133
|
config.OTEL_EXPORTER_OTLP_METRICS_HEADERS,
|
|
121
134
|
config.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT
|
|
122
135
|
)
|
|
@@ -11,15 +11,12 @@ class OtlpStatsExporter extends OtlpHttpExporterBase {
|
|
|
11
11
|
* @param {string} url
|
|
12
12
|
* @param {string} protocol
|
|
13
13
|
* @param {import('@opentelemetry/api').Attributes} resourceAttributes
|
|
14
|
-
* @param {boolean} [otelSemanticsEnabled]
|
|
15
|
-
* @param {string} [defaultService]
|
|
16
14
|
* @param {Record<string, string>} [headers]
|
|
17
15
|
* @param {number} [timeout]
|
|
18
16
|
*/
|
|
19
|
-
constructor (url, protocol, resourceAttributes,
|
|
20
|
-
headers, timeout = 10_000) {
|
|
17
|
+
constructor (url, protocol, resourceAttributes, headers, timeout = 10_000) {
|
|
21
18
|
super(url, headers, timeout, protocol, 'span-stats')
|
|
22
|
-
this.#transformer = new OtlpStatsTransformer(resourceAttributes, protocol
|
|
19
|
+
this.#transformer = new OtlpStatsTransformer(resourceAttributes, protocol)
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
/**
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { LogCollapsingLowestDenseDDSketch } = require('../../../../../vendor/dist/@datadog/sketches-js')
|
|
4
3
|
const OtlpTransformerBase = require('../otlp/otlp_transformer_base')
|
|
5
4
|
const { getProtobufTypes } = require('../otlp/protobuf_loader')
|
|
6
5
|
const { GRPC_STATUS_NAMES } = require('../../constants')
|
|
7
6
|
|
|
7
|
+
const { stableStringify } = OtlpTransformerBase
|
|
8
|
+
|
|
8
9
|
const NS_PER_S = 1e9
|
|
9
10
|
|
|
10
11
|
// Must match libdatadog's EXPLICIT_BOUNDS_SECONDS and OTel spanmetrics connector defaults.
|
|
@@ -12,6 +13,19 @@ const EXPLICIT_BOUNDS_SECONDS = [
|
|
|
12
13
|
0.002, 0.004, 0.006, 0.008, 0.01, 0.05, 0.1, 0.2, 0.4, 0.8, 1, 1.4, 2, 5, 10, 15,
|
|
13
14
|
]
|
|
14
15
|
|
|
16
|
+
const SPAN_KIND_METRIC_MAP = {
|
|
17
|
+
internal: 'SPAN_KIND_INTERNAL',
|
|
18
|
+
SPAN_KIND_INTERNAL: 'SPAN_KIND_INTERNAL',
|
|
19
|
+
server: 'SPAN_KIND_SERVER',
|
|
20
|
+
SPAN_KIND_SERVER: 'SPAN_KIND_SERVER',
|
|
21
|
+
client: 'SPAN_KIND_CLIENT',
|
|
22
|
+
SPAN_KIND_CLIENT: 'SPAN_KIND_CLIENT',
|
|
23
|
+
producer: 'SPAN_KIND_PRODUCER',
|
|
24
|
+
SPAN_KIND_PRODUCER: 'SPAN_KIND_PRODUCER',
|
|
25
|
+
consumer: 'SPAN_KIND_CONSUMER',
|
|
26
|
+
SPAN_KIND_CONSUMER: 'SPAN_KIND_CONSUMER',
|
|
27
|
+
}
|
|
28
|
+
|
|
15
29
|
/**
|
|
16
30
|
* @param {object} sketch
|
|
17
31
|
* @returns {number[]}
|
|
@@ -41,22 +55,16 @@ function getDeltaTemporality () {
|
|
|
41
55
|
return _deltaTemporality
|
|
42
56
|
}
|
|
43
57
|
|
|
44
|
-
const
|
|
58
|
+
const STATUS_CODE_OK = 'STATUS_CODE_OK'
|
|
59
|
+
const STATUS_CODE_ERROR = 'STATUS_CODE_ERROR'
|
|
45
60
|
|
|
46
61
|
class OtlpStatsTransformer extends OtlpTransformerBase {
|
|
47
|
-
#otelSemanticsEnabled
|
|
48
|
-
#defaultService
|
|
49
|
-
|
|
50
62
|
/**
|
|
51
63
|
* @param {import('@opentelemetry/api').Attributes} resourceAttributes
|
|
52
64
|
* @param {string} protocol
|
|
53
|
-
* @param {boolean} [otelSemanticsEnabled]
|
|
54
|
-
* @param {string} [defaultService]
|
|
55
65
|
*/
|
|
56
|
-
constructor (resourceAttributes, protocol
|
|
66
|
+
constructor (resourceAttributes, protocol) {
|
|
57
67
|
super(resourceAttributes, protocol, 'span-stats')
|
|
58
|
-
this.#otelSemanticsEnabled = otelSemanticsEnabled
|
|
59
|
-
this.#defaultService = defaultService
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
/**
|
|
@@ -82,32 +90,35 @@ class OtlpStatsTransformer extends OtlpTransformerBase {
|
|
|
82
90
|
const dataPoints = []
|
|
83
91
|
|
|
84
92
|
for (const { timeNs, bucket } of drained) {
|
|
93
|
+
const distributions = new Map()
|
|
85
94
|
const endTimeNs = timeNs + bucketSizeNs
|
|
86
95
|
const startNano = isJson ? String(timeNs) : timeNs
|
|
87
96
|
const endNano = isJson ? String(endTimeNs) : endTimeNs
|
|
88
97
|
|
|
89
98
|
for (const aggStats of bucket.values()) {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
const baseAttributes = this.#buildAttributes(aggStats.aggKey)
|
|
100
|
+
const baseKey = stableStringify(baseAttributes)
|
|
101
|
+
|
|
102
|
+
this.#addDistribution(
|
|
103
|
+
distributions, aggStats.topLevelOkDistribution, startNano, endNano,
|
|
104
|
+
baseAttributes, baseKey, true, STATUS_CODE_OK
|
|
105
|
+
)
|
|
106
|
+
this.#addDistribution(
|
|
107
|
+
distributions, aggStats.topLevelErrorDistribution, startNano, endNano,
|
|
108
|
+
baseAttributes, baseKey, true, STATUS_CODE_ERROR
|
|
109
|
+
)
|
|
110
|
+
this.#addDistribution(
|
|
111
|
+
distributions, aggStats.nonTopLevelOkDistribution, startNano, endNano,
|
|
112
|
+
baseAttributes, baseKey, false, STATUS_CODE_OK
|
|
113
|
+
)
|
|
114
|
+
this.#addDistribution(
|
|
115
|
+
distributions, aggStats.nonTopLevelErrorDistribution, startNano, endNano,
|
|
116
|
+
baseAttributes, baseKey, false, STATUS_CODE_ERROR
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (const { sketch, startNano, endNano, attributes } of distributions.values()) {
|
|
121
|
+
this.#pushPoint(dataPoints, sketch, startNano, endNano, attributes)
|
|
111
122
|
}
|
|
112
123
|
}
|
|
113
124
|
|
|
@@ -123,8 +134,45 @@ class OtlpStatsTransformer extends OtlpTransformerBase {
|
|
|
123
134
|
}]
|
|
124
135
|
}
|
|
125
136
|
|
|
126
|
-
|
|
137
|
+
/**
|
|
138
|
+
* @param {Map<string, {
|
|
139
|
+
* sketch: object,
|
|
140
|
+
* startNano: string | number,
|
|
141
|
+
* endNano: string | number,
|
|
142
|
+
* attributes: object[]
|
|
143
|
+
* }>} distributions
|
|
144
|
+
* @param {object} sketch
|
|
145
|
+
* @param {string | number} startNano
|
|
146
|
+
* @param {string | number} endNano
|
|
147
|
+
* @param {import('@opentelemetry/api').Attributes} baseAttributes
|
|
148
|
+
* @param {string} baseKey
|
|
149
|
+
* @param {boolean} topLevel
|
|
150
|
+
* @param {string} statusCode
|
|
151
|
+
* @returns {void}
|
|
152
|
+
*/
|
|
153
|
+
#addDistribution (distributions, sketch, startNano, endNano, baseAttributes, baseKey, topLevel, statusCode) {
|
|
127
154
|
if (!sketch || sketch.count === 0) return
|
|
155
|
+
|
|
156
|
+
const key = `${baseKey},${topLevel},${statusCode}`
|
|
157
|
+
const existing = distributions.get(key)
|
|
158
|
+
if (existing) {
|
|
159
|
+
existing.sketch.merge(sketch)
|
|
160
|
+
} else {
|
|
161
|
+
const attributes = this.transformAttributes(baseAttributes)
|
|
162
|
+
attributes.push(
|
|
163
|
+
{ key: 'datadog.span.top_level', value: { boolValue: topLevel } },
|
|
164
|
+
{ key: 'status.code', value: { stringValue: statusCode } }
|
|
165
|
+
)
|
|
166
|
+
distributions.set(key, {
|
|
167
|
+
sketch,
|
|
168
|
+
startNano,
|
|
169
|
+
endNano,
|
|
170
|
+
attributes,
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#pushPoint (points, sketch, startNano, endNano, attributes) {
|
|
128
176
|
points.push({
|
|
129
177
|
attributes,
|
|
130
178
|
startTimeUnixNano: startNano,
|
|
@@ -140,15 +188,18 @@ class OtlpStatsTransformer extends OtlpTransformerBase {
|
|
|
140
188
|
|
|
141
189
|
/**
|
|
142
190
|
* @param {import('../../span_stats').SpanAggKey} aggKey
|
|
191
|
+
* @returns {import('@opentelemetry/api').Attributes}
|
|
143
192
|
*/
|
|
144
193
|
#buildAttributes (aggKey) {
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
194
|
+
const spanKind = Object.hasOwn(SPAN_KIND_METRIC_MAP, aggKey.spanKind)
|
|
195
|
+
? SPAN_KIND_METRIC_MAP[aggKey.spanKind]
|
|
196
|
+
: 'SPAN_KIND_INTERNAL'
|
|
197
|
+
const raw = {
|
|
198
|
+
'span.name': aggKey.resource,
|
|
199
|
+
'service.name': aggKey.service,
|
|
200
|
+
'span.kind': spanKind,
|
|
149
201
|
}
|
|
150
202
|
|
|
151
|
-
if (aggKey.spanKind) raw['span.kind'] = aggKey.spanKind
|
|
152
203
|
if (aggKey.statusCode) raw['http.response.status_code'] = Number(aggKey.statusCode)
|
|
153
204
|
if (aggKey.method) raw['http.request.method'] = aggKey.method
|
|
154
205
|
if (aggKey.endpoint) raw['http.route'] = aggKey.endpoint
|
|
@@ -159,13 +210,15 @@ class OtlpStatsTransformer extends OtlpTransformerBase {
|
|
|
159
210
|
: String(aggKey.rpcStatusCode).toUpperCase()
|
|
160
211
|
}
|
|
161
212
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
213
|
+
// TODO: additional_metric_tags support is still evolving/TBD across most SDKs; not implemented here yet.
|
|
214
|
+
|
|
215
|
+
raw['datadog.operation.name'] = aggKey.name
|
|
216
|
+
if (aggKey.type) raw['datadog.span.type'] = aggKey.type
|
|
217
|
+
if (aggKey.synthetics) raw['datadog.origin'] = 'synthetics'
|
|
218
|
+
if (aggKey.srvSrc) raw['datadog.svc_src'] = aggKey.srvSrc
|
|
219
|
+
if (typeof aggKey.isTraceRoot === 'boolean') raw['datadog.is_trace_root'] = aggKey.isTraceRoot
|
|
167
220
|
|
|
168
|
-
return
|
|
221
|
+
return raw
|
|
169
222
|
}
|
|
170
223
|
}
|
|
171
224
|
|