dd-trace 5.101.0 → 5.103.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.
Files changed (235) hide show
  1. package/ext/exporters.js +1 -0
  2. package/package.json +20 -17
  3. package/packages/datadog-esbuild/src/utils.js +2 -2
  4. package/packages/datadog-instrumentations/src/aerospike.js +2 -2
  5. package/packages/datadog-instrumentations/src/ai.js +9 -9
  6. package/packages/datadog-instrumentations/src/amqplib.js +6 -7
  7. package/packages/datadog-instrumentations/src/anthropic.js +10 -10
  8. package/packages/datadog-instrumentations/src/apollo-server-core.js +3 -3
  9. package/packages/datadog-instrumentations/src/apollo-server.js +5 -5
  10. package/packages/datadog-instrumentations/src/avsc.js +6 -6
  11. package/packages/datadog-instrumentations/src/aws-sdk.js +151 -67
  12. package/packages/datadog-instrumentations/src/azure-durable-functions.js +8 -8
  13. package/packages/datadog-instrumentations/src/bluebird.js +2 -2
  14. package/packages/datadog-instrumentations/src/body-parser.js +2 -2
  15. package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
  16. package/packages/datadog-instrumentations/src/child_process.js +12 -12
  17. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +41 -24
  18. package/packages/datadog-instrumentations/src/connect.js +7 -7
  19. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  20. package/packages/datadog-instrumentations/src/cookie.js +2 -2
  21. package/packages/datadog-instrumentations/src/couchbase.js +73 -238
  22. package/packages/datadog-instrumentations/src/crypto.js +4 -4
  23. package/packages/datadog-instrumentations/src/cucumber.js +78 -17
  24. package/packages/datadog-instrumentations/src/dns.js +0 -3
  25. package/packages/datadog-instrumentations/src/elasticsearch.js +8 -11
  26. package/packages/datadog-instrumentations/src/electron/preload.js +42 -0
  27. package/packages/datadog-instrumentations/src/electron.js +240 -0
  28. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +6 -6
  29. package/packages/datadog-instrumentations/src/express-session.js +4 -4
  30. package/packages/datadog-instrumentations/src/express.js +10 -11
  31. package/packages/datadog-instrumentations/src/fastify.js +2 -2
  32. package/packages/datadog-instrumentations/src/fetch.js +5 -5
  33. package/packages/datadog-instrumentations/src/fs.js +14 -14
  34. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +5 -7
  35. package/packages/datadog-instrumentations/src/google-genai.js +4 -4
  36. package/packages/datadog-instrumentations/src/graphql.js +13 -12
  37. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  38. package/packages/datadog-instrumentations/src/hapi.js +2 -2
  39. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +9 -9
  40. package/packages/datadog-instrumentations/src/helpers/hook.js +4 -1
  41. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  42. package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
  43. package/packages/datadog-instrumentations/src/helpers/kafka.js +41 -0
  44. package/packages/datadog-instrumentations/src/helpers/promise.js +2 -2
  45. package/packages/datadog-instrumentations/src/hono.js +2 -2
  46. package/packages/datadog-instrumentations/src/http/client.js +6 -6
  47. package/packages/datadog-instrumentations/src/http/server.js +9 -9
  48. package/packages/datadog-instrumentations/src/ioredis.js +16 -12
  49. package/packages/datadog-instrumentations/src/jest.js +382 -81
  50. package/packages/datadog-instrumentations/src/kafkajs.js +165 -174
  51. package/packages/datadog-instrumentations/src/knex.js +17 -17
  52. package/packages/datadog-instrumentations/src/koa.js +12 -12
  53. package/packages/datadog-instrumentations/src/ldapjs.js +5 -5
  54. package/packages/datadog-instrumentations/src/light-my-request.js +2 -2
  55. package/packages/datadog-instrumentations/src/limitd-client.js +4 -4
  56. package/packages/datadog-instrumentations/src/lodash.js +4 -4
  57. package/packages/datadog-instrumentations/src/mariadb.js +13 -13
  58. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  59. package/packages/datadog-instrumentations/src/microgateway-core.js +2 -2
  60. package/packages/datadog-instrumentations/src/mocha/common.js +3 -3
  61. package/packages/datadog-instrumentations/src/mocha/main.js +85 -11
  62. package/packages/datadog-instrumentations/src/mocha/utils.js +133 -16
  63. package/packages/datadog-instrumentations/src/mocha/worker.js +7 -5
  64. package/packages/datadog-instrumentations/src/mongodb-core.js +42 -30
  65. package/packages/datadog-instrumentations/src/mongodb.js +5 -5
  66. package/packages/datadog-instrumentations/src/mongoose.js +21 -21
  67. package/packages/datadog-instrumentations/src/mquery.js +5 -5
  68. package/packages/datadog-instrumentations/src/multer.js +4 -4
  69. package/packages/datadog-instrumentations/src/mysql.js +16 -16
  70. package/packages/datadog-instrumentations/src/mysql2.js +4 -4
  71. package/packages/datadog-instrumentations/src/net.js +14 -8
  72. package/packages/datadog-instrumentations/src/nyc.js +5 -5
  73. package/packages/datadog-instrumentations/src/openai.js +19 -19
  74. package/packages/datadog-instrumentations/src/oracledb.js +6 -6
  75. package/packages/datadog-instrumentations/src/passport-utils.js +5 -5
  76. package/packages/datadog-instrumentations/src/pg.js +39 -25
  77. package/packages/datadog-instrumentations/src/pino.js +6 -10
  78. package/packages/datadog-instrumentations/src/playwright.js +445 -68
  79. package/packages/datadog-instrumentations/src/protobufjs.js +16 -16
  80. package/packages/datadog-instrumentations/src/redis.js +20 -12
  81. package/packages/datadog-instrumentations/src/restify.js +2 -2
  82. package/packages/datadog-instrumentations/src/router.js +12 -12
  83. package/packages/datadog-instrumentations/src/stripe.js +12 -12
  84. package/packages/datadog-instrumentations/src/vitest.js +107 -26
  85. package/packages/datadog-instrumentations/src/winston.js +4 -4
  86. package/packages/datadog-instrumentations/src/ws.js +7 -7
  87. package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -21
  88. package/packages/datadog-plugin-aws-sdk/src/base.js +70 -28
  89. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
  90. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +20 -13
  91. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +46 -36
  92. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +34 -23
  93. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
  94. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  95. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +14 -15
  96. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +74 -55
  97. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +20 -18
  98. package/packages/datadog-plugin-aws-sdk/src/util.js +22 -0
  99. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -6
  100. package/packages/datadog-plugin-couchbase/src/index.js +58 -52
  101. package/packages/datadog-plugin-cucumber/src/index.js +5 -0
  102. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +215 -26
  103. package/packages/datadog-plugin-cypress/src/support.js +13 -1
  104. package/packages/datadog-plugin-electron/src/index.js +17 -0
  105. package/packages/datadog-plugin-electron/src/ipc.js +143 -0
  106. package/packages/datadog-plugin-electron/src/net.js +82 -0
  107. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -5
  108. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +27 -18
  109. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +3 -1
  110. package/packages/datadog-plugin-graphql/src/execute.js +6 -28
  111. package/packages/datadog-plugin-graphql/src/resolve.js +30 -35
  112. package/packages/datadog-plugin-graphql/src/tools/signature.js +32 -7
  113. package/packages/datadog-plugin-graphql/src/tools/transforms.js +118 -100
  114. package/packages/datadog-plugin-graphql/src/utils.js +29 -0
  115. package/packages/datadog-plugin-grpc/src/client.js +6 -7
  116. package/packages/datadog-plugin-grpc/src/util.js +57 -22
  117. package/packages/datadog-plugin-http/src/client.js +3 -7
  118. package/packages/datadog-plugin-jest/src/index.js +92 -50
  119. package/packages/datadog-plugin-jest/src/util.js +1 -2
  120. package/packages/datadog-plugin-mocha/src/index.js +5 -0
  121. package/packages/datadog-plugin-mongodb-core/src/index.js +36 -69
  122. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  123. package/packages/datadog-plugin-openai/src/services.js +2 -1
  124. package/packages/datadog-plugin-openai/src/tracing.js +12 -23
  125. package/packages/datadog-plugin-pg/src/index.js +3 -3
  126. package/packages/datadog-plugin-playwright/src/index.js +5 -1
  127. package/packages/datadog-plugin-redis/src/index.js +18 -23
  128. package/packages/datadog-plugin-vitest/src/index.js +8 -1
  129. package/packages/datadog-shimmer/src/shimmer.js +7 -1
  130. package/packages/dd-trace/src/aiguard/index.js +3 -1
  131. package/packages/dd-trace/src/aiguard/sdk.js +36 -30
  132. package/packages/dd-trace/src/aiguard/tags.js +20 -11
  133. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  134. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +81 -81
  135. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  136. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
  137. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +4 -4
  138. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +2 -2
  139. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  140. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -3
  141. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +83 -48
  142. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  143. package/packages/dd-trace/src/appsec/index.js +21 -24
  144. package/packages/dd-trace/src/appsec/reporter.js +3 -1
  145. package/packages/dd-trace/src/appsec/rule_manager.js +4 -2
  146. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +31 -16
  147. package/packages/dd-trace/src/azure_metadata.js +17 -6
  148. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +4 -4
  149. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
  150. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -4
  151. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +1 -1
  152. package/packages/dd-trace/src/config/defaults.js +3 -14
  153. package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -1
  154. package/packages/dd-trace/src/config/git_properties.js +2 -2
  155. package/packages/dd-trace/src/config/helper.js +4 -0
  156. package/packages/dd-trace/src/config/index.js +2 -2
  157. package/packages/dd-trace/src/config/major-overrides.js +98 -0
  158. package/packages/dd-trace/src/config/parsers.js +7 -1
  159. package/packages/dd-trace/src/config/supported-configurations.json +51 -38
  160. package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
  161. package/packages/dd-trace/src/datastreams/index.js +2 -1
  162. package/packages/dd-trace/src/datastreams/manager.js +1 -1
  163. package/packages/dd-trace/src/datastreams/processor.js +3 -4
  164. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +2 -2
  165. package/packages/dd-trace/src/debugger/devtools_client/snapshot-pruner.js +1 -0
  166. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
  167. package/packages/dd-trace/src/debugger/devtools_client/state.js +2 -1
  168. package/packages/dd-trace/src/debugger/index.js +7 -7
  169. package/packages/dd-trace/src/dogstatsd.js +2 -2
  170. package/packages/dd-trace/src/encode/0.4.js +748 -232
  171. package/packages/dd-trace/src/encode/0.5.js +47 -10
  172. package/packages/dd-trace/src/encode/agentless-json.js +1 -1
  173. package/packages/dd-trace/src/exporter.js +2 -0
  174. package/packages/dd-trace/src/exporters/agent/index.js +2 -1
  175. package/packages/dd-trace/src/exporters/agentless/index.js +3 -2
  176. package/packages/dd-trace/src/exporters/agentless/writer.js +2 -2
  177. package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -1
  178. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  179. package/packages/dd-trace/src/exporters/electron/index.js +49 -0
  180. package/packages/dd-trace/src/external-logger/src/index.js +2 -1
  181. package/packages/dd-trace/src/git_metadata.js +10 -8
  182. package/packages/dd-trace/src/lambda/handler-paths.js +52 -0
  183. package/packages/dd-trace/src/lambda/index.js +62 -14
  184. package/packages/dd-trace/src/lambda/runtime/patch.js +21 -46
  185. package/packages/dd-trace/src/llmobs/index.js +13 -2
  186. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -2
  187. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +45 -15
  188. package/packages/dd-trace/src/llmobs/plugins/genai/util.js +6 -3
  189. package/packages/dd-trace/src/llmobs/sdk.js +24 -26
  190. package/packages/dd-trace/src/llmobs/span_processor.js +25 -5
  191. package/packages/dd-trace/src/llmobs/util.js +1 -0
  192. package/packages/dd-trace/src/llmobs/writers/base.js +2 -1
  193. package/packages/dd-trace/src/msgpack/chunk.js +6 -3
  194. package/packages/dd-trace/src/openfeature/noop.js +40 -36
  195. package/packages/dd-trace/src/openfeature/writers/base.js +2 -1
  196. package/packages/dd-trace/src/openfeature/writers/exposures.js +33 -52
  197. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
  198. package/packages/dd-trace/src/opentelemetry/otlp/otlp_transformer_base.js +1 -2
  199. package/packages/dd-trace/src/opentelemetry/tracer.js +0 -22
  200. package/packages/dd-trace/src/opentracing/propagation/text_map.js +20 -9
  201. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +2 -11
  202. package/packages/dd-trace/src/payload-tagging/config/index.js +2 -2
  203. package/packages/dd-trace/src/plugins/ci_plugin.js +49 -4
  204. package/packages/dd-trace/src/plugins/database.js +54 -12
  205. package/packages/dd-trace/src/plugins/index.js +1 -0
  206. package/packages/dd-trace/src/plugins/plugin.js +2 -4
  207. package/packages/dd-trace/src/plugins/util/ci.js +9 -9
  208. package/packages/dd-trace/src/plugins/util/git-cache.js +23 -23
  209. package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -2
  210. package/packages/dd-trace/src/plugins/util/test.js +56 -12
  211. package/packages/dd-trace/src/plugins/util/url.js +1 -3
  212. package/packages/dd-trace/src/plugins/util/user-provided-git.js +18 -16
  213. package/packages/dd-trace/src/plugins/util/web.js +5 -7
  214. package/packages/dd-trace/src/priority_sampler.js +1 -1
  215. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  216. package/packages/dd-trace/src/profiling/profilers/events.js +3 -23
  217. package/packages/dd-trace/src/profiling/profilers/wall.js +5 -6
  218. package/packages/dd-trace/src/profiling/ssi-heuristics.js +1 -1
  219. package/packages/dd-trace/src/rate_limiter.js +1 -1
  220. package/packages/dd-trace/src/remote_config/scheduler.js +1 -1
  221. package/packages/dd-trace/src/ritm.js +2 -1
  222. package/packages/dd-trace/src/runtime_metrics/index.js +2 -2
  223. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -8
  224. package/packages/dd-trace/src/scope.js +3 -10
  225. package/packages/dd-trace/src/serverless.js +6 -6
  226. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +27 -1
  227. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  228. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +24 -0
  229. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  230. package/packages/dd-trace/src/span_stats.js +1 -1
  231. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  232. package/packages/dd-trace/src/telemetry/endpoints.js +1 -1
  233. package/packages/dd-trace/src/telemetry/telemetry.js +2 -2
  234. package/packages/dd-trace/src/tracer.js +7 -7
  235. package/packages/dd-trace/src/lambda/runtime/ritm.js +0 -133
