dd-trace 5.55.0 → 5.57.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 (150) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/index.d.ts +44 -2
  3. package/init.js +4 -1
  4. package/package.json +24 -23
  5. package/packages/datadog-core/src/utils/src/set.js +8 -10
  6. package/packages/datadog-esbuild/index.js +22 -0
  7. package/packages/datadog-instrumentations/src/cassandra-driver.js +43 -60
  8. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +12 -12
  9. package/packages/datadog-instrumentations/src/cucumber.js +4 -6
  10. package/packages/datadog-instrumentations/src/elasticsearch.js +16 -19
  11. package/packages/datadog-instrumentations/src/fastify.js +91 -9
  12. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +20 -5
  13. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +2 -2
  14. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  15. package/packages/datadog-instrumentations/src/helpers/register.js +17 -5
  16. package/packages/datadog-instrumentations/src/ioredis.js +8 -13
  17. package/packages/datadog-instrumentations/src/iovalkey.js +10 -14
  18. package/packages/datadog-instrumentations/src/jest.js +423 -325
  19. package/packages/datadog-instrumentations/src/memcached.js +17 -24
  20. package/packages/datadog-instrumentations/src/mocha/main.js +7 -6
  21. package/packages/datadog-instrumentations/src/moleculer/client.js +9 -10
  22. package/packages/datadog-instrumentations/src/moleculer/server.js +12 -13
  23. package/packages/datadog-instrumentations/src/openai.js +30 -2
  24. package/packages/datadog-instrumentations/src/playwright.js +4 -1
  25. package/packages/datadog-instrumentations/src/prisma.js +116 -0
  26. package/packages/datadog-instrumentations/src/redis.js +32 -43
  27. package/packages/datadog-instrumentations/src/router.js +1 -1
  28. package/packages/datadog-instrumentations/src/sharedb.js +10 -16
  29. package/packages/datadog-instrumentations/src/vitest.js +4 -4
  30. package/packages/datadog-plugin-aws-sdk/src/base.js +6 -1
  31. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -4
  32. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +3 -2
  33. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -1
  34. package/packages/datadog-plugin-aws-sdk/src/util.js +2 -2
  35. package/packages/datadog-plugin-azure-functions/src/index.js +5 -4
  36. package/packages/datadog-plugin-bunyan/src/index.js +2 -2
  37. package/packages/datadog-plugin-cassandra-driver/src/index.js +6 -2
  38. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/batch-consumer.js +1 -1
  39. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/consumer.js +1 -1
  40. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
  41. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/producer.js +1 -1
  42. package/packages/datadog-plugin-cucumber/src/index.js +4 -2
  43. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -5
  44. package/packages/datadog-plugin-elasticsearch/src/index.js +12 -4
  45. package/packages/datadog-plugin-http/src/client.js +1 -0
  46. package/packages/datadog-plugin-http/src/server.js +2 -1
  47. package/packages/datadog-plugin-http2/src/client.js +1 -0
  48. package/packages/datadog-plugin-http2/src/server.js +1 -0
  49. package/packages/datadog-plugin-jest/src/index.js +4 -3
  50. package/packages/datadog-plugin-memcached/src/index.js +6 -2
  51. package/packages/datadog-plugin-mocha/src/index.js +3 -2
  52. package/packages/datadog-plugin-moleculer/src/client.js +15 -9
  53. package/packages/datadog-plugin-moleculer/src/server.js +9 -5
  54. package/packages/datadog-plugin-next/src/index.js +2 -1
  55. package/packages/datadog-plugin-openai/src/tracing.js +127 -80
  56. package/packages/datadog-plugin-oracledb/src/index.js +2 -1
  57. package/packages/datadog-plugin-pino/src/index.js +2 -2
  58. package/packages/datadog-plugin-prisma/src/client.js +62 -0
  59. package/packages/datadog-plugin-prisma/src/engine.js +81 -0
  60. package/packages/datadog-plugin-prisma/src/index.js +22 -0
  61. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  62. package/packages/datadog-plugin-redis/src/index.js +9 -3
  63. package/packages/datadog-plugin-router/src/index.js +1 -0
  64. package/packages/datadog-plugin-sharedb/src/index.js +13 -5
  65. package/packages/datadog-plugin-winston/src/index.js +2 -2
  66. package/packages/dd-trace/src/appsec/channels.js +26 -21
  67. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  68. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +13 -20
  69. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +1 -1
  70. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +44 -1
  71. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -1
  72. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +7 -2
  73. package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +0 -1
  74. package/packages/dd-trace/src/appsec/index.js +28 -2
  75. package/packages/dd-trace/src/appsec/rasp/utils.js +0 -5
  76. package/packages/dd-trace/src/appsec/reporter.js +6 -4
  77. package/packages/dd-trace/src/baggage.js +2 -2
  78. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +3 -3
  79. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  80. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  81. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  82. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  83. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +6 -6
  84. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -3
  85. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +3 -3
  86. package/packages/dd-trace/src/config.js +334 -312
  87. package/packages/dd-trace/src/constants.js +2 -1
  88. package/packages/dd-trace/src/crashtracking/crashtracker.js +12 -14
  89. package/packages/dd-trace/src/datastreams/context.js +1 -1
  90. package/packages/dd-trace/src/datastreams/processor.js +1 -1
  91. package/packages/dd-trace/src/datastreams/writer.js +3 -3
  92. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +6 -3
  93. package/packages/dd-trace/src/debugger/devtools_client/condition.js +1 -1
  94. package/packages/dd-trace/src/debugger/devtools_client/index.js +2 -3
  95. package/packages/dd-trace/src/debugger/devtools_client/send.js +5 -1
  96. package/packages/dd-trace/src/debugger/devtools_client/state.js +7 -4
  97. package/packages/dd-trace/src/debugger/devtools_client/status.js +5 -1
  98. package/packages/dd-trace/src/dogstatsd.js +3 -3
  99. package/packages/dd-trace/src/exporters/agent/index.js +10 -5
  100. package/packages/dd-trace/src/exporters/agent/writer.js +4 -2
  101. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +2 -2
  102. package/packages/dd-trace/src/exporters/log/index.js +1 -1
  103. package/packages/dd-trace/src/exporters/span-stats/writer.js +2 -2
  104. package/packages/dd-trace/src/guardrails/index.js +3 -1
  105. package/packages/dd-trace/src/guardrails/telemetry.js +1 -1
  106. package/packages/dd-trace/src/llmobs/index.js +11 -5
  107. package/packages/dd-trace/src/llmobs/plugins/base.js +2 -2
  108. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  109. package/packages/dd-trace/src/llmobs/tagger.js +13 -13
  110. package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
  111. package/packages/dd-trace/src/llmobs/writers/spans.js +2 -2
  112. package/packages/dd-trace/src/opentelemetry/tracer.js +1 -1
  113. package/packages/dd-trace/src/opentracing/propagation/text_map.js +22 -28
  114. package/packages/dd-trace/src/opentracing/span.js +1 -0
  115. package/packages/dd-trace/src/plugin_manager.js +3 -3
  116. package/packages/dd-trace/src/plugins/cache.js +2 -2
  117. package/packages/dd-trace/src/plugins/ci_plugin.js +11 -7
  118. package/packages/dd-trace/src/plugins/database.js +3 -1
  119. package/packages/dd-trace/src/plugins/index.js +1 -0
  120. package/packages/dd-trace/src/plugins/log_plugin.js +5 -1
  121. package/packages/dd-trace/src/plugins/outbound.js +8 -6
  122. package/packages/dd-trace/src/plugins/structured_log_plugin.js +9 -0
  123. package/packages/dd-trace/src/plugins/tracing.js +1 -1
  124. package/packages/dd-trace/src/plugins/util/ci.js +83 -30
  125. package/packages/dd-trace/src/plugins/util/git.js +1 -0
  126. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +3 -2
  127. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -0
  128. package/packages/dd-trace/src/plugins/util/tags.js +4 -1
  129. package/packages/dd-trace/src/plugins/util/test.js +80 -10
  130. package/packages/dd-trace/src/plugins/util/web.js +1 -0
  131. package/packages/dd-trace/src/profiler.js +0 -2
  132. package/packages/dd-trace/src/profiling/exporter_cli.js +1 -3
  133. package/packages/dd-trace/src/profiling/profilers/events.js +10 -2
  134. package/packages/dd-trace/src/profiling/ssi-heuristics.js +18 -126
  135. package/packages/dd-trace/src/proxy.js +12 -27
  136. package/packages/dd-trace/src/runtime_metrics/index.js +1 -1
  137. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +14 -45
  138. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +2 -2
  139. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +4 -0
  140. package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +2 -2
  141. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  142. package/packages/dd-trace/src/supported-configurations.json +13 -3
  143. package/packages/dd-trace/src/telemetry/telemetry.js +11 -4
  144. package/packages/dd-trace/src/tracer.js +11 -0
  145. package/packages/dd-trace/src/tracer_metadata.js +25 -0
  146. package/packages/dd-trace/src/util.js +11 -4
  147. package/version.js +3 -1
  148. package/packages/datadog-core/src/utils/src/get.js +0 -11
  149. package/packages/datadog-core/src/utils/src/has.js +0 -14
  150. package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +0 -30
