dd-trace 5.56.0 → 5.57.1

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 (134) hide show
  1. package/index.d.ts +44 -2
  2. package/init.js +4 -1
  3. package/package.json +20 -20
  4. package/packages/datadog-esbuild/index.js +22 -0
  5. package/packages/datadog-instrumentations/src/cassandra-driver.js +43 -60
  6. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +12 -12
  7. package/packages/datadog-instrumentations/src/cucumber.js +4 -6
  8. package/packages/datadog-instrumentations/src/elasticsearch.js +16 -19
  9. package/packages/datadog-instrumentations/src/fastify.js +91 -9
  10. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +20 -5
  11. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -2
  12. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  13. package/packages/datadog-instrumentations/src/helpers/register.js +17 -5
  14. package/packages/datadog-instrumentations/src/ioredis.js +8 -13
  15. package/packages/datadog-instrumentations/src/iovalkey.js +10 -14
  16. package/packages/datadog-instrumentations/src/jest.js +28 -6
  17. package/packages/datadog-instrumentations/src/memcached.js +17 -24
  18. package/packages/datadog-instrumentations/src/mocha/main.js +7 -6
  19. package/packages/datadog-instrumentations/src/moleculer/client.js +9 -10
  20. package/packages/datadog-instrumentations/src/moleculer/server.js +12 -13
  21. package/packages/datadog-instrumentations/src/openai.js +30 -2
  22. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  23. package/packages/datadog-instrumentations/src/prisma.js +116 -0
  24. package/packages/datadog-instrumentations/src/redis.js +32 -43
  25. package/packages/datadog-instrumentations/src/router.js +1 -1
  26. package/packages/datadog-instrumentations/src/sharedb.js +10 -16
  27. package/packages/datadog-instrumentations/src/vitest.js +4 -4
  28. package/packages/datadog-plugin-aws-sdk/src/base.js +6 -1
  29. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -4
  30. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +3 -2
  31. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -1
  32. package/packages/datadog-plugin-aws-sdk/src/util.js +2 -2
  33. package/packages/datadog-plugin-bunyan/src/index.js +2 -2
  34. package/packages/datadog-plugin-cassandra-driver/src/index.js +6 -2
  35. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/batch-consumer.js +1 -1
  36. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/consumer.js +1 -1
  37. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
  38. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/producer.js +1 -1
  39. package/packages/datadog-plugin-cucumber/src/index.js +4 -2
  40. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -5
  41. package/packages/datadog-plugin-elasticsearch/src/index.js +12 -4
  42. package/packages/datadog-plugin-http/src/client.js +1 -0
  43. package/packages/datadog-plugin-http/src/server.js +2 -1
  44. package/packages/datadog-plugin-http2/src/client.js +1 -0
  45. package/packages/datadog-plugin-http2/src/server.js +1 -0
  46. package/packages/datadog-plugin-jest/src/index.js +4 -3
  47. package/packages/datadog-plugin-memcached/src/index.js +6 -2
  48. package/packages/datadog-plugin-mocha/src/index.js +3 -2
  49. package/packages/datadog-plugin-moleculer/src/client.js +15 -9
  50. package/packages/datadog-plugin-moleculer/src/server.js +9 -5
  51. package/packages/datadog-plugin-next/src/index.js +2 -1
  52. package/packages/datadog-plugin-openai/src/tracing.js +127 -80
  53. package/packages/datadog-plugin-pino/src/index.js +2 -2
  54. package/packages/datadog-plugin-prisma/src/client.js +62 -0
  55. package/packages/datadog-plugin-prisma/src/engine.js +81 -0
  56. package/packages/datadog-plugin-prisma/src/index.js +22 -0
  57. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  58. package/packages/datadog-plugin-redis/src/index.js +9 -3
  59. package/packages/datadog-plugin-router/src/index.js +1 -0
  60. package/packages/datadog-plugin-sharedb/src/index.js +13 -5
  61. package/packages/datadog-plugin-winston/src/index.js +2 -2
  62. package/packages/dd-trace/src/appsec/channels.js +26 -21
  63. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +13 -20
  64. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +0 -1
  65. package/packages/dd-trace/src/appsec/index.js +16 -1
  66. package/packages/dd-trace/src/appsec/rasp/utils.js +0 -5
  67. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +3 -3
  68. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  69. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  70. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  71. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  72. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -6
  73. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -3
  74. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +3 -3
  75. package/packages/dd-trace/src/config.js +286 -270
  76. package/packages/dd-trace/src/constants.js +2 -1
  77. package/packages/dd-trace/src/crashtracking/crashtracker.js +12 -14
  78. package/packages/dd-trace/src/datastreams/context.js +1 -1
  79. package/packages/dd-trace/src/datastreams/processor.js +1 -1
  80. package/packages/dd-trace/src/datastreams/writer.js +3 -3
  81. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +6 -3
  82. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  83. package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -3
  84. package/packages/dd-trace/src/debugger/devtools_client/state.js +7 -4
  85. package/packages/dd-trace/src/dogstatsd.js +3 -3
  86. package/packages/dd-trace/src/exporters/agent/index.js +10 -5
  87. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  88. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +2 -2
  89. package/packages/dd-trace/src/exporters/log/index.js +1 -1
  90. package/packages/dd-trace/src/exporters/span-stats/writer.js +2 -2
  91. package/packages/dd-trace/src/guardrails/index.js +3 -1
  92. package/packages/dd-trace/src/guardrails/telemetry.js +1 -1
  93. package/packages/dd-trace/src/llmobs/index.js +11 -5
  94. package/packages/dd-trace/src/llmobs/plugins/base.js +2 -2
  95. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  96. package/packages/dd-trace/src/llmobs/tagger.js +13 -13
  97. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  98. package/packages/dd-trace/src/llmobs/writers/spans.js +2 -2
  99. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
  100. package/packages/dd-trace/src/opentracing/propagation/text_map.js +4 -4
  101. package/packages/dd-trace/src/opentracing/span.js +1 -0
  102. package/packages/dd-trace/src/plugin_manager.js +3 -3
  103. package/packages/dd-trace/src/plugins/cache.js +2 -2
  104. package/packages/dd-trace/src/plugins/ci_plugin.js +11 -7
  105. package/packages/dd-trace/src/plugins/database.js +3 -1
  106. package/packages/dd-trace/src/plugins/index.js +1 -0
  107. package/packages/dd-trace/src/plugins/log_plugin.js +5 -1
  108. package/packages/dd-trace/src/plugins/outbound.js +8 -6
  109. package/packages/dd-trace/src/plugins/structured_log_plugin.js +9 -0
  110. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  111. package/packages/dd-trace/src/plugins/util/ci.js +83 -30
  112. package/packages/dd-trace/src/plugins/util/git.js +1 -0
  113. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +3 -2
  114. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -0
  115. package/packages/dd-trace/src/plugins/util/tags.js +4 -1
  116. package/packages/dd-trace/src/plugins/util/test.js +80 -10
  117. package/packages/dd-trace/src/plugins/util/web.js +1 -0
  118. package/packages/dd-trace/src/profiler.js +0 -2
  119. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -3
  120. package/packages/dd-trace/src/profiling/ssi-heuristics.js +18 -126
  121. package/packages/dd-trace/src/proxy.js +12 -27
  122. package/packages/dd-trace/src/runtime_metrics/index.js +1 -1
  123. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +14 -45
  124. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +2 -2
  125. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +4 -0
  126. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +2 -2
  127. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  128. package/packages/dd-trace/src/supported-configurations.json +12 -3
  129. package/packages/dd-trace/src/telemetry/telemetry.js +5 -1
  130. package/packages/dd-trace/src/tracer.js +11 -0
  131. package/packages/dd-trace/src/tracer_metadata.js +25 -0
  132. package/packages/dd-trace/src/util.js +11 -4
  133. package/version.js +3 -1
  134. package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +0 -30