@@ -1,17 +1,18 @@
1
1
  'use strict'
2
2
 
3
3
  const { normalizeSpan } = require('./tags-processors')
4
- const { AgentEncoder: BaseEncoder } = require('./0.4')
4
+ const { AgentEncoder: BaseEncoder, stringifySpanEvents } = require('./0.4')
5
5
 
6
6
  const ARRAY_OF_TWO = 0x92
7
7
  const ARRAY_OF_TWELVE = 0x9C
8
8
 
9
9
  function formatSpan (span) {
10
10
  span = normalizeSpan(span)
11
- // ensure span events are encoded as tags
11
+ // v0.5 has no native span_events slot; always serialize as a meta tag.
12
12
  if (span.span_events) {
13
- span.meta.events = JSON.stringify(span.span_events)
14
- delete span.span_events
13
+ span.meta.events = stringifySpanEvents(span.span_events)
14
+ // `= undefined` over `delete` to keep the span's hidden class.
15
+ span.span_events = undefined
15
16
  }
16
17
  return span
17
18
  }
@@ -45,22 +46,58 @@ class AgentEncoder extends BaseEncoder {
45
46
  this._encodeId(bytes, span.trace_id)
46
47
  this._encodeId(bytes, span.span_id)
47
48
  this._encodeId(bytes, span.parent_id)
48
- this._encodeLong(bytes, span.start || 0)
49
- this._encodeLong(bytes, span.duration || 0)
50
- this._encodeInteger(bytes, span.error)
49
+ this._encodeIntOrFloat(bytes, span.start || 0)
50
+ this._encodeIntOrFloat(bytes, span.duration || 0)
51
+ this._encodeIntOrFloat(bytes, span.error)
51
52
  this._encodeMap(bytes, span.meta || {})
52
53
  this._encodeMap(bytes, span.metrics || {})
53
54
  this._encodeString(bytes, span.type)
54
55
  }