@@ -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':
@@ -11,7 +11,8 @@ class OracledbPlugin extends DatabasePlugin {
11
11
 
12
12
  start ({ query, connAttrs }) {
13
13
  const service = this.serviceName({ pluginConfig: this.config, params: connAttrs })
14
- const url = getUrl(connAttrs.connectString)
14
+ // Users can pass either connectString or connectionString
15
+ const url = getUrl(connAttrs.connectString || connAttrs.connectionString)
15
16
 
16
17
  this.startSpan(this.operationName(), {
17
18
  service,
@@ -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
@@ -0,0 +1,81 @@
1
+ 'use strict'
2
+
3
+ const DatabasePlugin = require('../../dd-trace/src/plugins/database')
4
+ const { CLIENT_PORT_KEY } = require('../../dd-trace/src/constants')
5
+
6
+ const databaseDriverMapper = {
7
+ postgresql: {
8
+ type: 'sql',
9
+ 'db.type': 'postgres'
10
+ },
11
+ mysql: {
12
+ type: 'sql',
13
+ 'db.type': 'mysql'
14
+ },
15
+ mongodb: {
16
+ type: 'mongodb',
17
+ 'db.type': 'mongodb'
18
+ },
19
+ sqlite: {
20
+ type: 'sql',
21
+ 'db.type': 'sqlite'
22
+ }
23
+ }
24
+
25
+ class PrismaEngine extends DatabasePlugin {
26
+ static get id () { return 'prisma' }
27
+ static get operation () { return 'engine' }
28
+ static get system () { return 'prisma' }
29
+
30
+ start (ctx) {
31
+ const { engineSpan, allEngineSpans, childOf, dbConfig } = ctx
32
+ const service = this.serviceName({ pluginConfig: this.config, system: this.system })
33
+ const spanName = engineSpan.name.slice(14) // remove 'prisma:engine:' prefix
34
+ const options = {
35
+ childOf,
36
+ resource: spanName,
37
+ service,
38
+ kind: engineSpan.kind,
39
+ meta: {
40
+ prisma: {
41
+ name: spanName,
42
+ type: 'engine'
43
+ }
44
+ }
45
+ }
46
+
47
+ if (spanName === 'db_query') {
48
+ const query = engineSpan.attributes['db.query.text']
49
+ const originalStatement = this.maybeTruncate(query)
50
+ const type = databaseDriverMapper[engineSpan.attributes['db.system']]?.type
51
+ const dbType = databaseDriverMapper[engineSpan.attributes['db.system']]?.['db.type']
52
+
53
+ options.resource = originalStatement
54
+ options.type = type || engineSpan.attributes['db.system']
55
+ options.meta['db.type'] = dbType || engineSpan.attributes['db.system']
56
+ options.meta['db.instance'] = dbConfig?.database
57
+ options.meta['db.name'] = dbConfig?.user
58
+ options.meta['out.host'] = dbConfig?.host
59
+ options.meta[CLIENT_PORT_KEY] = dbConfig?.port
60
+ }
61
+
62
+ const activeSpan = this.startSpan(this.operationName({ operation: this.operation }), options)
63
+ activeSpan._startTime = hrTimeToUnixTimeMs(engineSpan.startTime)
64
+ for (const span of allEngineSpans) {
65
+ if (span.parentId === engineSpan.id) {
66
+ const startCtx = { engineSpan: span, allEngineSpans, childOf: activeSpan, dbConfig }
67
+ this.start(startCtx)
68
+ }
69
+ }
70
+ const unixEndTime = hrTimeToUnixTimeMs(engineSpan.endTime)
71
+ activeSpan.finish(unixEndTime)
72
+ }
73
+ }
74
+
75
+ // Opentelemetry time format is defined here
76
+ // https://github.com/open-telemetry/opentelemetry-js/blob/cbc912d/api/src/common/Time.ts#L19-L30.
77
+ function hrTimeToUnixTimeMs ([seconds, nanoseconds]) {
78
+ return seconds * 1000 + nanoseconds / 1e6
79
+ }
80
+
81
+ module.exports = PrismaEngine
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ const CompositePlugin = require('../../dd-trace/src/plugins/composite')
4
+
5
+ const PrismaClientPlugin = require('./client')
6
+ const PrismaEnginePlugin = require('./engine')
7
+
8
+ class PrismaPlugin extends CompositePlugin {
9
+ static get id () { return 'prisma' }
10
+ static get plugins () {
11
+ return {
12
+ client: PrismaClientPlugin,
13
+ engine: PrismaEnginePlugin
14
+ }
15
+ }
16
+
17
+ configure (config) {
18
+ return super.configure(config)
19
+ }
20
+ }
21
+
22
+ module.exports = PrismaPlugin
@@ -108,7 +108,7 @@ class SchemaExtractor {
108
108
  }
109
109
  for (const field of schema.fieldsArray) {
110
110
  if (!this.extractProperty(field, schemaName, field.name, builder, depth)) {
111
- log.warn(`DSM: Unable to extract field with name: ${field.name} from Avro schema with name: ${schemaName}`)
111
+ log.warn('DSM: Unable to extract field with name: %s from Avro schema with name:', field.name, schemaName)
112
112
  }
113
113
  }
114
114
  return true
@@ -13,10 +13,14 @@ class RedisPlugin extends CachePlugin {
13
13
  this._spanType = 'redis'
14
14
  }
15
15
 
16
- start ({ db, command, args, connectionOptions = {}, connectionName }) {
16
+ bindStart (ctx) {
17
+ const { db, command, args, connectionOptions, connectionName } = ctx
18
+
17
19
  const resource = command
18
20
  const normalizedCommand = command.toUpperCase()
19
- if (!this.config.filter(normalizedCommand)) return this.skip()
21
+ if (!this.config.filter(normalizedCommand)) {
22
+ return { noop: true }
23
+ }
20
24
 
21
25
  this.startSpan({
22
26
  resource,
@@ -29,7 +33,9 @@ class RedisPlugin extends CachePlugin {
29
33
  'out.host': connectionOptions.host,
30
34
  [CLIENT_PORT_KEY]: connectionOptions.port
31
35
  }
32
- })
36
+ }, ctx)
37
+
38
+ return ctx.currentStore
33
39
  }
34
40
 
35
41
  configure (config) {
@@ -106,6 +106,7 @@ class RouterPlugin extends WebPlugin {
106
106
 
107
107
  const span = this.tracer.startSpan(`${this.constructor.id}.middleware`, {
108
108
  childOf,
109
+ integrationName: this.constructor.id,
109
110
  tags: {
110
111
  [COMPONENT]: this.constructor.id,
111
112
  'resource.name': name || '<anonymous>'