dd-trace 6.7.0 → 6.9.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/ci/diagnose.js +27 -25
- package/ci/init.js +6 -6
- package/ci/runbook.md +114 -20
- package/ci/test-optimization-validation/approval-artifacts.js +36 -3
- package/ci/test-optimization-validation/approval.js +78 -22
- package/ci/test-optimization-validation/blocker-category.js +24 -0
- package/ci/test-optimization-validation/ci-discovery.js +23 -17
- package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
- package/ci/test-optimization-validation/ci-remediation.js +1 -1
- package/ci/test-optimization-validation/cli.js +280 -52
- package/ci/test-optimization-validation/command-blocker.js +159 -20
- package/ci/test-optimization-validation/command-output-policy.js +14 -8
- package/ci/test-optimization-validation/command-runner.js +9 -7
- package/ci/test-optimization-validation/environment.js +4 -2
- package/ci/test-optimization-validation/executable.js +15 -13
- package/ci/test-optimization-validation/execution-lock.js +70 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
- package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +47 -37
- package/ci/test-optimization-validation/generated-test-contract.js +9 -7
- package/ci/test-optimization-validation/generated-verifier.js +24 -17
- package/ci/test-optimization-validation/literal-glob.js +52 -0
- package/ci/test-optimization-validation/manifest-loader.js +3 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
- package/ci/test-optimization-validation/manifest-schema.js +80 -17
- package/ci/test-optimization-validation/offline-fixtures.js +13 -4
- package/ci/test-optimization-validation/offline-output.js +6 -6
- package/ci/test-optimization-validation/package-check.js +94 -0
- package/ci/test-optimization-validation/plan-writer.js +183 -10
- package/ci/test-optimization-validation/preflight-runner.js +110 -31
- package/ci/test-optimization-validation/project-build-artifact.js +31 -0
- package/ci/test-optimization-validation/redaction.js +18 -27
- package/ci/test-optimization-validation/report-writer.js +182 -48
- package/ci/test-optimization-validation/result-semantics.js +20 -3
- package/ci/test-optimization-validation/runner-command.js +41 -21
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/safe-files.js +4 -4
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
- package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
- package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
- package/ci/test-optimization-validation/static-diagnosis.js +10 -3
- package/ci/test-optimization-validation/test-output.js +2 -1
- package/ci/test-optimization-validation/validation-blocker.js +21 -0
- package/ci/vitest-no-worker-init-setup.mjs +377 -84
- package/index.d.ts +175 -14
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +12 -4
- package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-esbuild/src/utils.js +17 -2
- package/packages/datadog-instrumentations/src/ai.js +61 -34
- package/packages/datadog-instrumentations/src/bluebird.js +6 -6
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
- package/packages/datadog-instrumentations/src/cucumber.js +131 -51
- package/packages/datadog-instrumentations/src/dns.js +21 -2
- package/packages/datadog-instrumentations/src/electron.js +1 -0
- package/packages/datadog-instrumentations/src/fastify.js +3 -1
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
- package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +986 -246
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
- package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
- package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/pg.js +180 -6
- package/packages/datadog-instrumentations/src/playwright.js +176 -81
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/rhea.js +1 -1
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
- package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
- package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
- package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aerospike/src/index.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
- package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
- package/packages/datadog-plugin-cucumber/src/index.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
- package/packages/datadog-plugin-graphql/src/execute.js +1 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +3 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +3 -21
- package/packages/datadog-plugin-jest/src/util.js +4 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +342 -6
- package/packages/datadog-plugin-next/src/index.js +57 -9
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-pg/src/index.js +65 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-prisma/src/index.js +5 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +179 -18
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/datadog-webpack/index.js +2 -2
- package/packages/dd-trace/src/aiguard/sdk.js +3 -0
- package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
- package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
- package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
- package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
- package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/defaults.js +14 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +31 -5
- 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 +13 -6
- package/packages/dd-trace/src/datastreams/encoding.js +3 -4
- package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/url.js +3 -5
- package/packages/dd-trace/src/exporters/electron/index.js +4 -1
- package/packages/dd-trace/src/external-logger/src/index.js +1 -2
- package/packages/dd-trace/src/flare/index.js +2 -2
- package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
- package/packages/dd-trace/src/guardrails/log.js +1 -10
- package/packages/dd-trace/src/id.js +1 -1
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
- package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
- package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
- package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
- package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
- package/packages/dd-trace/src/llmobs/noop.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.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 +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +152 -78
- package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
- package/packages/dd-trace/src/llmobs/tagger.js +1 -2
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
- package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
- package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
- package/packages/dd-trace/src/log/channels.js +1 -9
- package/packages/dd-trace/src/log/levels.js +12 -0
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -6
- package/packages/dd-trace/src/plugins/util/git.js +7 -5
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/llm.js +2 -2
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +356 -86
- package/packages/dd-trace/src/plugins/util/url.js +5 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +24 -2
- package/packages/dd-trace/src/priority_sampler.js +6 -3
- package/packages/dd-trace/src/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +10 -20
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
- package/packages/dd-trace/src/sampling_rule.js +4 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/packages/dd-trace/src/util.js +16 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const { channel } = require('dc-polyfill')
|
|
4
4
|
|
|
5
5
|
const { isError } = require('../util')
|
|
6
|
-
const tracerVersion = require('../../../../package.json').version
|
|
7
6
|
const logger = require('../log')
|
|
8
7
|
const { getValueFromEnvSources } = require('../config/helper')
|
|
9
8
|
const Span = require('../opentracing/span')
|
|
@@ -13,6 +12,17 @@ const {
|
|
|
13
12
|
INPUT_VALUE,
|
|
14
13
|
TRACE_ID,
|
|
15
14
|
} = require('./constants/tags')
|
|
15
|
+
const {
|
|
16
|
+
FEEDBACK_METRIC_TYPES,
|
|
17
|
+
FEEDBACK_TARGET_KEYS,
|
|
18
|
+
buildMetricTags,
|
|
19
|
+
validateAssessment,
|
|
20
|
+
validateLabel,
|
|
21
|
+
validateMetricType,
|
|
22
|
+
validateMetricValue,
|
|
23
|
+
validateReasoning,
|
|
24
|
+
validateTimestamp,
|
|
25
|
+
} = require('./eval-metric')
|
|
16
26
|
const {
|
|
17
27
|
getFunctionArguments,
|
|
18
28
|
validateKind,
|
|
@@ -35,12 +45,6 @@ class LLMObs extends NoopLLMObs {
|
|
|
35
45
|
*/
|
|
36
46
|
#hasUserSpanProcessor = false
|
|
37
47
|
|
|
38
|
-
/**
|
|
39
|
-
* Lazily-created experiments facade (see ./experiments).
|
|
40
|
-
* @type {import('./experiments').Experiments | undefined}
|
|
41
|
-
*/
|
|
42
|
-
#experiments
|
|
43
|
-
|
|
44
48
|
/**
|
|
45
49
|
* @param {import('../tracer')} tracer - Tracer instance
|
|
46
50
|
* @param {import('./index')} llmobsModule - LLMObs module instance
|
|
@@ -66,8 +70,7 @@ class LLMObs extends NoopLLMObs {
|
|
|
66
70
|
* a clear message on use.
|
|
67
71
|
*/
|
|
68
72
|
get experiments () {
|
|
69
|
-
|
|
70
|
-
return this.#experiments
|
|
73
|
+
return createExperiments(this._config, this)
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
enable (options = {}) {
|
|
@@ -318,14 +321,14 @@ class LLMObs extends NoopLLMObs {
|
|
|
318
321
|
}
|
|
319
322
|
throw e
|
|
320
323
|
} finally {
|
|
321
|
-
if (autoinstrumented
|
|
324
|
+
if (!autoinstrumented) {
|
|
322
325
|
telemetry.recordLLMObsAnnotate(span, err)
|
|
323
326
|
}
|
|
324
327
|
}
|
|
325
328
|
}
|
|
326
329
|
|
|
327
330
|
exportSpan (span) {
|
|
328
|
-
span
|
|
331
|
+
span ||= this._active()
|
|
329
332
|
let err = ''
|
|
330
333
|
try {
|
|
331
334
|
if (!span) {
|
|
@@ -399,92 +402,35 @@ class LLMObs extends NoopLLMObs {
|
|
|
399
402
|
}
|
|
400
403
|
|
|
401
404
|
const timestampMs = options.timestampMs || Date.now()
|
|
402
|
-
|
|
403
|
-
err = 'invalid_timestamp'
|
|
404
|
-
throw new Error('timestampMs must be a non-negative integer. Evaluation metric data will not be sent')
|
|
405
|
-
}
|
|
405
|
+
validateTimestamp(timestampMs, 'evaluation')
|
|
406
406
|
|
|
407
407
|
const { label, value, tags, reasoning, assessment, metadata } = options
|
|
408
408
|
const metricType = options.metricType?.toLowerCase()
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
err = 'invalid_metric_type'
|
|
415
|
-
throw new Error('metricType must be one of "categorical", "score", "boolean" or "json"')
|
|
416
|
-
}
|
|
417
|
-
if (metricType === 'categorical' && typeof value !== 'string') {
|
|
418
|
-
err = 'invalid_metric_value'
|
|
419
|
-
throw new Error('value must be a string for a categorical metric.')
|
|
420
|
-
}
|
|
421
|
-
if (metricType === 'score' && typeof value !== 'number') {
|
|
422
|
-
err = 'invalid_metric_value'
|
|
423
|
-
throw new Error('value must be a number for a score metric.')
|
|
424
|
-
}
|
|
425
|
-
if (metricType === 'boolean' && typeof value !== 'boolean') {
|
|
426
|
-
err = 'invalid_metric_value'
|
|
427
|
-
throw new Error('value must be a boolean for a boolean metric')
|
|
428
|
-
}
|
|
429
|
-
if (metricType === 'json' && !(typeof value === 'object' && value != null && !Array.isArray(value))) {
|
|
430
|
-
err = 'invalid_metric_value'
|
|
431
|
-
throw new Error('value must be a JSON object for a json metric')
|
|
432
|
-
}
|
|
433
|
-
if (assessment != null && assessment !== 'pass' && assessment !== 'fail') {
|
|
434
|
-
err = 'invalid_assessment'
|
|
435
|
-
throw new Error('assessment must be pass or fail')
|
|
436
|
-
}
|
|
437
|
-
if (reasoning != null && typeof reasoning !== 'string') {
|
|
438
|
-
err = 'invalid_reasoning'
|
|
439
|
-
throw new Error('reasoning must be a string')
|
|
440
|
-
}
|
|
409
|
+
const labelValue = validateLabel(label, 'evaluation')
|
|
410
|
+
validateMetricType(metricType, 'evaluation')
|
|
411
|
+
validateMetricValue(metricType, value)
|
|
412
|
+
validateAssessment(assessment)
|
|
413
|
+
validateReasoning(reasoning)
|
|
441
414
|
if (metadata != null && (typeof metadata !== 'object' || Array.isArray(metadata))) {
|
|
442
415
|
err = 'invalid_metadata'
|
|
443
416
|
throw new Error('metadata must be a JSON object')
|
|
444
417
|
}
|
|
445
418
|
|
|
446
|
-
const evaluationTags = {
|
|
447
|
-
'ddtrace.version': tracerVersion,
|
|
448
|
-
ml_app: mlApp,
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
if (tags) {
|
|
452
|
-
for (const key in tags) {
|
|
453
|
-
const tag = tags[key]
|
|
454
|
-
if (typeof tag === 'string') {
|
|
455
|
-
evaluationTags[key] = tag
|
|
456
|
-
} else if (typeof tag.toString === 'function') {
|
|
457
|
-
evaluationTags[key] = tag.toString()
|
|
458
|
-
} else if (tag == null) {
|
|
459
|
-
evaluationTags[key] = Object.prototype.toString.call(tag)
|
|
460
|
-
} else {
|
|
461
|
-
// should be a rare case
|
|
462
|
-
// every object in JS has a toString, otherwise every primitive has its own toString
|
|
463
|
-
// null and undefined are handled above
|
|
464
|
-
err = 'invalid_tags'
|
|
465
|
-
throw new Error('Failed to parse tags. Tags for evaluation metrics must be strings')
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// When OTel tracing is enabled, add source:otel tag to allow backend to wait for OTel span conversion
|
|
471
|
-
if (this._config.DD_TRACE_OTEL_ENABLED) {
|
|
472
|
-
evaluationTags.source = 'otel'
|
|
473
|
-
}
|
|
474
|
-
|
|
475
419
|
const payload = {
|
|
420
|
+
event_kind: 'evaluation',
|
|
476
421
|
join_on: {
|
|
477
422
|
span: {
|
|
478
423
|
span_id: spanId,
|
|
479
424
|
trace_id: traceId,
|
|
480
425
|
},
|
|
481
426
|
},
|
|
482
|
-
label,
|
|
427
|
+
label: labelValue,
|
|
483
428
|
metric_type: metricType,
|
|
484
429
|
ml_app: mlApp,
|
|
485
430
|
[`${metricType}_value`]: value,
|
|
486
431
|
timestamp_ms: timestampMs,
|
|
487
|
-
|
|
432
|
+
// When OTel tracing is enabled, `source:otel` lets the backend wait for OTel span conversion
|
|
433
|
+
tags: buildMetricTags(tags, mlApp, 'evaluation', this._config.DD_TRACE_OTEL_ENABLED),
|
|
488
434
|
}
|
|
489
435
|
if (reasoning != null) {
|
|
490
436
|
payload.reasoning = reasoning
|
|
@@ -498,11 +444,139 @@ class LLMObs extends NoopLLMObs {
|
|
|
498
444
|
const currentStore = storage.getStore()
|
|
499
445
|
const routing = currentStore?.routingContext
|
|
500
446
|
evalMetricAppendCh.publish({ payload, routing })
|
|
447
|
+
} catch (e) {
|
|
448
|
+
if (e.ddErrorTag) err = e.ddErrorTag
|
|
449
|
+
throw e
|
|
501
450
|
} finally {
|
|
502
451
|
telemetry.recordSubmitEvaluation(options, err)
|
|
503
452
|
}
|
|
504
453
|
}
|
|
505
454
|
|
|
455
|
+
/**
|
|
456
|
+
* Submits end-user feedback for a span, trace, session, or customer-defined entity.
|
|
457
|
+
*
|
|
458
|
+
* Exactly one target must be provided: `span` (as returned by `llmobs.exportSpan()`) or
|
|
459
|
+
* `spanId` to target a span, `traceId` a trace, `sessionId` a session, or `feedbackJoinKey`
|
|
460
|
+
* a customer-defined entity.
|
|
461
|
+
* `label`, `metricType`, `value` and `submitter` are required, and are validated at call time.
|
|
462
|
+
* @param {object} [options] - The feedback options.
|
|
463
|
+
* @param {string} [options.label] - The name of the feedback metric.
|
|
464
|
+
* @param {'categorical' | 'score' | 'boolean' | 'json' | 'text'} [options.metricType] - The value type.
|
|
465
|
+
* @param {string | number | boolean | Record<string, unknown>} [options.value] - The feedback value,
|
|
466
|
+
* matching `metricType`.
|
|
467
|
+
* @param {{ id: string, type?: string }} [options.submitter] - Who submitted the feedback.
|
|
468
|
+
* @param {{ traceId: string, spanId: string }} [options.span] - Span context to attach the feedback to.
|
|
469
|
+
* @param {string} [options.spanId] - ID of the span to attach the feedback to.
|
|
470
|
+
* @param {string} [options.traceId] - ID of the trace to attach the feedback to.
|
|
471
|
+
* @param {string} [options.sessionId] - ID of the session to attach the feedback to.
|
|
472
|
+
* @param {string} [options.feedbackJoinKey] - Customer-defined key to attach the feedback to.
|
|
473
|
+
* @param {Record<string, string>} [options.tags] - Tags to attach to the feedback.
|
|
474
|
+
* @param {string} [options.mlApp] - The ML app name. Defaults to the configured one.
|
|
475
|
+
* @param {number} [options.timestampMs] - When the feedback was generated. Defaults to now.
|
|
476
|
+
* @param {'pass' | 'fail'} [options.assessment] - Assessment of the feedback.
|
|
477
|
+
* @param {string} [options.reasoning] - Explanation of the feedback.
|
|
478
|
+
* @returns {void}
|
|
479
|
+
*/
|
|
480
|
+
submitFeedback (options = {}) {
|
|
481
|
+
if (!this.enabled) return
|
|
482
|
+
|
|
483
|
+
let err = ''
|
|
484
|
+
let targetType = 'other'
|
|
485
|
+
let metricTypeTag = 'other'
|
|
486
|
+
try {
|
|
487
|
+
const { span, spanId, traceId, sessionId, feedbackJoinKey, submitter } = options
|
|
488
|
+
|
|
489
|
+
// Resolved before any validation so telemetry still reports the metric type of a
|
|
490
|
+
// submission that fails on an unrelated field.
|
|
491
|
+
const metricType = options.metricType?.toLowerCase()
|
|
492
|
+
if (FEEDBACK_METRIC_TYPES.includes(metricType)) metricTypeTag = metricType
|
|
493
|
+
|
|
494
|
+
// The intake keys feedback off a single top-level identifier, so more than one target
|
|
495
|
+
// would be ambiguous and none would leave the feedback unattached. `span` also carries a
|
|
496
|
+
// traceId, but passing it is wire-equivalent to passing its `spanId` directly.
|
|
497
|
+
let targetName, targetValue
|
|
498
|
+
let targetCount = 0
|
|
499
|
+
if (span != null) { targetName = 'span'; targetValue = span.spanId; targetCount++ }
|
|
500
|
+
if (spanId != null) { targetName = 'spanId'; targetValue = spanId; targetCount++ }
|
|
501
|
+
if (traceId != null) { targetName = 'traceId'; targetValue = traceId; targetCount++ }
|
|
502
|
+
if (sessionId != null) { targetName = 'sessionId'; targetValue = sessionId; targetCount++ }
|
|
503
|
+
if (feedbackJoinKey != null) { targetName = 'feedbackJoinKey'; targetValue = feedbackJoinKey; targetCount++ }
|
|
504
|
+
|
|
505
|
+
if (targetCount !== 1) {
|
|
506
|
+
err = 'invalid_target_count'
|
|
507
|
+
throw new Error(
|
|
508
|
+
'Exactly one of `span`, `spanId`, `traceId`, `sessionId` or `feedbackJoinKey` ' +
|
|
509
|
+
'must be specified to submit feedback.'
|
|
510
|
+
)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
targetType = FEEDBACK_TARGET_KEYS[targetName]
|
|
514
|
+
if (typeof targetValue !== 'string' || !targetValue) {
|
|
515
|
+
if (targetName === 'span') {
|
|
516
|
+
err = 'invalid_span'
|
|
517
|
+
throw new TypeError(
|
|
518
|
+
'`span` must be an object containing a non-empty string spanId. ' +
|
|
519
|
+
'`llmobs.exportSpan()` can be used to generate this object from a given span.'
|
|
520
|
+
)
|
|
521
|
+
}
|
|
522
|
+
err = `invalid_${targetType}`
|
|
523
|
+
throw new TypeError(`\`${targetName}\` must be a non-empty string`)
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (typeof submitter?.id !== 'string' || !submitter.id) {
|
|
527
|
+
err = 'invalid_submitter'
|
|
528
|
+
throw new TypeError('submitter must be an object containing a non-empty string id')
|
|
529
|
+
}
|
|
530
|
+
if (submitter.type != null && typeof submitter.type !== 'string') {
|
|
531
|
+
err = 'invalid_submitter'
|
|
532
|
+
throw new TypeError('submitter.type must be a string')
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const mlApp = options.mlApp || this._config.llmobs.mlApp
|
|
536
|
+
if (!mlApp) {
|
|
537
|
+
err = 'missing_ml_app'
|
|
538
|
+
throw new Error('ML App name is required for sending feedback. Feedback data will not be sent.')
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const timestampMs = options.timestampMs || Date.now()
|
|
542
|
+
validateTimestamp(timestampMs, 'feedback')
|
|
543
|
+
|
|
544
|
+
const { label, value, tags, reasoning, assessment } = options
|
|
545
|
+
const labelValue = validateLabel(label, 'feedback')
|
|
546
|
+
validateMetricType(metricType, 'feedback')
|
|
547
|
+
validateMetricValue(metricType, value)
|
|
548
|
+
validateAssessment(assessment)
|
|
549
|
+
validateReasoning(reasoning)
|
|
550
|
+
|
|
551
|
+
const payload = {
|
|
552
|
+
event_kind: 'feedback',
|
|
553
|
+
[targetType]: targetValue,
|
|
554
|
+
label: labelValue,
|
|
555
|
+
metric_type: metricType,
|
|
556
|
+
ml_app: mlApp,
|
|
557
|
+
[`${metricType}_value`]: value,
|
|
558
|
+
timestamp_ms: timestampMs,
|
|
559
|
+
tags: buildMetricTags(tags, mlApp, 'feedback'),
|
|
560
|
+
submitter: submitter.type == null ? { id: submitter.id } : { id: submitter.id, type: submitter.type },
|
|
561
|
+
}
|
|
562
|
+
if (reasoning != null) {
|
|
563
|
+
payload.reasoning = reasoning
|
|
564
|
+
}
|
|
565
|
+
if (assessment != null) {
|
|
566
|
+
payload.assessment = assessment
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const currentStore = storage.getStore()
|
|
570
|
+
const routing = currentStore?.routingContext
|
|
571
|
+
evalMetricAppendCh.publish({ payload, routing })
|
|
572
|
+
} catch (e) {
|
|
573
|
+
if (e.ddErrorTag) err = e.ddErrorTag
|
|
574
|
+
throw e
|
|
575
|
+
} finally {
|
|
576
|
+
telemetry.recordSubmitFeedback(metricTypeTag, targetType, err)
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
506
580
|
annotationContext (options, fn) {
|
|
507
581
|
if (!this.enabled) return fn()
|
|
508
582
|
|
|
@@ -239,6 +239,14 @@ class LLMObsSpanProcessor {
|
|
|
239
239
|
|
|
240
240
|
const apmTraceId = span.context().toTraceId(true)
|
|
241
241
|
const llmobsTraceId = mlObsTags[TRACE_ID] ?? apmTraceId
|
|
242
|
+
const dd = {
|
|
243
|
+
span_id: span.context().toSpanId(),
|
|
244
|
+
trace_id: apmTraceId,
|
|
245
|
+
sample_rate: mlObsTags[SAMPLE_RATE],
|
|
246
|
+
sampling_decision: mlObsTags[SAMPLING_DECISION],
|
|
247
|
+
apm_trace_id: apmTraceId,
|
|
248
|
+
}
|
|
249
|
+
if (tags.experiment_id) dd.scope = 'experiments'
|
|
242
250
|
|
|
243
251
|
const llmObsSpanEvent = {
|
|
244
252
|
trace_id: llmobsTraceId,
|
|
@@ -251,13 +259,7 @@ class LLMObsSpanProcessor {
|
|
|
251
259
|
status: error ? 'error' : 'ok',
|
|
252
260
|
meta,
|
|
253
261
|
metrics,
|
|
254
|
-
_dd:
|
|
255
|
-
span_id: span.context().toSpanId(),
|
|
256
|
-
trace_id: apmTraceId,
|
|
257
|
-
sample_rate: mlObsTags[SAMPLE_RATE],
|
|
258
|
-
sampling_decision: mlObsTags[SAMPLING_DECISION],
|
|
259
|
-
apm_trace_id: apmTraceId,
|
|
260
|
-
},
|
|
262
|
+
_dd: dd,
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
if (sessionId) llmObsSpanEvent.session_id = sessionId
|
|
@@ -158,8 +158,7 @@ class LLMObsTagger {
|
|
|
158
158
|
if (modelName) this.tagModelName(span, modelName)
|
|
159
159
|
if (modelProvider) this._setTag(span, MODEL_PROVIDER, modelProvider)
|
|
160
160
|
|
|
161
|
-
sessionId
|
|
162
|
-
registry.get(parent)?.[SESSION_ID] ||
|
|
161
|
+
sessionId ||= registry.get(parent)?.[SESSION_ID] ||
|
|
163
162
|
traceTags[SESSION_ID_TRACE_DEFAULT_KEY] ||
|
|
164
163
|
traceTags[PROPAGATED_SESSION_ID_KEY]
|
|
165
164
|
if (sessionId) this._setTag(span, SESSION_ID, sessionId)
|
|
@@ -183,6 +183,23 @@ function recordSubmitEvaluation (options, err, value = 1) {
|
|
|
183
183
|
llmobsMetrics.count('evals_submitted', tags).inc(value)
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/**
|
|
187
|
+
* @param {string} metricType - The submitted metric type, `'other'` if unrecognized.
|
|
188
|
+
* @param {string} targetType - The payload key the feedback was attached to, `'other'` if unresolved.
|
|
189
|
+
* @param {string} err - The telemetry error tag, empty when the submission succeeded.
|
|
190
|
+
* @param {number} [value]
|
|
191
|
+
* @returns {void}
|
|
192
|
+
*/
|
|
193
|
+
function recordSubmitFeedback (metricType, targetType, err, value = 1) {
|
|
194
|
+
const tags = {
|
|
195
|
+
error: Number(!!err),
|
|
196
|
+
metric_type: metricType,
|
|
197
|
+
target_type: targetType,
|
|
198
|
+
}
|
|
199
|
+
if (err) tags.error_type = err
|
|
200
|
+
llmobsMetrics.count('feedback_submitted', tags).inc(value)
|
|
201
|
+
}
|
|
202
|
+
|
|
186
203
|
function recordLLMObsUserProcessorCalled (error, value = 1) {
|
|
187
204
|
const tags = { error: error ? 1 : 0 }
|
|
188
205
|
llmobsMetrics.count('user_processor_called', tags).inc(value)
|
|
@@ -201,5 +218,6 @@ module.exports = {
|
|
|
201
218
|
recordUserFlush,
|
|
202
219
|
recordExportSpan,
|
|
203
220
|
recordSubmitEvaluation,
|
|
221
|
+
recordSubmitFeedback,
|
|
204
222
|
recordLLMObsUserProcessorCalled,
|
|
205
223
|
}
|
|
@@ -88,6 +88,9 @@ class BaseLLMObsWriter {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
|
+
* @param {Record<string, unknown>} event
|
|
92
|
+
* @param {{ apiKey?: string, site?: string }} [routing]
|
|
93
|
+
* @param {number} [byteLength]
|
|
91
94
|
* @returns {boolean} `true` if the event was buffered, `false` if it was dropped
|
|
92
95
|
* (e.g. the per-routing buffer was full). Callers that depend on the event
|
|
93
96
|
* actually being submitted should check this value.
|
|
@@ -49,12 +49,18 @@ class LLMObsSpanWriter extends BaseWriter {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
makePayload (events) {
|
|
52
|
-
return events.map(event =>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
return events.map(event => {
|
|
53
|
+
const eventData = {
|
|
54
|
+
'_dd.stage': 'raw',
|
|
55
|
+
'_dd.tracer_version': tracerVersion,
|
|
56
|
+
event_type: this._eventType,
|
|
57
|
+
spans: [event],
|
|
58
|
+
}
|
|
59
|
+
if (event?._dd?.scope === 'experiments') {
|
|
60
|
+
eventData['_dd.scope'] = 'experiments'
|
|
61
|
+
}
|
|
62
|
+
return eventData
|
|
63
|
+
})
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
_truncateSpanEvent (event) {
|
|
@@ -7,6 +7,8 @@ const { fetchAgentInfo } = require('../../agent/info')
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @param {import('../../config/config-base')} config
|
|
10
|
+
* @param {(agentless: boolean) => void} setWritersAgentlessValue
|
|
11
|
+
* @returns {void}
|
|
10
12
|
*/
|
|
11
13
|
function setAgentStrategy (config, setWritersAgentlessValue) {
|
|
12
14
|
const agentlessEnabled = config.llmobs.agentlessEnabled
|
|
@@ -2,15 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { channel } = require('dc-polyfill')
|
|
4
4
|
|
|
5
|
-
const Level =
|
|
6
|
-
trace: 10,
|
|
7
|
-
debug: 20,
|
|
8
|
-
info: 30,
|
|
9
|
-
warn: 40,
|
|
10
|
-
error: 50,
|
|
11
|
-
critical: 50,
|
|
12
|
-
off: 100,
|
|
13
|
-
}
|
|
5
|
+
const Level = require('./levels')
|
|
14
6
|
|
|
15
7
|
const traceChannel = channel('datadog:log:trace')
|
|
16
8
|
const debugChannel = channel('datadog:log:debug')
|
|
@@ -55,7 +55,7 @@ class NoopProxy {
|
|
|
55
55
|
|
|
56
56
|
if (typeof fn !== 'function') return
|
|
57
57
|
|
|
58
|
-
options
|
|
58
|
+
options ||= {}
|
|
59
59
|
|
|
60
60
|
return this._tracer.trace(name, options, fn)
|
|
61
61
|
}
|
|
@@ -68,7 +68,7 @@ class NoopProxy {
|
|
|
68
68
|
|
|
69
69
|
if (typeof fn !== 'function') return fn
|
|
70
70
|
|
|
71
|
-
options
|
|
71
|
+
options ||= {}
|
|
72
72
|
|
|
73
73
|
return this._tracer.wrap(name, options, fn)
|
|
74
74
|
}
|
|
@@ -63,7 +63,7 @@ class ExposuresWriter extends BaseFFEWriter {
|
|
|
63
63
|
* @param {import('../../config/config-base')} config - Tracer configuration object
|
|
64
64
|
*/
|
|
65
65
|
constructor (config) {
|
|
66
|
-
const basePath = EVP_PROXY_AGENT_BASE_PATH.replace(
|
|
66
|
+
const basePath = EVP_PROXY_AGENT_BASE_PATH.replace(/\/$/, '')
|
|
67
67
|
const endpoint = EXPOSURES_ENDPOINT.replace(/^\/+/, '')
|
|
68
68
|
const fullEndpoint = `${basePath}/${endpoint}`
|
|
69
69
|
|
|
@@ -18,7 +18,7 @@ function setAgentStrategy (config, setWriterEnabledValue) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const endpoints = agentInfo.endpoints
|
|
21
|
-
const normalizedPath = EVP_PROXY_AGENT_BASE_PATH.replace(
|
|
21
|
+
const normalizedPath = EVP_PROXY_AGENT_BASE_PATH.replace(/\/$/, '')
|
|
22
22
|
const hasEndpoint = Array.isArray(endpoints) &&
|
|
23
23
|
endpoints.includes(normalizedPath) || endpoints.includes(normalizedPath + '/')
|
|
24
24
|
|
|
@@ -22,7 +22,7 @@ class BatchLogRecordProcessor {
|
|
|
22
22
|
/**
|
|
23
23
|
* Creates a new BatchLogRecordProcessor instance.
|
|
24
24
|
*
|
|
25
|
-
* @param {
|
|
25
|
+
* @param {import('./otlp_http_log_exporter')} exporter - Log processor for exporting batches to Datadog Agent
|
|
26
26
|
* @param {number} batchTimeout - Timeout in milliseconds for batch processing
|
|
27
27
|
* @param {number} maxExportBatchSize - Maximum number of log records per batch
|
|
28
28
|
*/
|
|
@@ -9,6 +9,8 @@ const { METRIC_TYPES } = require('./constants')
|
|
|
9
9
|
/**
|
|
10
10
|
* @typedef {import('@opentelemetry/api').MetricOptions} MetricOptions
|
|
11
11
|
* @typedef {import('@opentelemetry/core').InstrumentationScope} InstrumentationScope
|
|
12
|
+
* @typedef {Counter | UpDownCounter | Histogram | Gauge |
|
|
13
|
+
* ObservableGauge | ObservableCounter | ObservableUpDownCounter} Instrument
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -25,7 +27,7 @@ class Meter {
|
|
|
25
27
|
/**
|
|
26
28
|
* Creates a new Meter instance.
|
|
27
29
|
*
|
|
28
|
-
* @param {
|
|
30
|
+
* @param {import('./meter_provider')} meterProvider - Parent meter provider
|
|
29
31
|
* @param {InstrumentationScope} instrumentationScope - Instrumentation scope information
|
|
30
32
|
* @param {string} [instrumentationScope.name] - Meter name (defaults to 'dd-trace-js')
|
|
31
33
|
* @param {string} [instrumentationScope.version] - Meter version (defaults to tracer version)
|
|
@@ -50,11 +52,13 @@ class Meter {
|
|
|
50
52
|
* Instruments are cached by type and normalized (lowercase) name.
|
|
51
53
|
*
|
|
52
54
|
*
|
|
55
|
+
* @template {Instrument} T
|
|
53
56
|
* @param {string} name - Instrument name (will be normalized to lowercase)
|
|
54
57
|
* @param {string} type - Instrument type (e.g., 'counter', 'histogram', 'gauge')
|
|
55
|
-
* @param {
|
|
56
|
-
*
|
|
57
|
-
* @
|
|
58
|
+
* @param {new (name: string, options: object, instrumentationScope: InstrumentationScope,
|
|
59
|
+
* reader: object) => T} InstrumentClass - Constructor for the instrument type
|
|
60
|
+
* @param {MetricOptions} options - Instrument options (description, unit, etc.)
|
|
61
|
+
* @returns {T} The instrument instance (new or cached)
|
|
58
62
|
*/
|
|
59
63
|
#getOrCreateInstrument (name, type, InstrumentClass, options) {
|
|
60
64
|
const normalizedName = name.toLowerCase()
|
|
@@ -198,7 +198,7 @@ class OtlpTransformer extends OtlpTransformerBase {
|
|
|
198
198
|
if (isJson) {
|
|
199
199
|
dataPoint.startTimeUnixNano = String(dataPoint.startTimeUnixNano)
|
|
200
200
|
dataPoint.timeUnixNano = String(dataPoint.timeUnixNano)
|
|
201
|
-
dataPoint.count
|
|
201
|
+
dataPoint.count ||= 0
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
return dataPoint
|
|
@@ -109,7 +109,7 @@ class PeriodicMetricReader {
|
|
|
109
109
|
/**
|
|
110
110
|
* Creates a new PeriodicMetricReader instance.
|
|
111
111
|
*
|
|
112
|
-
* @param {
|
|
112
|
+
* @param {import('./otlp_http_metric_exporter')} exporter - Metric exporter for sending to Datadog Agent
|
|
113
113
|
* @param {number} exportInterval - Export interval in milliseconds
|
|
114
114
|
* @param {string} temporalityPreference - Temporality preference: DELTA, CUMULATIVE, or LOWMEMORY
|
|
115
115
|
* @param {number} maxBatchedQueueSize - Maximum number of measurements to queue before dropping
|
|
@@ -253,7 +253,8 @@ class PeriodicMetricReader {
|
|
|
253
253
|
#collectAndExport (callback = () => {}) {
|
|
254
254
|
// Atomically drain measurements for export. New measurements can be recorded
|
|
255
255
|
// during export without interfering with this batch.
|
|
256
|
-
const allMeasurements = this.#measurements
|
|
256
|
+
const allMeasurements = this.#measurements
|
|
257
|
+
this.#measurements = []
|
|
257
258
|
|
|
258
259
|
for (const instrument of this.observableInstruments) {
|
|
259
260
|
const observableMeasurements = instrument.collect()
|
|
@@ -38,6 +38,10 @@ function hrTimeToMilliseconds (hrTime) {
|
|
|
38
38
|
/**
|
|
39
39
|
* Several of these attributes are not yet supported by the Node.js OTel API.
|
|
40
40
|
* We check for old equivalents where we can, but not all had equivalents.
|
|
41
|
+
*
|
|
42
|
+
* @param {string | undefined} spanName
|
|
43
|
+
* @param {import('@opentelemetry/api').SpanKind} kind
|
|
44
|
+
* @param {import('@opentelemetry/api').Attributes} attributes
|
|
41
45
|
*/
|
|
42
46
|
function spanNameMapper (spanName, kind, attributes) {
|
|
43
47
|
if (spanName) return spanName
|