55
56
  }
56
57
 
58
+ // Override the inherited 0.4 `_encodeMap` so the v0.5 wire emits each numeric
59
+ // value via `_encodeIntOrFloat` (compact unsigned/signed int when integer,
60
+ // float64 otherwise) instead of always float64. The 0.4 base method stays on
61
+ // float64 because the CI-visibility encoders inherit it and target a
62
+ // different intake.
63
+ _encodeMap (bytes, value) {
64
+ const offset = bytes.length
65
+ bytes.reserve(5)
66
+ bytes.buffer[offset] = 0xDF
67
+
68
+ let count = 0
69
+ for (const key of Object.keys(value)) {
70
+ const entryValue = value[key]
71
+ if (typeof entryValue === 'string') {
72
+ this._encodeString(bytes, key)
73
+ this._encodeString(bytes, entryValue)
74
+ count++
75
+ } else if (typeof entryValue === 'number') {
76
+ this._encodeString(bytes, key)
77
+ this._encodeIntOrFloat(bytes, entryValue)
78
+ count++
79
+ }
80
+ }
81
+
82
+ const target = bytes.buffer
83
+ target[offset + 1] = count >>> 24
84
+ target[offset + 2] = count >>> 16
85
+ target[offset + 3] = count >>> 8
86
+ target[offset + 4] = count
87
+ }
88
+
57
89
  _encodeString (bytes, value = '') {
58
- this._cacheString(value)
59
- this._encodeInteger(bytes, this._stringMap[value])
90
+ let index = this._stringMap[value]
91
+ if (index === undefined) {
92
+ index = this._stringCount++
93
+ this._stringMap[value] = index
94
+ this._stringBytes.write(value)
95
+ }
96
+ this._encodeInteger(bytes, index)
60
97
  }
