dd-trace 5.24.0 → 5.26.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 (138) hide show
  1. package/LICENSE-3rdparty.csv +3 -0
  2. package/index.d.ts +345 -8
  3. package/init.js +60 -47
  4. package/package.json +16 -7
  5. package/packages/datadog-code-origin/index.js +4 -4
  6. package/packages/datadog-core/index.js +1 -3
  7. package/packages/datadog-core/src/storage.js +21 -0
  8. package/packages/datadog-core/src/utils/src/parse-tags.js +33 -0
  9. package/packages/datadog-esbuild/index.js +4 -2
  10. package/packages/datadog-instrumentations/src/amqplib.js +65 -5
  11. package/packages/datadog-instrumentations/src/child_process.js +135 -27
  12. package/packages/datadog-instrumentations/src/express.js +1 -1
  13. package/packages/datadog-instrumentations/src/handlebars.js +40 -0
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
  15. package/packages/datadog-instrumentations/src/helpers/register.js +9 -0
  16. package/packages/datadog-instrumentations/src/jest.js +6 -2
  17. package/packages/datadog-instrumentations/src/kafkajs.js +123 -63
  18. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -2
  19. package/packages/datadog-instrumentations/src/multer.js +37 -0
  20. package/packages/datadog-instrumentations/src/openai.js +2 -2
  21. package/packages/datadog-instrumentations/src/pug.js +23 -0
  22. package/packages/datadog-instrumentations/src/router.js +2 -3
  23. package/packages/datadog-instrumentations/src/url.js +84 -0
  24. package/packages/datadog-instrumentations/src/utils/src/extract-package-and-module-path.js +7 -4
  25. package/packages/datadog-plugin-amqplib/src/consumer.js +6 -5
  26. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -0
  27. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  28. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +10 -7
  29. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +35 -0
  30. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +11 -9
  31. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +59 -45
  32. package/packages/datadog-plugin-cypress/src/support.js +1 -0
  33. package/packages/datadog-plugin-fastify/src/code_origin.js +2 -2
  34. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +10 -2
  35. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +8 -0
  36. package/packages/datadog-plugin-grpc/src/client.js +3 -0
  37. package/packages/datadog-plugin-grpc/src/server.js +5 -1
  38. package/packages/datadog-plugin-http/src/client.js +42 -1
  39. package/packages/datadog-plugin-http2/src/client.js +26 -1
  40. package/packages/datadog-plugin-jest/src/index.js +2 -1
  41. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +6 -3
  42. package/packages/datadog-plugin-kafkajs/src/consumer.js +10 -5
  43. package/packages/datadog-plugin-kafkajs/src/producer.js +10 -4
  44. package/packages/datadog-plugin-mocha/src/index.js +5 -2
  45. package/packages/datadog-plugin-moleculer/src/server.js +2 -2
  46. package/packages/datadog-plugin-openai/src/index.js +9 -1015
  47. package/packages/datadog-plugin-openai/src/tracing.js +1023 -0
  48. package/packages/datadog-plugin-rhea/src/consumer.js +2 -1
  49. package/packages/datadog-plugin-vitest/src/index.js +2 -1
  50. package/packages/dd-trace/src/appsec/addresses.js +2 -0
  51. package/packages/dd-trace/src/appsec/api_security_sampler.js +50 -27
  52. package/packages/dd-trace/src/appsec/channels.js +3 -1
  53. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  54. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +33 -16
  55. package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +18 -0
  56. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +55 -7
  57. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -2
  58. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  59. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -2
  60. package/packages/dd-trace/src/appsec/index.js +9 -6
  61. package/packages/dd-trace/src/appsec/rasp/command_injection.js +49 -0
  62. package/packages/dd-trace/src/appsec/rasp/index.js +3 -0
  63. package/packages/dd-trace/src/appsec/rasp/ssrf.js +4 -3
  64. package/packages/dd-trace/src/appsec/rasp/utils.js +3 -2
  65. package/packages/dd-trace/src/appsec/recommended.json +354 -158
  66. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  67. package/packages/dd-trace/src/appsec/remote_config/index.js +2 -7
  68. package/packages/dd-trace/src/appsec/reporter.js +6 -4
  69. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -3
  70. package/packages/dd-trace/src/appsec/waf/waf_manager.js +4 -0
  71. package/packages/dd-trace/src/azure_metadata.js +120 -0
  72. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +97 -0
  73. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +90 -0
  74. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +19 -1
  75. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +53 -0
  76. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +8 -1
  77. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +43 -0
  78. package/packages/dd-trace/src/config.js +88 -10
  79. package/packages/dd-trace/src/constants.js +8 -1
  80. package/packages/dd-trace/src/crashtracking/crashtracker.js +98 -0
  81. package/packages/dd-trace/src/crashtracking/index.js +15 -0
  82. package/packages/dd-trace/src/crashtracking/noop.js +8 -0
  83. package/packages/dd-trace/src/datastreams/pathway.js +1 -0
  84. package/packages/dd-trace/src/debugger/devtools_client/index.js +9 -13
  85. package/packages/dd-trace/src/debugger/devtools_client/send.js +15 -1
  86. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +57 -23
  87. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +12 -2
  88. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +31 -20
  89. package/packages/dd-trace/src/debugger/devtools_client/snapshot/symbols.js +6 -0
  90. package/packages/dd-trace/src/debugger/devtools_client/state.js +11 -2
  91. package/packages/dd-trace/src/debugger/index.js +10 -3
  92. package/packages/dd-trace/src/llmobs/constants/tags.js +34 -0
  93. package/packages/dd-trace/src/llmobs/constants/text.js +6 -0
  94. package/packages/dd-trace/src/llmobs/constants/writers.js +13 -0
  95. package/packages/dd-trace/src/llmobs/index.js +103 -0
  96. package/packages/dd-trace/src/llmobs/noop.js +82 -0
  97. package/packages/dd-trace/src/llmobs/plugins/base.js +65 -0
  98. package/packages/dd-trace/src/llmobs/plugins/openai.js +205 -0
  99. package/packages/dd-trace/src/llmobs/sdk.js +377 -0
  100. package/packages/dd-trace/src/llmobs/span_processor.js +195 -0
  101. package/packages/dd-trace/src/llmobs/storage.js +7 -0
  102. package/packages/dd-trace/src/llmobs/tagger.js +322 -0
  103. package/packages/dd-trace/src/llmobs/util.js +176 -0
  104. package/packages/dd-trace/src/llmobs/writers/base.js +111 -0
  105. package/packages/dd-trace/src/llmobs/writers/evaluations.js +29 -0
  106. package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +23 -0
  107. package/packages/dd-trace/src/llmobs/writers/spans/agentless.js +17 -0
  108. package/packages/dd-trace/src/llmobs/writers/spans/base.js +52 -0
  109. package/packages/dd-trace/src/log/index.js +10 -13
  110. package/packages/dd-trace/src/log/log.js +52 -0
  111. package/packages/dd-trace/src/log/writer.js +50 -19
  112. package/packages/dd-trace/src/noop/proxy.js +3 -0
  113. package/packages/dd-trace/src/noop/span.js +4 -0
  114. package/packages/dd-trace/src/opentelemetry/span.js +16 -1
  115. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -0
  116. package/packages/dd-trace/src/opentracing/propagation/text_map.js +106 -32
  117. package/packages/dd-trace/src/opentracing/span.js +26 -0
  118. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  119. package/packages/dd-trace/src/opentracing/tracer.js +8 -1
  120. package/packages/dd-trace/src/payload-tagging/config/aws.json +71 -3
  121. package/packages/dd-trace/src/plugins/outbound.js +9 -0
  122. package/packages/dd-trace/src/plugins/tracing.js +3 -3
  123. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +121 -0
  124. package/packages/dd-trace/src/plugins/util/ip_extractor.js +0 -1
  125. package/packages/dd-trace/src/plugins/util/web.js +39 -11
  126. package/packages/dd-trace/src/priority_sampler.js +16 -0
  127. package/packages/dd-trace/src/profiling/config.js +3 -1
  128. package/packages/dd-trace/src/profiling/exporters/agent.js +7 -5
  129. package/packages/dd-trace/src/profiling/profilers/wall.js +2 -1
  130. package/packages/dd-trace/src/proxy.js +13 -1
  131. package/packages/dd-trace/src/span_processor.js +5 -0
  132. package/packages/dd-trace/src/telemetry/index.js +11 -1
  133. package/packages/dd-trace/src/telemetry/logs/index.js +16 -11
  134. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -8
  135. package/packages/dd-trace/src/telemetry/metrics.js +6 -1
  136. package/packages/dd-trace/src/util.js +16 -1
  137. package/version.js +4 -2
  138. /package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/{code-injection-sensitive-analyzer.js → tainted-range-based-sensitive-analyzer.js} +0 -0
