dd-trace 5.109.0 → 5.111.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 +13 -8
- package/ci/init.js +25 -5
- package/ci/vitest-no-worker-init-setup.mjs +430 -0
- package/ext/tags.js +2 -0
- package/index.d.ts +79 -24
- package/initialize.mjs +5 -6
- package/loader-hook.mjs +154 -47
- package/package.json +20 -16
- package/packages/datadog-esbuild/index.js +26 -0
- package/packages/datadog-esbuild/src/utils.js +46 -3
- package/packages/datadog-instrumentations/src/connect.js +4 -3
- package/packages/datadog-instrumentations/src/fastify.js +4 -12
- package/packages/datadog-instrumentations/src/fs.js +8 -6
- package/packages/datadog-instrumentations/src/graphql.js +26 -484
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +81 -8
- package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -2
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +65 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +6 -4
- package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +201 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +18 -2
- package/packages/datadog-instrumentations/src/koa.js +3 -2
- package/packages/datadog-instrumentations/src/mariadb.js +4 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +3 -3
- package/packages/datadog-instrumentations/src/mongoose.js +14 -2
- package/packages/datadog-instrumentations/src/next.js +10 -10
- package/packages/datadog-instrumentations/src/otel-sdk-trace.js +7 -6
- package/packages/datadog-instrumentations/src/playwright.js +1 -1
- package/packages/datadog-instrumentations/src/restify.js +4 -3
- package/packages/datadog-instrumentations/src/router.js +18 -5
- package/packages/datadog-instrumentations/src/selenium.js +1 -2
- package/packages/datadog-instrumentations/src/tedious.js +28 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1293 -0
- package/packages/datadog-instrumentations/src/vitest-main.js +1567 -0
- package/packages/datadog-instrumentations/src/vitest-util.js +249 -0
- package/packages/datadog-instrumentations/src/vitest-worker.js +753 -0
- package/packages/datadog-instrumentations/src/vitest.js +11 -1598
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +18 -10
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +47 -11
- package/packages/datadog-plugin-aws-sdk/src/base.js +13 -9
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +43 -6
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +83 -91
- package/packages/datadog-plugin-cucumber/src/index.js +1 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -5
- package/packages/datadog-plugin-cypress/src/support.js +45 -1
- package/packages/datadog-plugin-express/src/code_origin.js +1 -1
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +627 -11
- package/packages/datadog-plugin-graphql/src/index.js +20 -8
- package/packages/datadog-plugin-graphql/src/parse.js +24 -4
- package/packages/datadog-plugin-graphql/src/validate.js +16 -5
- package/packages/datadog-plugin-http/src/client.js +8 -3
- package/packages/datadog-plugin-http/src/index.js +6 -8
- package/packages/datadog-plugin-http2/src/client.js +5 -2
- package/packages/datadog-plugin-jest/src/index.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +1 -1
- package/packages/datadog-plugin-mysql/src/index.js +7 -2
- package/packages/datadog-plugin-openai/src/services.js +2 -2
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +2 -2
- package/packages/datadog-plugin-undici/src/index.js +5 -2
- package/packages/datadog-plugin-vitest/src/index.js +76 -64
- package/packages/datadog-shimmer/src/shimmer.js +37 -16
- package/packages/datadog-webpack/index.js +17 -1
- package/packages/datadog-webpack/src/optional-peer-loader.js +17 -0
- package/packages/dd-trace/src/aiguard/sdk.js +15 -3
- package/packages/dd-trace/src/appsec/api_security/index.js +55 -0
- package/packages/dd-trace/src/appsec/api_security/sampler.js +147 -0
- package/packages/dd-trace/src/appsec/channels.js +3 -1
- package/packages/dd-trace/src/appsec/downstream_requests.js +4 -4
- package/packages/dd-trace/src/appsec/graphql.js +5 -5
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +26 -19
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
- package/packages/dd-trace/src/appsec/iast/telemetry/index.js +2 -1
- package/packages/dd-trace/src/appsec/index.js +20 -7
- package/packages/dd-trace/src/appsec/lambda.js +135 -0
- package/packages/dd-trace/src/appsec/reporter.js +50 -10
- package/packages/dd-trace/src/appsec/telemetry/api_security.js +34 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +27 -1
- package/packages/dd-trace/src/appsec/waf/index.js +16 -4
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +21 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +3 -2
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +55 -13
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +17 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +47 -26
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +2 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +64 -53
- package/packages/dd-trace/src/ci-visibility/requests/request.js +1 -17
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +3 -3
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +23 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +128 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +287 -0
- package/packages/dd-trace/src/config/defaults.js +25 -5
- package/packages/dd-trace/src/config/generated-config-types.d.ts +596 -58
- package/packages/dd-trace/src/config/helper.js +134 -33
- package/packages/dd-trace/src/config/index.js +39 -23
- package/packages/dd-trace/src/config/major-overrides.js +4 -2
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +109 -57
- package/packages/dd-trace/src/constants.js +7 -0
- package/packages/dd-trace/src/datastreams/processor.js +11 -3
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +47 -35
- package/packages/dd-trace/src/debugger/devtools_client/index.js +31 -66
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +83 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -0
- package/packages/dd-trace/src/debugger/index.js +5 -0
- package/packages/dd-trace/src/debugger/probe_sampler.js +112 -0
- package/packages/dd-trace/src/debugger/probe_sampler_constants.js +19 -0
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +77 -26
- package/packages/dd-trace/src/exporters/agent/index.js +1 -1
- package/packages/dd-trace/src/exporters/agentless/writer.js +4 -4
- package/packages/dd-trace/src/exporters/common/request.js +1 -20
- package/packages/dd-trace/src/exporters/common/url.js +34 -0
- package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -3
- package/packages/dd-trace/src/guardrails/index.js +8 -5
- package/packages/dd-trace/src/index.js +6 -4
- package/packages/dd-trace/src/llmobs/constants/tags.js +6 -0
- package/packages/dd-trace/src/llmobs/index.js +17 -6
- package/packages/dd-trace/src/llmobs/plugins/base.js +4 -4
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +3 -3
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +5 -1
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +8 -6
- package/packages/dd-trace/src/llmobs/span_processor.js +5 -1
- package/packages/dd-trace/src/llmobs/tagger.js +58 -3
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
- package/packages/dd-trace/src/log/index.js +18 -20
- package/packages/dd-trace/src/openfeature/flagging_provider.js +2 -7
- package/packages/dd-trace/src/opentelemetry/bridge-span-base.js +5 -4
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +54 -5
- package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +2 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +40 -0
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +169 -0
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +4 -3
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +19 -0
- package/packages/dd-trace/src/opentelemetry/otlp/common.proto +2 -2
- package/packages/dd-trace/src/opentelemetry/otlp/logs.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/logs_service.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/metrics.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/metrics_service.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +44 -38
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +29 -13
- package/packages/dd-trace/src/opentelemetry/span.js +14 -3
- package/packages/dd-trace/src/opentelemetry/span_context.js +1 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +6 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +26 -13
- package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -3
- package/packages/dd-trace/src/opentracing/span_context.js +17 -0
- package/packages/dd-trace/src/opentracing/tracer.js +6 -1
- package/packages/dd-trace/src/plugin_manager.js +14 -8
- package/packages/dd-trace/src/plugins/ci_plugin.js +21 -4
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +276 -0
- package/packages/dd-trace/src/plugins/util/llm.js +6 -1
- package/packages/dd-trace/src/plugins/util/test.js +91 -9
- package/packages/dd-trace/src/plugins/util/url.js +68 -1
- package/packages/dd-trace/src/plugins/util/web.js +19 -36
- package/packages/dd-trace/src/priority_sampler.js +1 -13
- package/packages/dd-trace/src/profiling/config.js +129 -198
- package/packages/dd-trace/src/profiling/constants.js +4 -7
- package/packages/dd-trace/src/profiling/exporter_cli.js +10 -10
- package/packages/dd-trace/src/profiling/exporters/agent.js +23 -16
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +45 -14
- package/packages/dd-trace/src/profiling/exporters/file.js +16 -5
- package/packages/dd-trace/src/profiling/oom.js +71 -0
- package/packages/dd-trace/src/profiling/profiler.js +35 -23
- package/packages/dd-trace/src/profiling/profilers/events.js +14 -7
- package/packages/dd-trace/src/profiling/profilers/space.js +27 -18
- package/packages/dd-trace/src/profiling/profilers/wall.js +35 -25
- package/packages/dd-trace/src/proxy.js +8 -8
- package/packages/dd-trace/src/ritm.js +4 -2
- package/packages/dd-trace/src/serverless.js +1 -2
- package/packages/dd-trace/src/service-naming/schemas/util.js +36 -5
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +5 -3
- package/packages/dd-trace/src/span_format.js +2 -1
- package/packages/dd-trace/src/span_processor.js +11 -6
- package/packages/dd-trace/src/span_stats.js +96 -78
- package/packages/dd-trace/src/startup-log.js +2 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +6 -4
- package/packages/dd-trace/src/telemetry/index.js +2 -2
- package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/telemetry/send-data.js +20 -18
- package/packages/dd-trace/src/telemetry/session-propagation.js +1 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +9 -9
- package/packages/dd-trace/src/tracer.js +15 -1
- package/packages/dd-trace/src/util.js +14 -0
- package/register.js +58 -1
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
- package/packages/datadog-plugin-graphql/src/resolve.js +0 -170
- package/packages/dd-trace/src/appsec/api_security_sampler.js +0 -117
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const log = require('../log')
|
|
4
|
+
const Sampler = require('../sampler')
|
|
5
|
+
const { formatKnuthRate } = require('../util')
|
|
4
6
|
const {
|
|
5
7
|
MODEL_NAME,
|
|
6
8
|
MODEL_PROVIDER,
|
|
@@ -41,6 +43,12 @@ const {
|
|
|
41
43
|
ROUTING_SITE,
|
|
42
44
|
PROMPT_TRACKING_INSTRUMENTATION_METHOD,
|
|
43
45
|
INSTRUMENTATION_METHOD_ANNOTATED,
|
|
46
|
+
SAMPLE_RATE,
|
|
47
|
+
SAMPLING_DECISION,
|
|
48
|
+
SAMPLING_DECISION_SAMPLED,
|
|
49
|
+
SAMPLING_DECISION_DROPPED,
|
|
50
|
+
PROPAGATED_SAMPLE_RATE_KEY,
|
|
51
|
+
PROPAGATED_SAMPLING_DECISION_KEY,
|
|
44
52
|
} = require('./constants/tags')
|
|
45
53
|
const { storage } = require('./storage')
|
|
46
54
|
const { findGenAIAncestorSpanId, validateCostTags, writeBridgeTags, validateToolDefinitions } = require('./util')
|
|
@@ -53,12 +61,31 @@ class LLMObsTagger {
|
|
|
53
61
|
/** @type {import('../config/config-base')} */
|
|
54
62
|
#config
|
|
55
63
|
|
|
64
|
+
/** @type {import('../sampler') | null} */
|
|
65
|
+
#sampler = null
|
|
66
|
+
|
|
56
67
|
constructor (config, softFail = false) {
|
|
57
68
|
this.#config = config
|
|
58
69
|
|
|
59
70
|
this.softFail = softFail
|
|
60
71
|
}
|
|
61
72
|
|
|
73
|
+
/**
|
|
74
|
+
* The sampler reads its rate from `config.llmobs.sampleRate`, which can change
|
|
75
|
+
* at runtime (e.g. via remote config). Rebuild the sampler whenever the rate
|
|
76
|
+
* changes so decisions reflect the current config, while reusing the existing
|
|
77
|
+
* sampler when it hasn't.
|
|
78
|
+
*
|
|
79
|
+
* @returns {import('../sampler')}
|
|
80
|
+
*/
|
|
81
|
+
#getSampler () {
|
|
82
|
+
const rate = this.#config.llmobs?.sampleRate ?? 1
|
|
83
|
+
if (this.#sampler === null || rate !== this.#sampler.rate()) {
|
|
84
|
+
this.#sampler = new Sampler(rate)
|
|
85
|
+
}
|
|
86
|
+
return this.#sampler
|
|
87
|
+
}
|
|
88
|
+
|
|
62
89
|
static get tagMap () {
|
|
63
90
|
return registry
|
|
64
91
|
}
|
|
@@ -78,7 +105,7 @@ class LLMObsTagger {
|
|
|
78
105
|
integration,
|
|
79
106
|
_decorator,
|
|
80
107
|
} = {}) {
|
|
81
|
-
if (!this.#config.llmobs.
|
|
108
|
+
if (!this.#config.llmobs.DD_LLMOBS_ENABLED) return
|
|
82
109
|
if (!kind) return // do not register it in the map if it doesn't have an llmobs span kind
|
|
83
110
|
|
|
84
111
|
const spanMlApp =
|
|
@@ -124,6 +151,8 @@ class LLMObsTagger {
|
|
|
124
151
|
ROOT_PARENT_ID
|
|
125
152
|
this._setTag(span, PARENT_ID_KEY, parentId)
|
|
126
153
|
|
|
154
|
+
this.#tagSamplingDecision(span, parent)
|
|
155
|
+
|
|
127
156
|
// apply annotation context
|
|
128
157
|
const annotationContext = storage.getStore()?.annotationContext
|
|
129
158
|
|
|
@@ -153,6 +182,32 @@ class LLMObsTagger {
|
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
184
|
|
|
185
|
+
#tagSamplingDecision (span, parent) {
|
|
186
|
+
const traceTags = span.context()._trace.tags
|
|
187
|
+
const parentTags = registry.get(parent)
|
|
188
|
+
|
|
189
|
+
let sampleRate, samplingDecision
|
|
190
|
+
if (parentTags) {
|
|
191
|
+
// Local LLMObs parent: inherit its decision.
|
|
192
|
+
sampleRate = parentTags[SAMPLE_RATE]
|
|
193
|
+
samplingDecision = parentTags[SAMPLING_DECISION]
|
|
194
|
+
} else if (traceTags[PROPAGATED_PARENT_ID_KEY]) {
|
|
195
|
+
// Distributed LLMObs parent: inherit whatever was propagated. This may be
|
|
196
|
+
// absent if the upstream service predates sampling propagation, in which
|
|
197
|
+
// case we make no decision here rather than starting a divergent one.
|
|
198
|
+
sampleRate = traceTags[PROPAGATED_SAMPLE_RATE_KEY]
|
|
199
|
+
samplingDecision = traceTags[PROPAGATED_SAMPLING_DECISION_KEY]
|
|
200
|
+
} else {
|
|
201
|
+
// Root span: make the trace's one sampling decision.
|
|
202
|
+
const sampler = this.#getSampler()
|
|
203
|
+
sampleRate = formatKnuthRate(sampler.rate())
|
|
204
|
+
samplingDecision = sampler.isSampled(span) ? SAMPLING_DECISION_SAMPLED : SAMPLING_DECISION_DROPPED
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (sampleRate != null) this._setTag(span, SAMPLE_RATE, sampleRate)
|
|
208
|
+
if (samplingDecision != null) this._setTag(span, SAMPLING_DECISION, samplingDecision)
|
|
209
|
+
}
|
|
210
|
+
|
|
156
211
|
// TODO: similarly for the following `tag` methods,
|
|
157
212
|
// how can we transition from a span weakmap to core API functionality
|
|
158
213
|
tagLLMIO (span, inputData, outputData) {
|
|
@@ -679,7 +734,7 @@ class LLMObsTagger {
|
|
|
679
734
|
}
|
|
680
735
|
|
|
681
736
|
_register (span) {
|
|
682
|
-
if (!this.#config.llmobs.
|
|
737
|
+
if (!this.#config.llmobs.DD_LLMOBS_ENABLED) return
|
|
683
738
|
if (registry.has(span)) {
|
|
684
739
|
this.#handleFailure(`LLMObs Span "${span._name}" already registered.`)
|
|
685
740
|
return
|
|
@@ -689,7 +744,7 @@ class LLMObsTagger {
|
|
|
689
744
|
}
|
|
690
745
|
|
|
691
746
|
_setTag (span, key, value) {
|
|
692
|
-
if (!this.#config.llmobs.
|
|
747
|
+
if (!this.#config.llmobs.DD_LLMOBS_ENABLED) return
|
|
693
748
|
if (!registry.has(span)) {
|
|
694
749
|
this.#handleFailure(`Span "${span._name}" must be an LLMObs generated span.`)
|
|
695
750
|
return
|
|
@@ -87,6 +87,7 @@ function recordLLMObsEnabled (startTime, config, value = 1) {
|
|
|
87
87
|
site: config.site,
|
|
88
88
|
auto: Number(autoEnabled),
|
|
89
89
|
ml_app: config.llmobs.mlApp,
|
|
90
|
+
sample_rate: config.llmobs.sampleRate,
|
|
90
91
|
}
|
|
91
92
|
llmobsMetrics.count('product_enabled', tags).inc(value)
|
|
92
93
|
llmobsMetrics.distribution('init_time', tags).track(initTimeMs)
|
|
@@ -229,7 +229,7 @@ class BaseLLMObsWriter {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
if (this._agentless) {
|
|
232
|
-
options.headers['DD-API-KEY'] = this._config.
|
|
232
|
+
options.headers['DD-API-KEY'] = this._config.DD_API_KEY || ''
|
|
233
233
|
} else {
|
|
234
234
|
options.headers[EVP_SUBDOMAIN_HEADER_NAME] = this._intake
|
|
235
235
|
}
|
|
@@ -2,19 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
const { inspect } = require('util')
|
|
4
4
|
|
|
5
|
-
const { defaults } = require('../config/defaults')
|
|
6
|
-
const { isTrue } = require('../util')
|
|
7
5
|
const { getValueFromEnvSources } = require('../config/helper')
|
|
6
|
+
// Eager require restores the original startup module-load order: pulling `config/defaults` here
|
|
7
|
+
// also installs the instrumented `dns` it transitively loads before the tracer/agent connects.
|
|
8
|
+
// `config/defaults` defers its own `dns` require until after it exports, so this no longer hits
|
|
9
|
+
// the `config/defaults` <-> log parse cycle that motivated the lazy require below.
|
|
10
|
+
const { defaults } = require('../config/defaults')
|
|
8
11
|
const { traceChannel, debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
|
|
9
12
|
const logWriter = require('./writer')
|
|
10
13
|
const { Log, LogConfig, NoTransmitError } = require('./log')
|
|
11
14
|
|
|
12
|
-
const config = {
|
|
13
|
-
enabled: defaults.DD_TRACE_DEBUG,
|
|
14
|
-
logger: undefined,
|
|
15
|
-
logLevel: defaults.logLevel,
|
|
16
|
-
}
|
|
17
|
-
|
|
18
15
|
// In most places where we know we want to mute a log we use log.error() directly
|
|
19
16
|
const NO_TRANSMIT = new LogConfig(false)
|
|
20
17
|
|
|
@@ -77,19 +74,17 @@ const log = {
|
|
|
77
74
|
},
|
|
78
75
|
|
|
79
76
|
configure (options) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
getValueFromEnvSources('DD_TRACE_LOG_LEVEL') ??
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
getValueFromEnvSources('DD_TRACE_DEBUG') ??
|
|
77
|
+
const logger = options.logger
|
|
78
|
+
const logLevel = options.logLevel ??
|
|
79
|
+
getValueFromEnvSources('DD_TRACE_LOG_LEVEL', true) ??
|
|
80
|
+
defaults?.logLevel
|
|
81
|
+
const enabled = getValueFromEnvSources('DD_TRACE_DEBUG', true) ??
|
|
86
82
|
// TODO: Handle this by adding a log buffer so that configure may be called with the actual configurations.
|
|
87
83
|
// eslint-disable-next-line eslint-rules/eslint-process-env
|
|
88
|
-
(process.env.OTEL_LOG_LEVEL === 'debug' ||
|
|
89
|
-
)
|
|
90
|
-
logWriter.configure(config.enabled, config.logLevel, options.logger)
|
|
84
|
+
(process.env.OTEL_LOG_LEVEL === 'debug' || defaults?.DD_TRACE_DEBUG)
|
|
85
|
+
logWriter.configure(enabled, logLevel, logger)
|
|
91
86
|
|
|
92
|
-
return
|
|
87
|
+
return enabled
|
|
93
88
|
},
|
|
94
89
|
}
|
|
95
90
|
|
|
@@ -113,6 +108,9 @@ function getErrorLog (err) {
|
|
|
113
108
|
return err
|
|
114
109
|
}
|
|
115
110
|
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
// Assign before the bootstrap configure() call: an invalid DD_TRACE_LOG_LEVEL
|
|
112
|
+
// makes config/defaults re-require this module to warn, which must observe the
|
|
113
|
+
// fully built log object rather than a half-initialized one.
|
|
118
114
|
module.exports = log
|
|
115
|
+
|
|
116
|
+
log.configure({})
|
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { channel } = require('dc-polyfill')
|
|
4
|
+
const requireOptionalPeer = require('../../../datadog-instrumentations/src/helpers/require-optional-peer')
|
|
4
5
|
const log = require('../log')
|
|
5
6
|
const { EXPOSURE_CHANNEL } = require('./constants/constants')
|
|
6
7
|
const EvalMetricsHook = require('./eval-metrics-hook')
|
|
7
8
|
const SpanEnrichmentHook = require('./span-enrichment-hook')
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
// `@datadog/openfeature-node-server` -> `@openfeature/server-sdk` ->
|
|
11
|
-
// `@openfeature/core`. Same shape as `helpers/rewriter/compiler.js`.
|
|
12
|
-
// Refs: https://github.com/DataDog/dd-trace-js/issues/8635
|
|
13
|
-
// eslint-disable-next-line camelcase, no-undef
|
|
14
|
-
const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require
|
|
15
|
-
const { DatadogNodeServerProvider } = runtimeRequire(['@datadog/openfeature', 'node', 'server'].join('-'))
|
|
10
|
+
const { DatadogNodeServerProvider } = requireOptionalPeer('@datadog/openfeature-node-server')
|
|
16
11
|
|
|
17
12
|
/**
|
|
18
13
|
* OpenFeature provider that integrates with Datadog's feature flagging system.
|
|
@@ -30,6 +30,7 @@ class BridgeSpanBase {
|
|
|
30
30
|
*/
|
|
31
31
|
constructor (ddSpan) {
|
|
32
32
|
this._ddSpan = ddSpan
|
|
33
|
+
this._otelTraceSemanticsEnabled = false
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
get ended () {
|
|
@@ -45,7 +46,7 @@ class BridgeSpanBase {
|
|
|
45
46
|
* @param {import('@opentelemetry/api').AttributeValue} value
|
|
46
47
|
*/
|
|
47
48
|
setAttribute (key, value) {
|
|
48
|
-
setOtelAttribute(this._ddSpan, key, value)
|
|
49
|
+
setOtelAttribute(this._ddSpan, key, value, this._otelTraceSemanticsEnabled)
|
|
49
50
|
return this
|
|
50
51
|
}
|
|
51
52
|
|
|
@@ -53,7 +54,7 @@ class BridgeSpanBase {
|
|
|
53
54
|
* @param {import('@opentelemetry/api').Attributes} attributes
|
|
54
55
|
*/
|
|
55
56
|
setAttributes (attributes) {
|
|
56
|
-
setOtelAttributes(this._ddSpan, attributes)
|
|
57
|
+
setOtelAttributes(this._ddSpan, attributes, this._otelTraceSemanticsEnabled)
|
|
57
58
|
return this
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -91,14 +92,14 @@ class BridgeSpanBase {
|
|
|
91
92
|
* @param {import('@opentelemetry/api').TimeInput} [timeInput]
|
|
92
93
|
*/
|
|
93
94
|
recordException (exception, timeInput) {
|
|
94
|
-
recordException(this._ddSpan, exception, timeInput)
|
|
95
|
+
recordException(this._ddSpan, exception, timeInput, this._otelTraceSemanticsEnabled)
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
/**
|
|
98
99
|
* @param {import('@opentelemetry/api').SpanStatus} status
|
|
99
100
|
*/
|
|
100
101
|
setStatus (status) {
|
|
101
|
-
this.#statusCode = applyOtelStatus(this._ddSpan, this.#statusCode, status)
|
|
102
|
+
this.#statusCode = applyOtelStatus(this._ddSpan, this.#statusCode, status, this._otelTraceSemanticsEnabled)
|
|
102
103
|
return this
|
|
103
104
|
}
|
|
104
105
|
}
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
const os = require('os')
|
|
4
4
|
|
|
5
|
+
const { metrics } = require('@opentelemetry/api')
|
|
6
|
+
|
|
7
|
+
const { VERSION } = require('../../../../../version')
|
|
8
|
+
const processTags = require('../../process-tags')
|
|
9
|
+
const MeterProvider = require('./meter_provider')
|
|
10
|
+
const PeriodicMetricReader = require('./periodic_metric_reader')
|
|
11
|
+
const OtlpHttpMetricExporter = require('./otlp_http_metric_exporter')
|
|
12
|
+
|
|
5
13
|
/**
|
|
6
14
|
* @typedef {import('../../config')} Config
|
|
7
15
|
*/
|
|
@@ -28,11 +36,6 @@ const os = require('os')
|
|
|
28
36
|
* @package
|
|
29
37
|
*/
|
|
30
38
|
|
|
31
|
-
const { metrics } = require('@opentelemetry/api')
|
|
32
|
-
const MeterProvider = require('./meter_provider')
|
|
33
|
-
const PeriodicMetricReader = require('./periodic_metric_reader')
|
|
34
|
-
const OtlpHttpMetricExporter = require('./otlp_http_metric_exporter')
|
|
35
|
-
|
|
36
39
|
/**
|
|
37
40
|
* Initializes OpenTelemetry Metrics support
|
|
38
41
|
* @param {import('../../config/config-base')} config - Tracer configuration instance
|
|
@@ -75,7 +78,53 @@ function initializeOpenTelemetryMetrics (config) {
|
|
|
75
78
|
metrics.setGlobalMeterProvider(meterProvider)
|
|
76
79
|
}
|
|
77
80
|
|
|
81
|
+
function buildResourceAttributes (tags, { reportHostname, otelSemanticsEnabled, service, env, serviceVersion } = {}) {
|
|
82
|
+
const attrs = {
|
|
83
|
+
'telemetry.sdk.name': 'datadog',
|
|
84
|
+
'telemetry.sdk.language': 'nodejs',
|
|
85
|
+
'telemetry.sdk.version': VERSION,
|
|
86
|
+
}
|
|
87
|
+
if (service) attrs['service.name'] = service
|
|
88
|
+
if (serviceVersion) attrs['service.version'] = serviceVersion
|
|
89
|
+
if (env) attrs['deployment.environment.name'] = env
|
|
90
|
+
if (reportHostname) attrs['host.name'] = os.hostname()
|
|
91
|
+
|
|
92
|
+
if (!otelSemanticsEnabled) {
|
|
93
|
+
if (tags?.['runtime-id']) attrs['datadog.runtime_id'] = tags['runtime-id']
|
|
94
|
+
const processTagsObject = processTags.tagsObject
|
|
95
|
+
if (processTagsObject) {
|
|
96
|
+
for (const key of Object.keys(processTagsObject)) {
|
|
97
|
+
attrs[`datadog.${key}`] = processTagsObject[key]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return attrs
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function createOtlpSpanStatsExporter (config) {
|
|
105
|
+
const { OtlpStatsExporter } = require('./otlp_span_stats_exporter')
|
|
106
|
+
const protocol = config.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL || 'http/json'
|
|
107
|
+
const resourceAttributes = buildResourceAttributes(config.tags, {
|
|
108
|
+
reportHostname: config.reportHostname,
|
|
109
|
+
otelSemanticsEnabled: config.DD_TRACE_OTEL_SEMANTICS_ENABLED,
|
|
110
|
+
service: config.service,
|
|
111
|
+
env: config.env,
|
|
112
|
+
serviceVersion: config.version,
|
|
113
|
+
})
|
|
114
|
+
return new OtlpStatsExporter(
|
|
115
|
+
config.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
|
|
116
|
+
protocol,
|
|
117
|
+
resourceAttributes,
|
|
118
|
+
config.DD_TRACE_OTEL_SEMANTICS_ENABLED,
|
|
119
|
+
config.service,
|
|
120
|
+
config.OTEL_EXPORTER_OTLP_METRICS_HEADERS,
|
|
121
|
+
config.OTEL_EXPORTER_OTLP_METRICS_TIMEOUT
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
78
125
|
module.exports = {
|
|
79
126
|
MeterProvider,
|
|
80
127
|
initializeOpenTelemetryMetrics,
|
|
128
|
+
buildResourceAttributes,
|
|
129
|
+
createOtlpSpanStatsExporter,
|
|
81
130
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { sanitizeAttributes } = require('../../../../../vendor/dist/@opentelemetry/core')
|
|
4
4
|
const { METRIC_TYPES } = require('./constants')
|
|
5
|
+
const { nowUnixNano } = require('./time')
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @typedef {import('@opentelemetry/api').Attributes} Attributes
|
|
@@ -62,7 +63,7 @@ class Instrument {
|
|
|
62
63
|
type,
|
|
63
64
|
value,
|
|
64
65
|
attributes: sanitizeAttributes(attributes),
|
|
65
|
-
timestamp:
|
|
66
|
+
timestamp: nowUnixNano(),
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const log = require('../../log')
|
|
4
|
+
const OtlpHttpExporterBase = require('../otlp/otlp_http_exporter_base')
|
|
5
|
+
const OtlpStatsTransformer = require('./otlp_span_stats_transformer')
|
|
6
|
+
|
|
7
|
+
class OtlpStatsExporter extends OtlpHttpExporterBase {
|
|
8
|
+
#transformer
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} url
|
|
12
|
+
* @param {string} protocol
|
|
13
|
+
* @param {import('@opentelemetry/api').Attributes} resourceAttributes
|
|
14
|
+
* @param {boolean} [otelSemanticsEnabled]
|
|
15
|
+
* @param {string} [defaultService]
|
|
16
|
+
* @param {Record<string, string>} [headers]
|
|
17
|
+
* @param {number} [timeout]
|
|
18
|
+
*/
|
|
19
|
+
constructor (url, protocol, resourceAttributes, otelSemanticsEnabled = false, defaultService = '',
|
|
20
|
+
headers, timeout = 10_000) {
|
|
21
|
+
super(url, headers, timeout, protocol, 'span-stats')
|
|
22
|
+
this.#transformer = new OtlpStatsTransformer(resourceAttributes, protocol, otelSemanticsEnabled, defaultService)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {Array<{timeNs: number, bucket: import('../../span_stats').SpanBuckets}>} drained
|
|
27
|
+
* @param {number} bucketSizeNs
|
|
28
|
+
*/
|
|
29
|
+
export (drained, bucketSizeNs) {
|
|
30
|
+
if (drained.length === 0) return
|
|
31
|
+
const payload = this.#transformer.transform(drained, bucketSizeNs)
|
|
32
|
+
this.sendPayload(payload, (result) => {
|
|
33
|
+
if (result.code !== 0) {
|
|
34
|
+
log.error('Failed to export span stats: %s', result.error?.message)
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = { OtlpStatsExporter }
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { LogCollapsingLowestDenseDDSketch } = require('../../../../../vendor/dist/@datadog/sketches-js')
|
|
4
|
+
const OtlpTransformerBase = require('../otlp/otlp_transformer_base')
|
|
5
|
+
const { getProtobufTypes } = require('../otlp/protobuf_loader')
|
|
6
|
+
|
|
7
|
+
const NS_PER_S = 1e9
|
|
8
|
+
|
|
9
|
+
// Must match libdatadog's EXPLICIT_BOUNDS_SECONDS and OTel spanmetrics connector defaults.
|
|
10
|
+
const EXPLICIT_BOUNDS_SECONDS = [
|
|
11
|
+
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,
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {object} sketch
|
|
16
|
+
* @returns {number[]}
|
|
17
|
+
*/
|
|
18
|
+
function sketchToFixedHistogram (sketch) {
|
|
19
|
+
const bucketCounts = new Array(EXPLICIT_BOUNDS_SECONDS.length + 1).fill(0)
|
|
20
|
+
if (sketch.zeroCount > 0) bucketCounts[0] += sketch.zeroCount
|
|
21
|
+
const { store, mapping } = sketch
|
|
22
|
+
for (let key = store.minKey; key <= store.maxKey; key++) {
|
|
23
|
+
const weight = store.bins[key - store.offset]
|
|
24
|
+
if (!weight) continue
|
|
25
|
+
const seconds = mapping.value(key) / NS_PER_S
|
|
26
|
+
let idx = EXPLICIT_BOUNDS_SECONDS.findIndex((bound) => seconds <= bound)
|
|
27
|
+
if (idx === -1) idx = EXPLICIT_BOUNDS_SECONDS.length
|
|
28
|
+
bucketCounts[idx] += weight
|
|
29
|
+
}
|
|
30
|
+
return bucketCounts.map((weight) => Math.round(weight))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let _deltaTemporality
|
|
34
|
+
|
|
35
|
+
function getDeltaTemporality () {
|
|
36
|
+
if (_deltaTemporality === undefined) {
|
|
37
|
+
const { protoAggregationTemporality } = getProtobufTypes()
|
|
38
|
+
_deltaTemporality = protoAggregationTemporality.values.AGGREGATION_TEMPORALITY_DELTA
|
|
39
|
+
}
|
|
40
|
+
return _deltaTemporality
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const ERROR_STATUS_ATTR = { key: 'status.code', value: { intValue: 2 } }
|
|
44
|
+
|
|
45
|
+
class OtlpStatsTransformer extends OtlpTransformerBase {
|
|
46
|
+
#otelSemanticsEnabled
|
|
47
|
+
#defaultService
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {import('@opentelemetry/api').Attributes} resourceAttributes
|
|
51
|
+
* @param {string} protocol
|
|
52
|
+
* @param {boolean} [otelSemanticsEnabled]
|
|
53
|
+
* @param {string} [defaultService]
|
|
54
|
+
*/
|
|
55
|
+
constructor (resourceAttributes, protocol, otelSemanticsEnabled = false, defaultService = '') {
|
|
56
|
+
super(resourceAttributes, protocol, 'span-stats')
|
|
57
|
+
this.#otelSemanticsEnabled = otelSemanticsEnabled
|
|
58
|
+
this.#defaultService = defaultService
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {Array<{timeNs: number, bucket: import('../../span_stats').SpanBuckets}>} drained
|
|
63
|
+
* @param {number} bucketSizeNs
|
|
64
|
+
*/
|
|
65
|
+
transform (drained, bucketSizeNs) {
|
|
66
|
+
const isJson = this.protocol === 'http/json'
|
|
67
|
+
const data = {
|
|
68
|
+
resourceMetrics: [{
|
|
69
|
+
resource: this.transformResource(),
|
|
70
|
+
scopeMetrics: this.#buildScopeMetrics(drained, bucketSizeNs, isJson),
|
|
71
|
+
}],
|
|
72
|
+
}
|
|
73
|
+
return isJson
|
|
74
|
+
? this.serializeToJson(data)
|
|
75
|
+
: this.serializeToProtobuf(getProtobufTypes().protoMetricsService, data)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
#buildScopeMetrics (drained, bucketSizeNs, isJson) {
|
|
79
|
+
const temporality = isJson ? 'AGGREGATION_TEMPORALITY_DELTA' : getDeltaTemporality()
|
|
80
|
+
|
|
81
|
+
const dataPoints = []
|
|
82
|
+
|
|
83
|
+
for (const { timeNs, bucket } of drained) {
|
|
84
|
+
const endTimeNs = timeNs + bucketSizeNs
|
|
85
|
+
const startNano = isJson ? String(timeNs) : timeNs
|
|
86
|
+
const endNano = isJson ? String(endTimeNs) : endTimeNs
|
|
87
|
+
|
|
88
|
+
for (const aggStats of bucket.values()) {
|
|
89
|
+
const baseAttrs = this.#buildAttributes(aggStats.aggKey)
|
|
90
|
+
|
|
91
|
+
if (this.#otelSemanticsEnabled) {
|
|
92
|
+
const okDist = new LogCollapsingLowestDenseDDSketch()
|
|
93
|
+
okDist.merge(aggStats.topLevelOkDistribution)
|
|
94
|
+
okDist.merge(aggStats.nonTopLevelOkDistribution)
|
|
95
|
+
const errDist = new LogCollapsingLowestDenseDDSketch()
|
|
96
|
+
errDist.merge(aggStats.topLevelErrorDistribution)
|
|
97
|
+
errDist.merge(aggStats.nonTopLevelErrorDistribution)
|
|
98
|
+
this.#pushPoint(dataPoints, okDist, startNano, endNano, baseAttrs)
|
|
99
|
+
this.#pushPoint(dataPoints, errDist, startNano, endNano, [...baseAttrs, ERROR_STATUS_ATTR])
|
|
100
|
+
} else {
|
|
101
|
+
const tlAttrs = [...baseAttrs, { key: 'datadog.span.top_level', value: { boolValue: true } }]
|
|
102
|
+
const ntlAttrs = [...baseAttrs, { key: 'datadog.span.top_level', value: { boolValue: false } }]
|
|
103
|
+
this.#pushPoint(dataPoints, aggStats.topLevelOkDistribution, startNano, endNano, tlAttrs)
|
|
104
|
+
this.#pushPoint(dataPoints, aggStats.topLevelErrorDistribution, startNano, endNano,
|
|
105
|
+
[...tlAttrs, ERROR_STATUS_ATTR])
|
|
106
|
+
this.#pushPoint(dataPoints, aggStats.nonTopLevelOkDistribution, startNano, endNano, ntlAttrs)
|
|
107
|
+
this.#pushPoint(dataPoints, aggStats.nonTopLevelErrorDistribution, startNano, endNano,
|
|
108
|
+
[...ntlAttrs, ERROR_STATUS_ATTR])
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (dataPoints.length === 0) return []
|
|
114
|
+
return [{
|
|
115
|
+
metrics: [
|
|
116
|
+
{
|
|
117
|
+
name: 'traces.span.sdk.metrics.duration',
|
|
118
|
+
unit: 's',
|
|
119
|
+
histogram: { dataPoints, aggregationTemporality: temporality },
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
}]
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#pushPoint (points, sketch, startNano, endNano, attributes) {
|
|
126
|
+
if (!sketch || sketch.count === 0) return
|
|
127
|
+
points.push({
|
|
128
|
+
attributes,
|
|
129
|
+
startTimeUnixNano: startNano,
|
|
130
|
+
timeUnixNano: endNano,
|
|
131
|
+
count: sketch.count,
|
|
132
|
+
sum: sketch.sum / NS_PER_S,
|
|
133
|
+
min: sketch.min / NS_PER_S,
|
|
134
|
+
max: sketch.max / NS_PER_S,
|
|
135
|
+
bucketCounts: sketchToFixedHistogram(sketch),
|
|
136
|
+
explicitBounds: EXPLICIT_BOUNDS_SECONDS,
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @param {import('../../span_stats').SpanAggKey} aggKey
|
|
142
|
+
*/
|
|
143
|
+
#buildAttributes (aggKey) {
|
|
144
|
+
const raw = { 'span.name': aggKey.resource }
|
|
145
|
+
|
|
146
|
+
if (aggKey.service && aggKey.service !== this.#defaultService) {
|
|
147
|
+
raw['service.name'] = aggKey.service
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (aggKey.spanKind) raw['span.kind'] = aggKey.spanKind
|
|
151
|
+
if (aggKey.statusCode) raw['http.response.status_code'] = Number(aggKey.statusCode)
|
|
152
|
+
if (aggKey.method) raw['http.request.method'] = aggKey.method
|
|
153
|
+
if (aggKey.endpoint) raw['http.route'] = aggKey.endpoint
|
|
154
|
+
if (aggKey.rpcStatusCode !== '') {
|
|
155
|
+
raw['rpc.response.status_code'] = String(aggKey.rpcStatusCode).toUpperCase()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!this.#otelSemanticsEnabled) {
|
|
159
|
+
raw['datadog.operation.name'] = aggKey.name
|
|
160
|
+
if (aggKey.type) raw['datadog.span.type'] = aggKey.type
|
|
161
|
+
if (aggKey.synthetics) raw['datadog.origin'] = 'synthetics'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return this.transformAttributes(raw)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = OtlpStatsTransformer
|
|
169
|
+
module.exports.EXPLICIT_BOUNDS_SECONDS = EXPLICIT_BOUNDS_SECONDS
|
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
METRIC_TYPES, TEMPORALITY, DEFAULT_HISTOGRAM_BUCKETS, DEFAULT_MAX_MEASUREMENT_QUEUE_SIZE,
|
|
7
7
|
} = require('./constants')
|
|
8
8
|
const { ObservableInstrument } = require('./instruments')
|
|
9
|
+
const { nowUnixNano } = require('./time')
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @typedef {import('@opentelemetry/api').Attributes} Attributes
|
|
@@ -309,7 +310,7 @@ class PeriodicMetricReader {
|
|
|
309
310
|
*
|
|
310
311
|
*/
|
|
311
312
|
class MetricAggregator {
|
|
312
|
-
#startTime =
|
|
313
|
+
#startTime = nowUnixNano()
|
|
313
314
|
#temporalityPreference
|
|
314
315
|
#maxBatchedQueueSize
|
|
315
316
|
|
|
@@ -444,8 +445,8 @@ class MetricAggregator {
|
|
|
444
445
|
*/
|
|
445
446
|
#isDeltaType (type) {
|
|
446
447
|
return type === METRIC_TYPES.COUNTER ||
|
|
447
|
-
|
|
448
|
-
|
|
448
|
+
type === METRIC_TYPES.OBSERVABLECOUNTER ||
|
|
449
|
+
type === METRIC_TYPES.HISTOGRAM
|
|
449
450
|
}
|
|
450
451
|
|
|
451
452
|
/**
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { timeOrigin } = performance
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Current wall-clock time as UNIX epoch nanoseconds, the unit OTLP requires for
|
|
7
|
+
* `timeUnixNano` / `startTimeUnixNano`. `process.hrtime.bigint()` is a monotonic
|
|
8
|
+
* clock with an arbitrary origin, so its values decode as 1970 timestamps that
|
|
9
|
+
* the Datadog Agent silently drops. Anchoring on `performance.timeOrigin` puts
|
|
10
|
+
* the value on the epoch while `performance.now()` keeps it monotonic, so a
|
|
11
|
+
* backward wall-clock jump can't make `timeUnixNano` precede `startTimeUnixNano`.
|
|
12
|
+
*
|
|
13
|
+
* @returns {number} Nanoseconds since the UNIX epoch
|
|
14
|
+
*/
|
|
15
|
+
function nowUnixNano () {
|
|
16
|
+
return Math.round((timeOrigin + performance.now()) * 1e6)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = { nowUnixNano }
|
|
@@ -68,7 +68,7 @@ message KeyValue {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// InstrumentationScope is a message representing the instrumentation scope information
|
|
71
|
-
// such as the fully qualified name and version.
|
|
71
|
+
// such as the fully qualified name and version.
|
|
72
72
|
message InstrumentationScope {
|
|
73
73
|
// An empty instrumentation scope name means the name is unknown.
|
|
74
74
|
string name = 1;
|
|
@@ -113,4 +113,4 @@ message EntityRef {
|
|
|
113
113
|
// These attribute keys are not part of entity's identity.
|
|
114
114
|
// These keys MUST exist in the containing {message}.attributes.
|
|
115
115
|
repeated string description_keys = 4;
|
|
116
|
-
}
|
|
116
|
+
}
|