61
98
 
62
99
  _cacheString (value) {
63
- if (!(value in this._stringMap)) {
100
+ if (this._stringMap[value] === undefined) {
64
101
  this._stringMap[value] = this._stringCount++
65
102
  this._stringBytes.write(value)
66
103
  }
@@ -85,7 +85,7 @@ function spanToJSON (span) {
85
85
  class AgentlessJSONEncoder {
86
86
  /**
87
87
  * @param {object} writer - Writer instance with a flush() method, called when the buffer exceeds the soft limit
88
- * @param {object} [metadata={}] - Shared metadata spread into each trace object (hostname, env, tracerVersion, etc.)
88
+ * @param {object} [metadata] - Shared metadata spread into each trace object (hostname, env, tracerVersion, etc.)
89
89
  */
90
90
  constructor (writer, metadata = {}) {
91
91
  this._writer = writer
@@ -7,6 +7,8 @@ const constants = require('./constants')
7
7
 
8
8
  module.exports = function getExporter (name) {
9
9
  switch (name) {
10
+ case exporters.ELECTRON:
11
+ return require('./exporters/electron')
10
12
  case exporters.LOG:
11
13
  return require('./exporters/log')
12
14
  case exporters.AGENT:
@@ -50,7 +50,8 @@ class AgentExporter {
50
50
  this.#timer = setTimeout(() => {
51
51
  this._writer.flush()
52
52
  this.#timer = undefined
53
- }, flushInterval).unref()
53
+ }, flushInterval)
54
+ this.#timer.unref?.()
54
55
  }
55
56
  }
56
57
 
@@ -18,7 +18,7 @@ class AgentlessExporter {
18
18
 
19
19
  /**
20
20
  * @param {object} config - Configuration object
21
- * @param {string} [config.site='datadoghq.com'] - The Datadog site
21
+ * @param {string} [config.site] - The Datadog site. Defaults to 'datadoghq.com'.
22
22
  * @param {string} [config.url] - Override intake URL
23
23
  * @param {number} [config.flushInterval] - Batch flush interval in ms
24
24
  * @param {string} [config.env] - Environment name
@@ -109,7 +109,8 @@ class AgentlessExporter {
109
109
  log.error('Failed to flush traces on timer: %s', err.message)
110
110
  }
111
111
  this.#timer = undefined
112
- }, flushInterval).unref()
112
+ }, flushInterval)
113
+ this.#timer.unref?.()
113
114
  }
114
115
  }
115
116
 
@@ -19,8 +19,8 @@ class AgentlessWriter extends BaseWriter {
19
19
  /**
20
20
  * @param {object} options - Writer options
21
21
  * @param {URL} [options.url] - The intake URL. If not provided, constructed from site.
22
- * @param {string} [options.site='datadoghq.com'] - The Datadog site
23
- * @param {object} [options.metadata={}] - Metadata to pass to the encoder (hostname, env, etc.)
22
+ * @param {string} [options.site] - The Datadog site
23
+ * @param {object} [options.metadata] - Metadata to pass to the encoder (hostname, env, etc.)
24
24
  */
25
25
  constructor ({ url, site = 'datadoghq.com', metadata = {} }) {
26
26
  super({ url })
@@ -39,7 +39,8 @@ class BufferingExporter {
39
39
  this[timerKey] = setTimeout(() => {
40
40
  writer.flush()
41
41
  this[timerKey] = undefined
42
- }, flushInterval).unref()
42
+ }, flushInterval)
43
+ this[timerKey].unref?.()
43
44
  }
44
45
  }
45
46
 
@@ -180,7 +180,7 @@ function request (data, options, callback) {
180
180
  // Unref so a pending retry never keeps the host process alive past
181
181
  // its natural exit point; long-running apps still retry because the
182
182
  // event loop is held open by their own work.
183
- setTimeout(attempt, getRetryDelay(options, attemptIndex), attemptIndex + 1).unref()
183
+ setTimeout(attempt, getRetryDelay(options, attemptIndex), attemptIndex + 1).unref?.()
184
184
  } else {
185
185
  callback(error)
186
186
  }
@@ -0,0 +1,49 @@
1
+ 'use strict'
2
+
3
+ const { channel } = require('dc-polyfill')
4
+ const { truncateSpan, normalizeSpan } = require('../../encode/tags-processors')
5
+
6
+ const traceChannel = channel('datadog:apm:electron:export')
7
+
8
+ class ElectronExporter {
9
+ #timer
10
+ #traces = []
11
+
12
+ constructor (config) {
13
+ this._config = config
14
+
15
+ globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(this.flush.bind(this))
16
+ }
17
+
18
+ export (spans) {
19
+ this.#traces.push(spans)
20
+
21
+ const { flushInterval } = this._config
22
+
23
+ if (flushInterval === 0) {
24
+ this.flush()
25
+ } else if (this.#timer === undefined) {
26
+ this.#timer = setTimeout(() => {
27
+ this.flush()
28
+ this.#timer = undefined
29
+ }, flushInterval)
30
+ this.#timer.unref?.()
31
+ }
32
+ }
33
+
34
+ flush (done = () => {}) {
35
+ clearTimeout(this.#timer)
36
+ this.#timer = undefined
37
+
38
+ const traces = this.#traces.splice(0)
39
+
40
+ if (traces.length > 0 && traceChannel.hasSubscribers) {
41
+ const formattedTraces = traces.map(spans => spans.map(span => normalizeSpan(truncateSpan(span))))
42
+ traceChannel.publish(formattedTraces)
43
+ }
44
+
45
+ done()
46
+ }
47
+ }
48
+
49
+ module.exports = ElectronExporter
@@ -26,7 +26,8 @@ class ExternalLogger {
26
26
  }
