dd-trace 5.60.0 → 5.61.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 (45) hide show
  1. package/index.d.ts +6 -0
  2. package/package.json +5 -8
  3. package/packages/datadog-code-origin/index.js +3 -0
  4. package/packages/datadog-instrumentations/src/azure-functions.js +5 -0
  5. package/packages/datadog-instrumentations/src/azure-service-bus.js +38 -0
  6. package/packages/datadog-instrumentations/src/fastify.js +17 -0
  7. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  8. package/packages/datadog-instrumentations/src/next.js +17 -18
  9. package/packages/datadog-instrumentations/src/sequelize.js +4 -14
  10. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +6 -38
  11. package/packages/datadog-plugin-azure-functions/src/index.js +57 -28
  12. package/packages/datadog-plugin-azure-service-bus/src/index.js +15 -0
  13. package/packages/datadog-plugin-azure-service-bus/src/producer.js +36 -0
  14. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +24 -23
  15. package/packages/datadog-plugin-langchain/src/handlers/default.js +0 -18
  16. package/packages/datadog-plugin-langchain/src/handlers/embedding.js +0 -48
  17. package/packages/datadog-plugin-langchain/src/handlers/language_models.js +18 -0
  18. package/packages/datadog-plugin-langchain/src/tracing.js +5 -17
  19. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +8 -1
  20. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +2 -2
  21. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +11 -10
  22. package/packages/dd-trace/src/appsec/iast/analyzers/set-cookies-header-interceptor.js +25 -18
  23. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -5
  24. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +5 -1
  25. package/packages/dd-trace/src/appsec/iast/analyzers/xcontenttype-header-missing-analyzer.js +2 -2
  26. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +4 -0
  27. package/packages/dd-trace/src/appsec/iast/index.js +25 -7
  28. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +79 -21
  29. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -3
  30. package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +0 -4
  31. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +4 -8
  32. package/packages/dd-trace/src/datastreams/schemas/schema_sampler.js +2 -4
  33. package/packages/dd-trace/src/plugins/index.js +1 -0
  34. package/packages/dd-trace/src/plugins/util/ci.js +8 -0
  35. package/packages/dd-trace/src/plugins/util/git.js +50 -15
  36. package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
  37. package/packages/dd-trace/src/profiling/profilers/space.js +4 -3
  38. package/packages/dd-trace/src/profiling/profilers/wall.js +5 -4
  39. package/packages/dd-trace/src/remote_config/scheduler.js +2 -1
  40. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +4 -0
  41. package/packages/dd-trace/src/supported-configurations.json +1 -0
  42. package/packages/datadog-plugin-langchain/src/handlers/chain.js +0 -50
  43. package/packages/datadog-plugin-langchain/src/handlers/language_models/chat_model.js +0 -101
  44. package/packages/datadog-plugin-langchain/src/handlers/language_models/index.js +0 -48
  45. package/packages/datadog-plugin-langchain/src/handlers/language_models/llm.js +0 -58