@@ -0,0 +1,111 @@
1
+ 'use strict'
2
+
3
+ const request = require('../../exporters/common/request')
4
+ const { URL, format } = require('url')
5
+
6
+ const logger = require('../../log')
7
+
8
+ const { encodeUnicode } = require('../util')
9
+ const log = require('../../log')
10
+
11
+ class BaseLLMObsWriter {
12
+ constructor ({ interval, timeout, endpoint, intake, eventType, protocol, port }) {
13
+ this._interval = interval || 1000 // 1s
14
+ this._timeout = timeout || 5000 // 5s
15
+ this._eventType = eventType
16
+
17
+ this._buffer = []
18
+ this._bufferLimit = 1000
19
+ this._bufferSize = 0
20
+
21
+ this._url = new URL(format({
22
+ protocol: protocol || 'https:',
23
+ hostname: intake,
24
+ port: port || 443,
25
+ pathname: endpoint
26
+ }))
27
+
28
+ this._headers = {
29
+ 'Content-Type': 'application/json'
30
+ }
31
+
32
+ this._periodic = setInterval(() => {
33
+ this.flush()
34
+ }, this._interval).unref()
35
+
36
+ process.once('beforeExit', () => {
37
+ this.destroy()
38
+ })
39
+
40
+ this._destroyed = false
41
+
42
+ logger.debug(`Started ${this.constructor.name} to ${this._url}`)
43
+ }
44
+
45
+ append (event, byteLength) {
46
+ if (this._buffer.length >= this._bufferLimit) {
47
+ logger.warn(`${this.constructor.name} event buffer full (limit is ${this._bufferLimit}), dropping event`)
48
+ return
49
+ }
50
+
51
+ this._bufferSize += byteLength || Buffer.from(JSON.stringify(event)).byteLength
52
+ this._buffer.push(event)
53
+ }
54
+
55
+ flush () {
56
+ if (this._buffer.length === 0) {
57
+ return
58
+ }
59
+
60
+ const events = this._buffer
61
+ this._buffer = []
62
+ this._bufferSize = 0
63
+ const payload = this._encode(this.makePayload(events))
64
+
65
+ const options = {
66
+ headers: this._headers,
67
+ method: 'POST',
68
+ url: this._url,
69
+ timeout: this._timeout
70
+ }
71
+
72
+ log.debug(`Encoded LLMObs payload: ${payload}`)
73
+
74
+ request(payload, options, (err, resp, code) => {
75
+ if (err) {
76
+ logger.error(
77
+ `Error sending ${events.length} LLMObs ${this._eventType} events to ${this._url}: ${err.message}`
78
+ )
79
+ } else if (code >= 300) {
80
+ logger.error(
81
+ `Error sending ${events.length} LLMObs ${this._eventType} events to ${this._url}: ${code}`
82
+ )
83
+ } else {
84
+ logger.debug(`Sent ${events.length} LLMObs ${this._eventType} events to ${this._url}`)
85
+ }
86
+ })
87
+ }
88
+
89
+ makePayload (events) {}
90
+
91
+ destroy () {
92
+ if (!this._destroyed) {
93
+ logger.debug(`Stopping ${this.constructor.name}`)
94
+ clearInterval(this._periodic)
95
+ process.removeListener('beforeExit', this.destroy)
96
+ this.flush()
97
+ this._destroyed = true
98
+ }
99
+ }
100
+
101
+ _encode (payload) {
102
+ return JSON.stringify(payload, (key, value) => {
103
+ if (typeof value === 'string') {
104
+ return encodeUnicode(value) // serialize unicode characters
105
+ }
106
+ return value
107
+ }).replace(/\\\\u/g, '\\u') // remove double escaping
108
+ }
109
+ }
110
+
111
+ module.exports = BaseLLMObsWriter
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ const { AGENTLESS_EVALULATIONS_ENDPOINT } = require('../constants/writers')
4
+ const BaseWriter = require('./base')
5
+
6
+ class LLMObsEvalMetricsWriter extends BaseWriter {
7
+ constructor (config) {
8
+ super({
9
+ endpoint: AGENTLESS_EVALULATIONS_ENDPOINT,
10
+ intake: `api.${config.site}`,
11
+ eventType: 'evaluation_metric'
12
+ })
13
+
14
+ this._headers['DD-API-KEY'] = config.apiKey
15
+ }
16
+
17
+ makePayload (events) {
18
+ return {
19
+ data: {
20
+ type: this._eventType,
21
+ attributes: {
22
+ metrics: events
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+
29
+ module.exports = LLMObsEvalMetricsWriter
@@ -0,0 +1,23 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ EVP_SUBDOMAIN_HEADER_NAME,
5
+ EVP_SUBDOMAIN_HEADER_VALUE,
6
+ EVP_PROXY_AGENT_ENDPOINT
7
+ } = require('../../constants/writers')
8
+ const LLMObsBaseSpanWriter = require('./base')
9
+
10
+ class LLMObsAgentProxySpanWriter extends LLMObsBaseSpanWriter {
11
+ constructor (config) {
12
+ super({
13
+ intake: config.hostname || 'localhost',
14
+ protocol: 'http:',
15
+ endpoint: EVP_PROXY_AGENT_ENDPOINT,
16
+ port: config.port
17
+ })
18
+
19
+ this._headers[EVP_SUBDOMAIN_HEADER_NAME] = EVP_SUBDOMAIN_HEADER_VALUE
20
+ }
21
+ }
22
+
23
+ module.exports = LLMObsAgentProxySpanWriter
@@ -0,0 +1,17 @@
1
+ 'use strict'
2
+
3
+ const { AGENTLESS_SPANS_ENDPOINT } = require('../../constants/writers')
4
+ const LLMObsBaseSpanWriter = require('./base')
5
+
6
+ class LLMObsAgentlessSpanWriter extends LLMObsBaseSpanWriter {
7
+ constructor (config) {
8
+ super({
9
+ intake: `llmobs-intake.${config.site}`,
10
+ endpoint: AGENTLESS_SPANS_ENDPOINT
11
+ })
12
+
13
+ this._headers['DD-API-KEY'] = config.apiKey
14
+ }
15
+ }
16
+
17
+ module.exports = LLMObsAgentlessSpanWriter
@@ -0,0 +1,52 @@
1
+ 'use strict'
2
+
3
+ const { EVP_EVENT_SIZE_LIMIT, EVP_PAYLOAD_SIZE_LIMIT } = require('../../constants/writers')
4
+ const { DROPPED_VALUE_TEXT } = require('../../constants/text')
5
+ const { DROPPED_IO_COLLECTION_ERROR } = require('../../constants/tags')
6
+ const BaseWriter = require('../base')
7
+ const logger = require('../../../log')
8
+
9
+ const tracerVersion = require('../../../../../../package.json').version
10
+
11
+ class LLMObsSpanWriter extends BaseWriter {
12
+ constructor (options) {
13
+ super({
14
+ ...options,
15
+ eventType: 'span'
16
+ })
17
+ }
18
+
19
+ append (event) {
20
+ const eventSizeBytes = Buffer.from(JSON.stringify(event)).byteLength
21
+ if (eventSizeBytes > EVP_EVENT_SIZE_LIMIT) {
22
+ logger.warn(`Dropping event input/output because its size (${eventSizeBytes}) exceeds the 1MB event size limit`)
23
+ event = this._truncateSpanEvent(event)
24
+ }
25
+
26
+ if (this._bufferSize + eventSizeBytes > EVP_PAYLOAD_SIZE_LIMIT) {
27
+ logger.debug('Flusing queue because queing next event will exceed EvP payload limit')
28
+ this.flush()
29
+ }
30
+
31
+ super.append(event, eventSizeBytes)
32
+ }
33
+
34
+ makePayload (events) {
35
+ return {
36
+ '_dd.stage': 'raw',
37
+ '_dd.tracer_version': tracerVersion,
38
+ event_type: this._eventType,
39
+ spans: events
40
+ }
41
+ }
42
+
43
+ _truncateSpanEvent (event) {
44
+ event.meta.input = { value: DROPPED_VALUE_TEXT }
45
+ event.meta.output = { value: DROPPED_VALUE_TEXT }
46
+
47
+ event.collection_errors = [DROPPED_IO_COLLECTION_ERROR]
48
+ return event
49
+ }
50
+ }
51
+
52
+ module.exports = LLMObsSpanWriter
@@ -4,6 +4,7 @@ const coalesce = require('koalas')
4
4
  const { isTrue } = require('../util')
5
5
  const { debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
6
6
  const logWriter = require('./writer')
7
+ const { Log } = require('./log')
7
8
 
8
9
  const memoize = func => {
9
10
  const cache = {}
@@ -18,10 +19,6 @@ const memoize = func => {
18
19
  return memoized
19
20
  }
20
21
 
21
- function processMsg (msg) {
22
- return typeof msg === 'function' ? msg() : msg
23
- }
24
-
25
22
  const config = {
26
23
  enabled: false,
27
24
  logger: undefined,
@@ -52,37 +49,37 @@ const log = {
52
49
  reset () {
53
50
  logWriter.reset()
54
51
  this._deprecate = memoize((code, message) => {
55
- errorChannel.publish(message)
52
+ errorChannel.publish(Log.parse(message))
56
53
  return true
57
54
  })
58
55
 
59
56
  return this
60
57
  },
61
58
 
62
- debug (message) {
59
+ debug (...args) {
63
60
  if (debugChannel.hasSubscribers) {
64
- debugChannel.publish(processMsg(message))
61
+ debugChannel.publish(Log.parse(...args))
65
62
  }
66
63
  return this
67
64
  },
68
65
 
69
- info (message) {
66
+ info (...args) {
70
67
  if (infoChannel.hasSubscribers) {
71
- infoChannel.publish(processMsg(message))
68
+ infoChannel.publish(Log.parse(...args))
72
69
  }
73
70
  return this
74
71
  },
75
72
 
76
- warn (message) {
73
+ warn (...args) {
77
74
  if (warnChannel.hasSubscribers) {
78
- warnChannel.publish(processMsg(message))
75
+ warnChannel.publish(Log.parse(...args))
79
76
  }
80
77
  return this
81
78
  },
82
79
 
83
- error (err) {
80
+ error (...args) {
84
81
  if (errorChannel.hasSubscribers) {
85
- errorChannel.publish(processMsg(err))
82
+ errorChannel.publish(Log.parse(...args))
86
83
  }
87
84
  return this
88
85
  },
@@ -0,0 +1,52 @@
1
+ 'use strict'
2
+
3
+ const { format } = require('util')
4
+
5
+ class Log {
6
+ constructor (message, args, cause, delegate) {
7
+ this.message = message
8
+ this.args = args
9
+ this.cause = cause
10
+ this.delegate = delegate
11
+ }
12
+
13
+ get formatted () {
14
+ const { message, args } = this
15
+
16
+ let formatted = message
17
+ if (message && args && args.length) {
18
+ formatted = format(message, ...args)
19
+ }
20
+ return formatted
21
+ }
22
+
23
+ static parse (...args) {
24
+ let message, cause, delegate
25
+
26
+ const lastArg = args[args.length - 1]
27
+ if (lastArg && typeof lastArg === 'object' && lastArg.stack) { // lastArg instanceof Error?
28
+ cause = args.pop()
29
+ }
30
+
31
+ const firstArg = args.shift()
32
+ if (firstArg) {
33
+ if (typeof firstArg === 'string') {
34
+ message = firstArg
35
+ } else if (typeof firstArg === 'object') {
36
+ message = String(firstArg.message || firstArg)
37
+ } else if (typeof firstArg === 'function') {
38
+ delegate = firstArg
39
+ } else {
40
+ message = String(firstArg)
41
+ }
42
+ } else if (!cause) {
43
+ message = String(firstArg)
44
+ }
45
+
46
+ return new Log(message, args, cause, delegate)
47
+ }
48
+ }
49
+
50
+ module.exports = {
51
+ Log
52
+ }
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { storage } = require('../../../datadog-core')
4
4
  const { LogChannel } = require('./channels')
5
+ const { Log } = require('./log')
5
6
  const defaultLogger = {
6
7
  debug: msg => console.debug(msg), /* eslint-disable-line no-console */
7
8
  info: msg => console.info(msg), /* eslint-disable-line no-console */
@@ -22,7 +23,7 @@ function withNoop (fn) {
22
23
  }
23
24
 
24
25
  function unsubscribeAll () {
25
- logChannel.unsubscribe({ debug, info, warn, error })
26
+ logChannel.unsubscribe({ debug: onDebug, info: onInfo, warn: onWarn, error: onError })
26
27
  }
27
28
 
28
29
  function toggleSubscription (enable, level) {
@@ -30,7 +31,7 @@ function toggleSubscription (enable, level) {
30
31
 
31
32
  if (enable) {
32
33
  logChannel = new LogChannel(level)
33
- logChannel.subscribe({ debug, info, warn, error })
34
+ logChannel.subscribe({ debug: onDebug, info: onInfo, warn: onWarn, error: onError })
34
35
  }
35
36
  }
36
37
 
@@ -51,32 +52,62 @@ function reset () {
51
52
  toggleSubscription(false)
52
53
  }
53
54
 
54
- function error (err) {
55
- if (typeof err !== 'object' || !err) {
56
- err = String(err)
57
- } else if (!err.stack) {
58
- err = String(err.message || err)
55
+ function getErrorLog (err) {
56
+ if (err && typeof err.delegate === 'function') {
57
+ const result = err.delegate()
58
+ return Array.isArray(result) ? Log.parse(...result) : Log.parse(result)
59
+ } else {
60
+ return err
59
61
  }
62
+ }
60
63
 
61
- if (typeof err === 'string') {
62
- err = new Error(err)
63
- }
64
+ function onError (err) {
65
+ const { formatted, cause } = getErrorLog(err)
66
+
67
+ // calling twice logger.error() because Error cause is only available in nodejs v16.9.0
68
+ // TODO: replace it with Error(message, { cause }) when cause has broad support
69
+ if (formatted) withNoop(() => logger.error(new Error(formatted)))
70
+ if (cause) withNoop(() => logger.error(cause))
71
+ }
72
+
73
+ function onWarn (log) {
74
+ const { formatted, cause } = getErrorLog(log)
75
+ if (formatted) withNoop(() => logger.warn(formatted))
76
+ if (cause) withNoop(() => logger.warn(cause))
77
+ }
64
78
 
65
- withNoop(() => logger.error(err))
79
+ function onInfo (log) {
80
+ const { formatted, cause } = getErrorLog(log)
81
+ if (formatted) withNoop(() => logger.info(formatted))
82
+ if (cause) withNoop(() => logger.info(cause))
66
83
  }
67
84
 
68
- function warn (message) {
69
- if (!logger.warn) return debug(message)
70
- withNoop(() => logger.warn(message))
85
+ function onDebug (log) {
86
+ const { formatted, cause } = getErrorLog(log)
87
+ if (formatted) withNoop(() => logger.debug(formatted))
88
+ if (cause) withNoop(() => logger.debug(cause))
71
89
  }
72
90
 
73
- function info (message) {
74
- if (!logger.info) return debug(message)
75
- withNoop(() => logger.info(message))
91
+ function error (...args) {
92
+ onError(Log.parse(...args))
93
+ }
94
+
95
+ function warn (...args) {
96
+ const log = Log.parse(...args)
97
+ if (!logger.warn) return onDebug(log)
98
+
99
+ onWarn(log)
100
+ }
101
+
102
+ function info (...args) {
103
+ const log = Log.parse(...args)
104
+ if (!logger.info) return onDebug(log)
105
+
106
+ onInfo(log)
76
107
  }
77
108
 
78
- function debug (message) {
79
- withNoop(() => logger.debug(message))
109
+ function debug (...args) {
110
+ onDebug(Log.parse(...args))
80
111
  }
81
112
 
82
113
  module.exports = { use, toggle, reset, error, warn, info, debug }
@@ -3,16 +3,19 @@
3
3
  const NoopTracer = require('./tracer')
4
4
  const NoopAppsecSdk = require('../appsec/sdk/noop')
5
5
  const NoopDogStatsDClient = require('./dogstatsd')
6
+ const NoopLLMObsSDK = require('../llmobs/noop')
6
7
 
7
8
  const noop = new NoopTracer()
8
9
  const noopAppsec = new NoopAppsecSdk()
9
10
  const noopDogStatsDClient = new NoopDogStatsDClient()
11
+ const noopLLMObs = new NoopLLMObsSDK(noop)
10
12
 
11
13
  class Tracer {
12
14
  constructor () {
13
15
  this._tracer = noop
14
16
  this.appsec = noopAppsec
15
17
  this.dogstatsd = noopDogStatsDClient
18
+ this.llmobs = noopLLMObs
16
19
  }
17
20
 
18
21
  init () {
@@ -16,9 +16,13 @@ class NoopSpan {
16
16
  setOperationName (name) { return this }
17
17
  setBaggageItem (key, value) { return this }
18
18
  getBaggageItem (key) {}
19
+ getAllBaggageItems () {}
20
+ removeBaggageItem (key) { return this }
21
+ removeAllBaggageItems () { return this }
19
22
  setTag (key, value) { return this }
20
23
  addTags (keyValueMap) { return this }
21
24
  addLink (link) { return this }
25
+ addSpanPointer (ptrKind, ptrDir, ptrHash) { return this }
22
26
  log () { return this }
23
27
  logEvent () {}
24
28
  finish (finishTime) {}
@@ -14,6 +14,7 @@ const { SERVICE_NAME, RESOURCE_NAME } = require('../../../../ext/tags')
14
14
  const kinds = require('../../../../ext/kinds')
15
15
 
16
16
  const SpanContext = require('./span_context')
17
+ const id = require('../id')
17
18
 
18
19
  // The one built into OTel rounds so we lose sub-millisecond precision.
19
20
  function hrTimeToMilliseconds (time) {
@@ -142,7 +143,7 @@ class Span {
142
143
  context: spanContext._ddContext,
143
144
  startTime,
144
145
  hostname: _tracer._hostname,
145
- integrationName: 'otel',
146
+ integrationName: parentTracer?._isOtelLibrary ? 'otel.library' : 'otel',
146
147
  tags: {
147
148
  [SERVICE_NAME]: _tracer._service,
148
149
  [RESOURCE_NAME]: spanName
@@ -217,6 +218,20 @@ class Span {
217
218
  return this
218
219
  }
219
220
 
221
+ addSpanPointer (ptrKind, ptrDir, ptrHash) {
222
+ const zeroContext = new SpanContext({
223
+ traceId: id('0'),
224
+ spanId: id('0')
225
+ })
226
+ const attributes = {
227
+ 'ptr.kind': ptrKind,
228
+ 'ptr.dir': ptrDir,
229
+ 'ptr.hash': ptrHash,
230
+ 'link.kind': 'span-pointer'
231
+ }
232
+ return this.addLink(zeroContext, attributes)
233
+ }
234
+
220
235
  setStatus ({ code, message }) {
221
236
  if (!this.ended && !this._hasStatus && code) {
222
237
  this._hasStatus = true
@@ -16,6 +16,7 @@ class Tracer {
16
16
  this._tracerProvider = tracerProvider
17
17
  // Is there a reason this is public?
18
18
  this.instrumentationLibrary = library
19
+ this._isOtelLibrary = library?.name?.startsWith('@opentelemetry/instrumentation-')
19
20
  this._spanLimits = {}
20
21
  }
21
22