27
27
  this.timer = setInterval(() => {
28
28
  this.flush()
29
- }, this.interval).unref()
29
+ }, this.interval)
30
+ this.timer.unref?.()
30
31
 
31
32
  tracerLogger.debug(`started log writer to https://${this.intake}${this.endpoint}`)
32
33
  }
@@ -12,19 +12,21 @@ const {
12
12
  resolveGitHeadSHA,
13
13
  } = require('./config/git_properties')
14
14
 
15
- /** @type {{ commitSHA: string | undefined, repositoryUrl: string | undefined } | undefined} */
16
- let cached
15
+ /**
16
+ * @typedef {{ commitSHA: string | undefined, repositoryUrl: string | undefined }} GitMetadata
17
+ * @type {{ enabled?: GitMetadata, disabled?: GitMetadata }}
18
+ */
19
+ const cache = {}
17
20
 
18
21
  /**
19
22
  * @param {import('./config/config-types').ConfigProperties} config
20
23
  */
21
24
  function getGitMetadata (config) {
22
- if (cached) return cached
23
-
24
25
  if (!config.DD_TRACE_GIT_METADATA_ENABLED) {
25
- cached = { commitSHA: undefined, repositoryUrl: undefined }
26
- return cached
26
+ cache.disabled ??= { commitSHA: undefined, repositoryUrl: undefined }
27
+ return cache.disabled
27
28
  }
29
+ if (cache.enabled) return cache.enabled
28
30
 
29
31
  let repositoryUrl = removeUserSensitiveInfo(config.DD_GIT_REPOSITORY_URL ?? config.tags[GIT_REPOSITORY_URL])
30
32
  let commitSHA = config.DD_GIT_COMMIT_SHA ?? config.tags[GIT_COMMIT_SHA]
@@ -59,8 +61,8 @@ function getGitMetadata (config) {
59
61
 
60
62
  commitSHA ??= resolveGitHeadSHA(gitFolderPath)
61
63
 
62
- cached = { commitSHA, repositoryUrl }
63
- return cached
64
+ cache.enabled = { commitSHA, repositoryUrl }
65
+ return cache.enabled
64
66
  }
65
67
 
66
68
  module.exports = getGitMetadata
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * Modifications copyright 2022 Datadog, Inc.
4
+ *
5
+ * Some functions are part of aws-lambda-nodejs-runtime-interface-client
6
+ * https://github.com/aws/aws-lambda-nodejs-runtime-interface-client/blob/v2.1.0/src/utils/UserFunction.ts
7
+ */
8
+ 'use strict'
9
+
10
+ const path = require('path')
11
+
12
+ /**
13
+ * Example: `'./api/src/index.nested.handler'` → `['./api/src/', 'index.nested.handler']`.
14
+ *
15
+ * @param {string} fullHandler
16
+ */
17
+ function extractModuleRootAndHandler (fullHandler) {
18
+ const handlerString = path.basename(fullHandler)
19
+ const moduleRoot = fullHandler.slice(0, Math.max(0, fullHandler.indexOf(handlerString)))
20
+ return [moduleRoot, handlerString]
21
+ }
22
+
23
+ /**
24
+ * Example: `'index.nested.handler'` → `['index', 'nested.handler']`.
25
+ *
26
+ * @param {string} handler
27
+ * @throws {Error} When the handler is not of the form `<module>.<path>`.
28
+ */
29
+ function extractModuleNameAndHandlerPath (handler) {
30
+ const match = handler.match(/^([^.]*)\.(.*)$/)
31
+ if (!match || match.length !== 3) {
32
+ throw new Error(`Malformed handler name: ${handler}`)
33
+ }
34
+ return [match[1], match[2]]
35
+ }
36
+
37
+ /**
38
+ * @param {string} lambdaStylePath `LAMBDA_TASK_ROOT` joined with the module root and module name.
39
+ */
40
+ function getLambdaFilePaths (lambdaStylePath) {
41
+ return [
42
+ `${lambdaStylePath}.js`,
43
+ `${lambdaStylePath}.mjs`,
44
+ `${lambdaStylePath}.cjs`,
45
+ ]
46
+ }
47
+
48
+ module.exports = {
49
+ extractModuleRootAndHandler,
50
+ extractModuleNameAndHandlerPath,
51
+ getLambdaFilePaths,
52
+ }
@@ -1,17 +1,65 @@
1
1
  'use strict'
2
2
 
3
- const { getValueFromEnvSources } = require('../config/helper')
4
- const { registerLambdaHook } = require('./runtime/ritm')
5
-
6
- /**
7
- * It is safe to do it this way, since customers will never be expected to disable
8
- * this specific instrumentation through the init config object.
9
- */
10
- const _DD_TRACE_DISABLED_INSTRUMENTATIONS = getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS') || ''
11
- const _disabledInstrumentations = new Set(
12
- _DD_TRACE_DISABLED_INSTRUMENTATIONS ? _DD_TRACE_DISABLED_INSTRUMENTATIONS.split(',') : []
13
- )
14
-
15
- if (!_disabledInstrumentations.has('lambda')) {
16
- registerLambdaHook()
3
+ const path = require('path')
4
+
5
+ const log = require('../log')
6
+ const { getEnvironmentVariable, getValueFromEnvSources } = require('../config/helper')
7
+ const Hook = require('../../../datadog-instrumentations/src/helpers/hook')
8
+ const instrumentations = require('../../../datadog-instrumentations/src/helpers/instrumentations')
9
+ const {
10
+ filename,
11
+ pathSepExpr,
12
+ } = require('../../../datadog-instrumentations/src/helpers/register')
13
+ const {
14
+ extractModuleNameAndHandlerPath,
15
+ extractModuleRootAndHandler,
16
+ getLambdaFilePaths,
17
+ } = require('./handler-paths')
18
+
19
+ if (!getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS')?.split(',').includes('lambda')) {
20
+ const lambdaTaskRoot = getEnvironmentVariable('LAMBDA_TASK_ROOT')
21
+ const originalLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER')
22
+
23
+ if (originalLambdaHandler !== undefined && lambdaTaskRoot !== undefined) {
24
+ const [moduleRoot, moduleAndHandler] = extractModuleRootAndHandler(originalLambdaHandler)
25
+ const [moduleName] = extractModuleNameAndHandlerPath(moduleAndHandler)
26
+
27
+ const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, moduleName)
28
+ const lambdaFilePaths = getLambdaFilePaths(lambdaStylePath)
29
+
30
+ // TODO: Redo this like any other instrumentation.
31
+ Hook(lambdaFilePaths, (moduleExports, name, _, moduleVersion) => {
32
+ require('./runtime/patch')
33
+
34
+ for (const { hook } of instrumentations[name]) {
35
+ try {
36
+ moduleExports = hook(moduleExports, moduleVersion) ?? moduleExports
37
+ } catch (error) {
38
+ log.error('Error executing lambda hook', error)
39
+ }
40
+ }
41
+
42
+ return moduleExports
43
+ })
44
+ return
45
+ }
46
+
47
+ const moduleToPatch = 'datadog-lambda-js'
48
+ Hook([moduleToPatch], (moduleExports, moduleName, _, moduleVersion) => {
49
+ moduleName = moduleName.replace(pathSepExpr, '/')
50
+ require('./runtime/patch')
51
+
52
+ for (const { file, hook } of instrumentations[moduleToPatch]) {
53
+ const fullFilename = filename(moduleToPatch, file)
54
+ if (moduleName === fullFilename) {
55
+ try {
56
+ moduleExports = hook(moduleExports, moduleVersion) ?? moduleExports
57
+ } catch (error) {
58
+ log.error('Error executing lambda hook for datadog-lambda-js', error)
59
+ }
60
+ }
61
+ }
62
+
63
+ return moduleExports
64
+ })
17
65
  }
@@ -6,54 +6,32 @@ const { datadog } = require('../handler')
6
6
  const { addHook } = require('../../../../datadog-instrumentations/src/helpers/instrument')
7
7
  const shimmer = require('../../../../datadog-shimmer')
8
8
  const { getEnvironmentVariable, getValueFromEnvSources } = require('../../config/helper')
9
- const { _extractModuleNameAndHandlerPath, _extractModuleRootAndHandler, _getLambdaFilePaths } = require('./ritm')
10
-
11
- /**
12
- * Patches a Datadog Lambda module by calling `patchDatadogLambdaHandler`
13
- * with the handler name `datadog`.
14
- *
15
- * @param {object} datadogLambdaModule node module to be patched.
16
- * @returns a Datadog Lambda module with the `datadog` function from
17
- * `datadog-lambda-js` patched.
18
- */
19
- const patchDatadogLambdaModule = (datadogLambdaModule) => {
9
+ const {
10
+ extractModuleNameAndHandlerPath,
11
+ extractModuleRootAndHandler,
12
+ getLambdaFilePaths,
13
+ } = require('../handler-paths')
14
+
15
+ /** @param {object} datadogLambdaModule */
16
+ function patchDatadogLambdaModule (datadogLambdaModule) {
20
17
  shimmer.wrap(datadogLambdaModule, 'datadog', patchDatadogLambdaHandler)
21
-
22
18
  return datadogLambdaModule
23
19
  }
24
20
 
25
- /**
26
- * Patches a Datadog Lambda handler in order to do
27
- * Datadog instrumentation by getting the Lambda handler from its
28
- * arguments.
29
- *
30
- * @param {Function} datadogHandler the Datadog Lambda handler to destructure.
31
- * @returns the datadogHandler with its arguments patched.
32
- */
21
+ /** @param {Function} datadogHandler */
33
22
  function patchDatadogLambdaHandler (datadogHandler) {
34
- return (userHandler) => {
35
- return datadogHandler(datadog(userHandler))
36
- }
23
+ return userHandler => datadogHandler(datadog(userHandler))
37
24
  }
38
25
 
39
- /**
40
- * Patches a Lambda module on the given handler path.
41
- *
42
- * @param {string} handlerPath path of the handler to be patched.
43
- * @returns a module with the given handler path patched.
44
- */
45
- const patchLambdaModule = (handlerPath) => (lambdaModule) => {
46
- shimmer.wrap(lambdaModule, handlerPath, patchLambdaHandler)
47
-
48
- return lambdaModule
26
+ /** @param {string} handlerPath */
27
+ function patchLambdaModule (handlerPath) {
28
+ return lambdaModule => {
29
+ shimmer.wrap(lambdaModule, handlerPath, patchLambdaHandler)
30
+ return lambdaModule
31
+ }
49
32
  }
50
33
 
51
- /**
52
- * Patches a Lambda handler in order to do Datadog instrumentation.
53
- *
54
- * @param {Function} lambdaHandler the Lambda handler to be patched.
55
- * @returns a function which patches the given Lambda handler.
56
- */
34
+ /** @param {Function} lambdaHandler */
57
35
  function patchLambdaHandler (lambdaHandler) {
58
36
  return datadog(lambdaHandler)
59
37
  }
@@ -62,16 +40,13 @@ const lambdaTaskRoot = getEnvironmentVariable('LAMBDA_TASK_ROOT')
62
40
  const originalLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER')
63
41
 
64
42
  if (originalLambdaHandler === undefined) {
65
- // Instrumentation is done manually.
66
43
  addHook({ name: 'datadog-lambda-js' }, patchDatadogLambdaModule)
67
44
  } else {
68
- const [moduleRoot, moduleAndHandler] = _extractModuleRootAndHandler(originalLambdaHandler)
69
- const [_module, handlerPath] = _extractModuleNameAndHandlerPath(moduleAndHandler)
70
-
71
- const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, _module)
72
- const lambdaFilePaths = _getLambdaFilePaths(lambdaStylePath)
45
+ const [moduleRoot, moduleAndHandler] = extractModuleRootAndHandler(originalLambdaHandler)
46
+ const [moduleName, handlerPath] = extractModuleNameAndHandlerPath(moduleAndHandler)
73
47
 
74
- for (const lambdaFilePath of lambdaFilePaths) {
48
+ const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, moduleName)
49
+ for (const lambdaFilePath of getLambdaFilePaths(lambdaStylePath)) {
75
50
  addHook({ name: lambdaFilePath }, patchLambdaModule(handlerPath))
76
51
  }
77
52
  }
@@ -108,6 +108,10 @@ function disable () {
108
108
  // since LLMObs traces can extend between services and be the same trace,
109
109
  // we need to propagate the parent id and mlApp.
110
110
  function handleLLMObsParentIdInjection ({ carrier }) {
111
+ // Respect the standard propagator's gate: when trace tag propagation is
112
+ // disabled, don't write `x-datadog-tags` for LLMObs either.
113
+ if (globalTracerConfig.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) return
114
+
111
115
  const parent = storage.getStore()?.span
112
116
  const mlObsSpanTags = LLMObsTagger.tagMap.get(parent)
113
117
 
@@ -118,8 +122,15 @@ function handleLLMObsParentIdInjection ({ carrier }) {
118
122
  parentContext?._trace?.tags?.[PROPAGATED_ML_APP_KEY] ||
119
123
  globalTracerConfig.llmobs.mlApp
120
124
 
121
- if (parentId) carrier['x-datadog-tags'] += `,${PROPAGATED_PARENT_ID_KEY}=${parentId}`
122
- if (mlApp) carrier['x-datadog-tags'] += `,${PROPAGATED_ML_APP_KEY}=${mlApp}`
125
+ if (!parentId && !mlApp) return
126
+
127
+ // `_injectTags` only writes `x-datadog-tags` when the trace has `_dd.p.*`
128
+ // tags, so it may be undefined here — coalesce before appending.
129
+ const existing = carrier['x-datadog-tags']
130
+ let tags = existing || ''
131
+ if (parentId) tags += `${tags ? ',' : ''}${PROPAGATED_PARENT_ID_KEY}=${parentId}`
132
+ if (mlApp) tags += `${tags ? ',' : ''}${PROPAGATED_ML_APP_KEY}=${mlApp}`
133
+ if (tags !== existing) carrier['x-datadog-tags'] = tags
123
134
  }
124
135
 
125
136
  function handleFlush () {
@@ -41,8 +41,7 @@ const VERCEL_AI_GENERATION_METADATA_PREFIX = 'ai.settings.'
41
41
  */
42
42
  function getSpanTags (ctx) {
43
43
  const span = ctx.currentStore?.span
44
- const carrier = ctx.attributes ?? span?.context()._tags ?? {}
45
- return /** @type {SpanTags} */ (carrier)
44
+ return /** @type {SpanTags} */ (ctx.attributes ?? span?.context()._tags ?? {})
46
45
  }
47
46
 
48
47
  /**
@@ -14,7 +14,17 @@ const llmobsStore = storage('llmobs')
14
14
 
15
15
  const ENABLED_OPERATIONS = new Set(['invokeModel', 'invokeModelWithResponseStream'])
16
16
 
17
- const requestIdsToTokens = {}
17
+ /**
18
+ * @typedef {{
19
+ * inputTokensFromHeaders?: number,
20
+ * outputTokensFromHeaders?: number,
21
+ * cacheReadTokensFromHeaders?: number,
22
+ * cacheWriteTokensFromHeaders?: number,
23
+ * }} HeaderTokens
24
+ */
25
+
26
+ /** @type {Map<string, HeaderTokens>} */
27
+ const pendingTokenHeaders = new Map()
18
28
 
19
29
  class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
20
30
  constructor () {
@@ -24,33 +34,39 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
24
34
  const { response } = ctx
25
35
  const request = response.request
26
36
  const operation = request.operation
37
+
38
+ // Release the cached headers even for operations the plugin does not tag,
39
+ // so non-LLM Bedrock calls do not leak entries into pendingTokenHeaders.
40
+ const tokensFromHeaders = consumeTokenHeaders(response.$metadata?.requestId)
41
+
27
42
  // avoids instrumenting other non supported runtime operations
28
- if (!ENABLED_OPERATIONS.has(operation)) {
29
- return
30
- }
43
+ if (!ENABLED_OPERATIONS.has(operation)) return
44
+
31
45
  const { modelProvider, modelName } = parseModelId(request.params.modelId)
32
46
 
33
47
  // avoids instrumenting non llm type
34
- if (modelName.includes('embed')) {
35
- return
36
- }
48
+ if (modelName.includes('embed')) return
49
+
37
50
  const span = ctx.currentStore?.span
38
- this.setLLMObsTags({ ctx, request, span, response, modelProvider, modelName })
51
+ this.setLLMObsTags({ ctx, request, span, response, modelProvider, modelName, tokensFromHeaders })
39
52
  })
40
53
 
41
54
  this.addSub('apm:aws:response:deserialize:bedrockruntime', ({ headers }) => {
42
55
  const requestId = headers['x-amzn-requestid']
56
+ // No request id means no way to correlate with the :complete: event.
57
+ if (!requestId) return
58
+
43
59
  const inputTokenCount = headers['x-amzn-bedrock-input-token-count']
44
60
  const outputTokenCount = headers['x-amzn-bedrock-output-token-count']
45
61
  const cacheReadTokenCount = headers['x-amzn-bedrock-cache-read-input-token-count']
46
62
  const cacheWriteTokenCount = headers['x-amzn-bedrock-cache-write-input-token-count']
47
63
 
48
- requestIdsToTokens[requestId] = {
64
+ pendingTokenHeaders.set(requestId, {
49
65
  inputTokensFromHeaders: inputTokenCount && Number.parseInt(inputTokenCount),
50
66
  outputTokensFromHeaders: outputTokenCount && Number.parseInt(outputTokenCount),
51
67
  cacheReadTokensFromHeaders: cacheReadTokenCount && Number.parseInt(cacheReadTokenCount),
52
68
  cacheWriteTokensFromHeaders: cacheWriteTokenCount && Number.parseInt(cacheWriteTokenCount),
53
- }
69
+ })
54
70
  })
55
71
 
56
72
  this.addSub('apm:aws:response:streamed-chunk:bedrockruntime', ({ ctx, chunk }) => {
@@ -60,7 +76,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
60
76
  })
61
77
  }
62
78
 
63
- setLLMObsTags ({ ctx, request, span, response, modelProvider, modelName }) {
79
+ setLLMObsTags ({ ctx, request, span, response, modelProvider, modelName, tokensFromHeaders }) {
64
80
  const isStream = request?.operation?.toLowerCase().includes('stream')
65
81
  telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: 'bedrock' })
66
82
 
@@ -97,7 +113,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
97
113
 
98
114
  // add token metrics
99
115
  const { inputTokens, outputTokens, totalTokens, cacheReadTokens, cacheWriteTokens } = extractTokens({
100
- requestId: response.$metadata.requestId,
116
+ tokensFromHeaders,
101
117
  usage: textAndResponseReason.usage,
102
118
  })
103
119
  this._tagger.tagMetrics(span, {
@@ -110,14 +126,28 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
110
126
  }
111
127
  }
112
128
 
113
- function extractTokens ({ requestId, usage }) {
129
+ /**
130
+ * @param {string | undefined} requestId
131
+ * @returns {HeaderTokens | undefined}
132
+ */
133
+ function consumeTokenHeaders (requestId) {
134
+ const tokens = pendingTokenHeaders.get(requestId)
135
+ pendingTokenHeaders.delete(requestId)
136
+ return tokens
137
+ }
138
+
139
+ /**
140
+ * Combine response-body usage with header-derived counts, preferring the body.
141
+ *
142
+ * @param {{ tokensFromHeaders: HeaderTokens | undefined, usage: Record<string, number | undefined> }} options
143
+ */
144
+ function extractTokens ({ tokensFromHeaders, usage }) {
114
145
  const {
115
146
  inputTokensFromHeaders,
116
147
  outputTokensFromHeaders,
117
148
  cacheReadTokensFromHeaders,
118
149
  cacheWriteTokensFromHeaders,
119
- } = requestIdsToTokens[requestId] || {}
120
- delete requestIdsToTokens[requestId]
150
+ } = tokensFromHeaders ?? {}
121
151
 
122
152
  const inputTokens = usage.inputTokens || inputTokensFromHeaders || 0
123
153
  const outputTokens = usage.outputTokens || outputTokensFromHeaders || 0