dd-trace 4.51.1 → 4.53.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 (172) hide show
  1. package/LICENSE-3rdparty.csv +8 -2
  2. package/ci/init.js +16 -0
  3. package/index.d.ts +31 -13
  4. package/init.js +4 -66
  5. package/initialize.mjs +13 -10
  6. package/loader-hook.mjs +4 -0
  7. package/package.json +16 -11
  8. package/packages/datadog-core/src/storage.js +39 -2
  9. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  10. package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
  11. package/packages/datadog-instrumentations/src/cucumber.js +29 -3
  12. package/packages/datadog-instrumentations/src/express.js +38 -4
  13. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +3 -3
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -1
  15. package/packages/datadog-instrumentations/src/helpers/register.js +3 -4
  16. package/packages/datadog-instrumentations/src/http/client.js +1 -1
  17. package/packages/datadog-instrumentations/src/jest.js +27 -8
  18. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
  19. package/packages/datadog-instrumentations/src/mysql2.js +13 -8
  20. package/packages/datadog-instrumentations/src/next.js +7 -4
  21. package/packages/datadog-instrumentations/src/passport-http.js +2 -14
  22. package/packages/datadog-instrumentations/src/passport-local.js +2 -14
  23. package/packages/datadog-instrumentations/src/passport-utils.js +43 -19
  24. package/packages/datadog-instrumentations/src/pg.js +6 -6
  25. package/packages/datadog-instrumentations/src/playwright.js +17 -4
  26. package/packages/datadog-instrumentations/src/router.js +97 -1
  27. package/packages/datadog-instrumentations/src/sequelize.js +9 -4
  28. package/packages/datadog-instrumentations/src/url.js +4 -0
  29. package/packages/datadog-instrumentations/src/vitest.js +27 -2
  30. package/packages/datadog-plugin-avsc/src/schema_iterator.js +8 -3
  31. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +154 -0
  32. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
  33. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  34. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  35. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
  36. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
  37. package/packages/datadog-plugin-aws-sdk/src/util.js +92 -0
  38. package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
  39. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -1
  40. package/packages/datadog-plugin-cucumber/src/index.js +39 -4
  41. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +3 -3
  42. package/packages/datadog-plugin-grpc/src/client.js +2 -2
  43. package/packages/datadog-plugin-grpc/src/util.js +1 -1
  44. package/packages/datadog-plugin-jest/src/index.js +39 -4
  45. package/packages/datadog-plugin-langchain/src/handlers/language_models/chat_model.js +1 -1
  46. package/packages/datadog-plugin-langchain/src/handlers/language_models/llm.js +1 -1
  47. package/packages/datadog-plugin-mocha/src/index.js +36 -2
  48. package/packages/datadog-plugin-oracledb/src/index.js +1 -1
  49. package/packages/datadog-plugin-vitest/src/index.js +34 -2
  50. package/packages/datadog-shimmer/src/shimmer.js +8 -4
  51. package/packages/dd-trace/src/appsec/addresses.js +3 -0
  52. package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
  53. package/packages/dd-trace/src/appsec/blocked_templates.js +1 -1
  54. package/packages/dd-trace/src/appsec/blocking.js +1 -1
  55. package/packages/dd-trace/src/appsec/channels.js +1 -0
  56. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +4 -0
  57. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +2 -2
  58. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
  59. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +1 -1
  60. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +1 -1
  61. package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +10 -3
  62. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +4 -0
  63. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +4 -0
  64. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +8 -21
  65. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +3 -3
  66. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +2 -2
  67. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +64 -3
  68. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -8
  69. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
  70. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +7 -11
  71. package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +2 -3
  72. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +2 -2
  73. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +2 -2
  74. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +2 -2
  75. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
  76. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -3
  77. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
  78. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  79. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +32 -37
  80. package/packages/dd-trace/src/appsec/index.js +18 -13
  81. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +2 -2
  82. package/packages/dd-trace/src/appsec/rasp/utils.js +1 -1
  83. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -0
  84. package/packages/dd-trace/src/appsec/remote_config/index.js +25 -1
  85. package/packages/dd-trace/src/appsec/remote_config/manager.js +2 -2
  86. package/packages/dd-trace/src/appsec/reporter.js +3 -1
  87. package/packages/dd-trace/src/appsec/sdk/set_user.js +2 -2
  88. package/packages/dd-trace/src/appsec/sdk/track_event.js +37 -24
  89. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -4
  90. package/packages/dd-trace/src/appsec/telemetry.js +10 -0
  91. package/packages/dd-trace/src/appsec/user_tracking.js +168 -0
  92. package/packages/dd-trace/src/appsec/waf/index.js +2 -2
  93. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +2 -3
  94. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  95. package/packages/dd-trace/src/azure_metadata.js +4 -4
  96. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +5 -4
  97. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +39 -3
  98. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  99. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  100. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -1
  101. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
  102. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -9
  103. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
  104. package/packages/dd-trace/src/config.js +24 -32
  105. package/packages/dd-trace/src/constants.js +1 -0
  106. package/packages/dd-trace/src/crashtracking/crashtracker.js +3 -2
  107. package/packages/dd-trace/src/datastreams/processor.js +4 -6
  108. package/packages/dd-trace/src/datastreams/writer.js +6 -5
  109. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +80 -0
  110. package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
  111. package/packages/dd-trace/src/debugger/devtools_client/defaults.js +6 -0
  112. package/packages/dd-trace/src/debugger/devtools_client/index.js +63 -8
  113. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +10 -67
  114. package/packages/dd-trace/src/debugger/devtools_client/send.js +2 -1
  115. package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -1
  116. package/packages/dd-trace/src/debugger/devtools_client/status.js +4 -4
  117. package/packages/dd-trace/src/debugger/index.js +14 -10
  118. package/packages/dd-trace/src/dogstatsd.js +2 -2
  119. package/packages/dd-trace/src/encode/0.4.js +23 -78
  120. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +0 -32
  121. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -2
  122. package/packages/dd-trace/src/encode/span-stats.js +0 -30
  123. package/packages/dd-trace/src/exporters/agent/writer.js +3 -3
  124. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  125. package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -1
  126. package/packages/dd-trace/src/flare/index.js +1 -1
  127. package/packages/dd-trace/src/guardrails/index.js +64 -0
  128. package/packages/dd-trace/src/guardrails/log.js +32 -0
  129. package/packages/dd-trace/src/guardrails/telemetry.js +78 -0
  130. package/packages/dd-trace/src/guardrails/util.js +10 -0
  131. package/packages/dd-trace/src/lambda/runtime/ritm.js +2 -2
  132. package/packages/dd-trace/src/llmobs/storage.js +2 -3
  133. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  134. package/packages/dd-trace/src/{encode → msgpack}/chunk.js +8 -5
  135. package/packages/dd-trace/src/msgpack/encoder.js +309 -0
  136. package/packages/dd-trace/src/msgpack/index.js +6 -0
  137. package/packages/dd-trace/src/opentelemetry/context_manager.js +2 -2
  138. package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -9
  139. package/packages/dd-trace/src/opentracing/span.js +1 -1
  140. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  141. package/packages/dd-trace/src/plugin_manager.js +4 -2
  142. package/packages/dd-trace/src/plugins/ci_plugin.js +47 -4
  143. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  144. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  145. package/packages/dd-trace/src/plugins/util/git.js +7 -7
  146. package/packages/dd-trace/src/plugins/util/test.js +36 -3
  147. package/packages/dd-trace/src/plugins/util/web.js +2 -2
  148. package/packages/dd-trace/src/profiling/config.js +3 -0
  149. package/packages/dd-trace/src/profiling/exporters/agent.js +9 -68
  150. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +76 -0
  151. package/packages/dd-trace/src/profiling/exporters/file.js +8 -4
  152. package/packages/dd-trace/src/profiling/profiler.js +62 -10
  153. package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +22 -12
  154. package/packages/dd-trace/src/profiling/profilers/events.js +47 -8
  155. package/packages/dd-trace/src/profiling/profilers/wall.js +2 -17
  156. package/packages/dd-trace/src/profiling/webspan-utils.js +23 -0
  157. package/packages/dd-trace/src/proxy.js +7 -2
  158. package/packages/dd-trace/src/runtime_metrics.js +107 -4
  159. package/packages/dd-trace/src/serverless.js +1 -1
  160. package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +1 -1
  161. package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +1 -1
  162. package/packages/dd-trace/src/span_processor.js +10 -10
  163. package/packages/dd-trace/src/tagger.js +1 -1
  164. package/packages/dd-trace/src/telemetry/index.js +1 -0
  165. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  166. package/packages/dd-trace/src/telemetry/logs/log-collector.js +10 -2
  167. package/packages/dd-trace/src/telemetry/send-data.js +2 -2
  168. package/packages/dd-trace/src/util.js +5 -16
  169. package/packages/datadog-instrumentations/src/qs.js +0 -24
  170. package/packages/dd-trace/src/appsec/iast/iast-log.js +0 -86
  171. package/packages/dd-trace/src/appsec/passport.js +0 -110
  172. package/packages/dd-trace/src/telemetry/init-telemetry.js +0 -75