@@ -27,13 +27,14 @@ class HttpServerPlugin extends ServerPlugin {
27
27
  this.tracer,
28
28
  {
29
29
  ...this.config,
30
- service: this.config.service || this.serviceName()
30
+ service: this.config.service || this.serviceName(),
31
31
  },
32
32
  req,
33
33
  res,
34
34
  this.operationName()
35
35
  )
36
36
  span.setTag(COMPONENT, this.constructor.id)
37
+ span._integrationName = this.constructor.id
37
38
 
38
39
  this._parentStore = store
39
40
  this.enter(span, { ...store, req, res })
@@ -40,6 +40,7 @@ class Http2ClientPlugin extends ClientPlugin {
40
40
  const childOf = store && allowed ? store.span : null
41
41
  const span = this.startSpan(this.operationName(), {
42
42
  childOf,
43
+ integrationName: this.constructor.id,
43
44
  meta: {
44
45
  [COMPONENT]: this.constructor.id,
45
46
  [SPAN_KIND]: CLIENT,
@@ -30,6 +30,7 @@ class Http2ServerPlugin extends ServerPlugin {
30
30
  )
31
31
 
32
32
  span.setTag(COMPONENT, this.constructor.id)
33
+ span._integrationName = this.constructor.id
33
34
 
34
35
  this.enter(span, { ...store, req, res })
35
36
 
@@ -252,7 +252,8 @@ class JestPlugin extends CiPlugin {
252
252
  [COMPONENT]: this.constructor.id,
253
253
  ...this.testEnvironmentMetadata,
254
254
  ...testSuiteMetadata
255
- }
255
+ },
256
+ integrationName: this.constructor.id
256
257
  })
257
258
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'suite')
258
259
  if (_ddTestCodeCoverageEnabled) {
@@ -318,11 +319,11 @@ class JestPlugin extends CiPlugin {
318
319
  * because this subscription happens in a different process from the one
319
320
  * fetching the ITR config.
320
321
  */
321
- this.addSub('ci:jest:test-suite:code-coverage', ({ coverageFiles, testSuite }) => {
322
+ this.addSub('ci:jest:test-suite:code-coverage', ({ coverageFiles, testSuite, mockedFiles }) => {
322
323
  if (!coverageFiles.length) {
323
324
  this.telemetry.count(TELEMETRY_CODE_COVERAGE_EMPTY)
324
325
  }
325
- const files = [...coverageFiles, testSuite]
326
+ const files = [...coverageFiles, ...mockedFiles, testSuite]
326
327
 
327
328
  const { _traceId, _spanId } = this.testSuiteSpan.context()
328
329
  const formattedCoverage = {
@@ -6,7 +6,9 @@ const CachePlugin = require('../../dd-trace/src/plugins/cache')
6
6
  class MemcachedPlugin extends CachePlugin {
7
7
  static get id () { return 'memcached' }
8
8
 
9
- start ({ client, server, query }) {
9
+ bindStart (ctx) {
10
+ const { client, server, query } = ctx
11
+
10
12
  const address = getAddress(client, server, query)
11
13
 
12
14
  const meta = {
@@ -23,7 +25,9 @@ class MemcachedPlugin extends CachePlugin {
23
25
  resource: query.type,
24
26
  type: 'memcached',
25
27
  meta
26
- })
28
+ }, ctx)
29
+
30
+ return ctx.currentStore
27
31
  }
28
32
  }
29
33
 
@@ -152,7 +152,8 @@ class MochaPlugin extends CiPlugin {
152
152
  [COMPONENT]: this.constructor.id,
153
153
  ...this.testEnvironmentMetadata,
154
154
  ...testSuiteMetadata
155
- }
155
+ },
156
+ integrationName: this.constructor.id
156
157
  })
157
158
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'suite')
158
159
  if (this.libraryConfig?.isCodeCoverageEnabled) {
@@ -450,7 +451,7 @@ class MochaPlugin extends CiPlugin {
450
451
  const testSuite = span.meta[TEST_SUITE]
451
452
  const testSuiteSpan = this._testSuites.get(testSuite)
452
453
  if (!testSuiteSpan) {
453
- log.warn(`Test suite span not found for test span with test suite ${testSuite}`)
454
+ log.warn('Test suite span not found for test span with test suite', testSuite)
454
455
  return formattedSpan
455
456
  }
456
457
  const suiteTags = getTestSuiteLevelVisibilityTags(testSuiteSpan)
@@ -7,29 +7,35 @@ class MoleculerClientPlugin extends ClientPlugin {
7
7
  static get id () { return 'moleculer' }
8
8
  static get operation () { return 'call' }
9
9
 
10
- start ({ actionName, opts }) {
10
+ bindStart (ctx) {
11
+ const { actionName, opts } = ctx
12
+
11
13
  const span = this.startSpan(this.operationName(), {
12
14
  service: this.config.service || this.serviceName(),
13
15
  resource: actionName,
14
16
  kind: 'client'
15
- })
17
+ }, ctx)
16
18
 
17
19
  this.tracer.inject(span, 'text_map', opts.meta)
20
+
21
+ return ctx.currentStore
18
22
  }
19
23
 
20
- finish ({ broker, ctx }) {
21
- const span = this.activeSpan
24
+ finish (ctx) {
25
+ const { promiseCtx, broker } = ctx
26
+
27
+ const span = ctx.currentStore.span || this.activeSpan
22
28
 
23
- if (ctx) {
24
- const endpoint = ctx.endpoint || {}
29
+ if (promiseCtx) {
30
+ const endpoint = promiseCtx.endpoint || {}
25
31
  const node = endpoint.node || {}
26
32
 
27
- this.addHost(node.hostname, node.port)
33
+ this.addHost({ hostname: node.hostname, port: node.port })
28
34
 
29
- span.addTags(moleculerTags(broker, ctx, this.config))
35
+ span.addTags(moleculerTags(broker, promiseCtx, this.config))
30
36
  }
31
37
 
32
- super.finish()
38
+ super.finish(ctx)
33
39
  }
34
40
  }
35
41
 
@@ -7,19 +7,23 @@ class MoleculerServerPlugin extends ServerPlugin {
7
7
  static get id () { return 'moleculer' }
8
8
  static get operation () { return 'action' }
9
9
 
10
- start ({ action, ctx, broker }) {
11
- const followsFrom = this.tracer.extract('text_map', ctx.meta)
10
+ bindStart (ctx) {
11
+ const { action, middlewareCtx, broker } = ctx
12
+
13
+ const followsFrom = this.tracer.extract('text_map', middlewareCtx.meta)
12
14
  this.startSpan(this.operationName(), {
13
- childOf: followsFrom || this.activeSpan,
15
+ childOf: followsFrom || ctx?.currentStore?.span || this.activeSpan,
14
16
  service: this.config.service || this.serviceName(),
15
17
  resource: action.name,
16
18
  kind: 'server',
17
19
  type: 'web',
18
20
  meta: {
19
21
  'resource.name': action.name,
20
- ...moleculerTags(broker, ctx, this.config)
22
+ ...moleculerTags(broker, middlewareCtx, this.config)
21
23
  }
22
- })
24
+ }, ctx)
25
+
26
+ return ctx.currentStore
23
27
  }
24
28
  }
25
29
 
@@ -31,7 +31,8 @@ class NextPlugin extends ServerPlugin {
31
31
  'span.type': 'web',
32
32
  'span.kind': 'server',
33
33
  'http.method': req.method
34
- }
34
+ },
35
+ integrationName: this.constructor.id
35
36
  })
36
37
 
37
38
  analyticsSampler.sample(span, this.config.measured, true)
@@ -13,6 +13,8 @@ const makeUtilities = require('../../dd-trace/src/plugins/util/llm')
13
13
 
14
14
  let normalize
15
15
 
16
+ const { DD_MAJOR } = require('../../../version')
17
+
16
18
  function safeRequire (path) {
17
19
  try {
18
20
  return require(path)
@@ -59,11 +61,19 @@ class OpenAiTracingPlugin extends TracingPlugin {
59
61
  bindStart (ctx) {
60
62
  const { methodName, args, basePath, apiKey } = ctx
61
63
  const payload = normalizeRequestPayload(methodName, args)
64
+ const normalizedMethodName = normalizeMethodName(methodName)
65
+
62
66
  const store = storage('legacy').getStore() || {}
63
67
 
68
+ // hold onto these to make response extraction matching efficient
69
+ // the original method name corresponds to the SDK method name (e.g. createChatCompletion, chat.completions.create)
70
+ // the normalized method name corresponds to the resource name (e.g. createChatCompletion, createCompletion)
71
+ store.originalMethodName = methodName
72
+ store.normalizedMethodName = normalizedMethodName
73
+
64
74
  const span = this.startSpan('openai.request', {
65
75
  service: this.config.service,
66
- resource: methodName,
76
+ resource: DD_MAJOR >= 6 ? normalizedMethodName : methodName,
67
77
  type: 'openai',
68
78
  kind: 'client',
69
79
  meta: {
@@ -129,62 +139,43 @@ class OpenAiTracingPlugin extends TracingPlugin {
129
139
  tags['openai.request.stream'] = payload.stream
130
140
  }
131
141
 
132
- switch (methodName) {
142
+ switch (normalizedMethodName) {
133
143
  case 'createFineTune':
134
- case 'fine_tuning.jobs.create':
135
- case 'fine-tune.create':
136
144
  createFineTuneRequestExtraction(tags, payload)
137
145
  break
138
146
 
139
147
  case 'createImage':
140
- case 'images.generate':
141
148
  case 'createImageEdit':
142
- case 'images.edit':
143
149
  case 'createImageVariation':
144
- case 'images.createVariation':
145
150
  commonCreateImageRequestExtraction(tags, payload, openaiStore)
146
151
  break
147
152
 
148
153
  case 'createChatCompletion':
149
- case 'chat.completions.create':
150
154
  createChatCompletionRequestExtraction(tags, payload, openaiStore)
151
155
  break
152
156
 
153
157
  case 'createFile':
154
- case 'files.create':
155
158
  case 'retrieveFile':
156
- case 'files.retrieve':
157
159
  commonFileRequestExtraction(tags, payload)
158
160
  break
159
161
 
160
162
  case 'createTranscription':
161
- case 'audio.transcriptions.create':
162
163
  case 'createTranslation':
163
- case 'audio.translations.create':
164
164
  commonCreateAudioRequestExtraction(tags, payload, openaiStore)
165
165
  break
166
166
 
167
167
  case 'retrieveModel':
168
- case 'models.retrieve':
169
168
  retrieveModelRequestExtraction(tags, payload)
170
169
  break
171
170
 
172
171
  case 'listFineTuneEvents':
173
- case 'fine_tuning.jobs.listEvents':
174
- case 'fine-tune.listEvents':
175
172
  case 'retrieveFineTune':
176
- case 'fine_tuning.jobs.retrieve':
177
- case 'fine-tune.retrieve':
178
173
  case 'deleteModel':
179
- case 'models.del':
180
174
  case 'cancelFineTune':
181
- case 'fine_tuning.jobs.cancel':
182
- case 'fine-tune.cancel':
183
175
  commonLookupFineTuneRequestExtraction(tags, payload)
184
176
  break
185
177
 
186
178
  case 'createEdit':
187
- case 'edits.create':
188
179
  createEditRequestExtraction(tags, payload, openaiStore)
189
180
  break
190
181
  }
@@ -216,9 +207,11 @@ class OpenAiTracingPlugin extends TracingPlugin {
216
207
  if (!error && headers?.constructor.name === 'Headers') {
217
208
  headers = Object.fromEntries(headers)
218
209
  }
219
- const methodName = span._spanContext._tags['resource.name']
220
210
 
221
- body = coerceResponseBody(body, methodName)
211
+ const resource = span._spanContext._tags['resource.name']
212
+ const normalizedMethodName = store.normalizedMethodName
213
+
214
+ body = coerceResponseBody(body, normalizedMethodName)
222
215
 
223
216
  const openaiStore = store.openai
224
217
 
@@ -227,7 +220,9 @@ class OpenAiTracingPlugin extends TracingPlugin {
227
220
  // not using a full regex as it will likely be "https://api.openai.com/..."
228
221
  path = new URL(path).pathname
229
222
  }
230
- const endpoint = lookupOperationEndpoint(methodName, path)
223
+
224
+ const originalMethodName = store.originalMethodName
225
+ const endpoint = lookupOperationEndpoint(normalizedMethodName, originalMethodName, path)
231
226
 
232
227
  const tags = error
233
228
  ? {}
@@ -248,11 +243,11 @@ class OpenAiTracingPlugin extends TracingPlugin {
248
243
  'openai.response.created_at': body.created_at
249
244
  }
250
245
 
251
- responseDataExtractionByMethod(methodName, tags, body, openaiStore)
246
+ responseDataExtractionByMethod(normalizedMethodName, tags, body, openaiStore)
252
247
  span.addTags(tags)
253
248
 
254
249
  span.finish()
255
- this.sendLog(methodName, span, tags, openaiStore, error)
250
+ this.sendLog(resource, span, tags, openaiStore, error)
256
251
  this.sendMetrics(headers, body, endpoint, span._duration, error, tags)
257
252
  }
258
253
 
@@ -343,10 +338,90 @@ class OpenAiTracingPlugin extends TracingPlugin {
343
338
  }
344
339
  }
345
340
 
341
+ function normalizeMethodName (methodName) {
342
+ switch (methodName) {
343
+ // moderations
344
+ case 'moderations.create':
345
+ return 'createModeration'
346
+
347
+ // completions
348
+ case 'completions.create':
349
+ return 'createCompletion'
350
+
351
+ // chat completions
352
+ case 'chat.completions.create':
353
+ return 'createChatCompletion'
354
+
355
+ // edits
356
+ case 'edits.create':
357
+ return 'createEdit'
358
+
359
+ // embeddings
360
+ case 'embeddings.create':
361
+ return 'createEmbedding'
362
+
363
+ // files
364
+ case 'files.create':
365
+ return 'createFile'
366
+ case 'files.retrieve':
367
+ return 'retrieveFile'
368
+ case 'files.del':
369
+ case 'files.delete':
370
+ return 'deleteFile'
371
+ case 'files.retrieveContent':
372
+ case 'files.content':
373
+ return 'downloadFile'
374
+ case 'files.list':
375
+ return 'listFiles'
376
+
377
+ // fine-tuning
378
+ case 'fine_tuning.jobs.list':
379
+ case 'fine-tune.list':
380
+ return 'listFineTunes'
381
+ case 'fine_tuning.jobs.listEvents':
382
+ case 'fine-tune.listEvents':
383
+ return 'listFineTuneEvents'
384
+ case 'fine_tuning.jobs.create':
385
+ case 'fine-tune.create':
386
+ return 'createFineTune'
387
+ case 'fine_tuning.jobs.retrieve':
388
+ case 'fine-tune.retrieve':
389
+ return 'retrieveFineTune'
390
+ case 'fine_tuning.jobs.cancel':
391
+ case 'fine-tune.cancel':
392
+ return 'cancelFineTune'
393
+
394
+ // audio
395
+ case 'audio.transcriptions.create':
396
+ return 'createTranscription'
397
+ case 'audio.translations.create':
398
+ return 'createTranslation'
399
+
400
+ // images
401
+ case 'images.generate':
402
+ return 'createImage'
403
+ case 'images.edit':
404
+ return 'createImageEdit'
405
+ case 'images.createVariation':
406
+ return 'createImageVariation'
407
+
408
+ // models
409
+ case 'models.list':
410
+ return 'listModels'
411
+ case 'models.retrieve':
412
+ return 'retrieveModel'
413
+ case 'models.del':
414
+ case 'models.delete':
415
+ return 'deleteModel'
416
+ default:
417
+ return methodName
418
+ }
419
+ }
420
+
346
421
  function countPromptTokens (methodName, payload, model) {
347
422
  let promptTokens = 0
348
423
  let promptEstimated = false
349
- if (methodName === 'chat.completions.create') {
424
+ if (methodName === 'createChatCompletion') {
350
425
  const messages = payload.messages
351
426
  for (const message of messages) {
352
427
  const content = message.content
@@ -367,7 +442,7 @@ function countPromptTokens (methodName, payload, model) {
367
442
  }
368
443
  }
369
444
  }
370
- } else if (methodName === 'completions.create') {
445
+ } else if (methodName === 'createCompletion') {
371
446
  let prompt = payload.prompt
372
447
  if (!Array.isArray(prompt)) prompt = [prompt]
373
448
 
@@ -468,88 +543,60 @@ function commonCreateImageRequestExtraction (tags, payload, openaiStore) {
468
543
  function responseDataExtractionByMethod (methodName, tags, body, openaiStore) {
469
544
  switch (methodName) {
470
545
  case 'createModeration':
471
- case 'moderations.create':
472
546
  createModerationResponseExtraction(tags, body)
473
547
  break
474
548
 
475
549
  case 'createCompletion':
476
- case 'completions.create':
477
550
  case 'createChatCompletion':
478
- case 'chat.completions.create':
479
551
  case 'createEdit':
480
- case 'edits.create':
481
552
  commonCreateResponseExtraction(tags, body, openaiStore, methodName)
482
553
  break
483
554
 
484
555
  case 'listFiles':
485
- case 'files.list':
486
556
  case 'listFineTunes':
487
- case 'fine_tuning.jobs.list':
488
- case 'fine-tune.list':
489
557
  case 'listFineTuneEvents':
490
- case 'fine_tuning.jobs.listEvents':
491
- case 'fine-tune.listEvents':
492
558
  commonListCountResponseExtraction(tags, body)
493
559
  break
494
560
 
495
561
  case 'createEmbedding':
496
- case 'embeddings.create':
497
562
  createEmbeddingResponseExtraction(tags, body, openaiStore)
498
563
  break
499
564
 
500
565
  case 'createFile':
501
- case 'files.create':
502
566
  case 'retrieveFile':
503
- case 'files.retrieve':
504
567
  createRetrieveFileResponseExtraction(tags, body)
505
568
  break
506
569
 
507
570
  case 'deleteFile':
508
- case 'files.del':
509
571
  deleteFileResponseExtraction(tags, body)
510
572
  break
511
573
 
512
574
  case 'downloadFile':
513
- case 'files.retrieveContent':
514
- case 'files.content':
515
575
  downloadFileResponseExtraction(tags, body)
516
576
  break
517
577
 
518
578
  case 'createFineTune':
519
- case 'fine_tuning.jobs.create':
520
- case 'fine-tune.create':
521
579
  case 'retrieveFineTune':
522
- case 'fine_tuning.jobs.retrieve':
523
- case 'fine-tune.retrieve':
524
580
  case 'cancelFineTune':
525
- case 'fine_tuning.jobs.cancel':
526
- case 'fine-tune.cancel':
527
581
  commonFineTuneResponseExtraction(tags, body)
528
582
  break
529
583
 
530
584
  case 'createTranscription':
531
- case 'audio.transcriptions.create':
532
585
  case 'createTranslation':
533
- case 'audio.translations.create':
534
586
  createAudioResponseExtraction(tags, body)
535
587
  break
536
588
 
537
589
  case 'createImage':
538
- case 'images.generate':
539
590
  case 'createImageEdit':
540
- case 'images.edit':
541
591
  case 'createImageVariation':
542
- case 'images.createVariation':
543
592
  commonImageResponseExtraction(tags, body)
544
593
  break
545
594
 
546
595
  case 'listModels':
547
- case 'models.list':
548
596
  listModelsResponseExtraction(tags, body)
549
597
  break
550
598
 
551
599
  case 'retrieveModel':
552
- case 'models.retrieve':
553
600
  retrieveModelResponseExtraction(tags, body)
554
601
  break
555
602
  }
@@ -641,8 +688,8 @@ function commonFineTuneResponseExtraction (tags, body) {
641
688
 
642
689
  // the OpenAI package appears to stream the content download then provide it all as a singular string
643
690
  function downloadFileResponseExtraction (tags, body) {
644
- if (!body.file) return
645
- tags['openai.response.total_bytes'] = body.file.length
691
+ if (typeof body.file !== 'string') return
692
+ tags['openai.response.total_bytes'] = Buffer.byteLength(body.file)
646
693
  }
647
694
 
648
695
  function deleteFileResponseExtraction (tags, body) {
@@ -763,7 +810,7 @@ function usageExtraction (tags, body, methodName, openaiStore) {
763
810
  promptTokens = body.usage.prompt_tokens
764
811
  completionTokens = body.usage.completion_tokens
765
812
  totalTokens = body.usage.total_tokens
766
- } else if (body.model && ['chat.completions.create', 'completions.create'].includes(methodName)) {
813
+ } else if (body.model && ['createChatCompletion', 'createCompletion'].includes(methodName)) {
767
814
  // estimate tokens based on method name for completions and chat completions
768
815
  const { model } = body
769
816
 
@@ -819,8 +866,6 @@ function tagChatCompletionRequestContent (contents, messageIdx, tags) {
819
866
  function coerceResponseBody (body, methodName) {
820
867
  switch (methodName) {
821
868
  case 'downloadFile':
822
- case 'files.retrieveContent':
823
- case 'files.content':
824
869
  return { file: body }
825
870
  }
826
871
 
@@ -839,42 +884,42 @@ function coerceResponseBody (body, methodName) {
839
884
  }
840
885
 
841
886
  // This method is used to replace a dynamic URL segment with an asterisk
842
- function lookupOperationEndpoint (operationId, url) {
887
+ function lookupOperationEndpoint (operationId, methodName, url) {
843
888
  switch (operationId) {
844
889
  case 'deleteModel':
845
- case 'models.del':
846
890
  case 'retrieveModel':
847
- case 'models.retrieve':
848
891
  return '/v1/models/*'
849
892
 
850
893
  case 'deleteFile':
851
- case 'files.del':
852
894
  case 'retrieveFile':
853
- case 'files.retrieve':
854
895
  return '/v1/files/*'
855
896
 
856
897
  case 'downloadFile':
857
- case 'files.retrieveContent':
858
- case 'files.content':
859
898
  return '/v1/files/*/content'
860
899
 
861
900
  case 'retrieveFineTune':
862
- case 'fine-tune.retrieve':
863
- return '/v1/fine-tunes/*'
864
- case 'fine_tuning.jobs.retrieve':
865
- return '/v1/fine_tuning/jobs/*'
901
+ switch (methodName) {
902
+ case 'fine_tuning.jobs.retrieve':
903
+ return '/v1/fine_tuning/jobs/*'
904
+ default:
905
+ return '/v1/fine-tunes/*'
906
+ }
866
907
 
867
908
  case 'listFineTuneEvents':
868
- case 'fine-tune.listEvents':
869
- return '/v1/fine-tunes/*/events'
870
- case 'fine_tuning.jobs.listEvents':
871
- return '/v1/fine_tuning/jobs/*/events'
909
+ switch (methodName) {
910
+ case 'fine_tuning.jobs.listEvents':
911
+ return '/v1/fine_tuning/jobs/*/events'
912
+ default:
913
+ return '/v1/fine-tunes/*/events'
914
+ }
872
915
 
873
916
  case 'cancelFineTune':
874
- case 'fine-tune.cancel':
875
- return '/v1/fine-tunes/*/cancel'
876
- case 'fine_tuning.jobs.cancel':
877
- return '/v1/fine_tuning/jobs/*/cancel'
917
+ switch (methodName) {
918
+ case 'fine_tuning.jobs.cancel':
919
+ return '/v1/fine_tuning/jobs/*/cancel'
920
+ default:
921
+ return '/v1/fine-tunes/*/cancel'
922
+ }
878
923
  }
879
924
 
880
925
  return url
@@ -909,6 +954,7 @@ function normalizeRequestPayload (methodName, args) {
909
954
 
910
955
  case 'deleteFile':
911
956
  case 'files.del':
957
+ case 'files.delete':
912
958
  case 'retrieveFile':
913
959
  case 'files.retrieve':
914
960
  case 'downloadFile':
@@ -929,6 +975,7 @@ function normalizeRequestPayload (methodName, args) {
929
975
  case 'fine-tune.retrieve':
930
976
  case 'deleteModel':
931
977
  case 'models.del':
978
+ case 'models.delete':
932
979
  case 'cancelFineTune':
933
980
  case 'fine_tuning.jobs.cancel':
934
981
  case 'fine-tune.cancel':
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
- const LogPlugin = require('../../dd-trace/src/plugins/log_plugin')
3
+ const StructuredLogPlugin = require('../../dd-trace/src/plugins/structured_log_plugin')
4
4
 
5
- class PinoPlugin extends LogPlugin {
5
+ class PinoPlugin extends StructuredLogPlugin {
6
6
  static get id () {
7
7
  return 'pino'
8
8
  }
@@ -0,0 +1,62 @@
1
+ 'use strict'
2
+ const DatabasePlugin = require('../../dd-trace/src/plugins/database')
3
+ class PrismaClientPlugin extends DatabasePlugin {
4
+ static get id () { return 'prisma' }
5
+ static get operation () { return 'client' }
6
+ static get system () { return 'prisma' }
7
+ static get prefix () {
8
+ return 'tracing:apm:prisma:client'
9
+ }
10
+
11
+ bindStart (ctx) {
12
+ const service = this.serviceName({ pluginConfig: this.config })
13
+ const resource = formatResourceName(ctx.resourceName, ctx.attributes)
14
+
15
+ const options = { service, resource }
16
+
17
+ if (ctx.resourceName === 'operation') {
18
+ options.meta = {
19
+ prisma: {
20
+ method: ctx.attributes.method,
21
+ model: ctx.attributes.model,
22
+ type: 'client'
23
+ }
24
+ }
25
+ }
26
+ const operationName = this.operationName({ operation: this.operation })
27
+ this.startSpan(operationName, options, ctx)
28
+
29
+ return ctx.currentStore
30
+ }
31
+
32
+ end (ctx) {
33
+ // Only synchronous operations would have `result` on `end`.
34
+ if (Object.hasOwn(ctx, 'result')) {
35
+ this.finish(ctx)
36
+ }
37
+ }
38
+
39
+ bindAsyncStart (ctx) {
40
+ return this.bindFinish(ctx)
41
+ }
42
+
43
+ asyncStart (ctx) {
44
+ this.finish(ctx)
45
+ }
46
+
47
+ error (error) {
48
+ this.addError(error)
49
+ }
50
+ }
51
+
52
+ function formatResourceName (resource, attributes) {
53
+ if (attributes?.name) {
54
+ return `${attributes.name}`.trim()
55
+ }
56
+ if (attributes?.model && attributes.method) {
57
+ return `${attributes.model}.${attributes.method}`.trim()
58
+ }
59
+ return resource
60
+ }
61
+
62
+ module.exports = PrismaClientPlugin