@@ -485,27 +485,41 @@ function getGitMetadata (ciMetadata) {
485
485
 
486
486
  if (headCommitSha) {
487
487
  if (isShallowRepository()) {
488
- unshallowRepository(true)
488
+ fetchHeadCommitSha(headCommitSha)
489
489
  }
490
490
 
491
- tags[GIT_COMMIT_HEAD_MESSAGE] =
492
- sanitizedExec('git', ['show', '-s', '--format=%B', headCommitSha], null, null, null, false)
493
-
494
491
  const [
492
+ gitHeadCommitSha,
493
+ headAuthorDate,
495
494
  headAuthorName,
496
495
  headAuthorEmail,
497
- headAuthorDate,
496
+ headCommitterDate,
498
497
  headCommitterName,
499
498
  headCommitterEmail,
500
- headCommitterDate
501
- ] = sanitizedExec('git', ['show', '-s', '--format=%an,%ae,%aI,%cn,%ce,%cI', headCommitSha]).split(',')
502
-
503
- tags[GIT_COMMIT_HEAD_AUTHOR_DATE] = headAuthorDate
504
- tags[GIT_COMMIT_HEAD_AUTHOR_EMAIL] = headAuthorEmail
505
- tags[GIT_COMMIT_HEAD_AUTHOR_NAME] = headAuthorName
506
- tags[GIT_COMMIT_HEAD_COMMITTER_DATE] = headCommitterDate
507
- tags[GIT_COMMIT_HEAD_COMMITTER_EMAIL] = headCommitterEmail
508
- tags[GIT_COMMIT_HEAD_COMMITTER_NAME] = headCommitterName
499
+ headCommitMessage
500
+ ] = sanitizedExec(
501
+ 'git',
502
+ [
503
+ 'show',
504
+ '-s',
505
+ '--format=\'%H","%aI","%an","%ae","%cI","%cn","%ce","%B\'',
506
+ headCommitSha
507
+ ],
508
+ null,
509
+ null,
510
+ null,
511
+ false
512
+ ).split('","')
513
+
514
+ if (gitHeadCommitSha) {
515
+ tags[GIT_COMMIT_HEAD_AUTHOR_DATE] = headAuthorDate
516
+ tags[GIT_COMMIT_HEAD_AUTHOR_EMAIL] = headAuthorEmail
517
+ tags[GIT_COMMIT_HEAD_AUTHOR_NAME] = headAuthorName
518
+ tags[GIT_COMMIT_HEAD_COMMITTER_DATE] = headCommitterDate
519
+ tags[GIT_COMMIT_HEAD_COMMITTER_EMAIL] = headCommitterEmail
520
+ tags[GIT_COMMIT_HEAD_COMMITTER_NAME] = headCommitterName
521
+ tags[GIT_COMMIT_HEAD_MESSAGE] = headCommitMessage
522
+ }
509
523
  }
510
524
 