@@ -181,8 +181,13 @@ class Tracer extends NoopProxy {
181
181
  )
182
182
  }
183
183
  }
184
+
185
+ if (config.isTestDynamicInstrumentationEnabled) {
186
+ const testVisibilityDynamicInstrumentation = require('./ci-visibility/dynamic-instrumentation')
187
+ testVisibilityDynamicInstrumentation.start()
188
+ }
184
189
  } catch (e) {
185
- log.error(e)
190
+ log.error('Error initialising tracer', e)
186
191
  }
187
192
 
188
193
  return this
@@ -193,7 +198,7 @@ class Tracer extends NoopProxy {
193
198
  try {
194
199
  return require('./profiler').start(config)
195
200
  } catch (e) {
196
- log.error(e)
201
+ log.error('Error starting profiler', e)
197
202
  }
198
203
  }
199
204
 
@@ -7,11 +7,19 @@ const os = require('os')
7
7
  const { DogStatsDClient } = require('./dogstatsd')
8
8
  const log = require('./log')
9
9
  const Histogram = require('./histogram')
10
- const { performance } = require('perf_hooks')
10
+ const { performance, PerformanceObserver } = require('perf_hooks')
11
11
 
12
+ const { NODE_MAJOR, NODE_MINOR } = require('../../../version')
12
13
  const INTERVAL = 10 * 1000
