dd-trace 6.15.0 → 6.17.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 +15 -0
- package/ci/diagnose.js +0 -23
- package/ci/test-optimization-validation/approval-artifacts.js +0 -3
- package/ci/test-optimization-validation/approval.js +0 -6
- package/ci/test-optimization-validation/artifact-id.js +0 -1
- package/ci/test-optimization-validation/bounded-json.js +0 -1
- package/ci/test-optimization-validation/cli.js +0 -12
- package/ci/test-optimization-validation/command-output-policy.js +0 -1
- package/ci/test-optimization-validation/command-runner.js +0 -3
- package/ci/test-optimization-validation/environment.js +0 -4
- package/ci/test-optimization-validation/executable-approval.js +0 -1
- package/ci/test-optimization-validation/executable.js +0 -5
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +4 -8
- package/ci/test-optimization-validation/framework-adapters/cypress.js +0 -3
- package/ci/test-optimization-validation/framework-adapters/playwright.js +0 -6
- package/ci/test-optimization-validation/framework-adapters/vitest.js +0 -4
- package/ci/test-optimization-validation/generated-test-contract.js +0 -5
- package/ci/test-optimization-validation/generated-verifier.js +0 -1
- package/ci/test-optimization-validation/literal-environment.js +0 -1
- package/ci/test-optimization-validation/manifest-scaffold.js +0 -17
- package/ci/test-optimization-validation/manifest-schema.js +0 -21
- package/ci/test-optimization-validation/offline-fixtures.js +0 -4
- package/ci/test-optimization-validation/package-check.js +4 -1
- package/ci/test-optimization-validation/plan-writer.js +0 -11
- package/ci/test-optimization-validation/preflight-runner.js +0 -1
- package/ci/test-optimization-validation/redaction.js +0 -4
- package/ci/test-optimization-validation/report-writer.js +0 -16
- package/ci/test-optimization-validation/runner-command.js +0 -3
- package/ci/test-optimization-validation/runner-contract.js +0 -4
- package/ci/test-optimization-validation/safe-files.js +0 -1
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +0 -1
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +1 -2
- package/ci/test-optimization-validation/source-text.js +0 -3
- package/ci/vitest-no-worker-init-setup.mjs +41 -16
- package/index.d.ts +169 -0
- package/next.d.ts +27 -0
- package/next.js +3 -0
- package/package.json +28 -23
- package/packages/datadog-esbuild/index.js +14 -1
- package/packages/datadog-esbuild/src/resolver.js +284 -0
- package/packages/datadog-esbuild/src/utils.js +162 -120
- package/packages/datadog-instrumentations/src/aerospike.js +28 -6
- package/packages/datadog-instrumentations/src/ai.js +39 -97
- package/packages/datadog-instrumentations/src/anthropic.js +76 -134
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +1 -3
- package/packages/datadog-instrumentations/src/aws-sdk.js +0 -2
- package/packages/datadog-instrumentations/src/azure-cosmos.js +1 -1
- package/packages/datadog-instrumentations/src/azure-durable-functions.js +23 -9
- package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
- package/packages/datadog-instrumentations/src/bullmq.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -3
- package/packages/datadog-instrumentations/src/console.js +97 -0
- package/packages/datadog-instrumentations/src/cucumber.js +72 -12
- package/packages/datadog-instrumentations/src/cypress-config.js +0 -23
- package/packages/datadog-instrumentations/src/dd-trace-api.js +2 -2
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +39 -14
- package/packages/datadog-instrumentations/src/helpers/channel.js +0 -2
- package/packages/datadog-instrumentations/src/helpers/graphql-jit-runtime.js +0 -5
- package/packages/datadog-instrumentations/src/helpers/hooks.js +8 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +25 -8
- package/packages/datadog-instrumentations/src/helpers/instrumentation-utils.js +69 -0
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +0 -6
- package/packages/datadog-instrumentations/src/helpers/register.js +13 -64
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +109 -29
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentation-registry.js +39 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-durable-functions.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +3 -16
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +12 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/postgres.js +36 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/supabase.js +128 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +6 -7
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms/postgres.js +388 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +99 -75
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +0 -1
- package/packages/datadog-instrumentations/src/jest.js +141 -51
- package/packages/datadog-instrumentations/src/knex.js +0 -1
- package/packages/datadog-instrumentations/src/langchain.js +1 -1
- package/packages/datadog-instrumentations/src/langgraph.js +1 -1
- package/packages/datadog-instrumentations/src/mariadb-bundle.js +0 -24
- package/packages/datadog-instrumentations/src/mariadb.js +0 -2
- package/packages/datadog-instrumentations/src/mercurius.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/common.js +0 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +22 -25
- package/packages/datadog-instrumentations/src/mocha/utils.js +119 -49
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +0 -6
- package/packages/datadog-instrumentations/src/mocha/worker.js +14 -17
- package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/mysql2.js +0 -2
- package/packages/datadog-instrumentations/src/openai-agents.js +1 -1
- package/packages/datadog-instrumentations/src/openai-realtime/audio-accumulator.js +241 -0
- package/packages/datadog-instrumentations/src/openai-realtime/events.js +76 -0
- package/packages/datadog-instrumentations/src/openai-realtime/index.js +301 -0
- package/packages/datadog-instrumentations/src/openai-realtime/session.js +998 -0
- package/packages/datadog-instrumentations/src/openai-realtime/turns.js +211 -0
- package/packages/datadog-instrumentations/src/openai.js +97 -80
- package/packages/datadog-instrumentations/src/oracledb.js +9 -3
- package/packages/datadog-instrumentations/src/playwright-reporter.js +3 -16
- package/packages/datadog-instrumentations/src/playwright.js +238 -55
- package/packages/datadog-instrumentations/src/postgres.js +7 -0
- package/packages/datadog-instrumentations/src/router.js +0 -2
- package/packages/datadog-instrumentations/src/rum-browser-scripts.js +0 -2
- package/packages/datadog-instrumentations/src/sequelize.js +0 -1
- package/packages/datadog-instrumentations/src/supabase.js +15 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +18 -18
- package/packages/datadog-instrumentations/src/vitest-main.js +37 -17
- package/packages/datadog-instrumentations/src/vitest-util.js +7 -1
- package/packages/datadog-instrumentations/src/vitest-worker.js +56 -23
- package/packages/datadog-instrumentations/src/webdriverio.js +23 -42
- package/packages/datadog-instrumentations/src/ws.js +0 -1
- package/packages/datadog-plugin-ai/src/utils.js +0 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +0 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +0 -2
- package/packages/datadog-plugin-aws-sdk/src/base.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +7 -2
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +0 -1
- package/packages/datadog-plugin-aws-sdk/src/util.js +0 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +1 -1
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +95 -1
- package/packages/datadog-plugin-cucumber/src/index.js +10 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +171 -75
- package/packages/datadog-plugin-cypress/src/finalization.js +0 -3
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +0 -4
- package/packages/datadog-plugin-cypress/src/support.js +52 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -24
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -36
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-request-context.js +31 -0
- package/packages/datadog-plugin-graphql/src/resolve-error.js +32 -11
- package/packages/datadog-plugin-graphql/src/utils.js +0 -5
- package/packages/datadog-plugin-jest/src/index.js +13 -0
- package/packages/datadog-plugin-kafkajs/src/producer.js +0 -1
- package/packages/datadog-plugin-mocha/src/index.js +39 -11
- package/packages/datadog-plugin-mongodb-core/src/query.js +0 -1
- package/packages/datadog-plugin-openai/src/index.js +16 -1
- package/packages/datadog-plugin-openai/src/realtime.js +144 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +0 -4
- package/packages/datadog-plugin-openai-agents/src/util.js +0 -1
- package/packages/datadog-plugin-playwright/src/index.js +76 -9
- package/packages/datadog-plugin-postgres/src/index.js +167 -0
- package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +0 -1
- package/packages/datadog-plugin-redis/src/index.js +15 -1
- package/packages/datadog-plugin-supabase/src/error.js +18 -0
- package/packages/datadog-plugin-supabase/src/index.js +21 -0
- package/packages/datadog-plugin-supabase/src/supabase-auth-js-gotrueclient-getuser.js +69 -0
- package/packages/datadog-plugin-supabase/src/supabase-functions-js-functionsclient-invoke.js +70 -0
- package/packages/datadog-plugin-supabase/src/supabase-postgrest-js-postgrestbuilder-then.js +122 -0
- package/packages/datadog-plugin-supabase/src/supabase-realtime-js-realtimechannel-send.js +66 -0
- package/packages/datadog-plugin-supabase/src/supabase-storage-js-handle-request.js +93 -0
- package/packages/datadog-plugin-supabase/src/url.js +17 -0
- package/packages/datadog-plugin-vitest/src/index.js +10 -0
- package/packages/datadog-plugin-ws/src/util.js +0 -4
- package/packages/datadog-turbopack/index.js +206 -0
- package/packages/datadog-turbopack/src/constants.js +5 -0
- package/packages/datadog-turbopack/src/loader.js +484 -0
- package/packages/datadog-webpack/src/loader.js +0 -1
- package/packages/dd-trace/src/aiguard/client.js +2 -3
- package/packages/dd-trace/src/aiguard/evaluation.js +6 -12
- package/packages/dd-trace/src/aiguard/index.js +3 -2
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +53 -25
- package/packages/dd-trace/src/aiguard/integrations/evaluate.js +49 -25
- package/packages/dd-trace/src/aiguard/integrations/index.js +4 -3
- package/packages/dd-trace/src/aiguard/integrations/openai.js +132 -29
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +116 -42
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +0 -2
- package/packages/dd-trace/src/aiguard/messages/openai.js +64 -1
- package/packages/dd-trace/src/aiguard/messages/utils.js +29 -2
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +25 -0
- package/packages/dd-trace/src/aiguard/redaction.js +0 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/activation.js +1 -1
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +0 -5
- package/packages/dd-trace/src/appsec/api_security/sampler.js +0 -4
- package/packages/dd-trace/src/appsec/blocking/index.js +3 -3
- package/packages/dd-trace/src/appsec/downstream_requests.js +1 -4
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +5 -5
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +3 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +8 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +4 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +7 -7
- package/packages/dd-trace/src/appsec/index.js +2 -2
- package/packages/dd-trace/src/appsec/lambda.js +71 -2
- package/packages/dd-trace/src/appsec/rasp/utils.js +5 -1
- package/packages/dd-trace/src/appsec/remote_config.js +8 -6
- package/packages/dd-trace/src/appsec/reporter.js +10 -6
- package/packages/dd-trace/src/appsec/rule_manager.js +3 -3
- package/packages/dd-trace/src/appsec/sdk/track_event.js +0 -2
- package/packages/dd-trace/src/appsec/telemetry/api_security.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/common.js +4 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +23 -5
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +1 -20
- package/packages/dd-trace/src/appsec/telemetry/user.js +1 -3
- package/packages/dd-trace/src/appsec/telemetry/waf.js +1 -20
- package/packages/dd-trace/src/appsec/waf/index.js +2 -2
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +8 -5
- package/packages/dd-trace/src/carrier.js +0 -5
- package/packages/dd-trace/src/ci-visibility/dynamic-atr-retries.js +104 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +0 -2
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +34 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +0 -4
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +0 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +37 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +0 -3
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +0 -11
- package/packages/dd-trace/src/ci-visibility/exporters/settings-cache-key.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +0 -1
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +0 -6
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -2
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +0 -1
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +0 -5
- package/packages/dd-trace/src/ci-visibility/requests/video-request.js +0 -1
- package/packages/dd-trace/src/ci-visibility/telemetry.js +13 -0
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +0 -1
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +0 -2
- package/packages/dd-trace/src/ci-visibility/test-video.js +0 -1
- package/packages/dd-trace/src/config/defaults.js +3 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +74 -66
- package/packages/dd-trace/src/config/helper.js +9 -2
- package/packages/dd-trace/src/config/index.js +44 -29
- package/packages/dd-trace/src/config/parsers.js +34 -6
- package/packages/dd-trace/src/config/remote_config.js +25 -109
- package/packages/dd-trace/src/config/supported-configurations.json +146 -9
- package/packages/dd-trace/src/datastreams/encoding.js +0 -1
- package/packages/dd-trace/src/datastreams/pathway.js +0 -1
- package/packages/dd-trace/src/debugger/constants.js +10 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +76 -17
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
- package/packages/dd-trace/src/debugger/devtools_client/guardrail-metrics.js +15 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +103 -27
- package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +50 -7
- package/packages/dd-trace/src/debugger/devtools_client/log.js +3 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +34 -8
- package/packages/dd-trace/src/debugger/devtools_client/send.js +40 -14
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +53 -13
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +118 -71
- package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +0 -3
- package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -6
- package/packages/dd-trace/src/debugger/guardrail-metrics.js +167 -0
- package/packages/dd-trace/src/debugger/index.js +50 -2
- package/packages/dd-trace/src/debugger/inspect-segment.js +0 -3
- package/packages/dd-trace/src/debugger/probe_sampler.js +133 -9
- package/packages/dd-trace/src/debugger/probe_sampler_constants.js +31 -1
- package/packages/dd-trace/src/dogstatsd.js +0 -23
- package/packages/dd-trace/src/encode/0.4-cross-payload.js +0 -3
- package/packages/dd-trace/src/encode/0.4.js +0 -7
- package/packages/dd-trace/src/encode/0.5.js +0 -2
- package/packages/dd-trace/src/encode/tags-processors.js +0 -1
- package/packages/dd-trace/src/evp_proxy/discovery.js +3 -5
- package/packages/dd-trace/src/evp_proxy/path.js +11 -4
- package/packages/dd-trace/src/exporters/agent/writer.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/index.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/intake.js +0 -1
- package/packages/dd-trace/src/exporters/agentless/writer.js +0 -3
- package/packages/dd-trace/src/exporters/common/docker.js +4 -1
- package/packages/dd-trace/src/exporters/common/final-flush-request-tracker.js +0 -6
- package/packages/dd-trace/src/exporters/common/proxy.js +3 -0
- package/packages/dd-trace/src/exporters/common/request.js +1 -0
- package/packages/dd-trace/src/exporters/common/url.js +0 -2
- package/packages/dd-trace/src/exporters/common/writer.js +0 -2
- package/packages/dd-trace/src/id.js +0 -11
- package/packages/dd-trace/src/llmobs/audio-codec.js +192 -0
- package/packages/dd-trace/src/llmobs/audio-utils.js +121 -0
- package/packages/dd-trace/src/llmobs/constants/audio.js +35 -0
- package/packages/dd-trace/src/llmobs/constants/prompts.js +14 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +17 -0
- package/packages/dd-trace/src/llmobs/eval-metric.js +0 -6
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +0 -4
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +0 -3
- package/packages/dd-trace/src/llmobs/experiments/index.js +7 -6
- package/packages/dd-trace/src/llmobs/experiments/util.js +1 -11
- package/packages/dd-trace/src/llmobs/index.js +1 -3
- package/packages/dd-trace/src/llmobs/noop.js +10 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +0 -4
- package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +0 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +0 -4
- package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +0 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +0 -2
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +4 -6
- package/packages/dd-trace/src/llmobs/plugins/openai/realtime.js +285 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +16 -3
- package/packages/dd-trace/src/llmobs/prompts/cache.js +272 -0
- package/packages/dd-trace/src/llmobs/prompts/manager.js +639 -0
- package/packages/dd-trace/src/llmobs/prompts/noop.js +29 -0
- package/packages/dd-trace/src/llmobs/prompts/prompt.js +92 -0
- package/packages/dd-trace/src/llmobs/sdk.js +21 -6
- package/packages/dd-trace/src/llmobs/span_processor.js +81 -2
- package/packages/dd-trace/src/llmobs/tagger.js +30 -7
- package/packages/dd-trace/src/llmobs/telemetry.js +36 -4
- package/packages/dd-trace/src/llmobs/util.js +0 -34
- package/packages/dd-trace/src/llmobs/writers/base.js +0 -1
- package/packages/dd-trace/src/llmobs/writers/util.js +1 -2
- package/packages/dd-trace/src/log/channels.js +3 -0
- package/packages/dd-trace/src/log/index.js +23 -5
- package/packages/dd-trace/src/log-submission/log-submission-plugin.js +74 -6
- package/packages/dd-trace/src/msgpack/chunk.js +0 -1
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +0 -12
- package/packages/dd-trace/src/openfeature/encoding.js +0 -2
- package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/index.js +0 -4
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +0 -1
- package/packages/dd-trace/src/openfeature/span-enrichment.js +0 -4
- package/packages/dd-trace/src/openfeature/writers/base.js +0 -6
- package/packages/dd-trace/src/openfeature/writers/exposures.js +0 -5
- package/packages/dd-trace/src/openfeature/writers/util.js +0 -4
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger_provider.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +0 -1
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +0 -2
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter_provider.js +4 -4
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +0 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +103 -35
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +0 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +36 -13
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +0 -1
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +0 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +0 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +0 -3
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +0 -6
- package/packages/dd-trace/src/opentracing/span_context.js +0 -1
- package/packages/dd-trace/src/otel-thread-ctx.js +38 -11
- package/packages/dd-trace/src/payload-tagging/tagging.js +15 -3
- package/packages/dd-trace/src/plugin_manager.js +9 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +0 -1
- package/packages/dd-trace/src/plugins/database.js +2 -6
- package/packages/dd-trace/src/plugins/index.js +8 -0
- package/packages/dd-trace/src/plugins/plugin.js +0 -4
- package/packages/dd-trace/src/plugins/tracing.js +1 -1
- package/packages/dd-trace/src/plugins/util/git.js +1 -3
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +0 -1
- package/packages/dd-trace/src/plugins/util/llm.js +0 -2
- package/packages/dd-trace/src/plugins/util/status-validator.js +0 -1
- package/packages/dd-trace/src/plugins/util/test.js +25 -21
- package/packages/dd-trace/src/plugins/util/url.js +0 -5
- package/packages/dd-trace/src/priority_sampler.js +0 -6
- package/packages/dd-trace/src/process-tags/index.js +0 -1
- package/packages/dd-trace/src/profiler.js +132 -35
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +0 -1
- package/packages/dd-trace/src/profiling/profiler.js +101 -41
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +29 -15
- package/packages/dd-trace/src/propagation-hash/index.js +0 -1
- package/packages/dd-trace/src/proxy.js +21 -45
- package/packages/dd-trace/src/random_sampler.js +0 -4
- package/packages/dd-trace/src/rate_limiter.js +0 -4
- package/packages/dd-trace/src/remote_config/capabilities.js +1 -9
- package/packages/dd-trace/src/remote_config/index.js +0 -1
- package/packages/dd-trace/src/runtime_metrics/otlp_runtime_metrics.js +0 -3
- package/packages/dd-trace/src/sampler.js +0 -4
- package/packages/dd-trace/src/sampling_rule.js +0 -7
- package/packages/dd-trace/src/serverless/vercel.js +0 -1
- package/packages/dd-trace/src/serverless.js +0 -1
- package/packages/dd-trace/src/service-naming/index.js +0 -1
- package/packages/dd-trace/src/service-naming/schemas/util.js +0 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +7 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +5 -0
- package/packages/dd-trace/src/span_processor.js +2 -2
- package/packages/dd-trace/src/span_sampler.js +0 -1
- package/packages/dd-trace/src/standalone/product.js +2 -2
- package/packages/dd-trace/src/standalone/tracesource.js +0 -1
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +0 -8
- package/packages/dd-trace/src/telemetry/logs/index.js +16 -5
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +16 -6
- package/packages/dd-trace/src/telemetry/metrics.js +0 -2
- package/packages/dd-trace/src/telemetry/telemetry.js +4 -1
- package/packages/dd-trace/src/util.js +13 -1
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/utils.js +0 -10
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const VARIABLE_PATTERN = /(?<!\{)(?:\{\{\s*(\w+)\s*\}\}(?!\})|\{\s*(\w+)\s*\}(?!\}))/g
|
|
4
|
+
|
|
5
|
+
function render (template, variables) {
|
|
6
|
+
return template.replaceAll(VARIABLE_PATTERN, (match, doubleName, singleName) => {
|
|
7
|
+
const name = doubleName ?? singleName
|
|
8
|
+
return Object.hasOwn(variables, name) ? String(variables[name]) : match
|
|
9
|
+
})
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class ManagedPrompt {
|
|
13
|
+
/**
|
|
14
|
+
* @param {object} data
|
|
15
|
+
* @param {string} data.id
|
|
16
|
+
* @param {string} data.version
|
|
17
|
+
* @param {'registry'|'cache'|'fallback'|'ff'|'resolve'} data.source
|
|
18
|
+
* @param {string | Array<{role: string, content: string}>} data.template
|
|
19
|
+
* @param {string} [data.promptUuid]
|
|
20
|
+
* @param {string} [data.promptVersionUuid]
|
|
21
|
+
*/
|
|
22
|
+
constructor ({ id, version, source, template, promptUuid, promptVersionUuid }) {
|
|
23
|
+
this.id = id
|
|
24
|
+
this.version = version
|
|
25
|
+
this.source = source
|
|
26
|
+
this.template = Array.isArray(template)
|
|
27
|
+
? Object.freeze(template.map(message => Object.freeze({ role: message.role, content: message.content })))
|
|
28
|
+
: template
|
|
29
|
+
this.promptUuid = promptUuid
|
|
30
|
+
this.promptVersionUuid = promptVersionUuid
|
|
31
|
+
Object.freeze(this)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Render the prompt without changing its stored template.
|
|
36
|
+
* @param {Record<string, unknown>} [variables]
|
|
37
|
+
* @returns {string | Array<{role: string, content: string}>}
|
|
38
|
+
*/
|
|
39
|
+
format (variables = {}) {
|
|
40
|
+
if (typeof this.template === 'string') return render(this.template, variables)
|
|
41
|
+
return this.template.map(message => ({ role: message.role, content: render(message.content, variables) }))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Convert the managed prompt to the existing public annotation shape.
|
|
46
|
+
* @param {Record<string, unknown>} [variables]
|
|
47
|
+
* @returns {Record<string, unknown>}
|
|
48
|
+
*/
|
|
49
|
+
toAnnotation (variables) {
|
|
50
|
+
const annotation = {
|
|
51
|
+
id: this.id,
|
|
52
|
+
version: this.version,
|
|
53
|
+
template: typeof this.template === 'string' ? this.template : this.template.map(message => ({ ...message })),
|
|
54
|
+
}
|
|
55
|
+
const entries = Object.entries(variables ?? {})
|
|
56
|
+
if (entries.length) {
|
|
57
|
+
annotation.variables = Object.fromEntries(entries.map(([name, value]) => [name, String(value)]))
|
|
58
|
+
}
|
|
59
|
+
if (this.promptUuid) annotation.promptUuid = this.promptUuid
|
|
60
|
+
if (this.promptVersionUuid) annotation.promptVersionUuid = this.promptVersionUuid
|
|
61
|
+
return annotation
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Convert a caller fallback to a managed prompt.
|
|
66
|
+
* @param {string} promptId
|
|
67
|
+
* @param {string | object | Array<{role: string, content: string}> |
|
|
68
|
+
* (() => string | object | Array<{role: string, content: string}>)} fallback
|
|
69
|
+
* @returns {ManagedPrompt}
|
|
70
|
+
*/
|
|
71
|
+
static fromFallback (promptId, fallback) {
|
|
72
|
+
const value = typeof fallback === 'function' ? fallback() : fallback
|
|
73
|
+
const promptLike = value && !Array.isArray(value) && typeof value === 'object'
|
|
74
|
+
const template = promptLike ? value.template : value
|
|
75
|
+
const validTemplate = typeof template === 'string' || (
|
|
76
|
+
Array.isArray(template) && template.every(message => {
|
|
77
|
+
return message && typeof message.role === 'string' && typeof message.content === 'string'
|
|
78
|
+
})
|
|
79
|
+
)
|
|
80
|
+
if (!validTemplate) {
|
|
81
|
+
throw new TypeError('Invalid prompt fallback: expected a string, chat message array, or object with a template')
|
|
82
|
+
}
|
|
83
|
+
return new ManagedPrompt({
|
|
84
|
+
id: promptId,
|
|
85
|
+
version: String(promptLike && value.version ? value.version : 'fallback'),
|
|
86
|
+
source: 'fallback',
|
|
87
|
+
template,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = ManagedPrompt
|
|
@@ -31,6 +31,7 @@ const { storage } = require('./storage')
|
|
|
31
31
|
const telemetry = require('./telemetry')
|
|
32
32
|
const LLMObsTagger = require('./tagger')
|
|
33
33
|
const { createExperiments } = require('./experiments')
|
|
34
|
+
const PromptManager = require('./prompts/manager')
|
|
34
35
|
|
|
35
36
|
// communicating with writer
|
|
36
37
|
const evalMetricAppendCh = channel('llmobs:eval-metric:append')
|
|
@@ -45,12 +46,17 @@ class LLMObs extends NoopLLMObs {
|
|
|
45
46
|
*/
|
|
46
47
|
#hasUserSpanProcessor = false
|
|
47
48
|
|
|
49
|
+
#promptManager
|
|
50
|
+
|
|
51
|
+
#getOpenFeatureProvider
|
|
52
|
+
|
|
48
53
|
/**
|
|
49
54
|
* @param {import('../tracer')} tracer - Tracer instance
|
|
50
55
|
* @param {import('./index')} llmobsModule - LLMObs module instance
|
|
51
56
|
* @param {import('../config/config-base')} config - Tracer configuration
|
|
57
|
+
* @param {() => object} getOpenFeatureProvider - Lazy getter for the tracer's existing OpenFeature provider
|
|
52
58
|
*/
|
|
53
|
-
constructor (tracer, llmobsModule, config) {
|
|
59
|
+
constructor (tracer, llmobsModule, config, getOpenFeatureProvider = () => {}) {
|
|
54
60
|
super(tracer)
|
|
55
61
|
|
|
56
62
|
/** @type {import('../config/config-base')} */
|
|
@@ -58,6 +64,7 @@ class LLMObs extends NoopLLMObs {
|
|
|
58
64
|
|
|
59
65
|
this._llmobsModule = llmobsModule
|
|
60
66
|
this._tagger = new LLMObsTagger(config)
|
|
67
|
+
this.#getOpenFeatureProvider = getOpenFeatureProvider
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
get enabled () {
|
|
@@ -73,6 +80,15 @@ class LLMObs extends NoopLLMObs {
|
|
|
73
80
|
return createExperiments(this._config, this)
|
|
74
81
|
}
|
|
75
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Prompt Management API.
|
|
85
|
+
* @returns {import('../../../../index').llmobs.Prompts}
|
|
86
|
+
*/
|
|
87
|
+
get prompts () {
|
|
88
|
+
this.#promptManager ??= new PromptManager(this._config, this.#getOpenFeatureProvider)
|
|
89
|
+
return this.#promptManager
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
enable (options = {}) {
|
|
77
93
|
logger.warn(
|
|
78
94
|
'Enabling LLM Observability via `llmobs.enable()` is deprecated and will be removed in dd-trace@7.0.0. ' +
|
|
@@ -97,8 +113,8 @@ class LLMObs extends NoopLLMObs {
|
|
|
97
113
|
|
|
98
114
|
// TODO: These configs should be passed through directly at construction time instead.
|
|
99
115
|
this._config.llmobs.DD_LLMOBS_ENABLED = true
|
|
100
|
-
this._config.llmobs.
|
|
101
|
-
this._config.llmobs.
|
|
116
|
+
this._config.llmobs.DD_LLMOBS_ML_APP = options.mlApp
|
|
117
|
+
this._config.llmobs.DD_LLMOBS_AGENTLESS_ENABLED = options.agentlessEnabled
|
|
102
118
|
|
|
103
119
|
// configure writers and channel subscribers
|
|
104
120
|
this._llmobsModule.enable(this._config)
|
|
@@ -393,7 +409,7 @@ class LLMObs extends NoopLLMObs {
|
|
|
393
409
|
'spanId and traceId must both be specified for the given evaluation metric to be submitted.'
|
|
394
410
|
)
|
|
395
411
|
}
|
|
396
|
-
const mlApp = options.mlApp || this._config.llmobs.
|
|
412
|
+
const mlApp = options.mlApp || this._config.llmobs.DD_LLMOBS_ML_APP
|
|
397
413
|
if (!mlApp) {
|
|
398
414
|
err = 'missing_ml_app'
|
|
399
415
|
throw new Error(
|
|
@@ -475,7 +491,6 @@ class LLMObs extends NoopLLMObs {
|
|
|
475
491
|
* @param {number} [options.timestampMs] - When the feedback was generated. Defaults to now.
|
|
476
492
|
* @param {'pass' | 'fail'} [options.assessment] - Assessment of the feedback.
|
|
477
493
|
* @param {string} [options.reasoning] - Explanation of the feedback.
|
|
478
|
-
* @returns {void}
|
|
479
494
|
*/
|
|
480
495
|
submitFeedback (options = {}) {
|
|
481
496
|
if (!this.enabled) return
|
|
@@ -532,7 +547,7 @@ class LLMObs extends NoopLLMObs {
|
|
|
532
547
|
throw new TypeError('submitter.type must be a string')
|
|
533
548
|
}
|
|
534
549
|
|
|
535
|
-
const mlApp = options.mlApp || this._config.llmobs.
|
|
550
|
+
const mlApp = options.mlApp || this._config.llmobs.DD_LLMOBS_ML_APP
|
|
536
551
|
if (!mlApp) {
|
|
537
552
|
err = 'missing_ml_app'
|
|
538
553
|
throw new Error('ML App name is required for sending feedback. Feedback data will not be sent.')
|
|
@@ -38,11 +38,41 @@ const {
|
|
|
38
38
|
SAMPLE_RATE,
|
|
39
39
|
SAMPLING_DECISION,
|
|
40
40
|
TRACE_ID,
|
|
41
|
+
INPUT_TOKENS_METRIC_KEY,
|
|
42
|
+
OUTPUT_TOKENS_METRIC_KEY,
|
|
43
|
+
TOTAL_TOKENS_METRIC_KEY,
|
|
44
|
+
CACHE_READ_INPUT_TOKENS_METRIC_KEY,
|
|
45
|
+
CACHE_WRITE_INPUT_TOKENS_METRIC_KEY,
|
|
46
|
+
REASONING_OUTPUT_TOKENS_METRIC_KEY,
|
|
47
|
+
GEN_AI_OPERATION_NAME,
|
|
48
|
+
GEN_AI_REQUEST_MODEL,
|
|
49
|
+
GEN_AI_PROVIDER_NAME,
|
|
50
|
+
GEN_AI_APPLICATION_NAME,
|
|
51
|
+
GEN_AI_CONVERSATION_ID,
|
|
52
|
+
GEN_AI_USAGE_INPUT_TOKENS_METRIC_KEY,
|
|
53
|
+
GEN_AI_USAGE_OUTPUT_TOKENS_METRIC_KEY,
|
|
54
|
+
GEN_AI_USAGE_TOTAL_TOKENS_METRIC_KEY,
|
|
55
|
+
GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS_METRIC_KEY,
|
|
56
|
+
GEN_AI_USAGE_CACHE_WRITE_INPUT_TOKENS_METRIC_KEY,
|
|
57
|
+
GEN_AI_USAGE_REASONING_OUTPUT_TOKENS_METRIC_KEY,
|
|
58
|
+
ARTIFICIAL_GEN_AI_TAGS,
|
|
41
59
|
} = require('./constants/tags')
|
|
42
60
|
const { UNSERIALIZABLE_VALUE_TEXT } = require('./constants/text')
|
|
43
61
|
const telemetry = require('./telemetry')
|
|
44
62
|
const LLMObsTagger = require('./tagger')
|
|
45
63
|
|
|
64
|
+
const DEFAULT_MODEL = 'custom'
|
|
65
|
+
const MODEL_BACKED_SPAN_KINDS = new Set(['llm', 'embedding'])
|
|
66
|
+
|
|
67
|
+
const GEN_AI_TOKEN_METRIC_KEYS = [
|
|
68
|
+
[INPUT_TOKENS_METRIC_KEY, GEN_AI_USAGE_INPUT_TOKENS_METRIC_KEY],
|
|
69
|
+
[OUTPUT_TOKENS_METRIC_KEY, GEN_AI_USAGE_OUTPUT_TOKENS_METRIC_KEY],
|
|
70
|
+
[TOTAL_TOKENS_METRIC_KEY, GEN_AI_USAGE_TOTAL_TOKENS_METRIC_KEY],
|
|
71
|
+
[CACHE_READ_INPUT_TOKENS_METRIC_KEY, GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS_METRIC_KEY],
|
|
72
|
+
[CACHE_WRITE_INPUT_TOKENS_METRIC_KEY, GEN_AI_USAGE_CACHE_WRITE_INPUT_TOKENS_METRIC_KEY],
|
|
73
|
+
[REASONING_OUTPUT_TOKENS_METRIC_KEY, GEN_AI_USAGE_REASONING_OUTPUT_TOKENS_METRIC_KEY],
|
|
74
|
+
]
|
|
75
|
+
|
|
46
76
|
class LLMObservabilitySpan {
|
|
47
77
|
/**
|
|
48
78
|
* @param {string} kind span kind
|
|
@@ -90,6 +120,12 @@ class LLMObsSpanProcessor {
|
|
|
90
120
|
// if the span is not in our private tagger map, it is not an llmobs span
|
|
91
121
|
if (!LLMObsTagger.tagMap.has(span)) return
|
|
92
122
|
|
|
123
|
+
try {
|
|
124
|
+
this.#setGenAiApmTags(span)
|
|
125
|
+
} catch (e) {
|
|
126
|
+
logger.debug('Failed to set gen_ai APM tags:', e.message)
|
|
127
|
+
}
|
|
128
|
+
|
|
93
129
|
try {
|
|
94
130
|
const formattedEvent = this.format(span)
|
|
95
131
|
telemetry.incrementLLMObsSpanFinishedCount(span)
|
|
@@ -138,8 +174,8 @@ class LLMObsSpanProcessor {
|
|
|
138
174
|
const output = {}
|
|
139
175
|
|
|
140
176
|
if (['llm', 'embedding'].includes(spanKind)) {
|
|
141
|
-
meta.model_name = mlObsTags[MODEL_NAME] ||
|
|
142
|
-
meta.model_provider = (mlObsTags[MODEL_PROVIDER] ||
|
|
177
|
+
meta.model_name = mlObsTags[MODEL_NAME] || DEFAULT_MODEL
|
|
178
|
+
meta.model_provider = (mlObsTags[MODEL_PROVIDER] || DEFAULT_MODEL).toLowerCase()
|
|
143
179
|
}
|
|
144
180
|
|
|
145
181
|
if (mlObsTags[METADATA] || mlObsTags[COST_TAGS]) {
|
|
@@ -283,6 +319,49 @@ class LLMObsSpanProcessor {
|
|
|
283
319
|
return llmObsSpanEvent
|
|
284
320
|
}
|
|
285
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Writes the scalar `gen_ai.*` attributes onto the APM span, so model, provider, application,
|
|
324
|
+
* conversation and token usage are searchable in APM. Message bodies stay off the APM span.
|
|
325
|
+
*
|
|
326
|
+
* @param {import('../opentracing/span')} span
|
|
327
|
+
*/
|
|
328
|
+
#setGenAiApmTags (span) {
|
|
329
|
+
const mlObsTags = LLMObsTagger.tagMap.get(span)
|
|
330
|
+
const spanContext = span.context()
|
|
331
|
+
const spanKind = mlObsTags[SPAN_KIND]
|
|
332
|
+
|
|
333
|
+
if (spanKind) spanContext.setTag(GEN_AI_OPERATION_NAME, spanKind)
|
|
334
|
+
|
|
335
|
+
const modelName = mlObsTags[MODEL_NAME]
|
|
336
|
+
const modelProvider = mlObsTags[MODEL_PROVIDER]
|
|
337
|
+
const modelBacked = MODEL_BACKED_SPAN_KINDS.has(spanKind)
|
|
338
|
+
if (modelBacked) {
|
|
339
|
+
spanContext.setTag(GEN_AI_REQUEST_MODEL, modelName || DEFAULT_MODEL)
|
|
340
|
+
spanContext.setTag(GEN_AI_PROVIDER_NAME, (modelProvider || DEFAULT_MODEL).toLowerCase())
|
|
341
|
+
} else {
|
|
342
|
+
if (modelName) spanContext.setTag(GEN_AI_REQUEST_MODEL, modelName)
|
|
343
|
+
if (modelProvider) spanContext.setTag(GEN_AI_PROVIDER_NAME, modelProvider.toLowerCase())
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const mlApp = mlObsTags[ML_APP]
|
|
347
|
+
if (mlApp) spanContext.setTag(GEN_AI_APPLICATION_NAME, mlApp)
|
|
348
|
+
|
|
349
|
+
const sessionId = mlObsTags[SESSION_ID]
|
|
350
|
+
if (sessionId) spanContext.setTag(GEN_AI_CONVERSATION_ID, sessionId)
|
|
351
|
+
|
|
352
|
+
const metrics = mlObsTags[METRICS]
|
|
353
|
+
// Other kinds carry unrelated metrics that would be misleading under a `gen_ai.usage.*` key.
|
|
354
|
+
if (modelBacked && metrics) {
|
|
355
|
+
for (const [metricKey, genAiKey] of GEN_AI_TOKEN_METRIC_KEYS) {
|
|
356
|
+
const value = metrics[metricKey]
|
|
357
|
+
if (value != null) spanContext.setTag(genAiKey, value)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// matches the value dd-trace-py writes
|
|
362
|
+
spanContext.setTag(ARTIFICIAL_GEN_AI_TAGS, 'true')
|
|
363
|
+
}
|
|
364
|
+
|
|
286
365
|
// For now, this only applies to metadata, as we let users annotate this field with any object
|
|
287
366
|
// However, we want to protect against circular references or BigInts (unserializable)
|
|
288
367
|
// This function can be reused for other fields if needed
|
|
@@ -87,7 +87,7 @@ class LLMObsTagger {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* The sampler reads its rate from `config.llmobs.
|
|
90
|
+
* The sampler reads its rate from `config.llmobs.DD_LLMOBS_SAMPLE_RATE`, which can change
|
|
91
91
|
* at runtime (e.g. via remote config). Rebuild the sampler whenever the rate
|
|
92
92
|
* changes so decisions reflect the current config, while reusing the existing
|
|
93
93
|
* sampler when it hasn't.
|
|
@@ -95,7 +95,7 @@ class LLMObsTagger {
|
|
|
95
95
|
* @returns {import('../sampler')}
|
|
96
96
|
*/
|
|
97
97
|
#getSampler () {
|
|
98
|
-
const rate = this.#config.llmobs?.
|
|
98
|
+
const rate = this.#config.llmobs?.DD_LLMOBS_SAMPLE_RATE ?? 1
|
|
99
99
|
if (this.#sampler === null || rate !== this.#sampler.rate()) {
|
|
100
100
|
this.#sampler = new Sampler(rate)
|
|
101
101
|
}
|
|
@@ -128,7 +128,7 @@ class LLMObsTagger {
|
|
|
128
128
|
mlApp ||
|
|
129
129
|
registry.get(parent)?.[ML_APP] ||
|
|
130
130
|
span.context()._trace.tags[PROPAGATED_ML_APP_KEY] ||
|
|
131
|
-
this.#config.llmobs.
|
|
131
|
+
this.#config.llmobs.DD_LLMOBS_ML_APP ||
|
|
132
132
|
this.#config.service // this should always have a default
|
|
133
133
|
|
|
134
134
|
if (!spanMlApp) {
|
|
@@ -415,6 +415,8 @@ class LLMObsTagger {
|
|
|
415
415
|
template,
|
|
416
416
|
contextVariables,
|
|
417
417
|
queryVariables,
|
|
418
|
+
promptUuid,
|
|
419
|
+
promptVersionUuid,
|
|
418
420
|
} = prompt
|
|
419
421
|
|
|
420
422
|
if (strictValidation) {
|
|
@@ -429,6 +431,8 @@ class LLMObsTagger {
|
|
|
429
431
|
}
|
|
430
432
|
}
|
|
431
433
|
|
|
434
|
+
const currentPrompt = registry.get(span)?.[INPUT_PROMPT]
|
|
435
|
+
const replacesPrompt = id != null || version != null || template != null
|
|
432
436
|
const finalPromptId = id ?? `${mlApp}_${DEFAULT_PROMPT_NAME}`
|
|
433
437
|
const finalCtxVariablesKeys = contextVariables ?? ['context']
|
|
434
438
|
const finalQueryVariablesKeys = queryVariables ?? ['question']
|
|
@@ -471,6 +475,16 @@ class LLMObsTagger {
|
|
|
471
475
|
return
|
|
472
476
|
}
|
|
473
477
|
|
|
478
|
+
if (promptUuid != null && typeof promptUuid !== 'string') {
|
|
479
|
+
this.#handleFailure('Prompt UUID must be a string.', 'invalid_prompt')
|
|
480
|
+
return
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (promptVersionUuid != null && typeof promptVersionUuid !== 'string') {
|
|
484
|
+
this.#handleFailure('Prompt version UUID must be a string.', 'invalid_prompt')
|
|
485
|
+
return
|
|
486
|
+
}
|
|
487
|
+
|
|
474
488
|
// validate prompt tags
|
|
475
489
|
if (tags && (typeof tags !== 'object' || tags instanceof Map)) {
|
|
476
490
|
this.#handleFailure('Prompt tags must be an non-Map object.', 'invalid_prompt')
|
|
@@ -522,17 +536,26 @@ class LLMObsTagger {
|
|
|
522
536
|
}
|
|
523
537
|
|
|
524
538
|
const validatedPrompt = {}
|
|
525
|
-
if (finalPromptId) validatedPrompt.id = finalPromptId
|
|
539
|
+
if (finalPromptId && (!currentPrompt || replacesPrompt)) validatedPrompt.id = finalPromptId
|
|
526
540
|
if (version) validatedPrompt.version = version
|
|
541
|
+
if (promptUuid) validatedPrompt.prompt_uuid = promptUuid
|
|
542
|
+
if (promptVersionUuid) validatedPrompt.prompt_version_uuid = promptVersionUuid
|
|
527
543
|
if (variables) validatedPrompt.variables = variables
|
|
528
544
|
if (finalTemplate) validatedPrompt.template = finalTemplate
|
|
529
545
|
if (finalChatTemplate?.length) validatedPrompt.chat_template = finalChatTemplate
|
|
530
546
|
if (tags) validatedPrompt.tags = tags
|
|
531
|
-
if (finalCtxVariablesKeys
|
|
532
|
-
|
|
547
|
+
if (finalCtxVariablesKeys && (!currentPrompt || replacesPrompt || contextVariables != null)) {
|
|
548
|
+
validatedPrompt[INTERNAL_CONTEXT_VARIABLE_KEYS] = finalCtxVariablesKeys
|
|
549
|
+
}
|
|
550
|
+
if (finalQueryVariablesKeys && (!currentPrompt || replacesPrompt || queryVariables != null)) {
|
|
551
|
+
validatedPrompt[INTERNAL_QUERY_VARIABLE_KEYS] = finalQueryVariablesKeys
|
|
552
|
+
}
|
|
533
553
|
|
|
534
|
-
const currentPrompt = registry.get(span)?.[INPUT_PROMPT]
|
|
535
554
|
if (currentPrompt) {
|
|
555
|
+
if (replacesPrompt) {
|
|
556
|
+
if (promptUuid == null) currentPrompt.prompt_uuid = undefined
|
|
557
|
+
if (promptVersionUuid == null) currentPrompt.prompt_version_uuid = undefined
|
|
558
|
+
}
|
|
536
559
|
Object.assign(currentPrompt, validatedPrompt)
|
|
537
560
|
} else {
|
|
538
561
|
this._setTag(span, INPUT_PROMPT, validatedPrompt)
|
|
@@ -84,11 +84,11 @@ function recordLLMObsEnabled (startTime, config, value = 1) {
|
|
|
84
84
|
const autoEnabled = !!config._env?.['llmobs.enabled']
|
|
85
85
|
const tags = {
|
|
86
86
|
error: 0,
|
|
87
|
-
agentless: Number(config.llmobs.
|
|
87
|
+
agentless: Number(config.llmobs.DD_LLMOBS_AGENTLESS_ENABLED),
|
|
88
88
|
site: config.site,
|
|
89
89
|
auto: Number(autoEnabled),
|
|
90
|
-
ml_app: config.llmobs.
|
|
91
|
-
sample_rate: config.llmobs.
|
|
90
|
+
ml_app: config.llmobs.DD_LLMOBS_ML_APP,
|
|
91
|
+
sample_rate: config.llmobs.DD_LLMOBS_SAMPLE_RATE,
|
|
92
92
|
}
|
|
93
93
|
llmobsMetrics.count('product_enabled', tags).inc(value)
|
|
94
94
|
llmobsMetrics.distribution('init_time', tags).track(initTimeMs)
|
|
@@ -188,7 +188,6 @@ function recordSubmitEvaluation (options, err, value = 1) {
|
|
|
188
188
|
* @param {string} targetType - The payload key the feedback was attached to, `'other'` if unresolved.
|
|
189
189
|
* @param {string} err - The telemetry error tag, empty when the submission succeeded.
|
|
190
190
|
* @param {number} [value]
|
|
191
|
-
* @returns {void}
|
|
192
191
|
*/
|
|
193
192
|
function recordSubmitFeedback (metricType, targetType, err, value = 1) {
|
|
194
193
|
const tags = {
|
|
@@ -205,6 +204,36 @@ function recordLLMObsUserProcessorCalled (error, value = 1) {
|
|
|
205
204
|
llmobsMetrics.count('user_processor_called', tags).inc(value)
|
|
206
205
|
}
|
|
207
206
|
|
|
207
|
+
/**
|
|
208
|
+
* @param {'hot_cache'|'warm_cache'|'registry'|'resolve'|'fallback'|'ff'} source
|
|
209
|
+
* @param {number} [value]
|
|
210
|
+
*/
|
|
211
|
+
function recordPromptSource (source, value = 1) {
|
|
212
|
+
llmobsMetrics.count('prompt.source', { from: source }).inc(value)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @param {'NotFound'|'FetchError'} errorType
|
|
217
|
+
* @param {number} [value]
|
|
218
|
+
*/
|
|
219
|
+
function recordPromptFetchError (errorType, value = 1) {
|
|
220
|
+
llmobsMetrics.count('prompt.fetch.error', { error_type: errorType }).inc(value)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @param {'GET'|'POST'|'PATCH'|'DELETE'} method
|
|
225
|
+
* @param {string} errorType
|
|
226
|
+
* @param {number} status
|
|
227
|
+
* @param {number} [value]
|
|
228
|
+
*/
|
|
229
|
+
function recordPromptCrudError (method, errorType, status, value = 1) {
|
|
230
|
+
llmobsMetrics.count('prompt.crud.error', {
|
|
231
|
+
method,
|
|
232
|
+
error_type: errorType,
|
|
233
|
+
status: String(status),
|
|
234
|
+
}).inc(value)
|
|
235
|
+
}
|
|
236
|
+
|
|
208
237
|
module.exports = {
|
|
209
238
|
recordLLMObsEnabled,
|
|
210
239
|
incrementLLMObsSpanStartCount,
|
|
@@ -220,4 +249,7 @@ module.exports = {
|
|
|
220
249
|
recordSubmitEvaluation,
|
|
221
250
|
recordSubmitFeedback,
|
|
222
251
|
recordLLMObsUserProcessorCalled,
|
|
252
|
+
recordPromptSource,
|
|
253
|
+
recordPromptFetchError,
|
|
254
|
+
recordPromptCrudError,
|
|
223
255
|
}
|
|
@@ -306,7 +306,6 @@ function getFunctionArguments (fn, args = []) {
|
|
|
306
306
|
// keys), so a name containing `=` is safe and must not be dropped.
|
|
307
307
|
/**
|
|
308
308
|
* @param {string} name
|
|
309
|
-
* @returns {boolean}
|
|
310
309
|
*/
|
|
311
310
|
function agentNameWireSafe (name) {
|
|
312
311
|
// Conservative slice of the 512B shared tagset budget, mirroring dd-trace-py.
|
|
@@ -413,7 +412,6 @@ function findGenAIAncestorSpanId (span) {
|
|
|
413
412
|
/**
|
|
414
413
|
* Generate a 128-bit LLMObs trace ID with the span start time encoded in its high bits.
|
|
415
414
|
* @param {number} startTime
|
|
416
|
-
* @returns {string}
|
|
417
415
|
*/
|
|
418
416
|
function generateLlmObsTraceId (startTime) {
|
|
419
417
|
const identifier = id()
|
|
@@ -455,45 +453,13 @@ function normalizeLlmObsTraceId (traceId) {
|
|
|
455
453
|
return identifier > MAX_UINT_64 ? identifier.toString(16).padStart(32, '0') : traceId
|
|
456
454
|
}
|
|
457
455
|
|
|
458
|
-
// Maps an audio `format` (e.g. "wav", "mp3") to a MIME type. Defaults to `audio/wav` when the
|
|
459
|
-
// format is missing. Provider-specific overrides (e.g. OpenAI's mp3 -> audio/mpeg) are passed in
|
|
460
|
-
// via `mimeTypeLookup` so this stays provider-agnostic. A non-string `format` is treated as missing
|
|
461
|
-
// so a malformed auto-instrumented payload can't throw and disable the plugin.
|
|
462
|
-
/**
|
|
463
|
-
* @param {string} fmt
|
|
464
|
-
* @param {Record<string, string>} [mimeTypeLookup]
|
|
465
|
-
* @returns {string}
|
|
466
|
-
*/
|
|
467
|
-
function audioMimeTypeFromFormat (fmt, mimeTypeLookup = {}) {
|
|
468
|
-
fmt = typeof fmt === 'string' ? fmt.trim().toLowerCase() : ''
|
|
469
|
-
if (!fmt) return 'audio/wav'
|
|
470
|
-
return mimeTypeLookup[fmt] ?? `audio/${fmt}`
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// Builds an audio part from raw audio bytes (base64-encoded) or an existing base64 string. Only
|
|
474
|
-
// Buffer/Uint8Array inputs are base64-encoded; any other shape is passed through so a malformed
|
|
475
|
-
// auto-instrumented payload can't throw (the tagger soft-skips a non-string `content`).
|
|
476
|
-
/**
|
|
477
|
-
* @param {Buffer | Uint8Array | string} data
|
|
478
|
-
* @param {string} mimeType
|
|
479
|
-
* @returns {{ mimeType: string, content: string }}
|
|
480
|
-
*/
|
|
481
|
-
function formatAudioPart (data, mimeType) {
|
|
482
|
-
const content = Buffer.isBuffer(data) || ArrayBuffer.isView(data)
|
|
483
|
-
? Buffer.from(data).toString('base64')
|
|
484
|
-
: data
|
|
485
|
-
return { mimeType, content }
|
|
486
|
-
}
|
|
487
|
-
|
|
488
456
|
module.exports = {
|
|
489
457
|
agentNameWireSafe,
|
|
490
|
-
audioMimeTypeFromFormat,
|
|
491
458
|
encodeUnicode,
|
|
492
459
|
findGenAIAncestorSpanId,
|
|
493
460
|
generateLlmObsTraceId,
|
|
494
461
|
llmObsTraceIdToWire,
|
|
495
462
|
normalizeLlmObsTraceId,
|
|
496
|
-
formatAudioPart,
|
|
497
463
|
resolveAgentAttribution,
|
|
498
464
|
validateCostTags,
|
|
499
465
|
validateKind,
|
|
@@ -102,7 +102,6 @@ class BaseLLMObsWriter {
|
|
|
102
102
|
* @param {Record<string, unknown>} event
|
|
103
103
|
* @param {{ apiKey?: string, site?: string }} [routing]
|
|
104
104
|
* @param {number} [byteLength]
|
|
105
|
-
* @returns {boolean} `true` if the event was buffered, `false` if it was dropped
|
|
106
105
|
* (e.g. the per-routing buffer was full). Callers that depend on the event
|
|
107
106
|
* actually being submitted should check this value.
|
|
108
107
|
*/
|
|
@@ -8,10 +8,9 @@ const { fetchAgentInfo } = require('../../agent/info')
|
|
|
8
8
|
/**
|
|
9
9
|
* @param {import('../../config/config-base')} config
|
|
10
10
|
* @param {(agentless: boolean) => void} setWritersAgentlessValue
|
|
11
|
-
* @returns {void}
|
|
12
11
|
*/
|
|
13
12
|
function setAgentStrategy (config, setWritersAgentlessValue) {
|
|
14
|
-
const agentlessEnabled = config.llmobs.
|
|
13
|
+
const agentlessEnabled = config.llmobs.DD_LLMOBS_AGENTLESS_ENABLED
|
|
15
14
|
|
|
16
15
|
if (agentlessEnabled != null) {
|
|
17
16
|
setWritersAgentlessValue(agentlessEnabled)
|
|
@@ -9,6 +9,8 @@ const debugChannel = channel('datadog:log:debug')
|
|
|
9
9
|
const infoChannel = channel('datadog:log:info')
|
|
10
10
|
const warnChannel = channel('datadog:log:warn')
|
|
11
11
|
const errorChannel = channel('datadog:log:error')
|
|
12
|
+
// Telemetry needs the unformatted message, cause and transmission policy, not console output.
|
|
13
|
+
const errorRecordChannel = channel('datadog:log:error:record')
|
|
12
14
|
|
|
13
15
|
const defaultLevel = Level.debug
|
|
14
16
|
|
|
@@ -67,4 +69,5 @@ module.exports = {
|
|
|
67
69
|
infoChannel,
|
|
68
70
|
warnChannel,
|
|
69
71
|
errorChannel,
|
|
72
|
+
errorRecordChannel,
|
|
70
73
|
}
|
|
@@ -8,7 +8,7 @@ const { getValueFromEnvSources } = require('../config/helper')
|
|
|
8
8
|
// `config/defaults` defers its own `dns` require until after it exports, so this no longer hits
|
|
9
9
|
// the `config/defaults` <-> log parse cycle that motivated the lazy require below.
|
|
10
10
|
const { defaults } = require('../config/defaults')
|
|
11
|
-
const { traceChannel, debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
|
|
11
|
+
const { traceChannel, debugChannel, infoChannel, warnChannel, errorChannel, errorRecordChannel } = require('./channels')
|
|
12
12
|
const logWriter = require('./writer')
|
|
13
13
|
const { Log, LogConfig, NoTransmitError } = require('./log')
|
|
14
14
|
|
|
@@ -95,10 +95,25 @@ const log = {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
function publishFormatted (ch, formatter, ...args) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
const publishRecord = ch === errorChannel && errorRecordChannel.hasSubscribers
|
|
99
|
+
const publishLog = ch.hasSubscribers
|
|
100
|
+
if (!publishLog && !publishRecord) return
|
|
101
|
+
|
|
102
|
+
let record
|
|
103
|
+
try {
|
|
104
|
+
const parsed = Log.parse(...args)
|
|
105
|
+
if (!publishLog && !parsed.sendViaTelemetry) return
|
|
106
|
+
record = getErrorLog(parsed)
|
|
107
|
+
} catch (err) {
|
|
108
|
+
// Telemetry must not expose parsing failures while the configured logger is disabled.
|
|
109
|
+
if (!publishLog) return
|
|
110
|
+
throw err
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (publishRecord) errorRecordChannel.publish(record)
|
|
101
114
|
|
|
115
|
+
if (publishLog) {
|
|
116
|
+
const { formatted, cause } = record
|
|
102
117
|
// calling twice ch.publish() because Error cause is only available in Node.js v16.9.0
|
|
103
118
|
// TODO: replace it with Error(message, { cause }) when cause has broad support
|
|
104
119
|
if (formatted) ch.publish(formatter?.(formatted) || formatted)
|
|
@@ -109,7 +124,10 @@ function publishFormatted (ch, formatter, ...args) {
|
|
|
109
124
|
function getErrorLog (err) {
|
|
110
125
|
if (typeof err?.delegate === 'function') {
|
|
111
126
|
const result = err.delegate(...err.args)
|
|
112
|
-
|
|
127
|
+
const resolved = Array.isArray(result) ? Log.parse(...result) : Log.parse(result)
|
|
128
|
+
resolved.cause ??= err.cause
|
|
129
|
+
resolved.sendViaTelemetry &&= err.sendViaTelemetry
|
|
130
|
+
return resolved
|
|
113
131
|
}
|
|
114
132
|
return err
|
|
115
133
|
}
|