511
525
  const entries = [
@@ -544,6 +558,26 @@ function getGitInformationDiscrepancy () {
544
558
  return { gitRepositoryUrl, gitCommitSHA }
545
559
  }
546
560
 
561
+ function fetchHeadCommitSha (headSha) {
562
+ const remoteName = getGitRemoteName()
563
+
564
+ sanitizedExec(
565
+ 'git',
566
+ [
567
+ 'fetch',
568
+ '--update-shallow',
569
+ '--filter=blob:none',
570
+ '--recurse-submodules=no',
571
+ '--no-write-fetch-head',
572
+ remoteName,
573
+ headSha
574
+ ],
575
+ { name: TELEMETRY_GIT_COMMAND, tags: { command: 'fetch_head_commit_sha' } },
576
+ { name: TELEMETRY_GIT_COMMAND_MS, tags: { command: 'fetch_head_commit_sha' } },
577
+ { name: TELEMETRY_GIT_COMMAND_ERRORS, tags: { command: 'fetch_head_commit_sha' } }
578
+ )
579
+ }
580
+
547
581
  module.exports = {
548
582
  getGitMetadata,
549
583
  getLatestCommits,
@@ -561,5 +595,6 @@ module.exports = {
561
595
  checkAndFetchBranch,
562
596
  getLocalBranches,
563
597
  getMergeBase,
564
- getCounts
598
+ getCounts,
599
+ fetchHeadCommitSha
565
600
  }
@@ -375,10 +375,10 @@ function createPossionProcessSamplingFilter (samplingIntervalMillis) {
375
375
  * source with a sampling event filter and an event serializer.
376
376
  */
377
377
  class EventsProfiler {
378
- constructor (options = {}) {
379
- this.type = 'events'
380
- this.eventSerializer = new EventSerializer()
378
+ type = 'events'
379
+ eventSerializer = new EventSerializer()
381
380
 
381
+ constructor (options = {}) {
382
382
  const eventHandler = event => this.eventSerializer.addEvent(event)
383
383
  const eventFilter = options.timelineSamplingEnabled
384
384
  // options.samplingInterval comes in microseconds, we need millis
@@ -8,13 +8,14 @@ function strategiesToCallbackMode (strategies, callbackMode) {
8
8
  }
9
9
 
10
10
  class NativeSpaceProfiler {
11
+ type = 'space'
12
+ _pprof
13
+ _started = false
14
+
11
15
  constructor (options = {}) {
12
- this.type = 'space'
13
16
  this._samplingInterval = options.heapSamplingInterval || 512 * 1024
14
17
  this._stackDepth = options.stackDepth || 64
15
- this._pprof = undefined
16
18
  this._oomMonitoring = options.oomMonitoring || {}
17
- this._started = false
18
19
  }
19
20
 
20
21
  start ({ mapper, nearOOMCallback } = {}) {
@@ -69,8 +69,12 @@ function ensureChannelsActivated () {
69
69
  }
70
70
 
71
71
  class NativeWallProfiler {
72
+ type = 'wall'
73
+ _mapper
74
+ _pprof
75
+ _started = false
76
+
72
77
  constructor (options = {}) {
73
- this.type = 'wall'
74
78
  this._samplingIntervalMicros = options.samplingInterval || 1e6 / 99 // 99hz
75
79
  this._flushIntervalMillis = options.flushInterval || 60 * 1e3 // 60 seconds
76
80
  this._codeHotspotsEnabled = !!options.codeHotspotsEnabled
@@ -86,8 +90,6 @@ class NativeWallProfiler {
86
90
  // cpu profiling is enabled.
87
91
  this._withContexts = this._captureSpanData || this._timelineEnabled || this._cpuProfilingEnabled
88
92
  this._v8ProfilerBugWorkaroundEnabled = !!options.v8ProfilerBugWorkaroundEnabled
89
- this._mapper = undefined
90
- this._pprof = undefined
91
93
 
92
94
  // Bind these to this so they can be used as callbacks
93
95
  if (this._withContexts && this._captureSpanData) {
@@ -97,7 +99,6 @@ class NativeWallProfiler {
97
99
  this._generateLabels = this._generateLabels.bind(this)
98
100
 
99
101
  this._logger = options.logger
100
- this._started = false
101
102
  }
102
103
 
103
104
  codeHotspotsEnabled () {
@@ -1,8 +1,9 @@
1
1
  'use strict'
2
2
 
3
3
  class Scheduler {
4
+ _timer = null
5
+
4
6
  constructor (callback, interval) {
5
- this._timer = null
6
7
  this._callback = callback
7
8
  this._interval = interval
8
9
  }
@@ -16,6 +16,10 @@ const messaging = {
16
16
  opName: () => 'amqp.send',
17
17
  serviceName: amqpServiceName
18
18
  },
19
+ 'azure-service-bus': {
20
+ opName: () => 'azure.servicebus.send',
21
+ serviceName: ({ tracerService }) => `${tracerService}-azure-service-bus`
22
+ },
19
23
  'google-cloud-pubsub': {
20
24
  opName: () => 'pubsub.request',
21
25
  serviceName: ({ tracerService }) => `${tracerService}-pubsub`
@@ -209,6 +209,7 @@
209
209
  "DD_TRACE_AWS_SDK_STEPFUNCTIONS_ENABLED": ["A"],
210
210
  "DD_TRACE_AXIOS_ENABLED": ["A"],
211
211
  "DD_TRACE_AZURE_FUNCTIONS_ENABLED": ["A"],
212
+ "DD_TRACE_AZURE_SERVICE_BUS_ENABLED": ["A"],
212
213
  "DD_TRACE_BAGGAGE_MAX_BYTES": ["A"],
213
214
  "DD_TRACE_BAGGAGE_MAX_ITEMS": ["A"],
214
215
  "DD_TRACE_BAGGAGE_TAG_KEYS": ["A"],
@@ -1,50 +0,0 @@
1
- 'use strict'
2
-
3
- const LangChainHandler = require('./default')
4
-
5
- class LangChainChainHandler extends LangChainHandler {
6
- getSpanStartTags (ctx, provider, span) {
7
- const tags = {}
8
-
9
- if (!this.isPromptCompletionSampled(span)) return tags
10
-
11
- let inputs = ctx.args?.[0]
12
- inputs = Array.isArray(inputs) ? inputs : [inputs]
13
-
14
- for (const idx in inputs) {
15
- const input = inputs[idx]
16
- if (input !== null && typeof input === 'object') {
17
- for (const [key, value] of Object.entries(input)) {
18
- // these are mappings to the python client names, ie lc_kwargs
19
- // only present on BaseMessage types
20
- if (key.includes('lc_')) continue
21
- tags[`langchain.request.inputs.${idx}.${key}`] = this.normalize(value)
22
- }
23
- } else {
24
- tags[`langchain.request.inputs.${idx}`] = this.normalize(input)
25
- }
26
- }
27
-
28
- return tags
29
- }
30
-
31
- getSpanEndTags (ctx, span) {
32
- const tags = {}
33
-
34
- if (!this.isPromptCompletionSampled(span)) return tags
35
-
36
- let outputs = ctx.result
37
- outputs = Array.isArray(outputs) ? outputs : [outputs]
38
-
39
- for (const idx in outputs) {
40
- const output = outputs[idx]
41
- tags[`langchain.response.outputs.${idx}`] = this.normalize(
42
- typeof output === 'string' ? output : JSON.stringify(output)
43
- )
44
- }
45
-
46
- return tags
47
- }
48
- }
49
-
50
- module.exports = LangChainChainHandler
@@ -1,101 +0,0 @@
1
- 'use strict'
2
-
3
- const LangChainLanguageModelHandler = require('.')
4
-
5
- const COMPLETIONS = 'langchain.response.completions'
6
-
7
- class LangChainChatModelHandler extends LangChainLanguageModelHandler {
8
- getSpanStartTags (ctx, provider, span) {
9
- const tags = {}
10
-
11
- const inputs = ctx.args?.[0]
12
-
13
- for (const messageSetIndex in inputs) {
14
- const messageSet = inputs[messageSetIndex]
15
-
16
- for (const messageIndex in messageSet) {
17
- const message = messageSet[messageIndex]
18
- if (this.isPromptCompletionSampled(span)) {
19
- tags[`langchain.request.messages.${messageSetIndex}.${messageIndex}.content`] =
20
- this.normalize(message.content) || ''
21
- }
22
- tags[`langchain.request.messages.${messageSetIndex}.${messageIndex}.message_type`] = message.constructor.name
23
- }
24
- }
25
-
26
- const instance = ctx.instance
27
- const identifyingParams = (typeof instance._identifyingParams === 'function' && instance._identifyingParams()) || {}
28
- for (const [param, val] of Object.entries(identifyingParams)) {
29
- if (param.toLowerCase().includes('apikey') || param.toLowerCase().includes('apitoken')) continue
30
- if (val !== null && typeof val === 'object') {
31
- for (const [key, value] of Object.entries(val)) {
32
- tags[`langchain.request.${provider}.parameters.${param}.${key}`] = value
33
- }
34
- } else {
35
- tags[`langchain.request.${provider}.parameters.${param}`] = val
36
- }
37
- }
38
-
39
- return tags
40
- }
41
-
42
- getSpanEndTags (ctx, span) {
43
- const { result } = ctx
44
-
45
- const tags = {}
46
-
47
- const sampled = this.isPromptCompletionSampled(span)
48
-
49
- this.extractTokenMetrics(ctx.currentStore?.span, result)
50
-
51
- for (const messageSetIdx in result?.generations) {
52
- const messageSet = result.generations[messageSetIdx]
53
-
54
- for (const chatCompletionIdx in messageSet) {
55
- const chatCompletion = messageSet[chatCompletionIdx]
56
-
57
- const text = chatCompletion.text
58
- const message = chatCompletion.message
59
- let toolCalls = message.tool_calls
60
-
61
- if (text && sampled) {
62
- tags[
63
- `${COMPLETIONS}.${messageSetIdx}.${chatCompletionIdx}.content`
64
- ] = this.normalize(text)
65
- }
66
-
67
- tags[
68
- `${COMPLETIONS}.${messageSetIdx}.${chatCompletionIdx}.message_type`
69
- ] = message.constructor.name
70
-
71
- if (toolCalls) {
72
- if (!Array.isArray(toolCalls)) {
73
- toolCalls = [toolCalls]
74
- }
75
-
76
- for (const toolCallIndex in toolCalls) {
77
- const toolCall = toolCalls[toolCallIndex]
78
-
79
- tags[
80
- `${COMPLETIONS}.${messageSetIdx}.${chatCompletionIdx}.tool_calls.${toolCallIndex}.id`
81
- ] = toolCall.id
82
- tags[
83
- `${COMPLETIONS}.${messageSetIdx}.${chatCompletionIdx}.tool_calls.${toolCallIndex}.name`
84
- ] = toolCall.name
85
-
86
- const args = toolCall.args || {}
87
- for (const [name, value] of Object.entries(args)) {
88
- tags[
89
- `${COMPLETIONS}.${messageSetIdx}.${chatCompletionIdx}.tool_calls.${toolCallIndex}.args.${name}`
90
- ] = this.normalize(value)
91
- }
92
- }
93
- }
94
- }
95
- }
96
-
97
- return tags
98
- }
99
- }
100
-
101
- module.exports = LangChainChatModelHandler
@@ -1,48 +0,0 @@
1
- 'use strict'
2
-
3
- const { getTokensFromLlmOutput } = require('../../tokens')
4
- const LangChainHandler = require('../default')
5
-
6
- class LangChainLanguageModelHandler extends LangChainHandler {
7
- extractApiKey (instance) {
8
- const key = Object.keys(instance)
9
- .find(key => {
10
- const lower = key.toLowerCase()
11
- return lower.includes('apikey') || lower.includes('apitoken')
12
- })
13
-
14
- let apiKey = instance[key]
15
- if (apiKey?.secretValue && typeof apiKey.secretValue === 'function') {
16
- apiKey = apiKey.secretValue()
17
- }
18
- if (!apiKey || apiKey.length < 4) return ''
19
- return `...${apiKey.slice(-4)}`
20
- }
21
-
22
- extractProvider (instance) {
23
- return typeof instance._llmType === 'function' && instance._llmType().split('-')[0]
24
- }
25
-
26
- extractModel (instance) {
27
- for (const attr of ['model', 'modelName', 'modelId', 'modelKey', 'repoId']) {
28
- const modelName = instance[attr]
29
- if (modelName) return modelName
30
- }
31
- }
32
-
33
- extractTokenMetrics (span, result) {
34
- if (!span || !result) return
35
-
36
- // we do not tag token metrics for non-openai providers
37
- const provider = span.context()._tags['langchain.request.provider']
38
- if (provider !== 'openai') return
39
-
40
- const tokens = getTokensFromLlmOutput(result)
41
-
42
- for (const [tokenKey, tokenCount] of Object.entries(tokens)) {
43
- span.setTag(`langchain.tokens.${tokenKey}_tokens`, tokenCount)
44
- }
45
- }
46
- }
47
-
48
- module.exports = LangChainLanguageModelHandler
@@ -1,58 +0,0 @@
1
- 'use strict'
2
-
3
- const LangChainLanguageModelHandler = require('.')
4
-
5
- class LangChainLLMHandler extends LangChainLanguageModelHandler {
6
- getSpanStartTags (ctx, provider, span) {
7
- const tags = {}
8
-
9
- const prompts = ctx.args?.[0]
10
- for (const promptIdx in prompts) {
11
- if (!this.isPromptCompletionSampled(span)) continue
12
-
13
- const prompt = prompts[promptIdx]
14
- tags[`langchain.request.prompts.${promptIdx}.content`] = this.normalize(prompt) || ''
15
- }
16
-
17
- const instance = ctx.instance
18
- const identifyingParams = (typeof instance._identifyingParams === 'function' && instance._identifyingParams()) || {}
19
- for (const [param, val] of Object.entries(identifyingParams)) {
20
- if (param.toLowerCase().includes('apikey') || param.toLowerCase().includes('apitoken')) continue
21
- if (val !== null && typeof val === 'object') {
22
- for (const [key, value] of Object.entries(val)) {
23
- tags[`langchain.request.${provider}.parameters.${param}.${key}`] = value
24
- }
25
- } else {
26
- tags[`langchain.request.${provider}.parameters.${param}`] = val
27
- }
28
- }
29
-
30
- return tags
31
- }
32
-
33
- getSpanEndTags (ctx, span) {
34
- const { result } = ctx
35
-
36
- const tags = {}
37
- const sampled = this.isPromptCompletionSampled(span)
38
-
39
- this.extractTokenMetrics(ctx.currentStore?.span, result)
40
-
41
- for (const completionIdx in result?.generations) {
42
- const completion = result.generations[completionIdx]
43
- if (sampled) {
44
- tags[`langchain.response.completions.${completionIdx}.text`] = this.normalize(completion[0].text) || ''
45
- }
46
-
47
- if (completion && completion[0].generationInfo) {
48
- const generationInfo = completion[0].generationInfo
49
- tags[`langchain.response.completions.${completionIdx}.finish_reason`] = generationInfo.finishReason
50
- tags[`langchain.response.completions.${completionIdx}.logprobs`] = generationInfo.logprobs
51
- }
52
- }
53
-
54
- return tags
55
- }
56
- }
57
-
58
- module.exports = LangChainLLMHandler