13
14
 
15
+ // Node >=16 has PerformanceObserver with `gc` type, but <16.7 had a critical bug.
16
+ // See: https://github.com/nodejs/node/issues/39548
17
+ const hasGCObserver = NODE_MAJOR >= 18 || (NODE_MAJOR === 16 && NODE_MINOR >= 7)
18
+ const hasGCProfiler = NODE_MAJOR >= 20 || (NODE_MAJOR === 18 && NODE_MINOR >= 15)
19
+
14
20
  let nativeMetrics = null
21
+ let gcObserver = null
22
+ let gcProfiler = null
15
23
 
16
24
  let interval
17
25
  let client
@@ -24,15 +32,20 @@ let elu
24
32
 
25
33
  reset()
26
34
 
27
- module.exports = {
35
+ const runtimeMetrics = module.exports = {
28
36
  start (config) {
29
37
  const clientConfig = DogStatsDClient.generateClientConfig(config)
30
38
 
31
39
  try {
32
40
  nativeMetrics = require('@datadog/native-metrics')
33
- nativeMetrics.start()
41
+
42
+ if (hasGCObserver) {
43
+ nativeMetrics.start('loop') // Only add event loop watcher and not GC.
44
+ } else {
45
+ nativeMetrics.start()
46
+ }
34
47
  } catch (e) {
35
- log.error(e)
48
+ log.error('Error starting native metrics', e)
36
49
  nativeMetrics = null
37
50
  }
38
51
 
@@ -40,6 +53,9 @@ module.exports = {
40
53
 
41
54
  time = process.hrtime()
42
55
 
56
+ startGCObserver()
57
+ startGCProfiler()
58
+
43
59
  if (nativeMetrics) {
44
60
  interval = setInterval(() => {
45
61
  captureCommonMetrics()
@@ -138,6 +154,10 @@ function reset () {
138
154
  counters = {}
139
155
  histograms = {}
140
156
  nativeMetrics = null
157
+ gcObserver && gcObserver.disconnect()
158
+ gcObserver = null
159
+ gcProfiler && gcProfiler.stop()
160
+ gcProfiler = null
141
161
  }
142
162
 
143
163
  function captureCpuUsage () {
@@ -202,6 +222,29 @@ function captureHeapSpace () {
202
222
  client.gauge('runtime.node.heap.physical_size.by.space', stats[i].physical_space_size, tags)
203
223
  }
204
224
  }
225
+ function captureGCMetrics () {
226
+ if (!gcProfiler) return
227
+
228
+ const profile = gcProfiler.stop()
229
+ const pauseAll = new Histogram()
230
+ const pause = {}
231
+
232
+ for (const stat of profile.statistics) {
233
+ const type = stat.gcType.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase()
234
+
235
+ pause[type] = pause[type] || new Histogram()
236
+ pause[type].record(stat.cost)
237
+ pauseAll.record(stat.cost)
238
+ }
239
+
240
+ histogram('runtime.node.gc.pause', pauseAll)
241
+
242
+ for (const type in pause) {
243
+ histogram('runtime.node.gc.pause.by.type', pause[type], [`gc_type:${type}`])
244
+ }
245
+
246
+ gcProfiler.start()
247
+ }
205
248
 
206
249
  function captureGauges () {
207
250
  Object.keys(gauges).forEach(name => {
@@ -256,6 +299,7 @@ function captureCommonMetrics () {
256
299
  captureCounters()
257
300
  captureHistograms()
258
301
  captureELU()
302
+ captureGCMetrics()
259
303
  }
260
304
 
261
305
  function captureNativeMetrics () {
@@ -297,6 +341,11 @@ function captureNativeMetrics () {
297
341
  function histogram (name, stats, tags) {
298
342
  tags = [].concat(tags)
299
343
 
344
+ // Stats can contain garbage data when a value was never recorded.
345
+ if (stats.count === 0) {
346
+ stats = { max: 0, min: 0, sum: 0, avg: 0, median: 0, p95: 0, count: 0 }
347
+ }
348
+
300
349
  client.gauge(`${name}.min`, stats.min, tags)
301
350
  client.gauge(`${name}.max`, stats.max, tags)
302
351
  client.increment(`${name}.sum`, stats.sum, tags)
@@ -306,3 +355,57 @@ function histogram (name, stats, tags) {
306
355
  client.gauge(`${name}.median`, stats.median, tags)
307
356
  client.gauge(`${name}.95percentile`, stats.p95, tags)
308
357
  }
358
+
359
+ function startGCObserver () {
360
+ if (gcObserver || hasGCProfiler || !hasGCObserver) return
361
+
362
+ gcObserver = new PerformanceObserver(list => {
363
+ for (const entry of list.getEntries()) {
364
+ const type = gcType(entry.detail?.kind || entry.kind)
365
+
366
+ runtimeMetrics.histogram('runtime.node.gc.pause.by.type', entry.duration, `gc_type:${type}`)
367
+ runtimeMetrics.histogram('runtime.node.gc.pause', entry.duration)
368
+ }
369
+ })
370
+
371
+ gcObserver.observe({ type: 'gc' })
372
+ }
373
+
374
+ function startGCProfiler () {
375
+ if (gcProfiler || !hasGCProfiler) return
376
+
377
+ gcProfiler = new v8.GCProfiler()
378
+ gcProfiler.start()
379
+ }
380
+
381
+ function gcType (kind) {
382
+ if (NODE_MAJOR >= 22) {
383
+ switch (kind) {
384
+ case 1: return 'scavenge'
385
+ case 2: return 'minor_mark_sweep'
386
+ case 4: return 'mark_sweep_compact' // Deprecated, might be removed soon.
387
+ case 8: return 'incremental_marking'
388
+ case 16: return 'process_weak_callbacks'
389
+ case 31: return 'all'
390
+ }
391
+ } else if (NODE_MAJOR >= 18) {
392
+ switch (kind) {
393
+ case 1: return 'scavenge'
394
+ case 2: return 'minor_mark_compact'
395
+ case 4: return 'mark_sweep_compact'
396
+ case 8: return 'incremental_marking'
397
+ case 16: return 'process_weak_callbacks'
398
+ case 31: return 'all'
399
+ }
400
+ } else {
401
+ switch (kind) {
402
+ case 1: return 'scavenge'
403
+ case 2: return 'mark_sweep_compact'
404
+ case 4: return 'incremental_marking'
405
+ case 8: return 'process_weak_callbacks'
406
+ case 15: return 'all'
407
+ }
408
+ }
409
+
410
+ return 'unknown'
411
+ }
@@ -23,7 +23,7 @@ function maybeStartServerlessMiniAgent (config) {
23
23
  try {
24
24
  require('child_process').spawn(rustBinaryPath, { stdio: 'inherit' })
25
25
  } catch (err) {
26
- log.error(`Error spawning mini agent process: ${err}`)
26
+ log.error('Error spawning mini agent process: %s', err.message)
27
27
  }
28
28
  }
29
29
 
@@ -3,7 +3,7 @@ const { identityService } = require('../util')
3
3
  const serverless = {
4
4
  server: {
5
5
  'azure-functions': {
6
- opName: () => 'azure-functions.invoke',
6
+ opName: () => 'azure.functions.invoke',
7
7
  serviceName: identityService
8
8
  }
9
9
  }
@@ -3,7 +3,7 @@ const { identityService } = require('../util')
3
3
  const serverless = {
4
4
  server: {
5
5
  'azure-functions': {
6
- opName: () => 'azure-functions.invoke',
6
+ opName: () => 'azure.functions.invoke',
7
7
  serviceName: identityService
8
8
  }
9
9
  }
@@ -87,22 +87,22 @@ class SpanProcessor {
87
87
  const id = context.toSpanId()
88
88
 
89
89
  if (finished.has(span)) {
90
- log.error(`Span was already finished in the same trace: ${span}`)
90
+ log.error('Span was already finished in the same trace: %s', span)
91
91
  } else {
92
92
  finished.add(span)
93
93
 
94
94
  if (finishedIds.has(id)) {
95
- log.error(`Another span with the same ID was already finished in the same trace: ${span}`)
95
+ log.error('Another span with the same ID was already finished in the same trace: %s', span)
96
96
  } else {
97
97
  finishedIds.add(id)
98
98
  }
99
99
 
100
100
  if (context._trace !== trace) {
101
- log.error(`A span was finished in the wrong trace: ${span}.`)
101
+ log.error('A span was finished in the wrong trace: %s', span)
102
102
  }
103
103
 
104
104
  if (finishedSpans.has(span)) {
105
- log.error(`Span was already finished in a different trace: ${span}`)
105
+ log.error('Span was already finished in a different trace: %s', span)
106
106
  } else {
107
107
  finishedSpans.add(span)
108
108
  }
@@ -114,35 +114,35 @@ class SpanProcessor {
114
114
  const id = context.toSpanId()
115
115
 
116
116
  if (started.has(span)) {
117
- log.error(`Span was already started in the same trace: ${span}`)
117
+ log.error('Span was already started in the same trace: %s', span)
118
118
  } else {
119
119
  started.add(span)
120
120
 
121
121
  if (startedIds.has(id)) {
122
- log.error(`Another span with the same ID was already started in the same trace: ${span}`)
122
+ log.error('Another span with the same ID was already started in the same trace: %s', span)
123
123
  } else {
124
124
  startedIds.add(id)
125
125
  }
126
126
 
127
127
  if (context._trace !== trace) {
128
- log.error(`A span was started in the wrong trace: ${span}.`)
128
+ log.error('A span was started in the wrong trace: %s', span)
129
129
  }
130
130
 
131
131
  if (startedSpans.has(span)) {
132
- log.error(`Span was already started in a different trace: ${span}`)
132
+ log.error('Span was already started in a different trace: %s', span)
133
133
  } else {
134
134
  startedSpans.add(span)
135
135
  }
136
136
  }
137
137
 
138
138
  if (!finished.has(span)) {
139
- log.error(`Span started in one trace but was finished in another trace: ${span}`)
139
+ log.error('Span started in one trace but was finished in another trace: %s', span)
140
140
  }
141
141
  }
142
142
 
143
143
  for (const span of trace.finished) {
144
144
  if (!started.has(span)) {
145
- log.error(`Span finished in one trace but was started in another trace: ${span}`)
145
+ log.error('Span finished in one trace but was started in another trace: %s', span)
146
146
  }
147
147
  }
148
148
  }
@@ -44,7 +44,7 @@ function add (carrier, keyValuePairs, parseOtelTags = false) {
44
44
  Object.assign(carrier, keyValuePairs)
45
45
  }
46
46
  } catch (e) {
47
- log.error(e)
47
+ log.error('Error adding tags', e)
48
48
  }
49
49
  }
50
50
 
@@ -137,6 +137,7 @@ function appClosing () {
137
137
  sendData(config, application, host, reqType, payload)
138
138
  // We flush before shutting down.
139
139
  metricsManager.send(config, application, host)
140
+ telemetryLogger.send(config, application, host)
140
141
  }
141
142
 
142
143
  function onBeforeExit () {
@@ -40,6 +40,7 @@ function onErrorLog (msg) {
40
40
 
41
41
  const telLog = {
42
42
  level: 'ERROR',
43
+ count: 1,
43
44
 
44
45
  // existing log.error(err) without message will be reported as 'Generic Error'
45
46
  message: message ?? 'Generic Error'
@@ -47,8 +48,7 @@ function onErrorLog (msg) {
47
48
 
48
49
  if (cause) {
49
50
  telLog.stack_trace = cause.stack
50
- const errorType = cause.name ?? 'Error'
51
- telLog.message = `${errorType}: ${telLog.message}`
51
+ telLog.errorType = cause.constructor.name
52
52
  }
53
53
 
54
54
  onLog(telLog)
@@ -3,7 +3,7 @@
3
3
  const log = require('../../log')
4
4
  const { calculateDDBasePath } = require('../../util')
5
5
 
6
- const logs = new Map()
6
+ const logs = new Map() // hash -> log
7
7
 
8
8
  // NOTE: Is this a reasonable number?
9
9
  let maxEntries = 10000
@@ -47,8 +47,14 @@ function sanitize (logEntry) {
47
47
  .filter((line, index) => (isDDCode && index < firstIndex) || line.includes(ddBasePath))
48
48
  .map(line => line.replace(ddBasePath, ''))
49
49
 
50
+ if (!isDDCode && logEntry.errorType && stackLines.length) {
51
+ stackLines = [`${logEntry.errorType}: redacted`, ...stackLines]
52
+ }
53
+
54
+ delete logEntry.errorType
55
+
50
56
  logEntry.stack_trace = stackLines.join(EOL)
51
- if (logEntry.stack_trace === '' && !logEntry.message) {
57
+ if (logEntry.stack_trace === '' && (!logEntry.message || logEntry.message === 'Generic Error')) {
52
58
  // If entire stack was removed and there is no message we'd rather not log it at all.
53
59
  return null
54
60
  }
@@ -75,6 +81,8 @@ const logCollector = {
75
81
  if (!logs.has(hash)) {
76
82
  logs.set(hash, logEntry)
77
83
  return true
84
+ } else {
85
+ logs.get(hash).count++
78
86
  }
79
87
  } catch (e) {
80
88
  log.error('Unable to add log to logCollector: %s', e.message)
@@ -57,7 +57,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
57
57
  try {
58
58
  url = url || new URL(getAgentlessTelemetryEndpoint(config.site))
59
59
  } catch (err) {
60
- log.error(err)
60
+ log.error('Telemetry endpoint url is invalid', err)
61
61
  // No point to do the request if the URL is invalid
62
62
  return cb(err, { payload, reqType })
63
63
  }
@@ -100,7 +100,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
100
100
  path: '/api/v2/apmtelemetry'
101
101
  }
102
102
  if (backendUrl) {
103
- request(data, backendOptions, (error) => { log.error(error) })
103
+ request(data, backendOptions, (error) => { log.error('Error sending telemetry data', error) })
104
104
  } else {
105
105
  log.error('Invalid Telemetry URL')
106
106
  }
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const crypto = require('crypto')
4
3
  const path = require('path')
5
4
 
6
5
  function isTrue (str) {
@@ -25,6 +24,8 @@ function isError (value) {
25
24
 
26
25
  // Matches a glob pattern to a given subject string
27
26
  function globMatch (pattern, subject) {
27
+ if (typeof pattern === 'string') pattern = pattern.toLowerCase()
28
+ if (typeof subject === 'string') subject = subject.toLowerCase()
28
29
  let px = 0 // [p]attern inde[x]
29
30
  let sx = 0 // [s]ubject inde[x]
30
31
  let nextPx = 0
@@ -64,6 +65,8 @@ function globMatch (pattern, subject) {
64
65
  return true
65
66
  }
66
67
 
68
+ // TODO: this adds stack traces relative to packages/
69
+ // shouldn't paths be relative to the root of dd-trace?
67
70
  function calculateDDBasePath (dirname) {
68
71
  const dirSteps = dirname.split(path.sep)
69
72
  const packagesIndex = dirSteps.lastIndexOf('packages')
@@ -74,25 +77,11 @@ function hasOwn (object, prop) {
74
77
  return Object.prototype.hasOwnProperty.call(object, prop)
75
78
  }
76
79
 
77
- /**
78
- * Generates a unique hash from an array of strings by joining them with | before hashing.
79
- * Used to uniquely identify AWS requests for span pointers.
80
- * @param {string[]} components - Array of strings to hash
81
- * @returns {string} A 32-character hash uniquely identifying the components
82
- */
83
- function generatePointerHash (components) {
84
- // If passing S3's ETag as a component, make sure any quotes have already been removed!
85
- const dataToHash = components.join('|')
86
- const hash = crypto.createHash('sha256').update(dataToHash).digest('hex')
87
- return hash.substring(0, 32)
88
- }
89
-
90
80
  module.exports = {
91
81
  isTrue,
92
82
  isFalse,
93
83
  isError,
94
84
  globMatch,
95
85
  calculateDDBasePath,
96
- hasOwn,
97
- generatePointerHash
86
+ hasOwn
98
87
  }
@@ -1,24 +0,0 @@
1
- 'use strict'
2
-
3
- const { addHook, channel } = require('./helpers/instrument')
4
- const shimmer = require('../../datadog-shimmer')
5
-
6
- const qsParseCh = channel('datadog:qs:parse:finish')
7
-
8
- function wrapParse (originalParse) {
9
- return function () {
10
- const qsParsedObj = originalParse.apply(this, arguments)
11
- if (qsParseCh.hasSubscribers && qsParsedObj) {
12
- qsParseCh.publish({ qs: qsParsedObj })
13
- }
14
- return qsParsedObj
15
- }
16
- }
17
-
18
- addHook({
19
- name: 'qs',
20
- versions: ['>=1']
21
- }, qs => {
22
- shimmer.wrap(qs, 'parse', wrapParse)
23
- return qs
24
- })
@@ -1,86 +0,0 @@
1
- 'use strict'
2
-
3
- const dc = require('dc-polyfill')
4
- const log = require('../../log')
5
-
6
- const telemetryLog = dc.channel('datadog:telemetry:log')
7
-
8
- function getTelemetryLog (data, level) {
9
- try {
10
- data = typeof data === 'function' ? data() : data
11
-
12
- let message
13
- if (typeof data !== 'object' || !data) {
14
- message = String(data)
15
- } else {
16
- message = String(data.message || data)
17
- }
18
-
19
- const logEntry = {
20
- message,
21
- level
22
- }
23
- if (data.stack) {
24
- logEntry.stack_trace = data.stack
25
- }
26
- return logEntry
27
- } catch (e) {
28
- log.error(e)
29
- }
30
- }
31
-
32
- const iastLog = {
33
- debug (data) {
34
- log.debug(data)
35
- return this
36
- },
37
-
38
- info (data) {
39
- log.info(data)
40
- return this
41
- },
42
-
43
- warn (data) {
44
- log.warn(data)
45
- return this
46
- },
47
-
48
- error (data) {
49
- log.error(data)
50
- return this
51
- },
52
-
53
- publish (data, level) {
54
- if (telemetryLog.hasSubscribers) {
55
- telemetryLog.publish(getTelemetryLog(data, level))
56
- }
57
- return this
58
- },
59
-
60
- debugAndPublish (data) {
61
- this.debug(data)
62
- return this.publish(data, 'DEBUG')
63
- },
64
-
65
- /**
66
- * forward 'INFO' log level to 'DEBUG' telemetry log level
67
- * see also {@link ../../telemetry/logs#isLevelEnabled } method
68
- */
69
- infoAndPublish (data) {
70
- this.info(data)
71
- return this.publish(data, 'DEBUG')
72
- },
73
-
74
- warnAndPublish (data) {
75
- this.warn(data)
76
- return this.publish(data, 'WARN')
77
- },
78
-
79
- errorAndPublish (data) {
80
- this.error(data)
81
- // publish is done automatically by log.error()
82
- return this
83
- }
84
- }
85
-
86
- module.exports = iastLog
@@ -1,110 +0,0 @@
1
- 'use strict'
2
-
3
- const log = require('../log')
4
- const { trackEvent } = require('./sdk/track_event')
5
- const { setUserTags } = require('./sdk/set_user')
6
-
7
- const UUID_PATTERN = '^[0-9A-F]{8}-[0-9A-F]{4}-[1-5][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$'
8
- const regexUsername = new RegExp(UUID_PATTERN, 'i')
9
-
10
- const SDK_USER_EVENT_PATTERN = '^_dd\\.appsec\\.events\\.users\\.[\\W\\w+]+\\.sdk$'
11
- const regexSdkEvent = new RegExp(SDK_USER_EVENT_PATTERN, 'i')
12
-
13
- function isSdkCalled (tags) {
14
- let called = false
15
-
16
- if (tags !== null && typeof tags === 'object') {
17
- called = Object.entries(tags).some(([key, value]) => regexSdkEvent.test(key) && value === 'true')
18
- }
19
-
20
- return called
21
- }
22
-
23
- // delete this function later if we know it's always credential.username
24
- function getLogin (credentials) {
25
- const type = credentials && credentials.type
26
- let login
27
- if (type === 'local' || type === 'http') {
28
- login = credentials.username
29
- }
30
-
31
- return login
32
- }
33
-
34
- function parseUser (login, passportUser, mode) {
35
- const user = {
36
- 'usr.id': login
37
- }
38
-
39
- if (!user['usr.id']) {
40
- return user
41
- }
42
-
43
- if (passportUser) {
44
- // Guess id
45
- if (passportUser.id) {
46
- user['usr.id'] = passportUser.id
47
- } else if (passportUser._id) {
48
- user['usr.id'] = passportUser._id
49
- }
50
-
51
- if (mode === 'extended') {
52
- if (login) {
53
- user['usr.login'] = login
54
- }
55
-
56
- if (passportUser.email) {
57
- user['usr.email'] = passportUser.email
58
- }
59
-
60
- // Guess username
61
- if (passportUser.username) {
62
- user['usr.username'] = passportUser.username
63
- } else if (passportUser.name) {
64
- user['usr.username'] = passportUser.name
65
- }
66
- }
67
- }
68
-
69
- if (mode === 'safe') {
70
- // Remove PII in safe mode
71
- if (!regexUsername.test(user['usr.id'])) {
72
- user['usr.id'] = ''
73
- }
74
- }
75
-
76
- return user
77
- }
78
-
79
- function passportTrackEvent (credentials, passportUser, rootSpan, mode) {
80
- const tags = rootSpan && rootSpan.context() && rootSpan.context()._tags
81
-
82
- if (isSdkCalled(tags)) {
83
- // Don't overwrite tags set by SDK callings
84
- return
85
- }
86
- const user = parseUser(getLogin(credentials), passportUser, mode)
87
-
88
- if (user['usr.id'] === undefined) {
89
- log.warn('No user ID found in authentication instrumentation')
90
- return
91
- }
92
-
93
- if (passportUser) {
94
- // If a passportUser object is published then the login succeded
95
- const userTags = {}
96
- Object.entries(user).forEach(([k, v]) => {
97
- const attr = k.split('.', 2)[1]
98
- userTags[attr] = v
99
- })
100
-
101
- setUserTags(userTags, rootSpan)
102
- trackEvent('users.login.success', null, 'passportTrackEvent', rootSpan, mode)
103
- } else {
104
- trackEvent('users.login.failure', user, 'passportTrackEvent', rootSpan, mode)
105
- }
106
- }
107
-
108
- module.exports = {
109
- passportTrackEvent
110
- }