dd-trace 5.62.0 → 5.63.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 (35) hide show
  1. package/README.md +0 -5
  2. package/package.json +2 -2
  3. package/packages/datadog-instrumentations/src/ai.js +140 -0
  4. package/packages/datadog-instrumentations/src/couchbase.js +102 -65
  5. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  6. package/packages/datadog-instrumentations/src/helpers/register.js +2 -22
  7. package/packages/datadog-instrumentations/src/hono.js +11 -8
  8. package/packages/datadog-instrumentations/src/knex.js +15 -17
  9. package/packages/datadog-instrumentations/src/moleculer/client.js +2 -3
  10. package/packages/datadog-instrumentations/src/mongodb-core.js +4 -6
  11. package/packages/datadog-instrumentations/src/next.js +4 -8
  12. package/packages/datadog-instrumentations/src/pg.js +38 -48
  13. package/packages/datadog-plugin-aerospike/src/index.js +6 -2
  14. package/packages/datadog-plugin-ai/src/index.js +17 -0
  15. package/packages/datadog-plugin-ai/src/tracing.js +33 -0
  16. package/packages/datadog-plugin-ai/src/utils.js +28 -0
  17. package/packages/datadog-plugin-couchbase/src/index.js +37 -17
  18. package/packages/datadog-plugin-pg/src/index.js +5 -2
  19. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +14 -7
  20. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
  21. package/packages/dd-trace/src/appsec/recommended.json +271 -2
  22. package/packages/dd-trace/src/guardrails/telemetry.js +18 -2
  23. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +351 -0
  24. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +179 -0
  25. package/packages/dd-trace/src/llmobs/writers/base.js +8 -3
  26. package/packages/dd-trace/src/opentracing/propagation/text_map.js +2 -2
  27. package/packages/dd-trace/src/opentracing/span_context.js +4 -0
  28. package/packages/dd-trace/src/plugin_manager.js +8 -4
  29. package/packages/dd-trace/src/plugins/index.js +1 -0
  30. package/packages/dd-trace/src/plugins/util/ip_extractor.js +44 -3
  31. package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +24 -23
  32. package/packages/dd-trace/src/profiling/profilers/events.js +3 -2
  33. package/packages/dd-trace/src/profiling/profilers/wall.js +2 -2
  34. package/packages/dd-trace/src/supported-configurations.json +6 -0
  35. package/packages/dd-trace/src/tracer_metadata.js +1 -1
@@ -0,0 +1,179 @@
1
+ 'use strict'
2
+
3
+ const MODEL_METADATA_KEYS = new Set([
4
+ 'frequency_penalty',
5
+ 'max_tokens',
6
+ 'presence_penalty',
7
+ 'temperature',
8
+ 'top_p',
9
+ 'top_k',
10
+ 'stop_sequences'
11
+ ])
12
+
13
+ /**
14
+ * Get the span tags from the context (either the attributes or the span tags).
15
+ *
16
+ * @param {Record<string, any>} ctx
17
+ * @returns {Record<string, any>}
18
+ */
19
+ function getSpanTags (ctx) {
20
+ const span = ctx.currentStore?.span
21
+ const carrier = ctx.attributes ?? span?.context()._tags ?? {}
22
+ return carrier
23
+ }
24
+
25
+ /**
26
+ * Get the operation name from the span name
27
+ *
28
+ * @example
29
+ * span._name = 'ai.generateText'
30
+ * getOperation(span) // 'generateText'
31
+ *
32
+ * @example
33
+ * span._name = 'ai.generateText.doGenerate'
34
+ * getOperation(span) // 'doGenerate'
35
+ *
36
+ * @param {import('../../../opentracing/span')} span
37
+ * @returns {string}
38
+ */
39
+ function getOperation (span) {
40
+ const name = span._name
41
+ if (!name) return
42
+
43
+ return name.split('.').pop()
44
+ }
45
+
46
+ /**
47
+ * Get the LLM token usage from the span tags
48
+ * @param {Record<string, string>} tags
49
+ * @returns {{inputTokens: number, outputTokens: number, totalTokens: number}}
50
+ */
51
+ function getUsage (tags) {
52
+ const usage = {}
53
+ const inputTokens = tags['ai.usage.promptTokens']
54
+ const outputTokens = tags['ai.usage.completionTokens']
55
+
56
+ if (inputTokens != null) usage.inputTokens = inputTokens
57
+ if (outputTokens != null) usage.outputTokens = outputTokens
58
+
59
+ const totalTokens = inputTokens + outputTokens
60
+ if (!Number.isNaN(totalTokens)) usage.totalTokens = totalTokens
61
+
62
+ return usage
63
+ }
64
+
65
+ /**
66
+ * Safely JSON parses a string value with a default fallback
67
+ * @param {string} str
68
+ * @param {any} defaultValue
69
+ * @returns {Record<string, any> | string | Array<any>}
70
+ */
71
+ function getJsonStringValue (str, defaultValue) {
72
+ let maybeValue = defaultValue
73
+ try {
74
+ maybeValue = JSON.parse(str)
75
+ } catch {
76
+ // do nothing
77
+ }
78
+
79
+ return maybeValue
80
+ }
81
+
82
+ /**
83
+ * Get the model metadata from the span tags (top_p, top_k, temperature, etc.)
84
+ * @param {import('../../../opentracing/span')} span
85
+ * @returns {Record<string, string> | null}
86
+ */
87
+ function getModelMetadata (tags) {
88
+ const modelMetadata = {}
89
+ for (const metadata of MODEL_METADATA_KEYS) {
90
+ const metadataTagKey = `gen_ai.request.${metadata}`
91
+ const metadataValue = tags[metadataTagKey]
92
+ if (metadataValue) {
93
+ modelMetadata[metadata] = metadataValue
94
+ }
95
+ }
96
+
97
+ return Object.keys(modelMetadata).length ? modelMetadata : null
98
+ }
99
+
100
+ /**
101
+ * Get the generation metadata from the span tags (maxSteps, maxRetries, etc.)
102
+ * @param {Record<string, string>} tags
103
+ * @returns {Record<string, string> | null}
104
+ */
105
+ function getGenerationMetadata (tags) {
106
+ const metadata = {}
107
+
108
+ for (const tag of Object.keys(tags)) {
109
+ if (!tag.startsWith('ai.settings')) continue
110
+
111
+ const settingKey = tag.split('.').pop()
112
+ const transformedKey = settingKey.replaceAll(/[A-Z]/g, letter => '_' + letter.toLowerCase())
113
+ if (MODEL_METADATA_KEYS.has(transformedKey)) continue
114
+
115
+ const settingValue = tags[tag]
116
+ metadata[settingKey] = settingValue
117
+ }
118
+
119
+ return Object.keys(metadata).length ? metadata : null
120
+ }
121
+
122
+ /**
123
+ * Get the tool name from the span tags.
124
+ * If the tool name is a parsable number, or is not found, null is returned.
125
+ * Older versions of the ai sdk would tag the tool name as its index in the tools array.
126
+ *
127
+ * @param {Record<string, string>} tags
128
+ * @returns {string | null}
129
+ */
130
+ function getToolNameFromTags (tags) {
131
+ const toolName = tags['ai.toolCall.name']
132
+ if (!toolName) return null
133
+
134
+ const parsedToolName = Number.parseInt(toolName)
135
+ if (!Number.isNaN(parsedToolName)) return null
136
+
137
+ return toolName
138
+ }
139
+
140
+ /**
141
+ * Get the content of a tool call result.
142
+ * Version 5 of the ai sdk sets this tag as `content.output`, with a `
143
+ * @param {Record<string, any>} content
144
+ * @returns {string}
145
+ */
146
+ function getToolCallResultContent (content) {
147
+ const { output, result } = content
148
+ if (output) {
149
+ if (output.type === 'text') {
150
+ return output.value
151
+ } else if (output.type === 'json') {
152
+ return JSON.stringify(output.value)
153
+ }
154
+ return '[Unparsable Tool Result]'
155
+ } else if (result) {
156
+ if (typeof result === 'string') {
157
+ return result
158
+ }
159
+
160
+ try {
161
+ return JSON.stringify(result)
162
+ } catch {
163
+ return '[Unparsable Tool Result]'
164
+ }
165
+ } else {
166
+ return '[Unsupported Tool Result]'
167
+ }
168
+ }
169
+
170
+ module.exports = {
171
+ getSpanTags,
172
+ getOperation,
173
+ getUsage,
174
+ getJsonStringValue,
175
+ getModelMetadata,
176
+ getGenerationMetadata,
177
+ getToolNameFromTags,
178
+ getToolCallResultContent
179
+ }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const request = require('../../exporters/common/request')
4
+ const { getEnvironmentVariable } = require('../../config-helper')
4
5
  const { URL, format } = require('node:url')
5
6
  const path = require('node:path')
6
7
 
@@ -17,8 +18,8 @@ const { parseResponseAndLog } = require('./util')
17
18
 
18
19
  class BaseLLMObsWriter {
19
20
  constructor ({ interval, timeout, eventType, config, endpoint, intake }) {
20
- this._interval = interval || 1000 // 1s
21
- this._timeout = timeout || 5000 // 5s
21
+ this._interval = interval ?? getEnvironmentVariable('_DD_LLMOBS_FLUSH_INTERVAL') ?? 1000 // 1s
22
+ this._timeout = timeout ?? getEnvironmentVariable('_DD_LLMOBS_TIMEOUT') ?? 5000 // 5s
22
23
  this._eventType = eventType
23
24
 
24
25
  this._buffer = []
@@ -119,7 +120,11 @@ class BaseLLMObsWriter {
119
120
  }
120
121
 
121
122
  const { hostname, port } = this._config
122
- const base = this._config.url || new URL(format({
123
+
124
+ const overrideOriginEnv = getEnvironmentVariable('_DD_LLMOBS_OVERRIDE_ORIGIN')
125
+ const overrideOriginUrl = overrideOriginEnv && new URL(overrideOriginEnv)
126
+
127
+ const base = overrideOriginUrl ?? this._config.url ?? new URL(format({
123
128
  protocol: 'http:',
124
129
  hostname,
125
130
  port
@@ -148,13 +148,13 @@ class TextMapPropagator {
148
148
 
149
149
  // Check for item count limit exceeded
150
150
  if (itemCounter > this._config.baggageMaxItems) {
151
- tracerMetrics.count('context_header_style.truncated', ['truncation_reason:baggage_item_count_exceeded']).inc()
151
+ tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_item_count_exceeded']).inc()
152
152
  break
153
153
  }
154
154
 
155
155
  // Check for byte count limit exceeded
156
156
  if (byteCounter > this._config.baggageMaxBytes) {
157
- tracerMetrics.count('context_header_style.truncated', ['truncation_reason:baggage_byte_count_exceeded']).inc()
157
+ tracerMetrics.count('context_header.truncated', ['truncation_reason:baggage_byte_count_exceeded']).inc()
158
158
  break
159
159
  }
160
160
 
@@ -59,6 +59,10 @@ class DatadogSpanContext {
59
59
  return this._spanId.toString(10)
60
60
  }
61
61
 
62
+ toBigIntSpanId () {
63
+ return this._spanId.toBigInt()
64
+ }
65
+
62
66
  toTraceparent () {
63
67
  const flags = this._sampling.priority >= AUTO_KEEP ? '01' : '00'
64
68
  const traceId = this.toTraceId(true)
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { channel } = require('dc-polyfill')
4
- const { isFalse, normalizePluginEnvName } = require('./util')
4
+ const { isFalse, isTrue, normalizePluginEnvName } = require('./util')
5
5
  const plugins = require('./plugins')
6
6
  const log = require('./log')
7
7
  const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
@@ -32,8 +32,7 @@ loadChannel.subscribe(({ name }) => {
32
32
  function maybeEnable (Plugin) {
33
33
  if (!Plugin || typeof Plugin !== 'function') return
34
34
  if (!pluginClasses[Plugin.id]) {
35
- const envName = `DD_TRACE_${Plugin.id.toUpperCase()}_ENABLED`
36
- const enabled = getEnvironmentVariable(normalizePluginEnvName(envName))
35
+ const enabled = getEnvEnabled(Plugin)
37
36
 
38
37
  // TODO: remove the need to load the plugin class in order to disable the plugin
39
38
  if (isFalse(enabled) || disabledPlugins.has(Plugin.id)) {
@@ -46,6 +45,11 @@ function maybeEnable (Plugin) {
46
45
  }
47
46
  }
48
47
 
48
+ function getEnvEnabled (Plugin) {
49
+ const envName = `DD_TRACE_${Plugin.id.toUpperCase()}_ENABLED`
50
+ return getEnvironmentVariable(normalizePluginEnvName(envName))
51
+ }
52
+
49
53
  // TODO this must always be a singleton.
50
54
  module.exports = class PluginManager {
51
55
  constructor (tracer) {
@@ -74,7 +78,7 @@ module.exports = class PluginManager {
74
78
  this._pluginsByName[name] = new Plugin(this._tracer, this._tracerConfig)
75
79
  }
76
80
  const pluginConfig = this._configsByName[name] || {
77
- enabled: this._tracerConfig.plugins !== false
81
+ enabled: this._tracerConfig.plugins !== false && (!Plugin.experimental || isTrue(getEnvEnabled(Plugin)))
78
82
  }
79
83
 
80
84
  // extracts predetermined configuration from tracer and combines it with plugin-specific config
@@ -26,6 +26,7 @@ module.exports = {
26
26
  get '@smithy/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
27
27
  get '@vitest/runner' () { return require('../../../datadog-plugin-vitest/src') },
28
28
  get aerospike () { return require('../../../datadog-plugin-aerospike/src') },
29
+ get ai () { return require('../../../datadog-plugin-ai/src') },
29
30
  get amqp10 () { return require('../../../datadog-plugin-amqp10/src') },
30
31
  get amqplib () { return require('../../../datadog-plugin-amqplib/src') },
31
32
  get avsc () { return require('../../../datadog-plugin-avsc/src') },
@@ -3,11 +3,14 @@
3
3
  const { BlockList } = require('net')
4
4
  const net = require('net')
5
5
 
6
+ const FORWARED_HEADER_NAME = 'forwarded'
7
+
6
8
  const ipHeaderList = [
7
9
  'x-forwarded-for',
8
10
  'x-real-ip',
9
11
  'true-client-ip',
10
12
  'x-client-ip',
13
+ FORWARED_HEADER_NAME,
11
14
  'forwarded-for',
12
15
  'x-cluster-client-ip',
13
16
  'fastly-client-ip',
@@ -49,7 +52,8 @@ function extractIp (config, req) {
49
52
  let firstPrivateIp
50
53
  if (headers) {
51
54
  for (const ipHeaderName of ipHeaderList) {
52
- const firstIp = findFirstIp(headers[ipHeaderName])
55
+ const header = headers[ipHeaderName]
56
+ const firstIp = ipHeaderName === FORWARED_HEADER_NAME ? findFirstIpForwardedFormat(header) : findFirstIp(header)
53
57
 
54
58
  if (firstIp.public) {
55
59
  return firstIp.public
@@ -62,6 +66,10 @@ function extractIp (config, req) {
62
66
  return firstPrivateIp || req.socket?.remoteAddress
63
67
  }
64
68
 
69
+ function isPublicIp (ip, type) {
70
+ return !privateIPMatcher.check(ip, type === 6 ? 'ipv6' : 'ipv4')
71
+ }
72
+
65
73
  function findFirstIp (str) {
66
74
  const result = {}
67
75
  if (!str) return result
@@ -76,10 +84,10 @@ function findFirstIp (str) {
76
84
  const type = net.isIP(chunk)
77
85
  if (!type) continue
78
86
 
79
- if (!privateIPMatcher.check(chunk, type === 6 ? 'ipv6' : 'ipv4')) {
87
+ if (isPublicIp(chunk, type)) {
80
88
  // it's public, return it immediately
81
89
  result.public = chunk
82
- break
90
+ return result
83
91
  }
84
92
 
85
93
  // it's private, only save the first one found
@@ -89,6 +97,39 @@ function findFirstIp (str) {
89
97
  return result
90
98
  }
91
99
 
100
+ const forwardedForRegexp = /for="?\[?(([0-9]+\.)+[0-9]+|[0-9a-f:]*:[0-9a-f]*)/i
101
+ const forwardedByRegexp = /by="?\[?(([0-9]+\.)+[0-9]+|[0-9a-f:]*:[0-9a-f]*)/i
102
+ const forwardedRegexps = [forwardedForRegexp, forwardedByRegexp]
103
+
104
+ function findFirstIpForwardedFormat (str) {
105
+ const result = {}
106
+ if (!str) return result
107
+
108
+ const splitted = str.split(',')
109
+
110
+ for (const part of splitted) {
111
+ const chunk = part.trim()
112
+
113
+ for (const regex of forwardedRegexps) {
114
+ const ip = regex.exec(chunk)?.[1]
115
+
116
+ const type = net.isIP(ip)
117
+ if (!type) continue
118
+
119
+ if (isPublicIp(ip, type)) {
120
+ // it's public, return it immediately
121
+ result.public = ip
122
+ return result
123
+ }
124
+
125
+ // it's private, only save the first one found
126
+ if (!result.private) result.private = ip
127
+ }
128
+ }
129
+
130
+ return result
131
+ }
132
+
92
133
  module.exports = {
93
134
  extractIp,
94
135
  ipHeaderList
@@ -7,54 +7,55 @@ const { performance } = require('perf_hooks')
7
7
  // start/error/finish methods to the appropriate diagnostic channels.
8
8
  // TODO: Decouple this from TracingPlugin.
9
9
  class EventPlugin extends TracingPlugin {
10
+ #eventHandler
11
+ #eventFilter
12
+ #dataSymbol
13
+ #entryType
14
+
10
15
  constructor (eventHandler, eventFilter) {
11
16
  super()
12
- this.eventHandler = eventHandler
13
- this.eventFilter = eventFilter
14
- this.contextData = new WeakMap()
15
- this.entryType = this.constructor.entryType
17
+ this.#eventHandler = eventHandler
18
+ this.#eventFilter = eventFilter
19
+ this.#entryType = this.constructor.entryType
20
+ this.#dataSymbol = Symbol(`dd-trace.profiling.event.${this.#entryType}.${this.constructor.operation}`)
16
21
  }
17
22
 
18
23
  start (ctx) {
19
- this.contextData.set(ctx, {
20
- startEvent: ctx,
21
- startTime: performance.now()
22
- })
24
+ ctx[this.#dataSymbol] = performance.now()
23
25
  }
24
26
 
25
27
  error (ctx) {
26
- const data = this.contextData.get(ctx)
27
- if (data) {
28
- data.error = true
29
- }
28
+ // We don't emit perf events for failed operations
29
+ ctx[this.#dataSymbol] = undefined
30
30
  }
31
31
 
32
32
  finish (ctx) {
33
- const data = this.contextData.get(ctx)
34
-
35
- if (!data) return
33
+ const startTime = ctx[this.#dataSymbol]
34
+ if (startTime === undefined) {
35
+ return
36
+ }
37
+ ctx[this.#dataSymbol] = undefined
36
38
 
37
- const { startEvent, startTime, error } = data
38
- if (error || this.ignoreEvent(startEvent)) {
39
- return // don't emit perf events for failed operations or ignored events
39
+ if (this.ignoreEvent(ctx)) {
40
+ return // don't emit perf events for ignored events
40
41
  }
41
42
 
42
43
  const duration = performance.now() - startTime
43
44
  const event = {
44
- entryType: this.entryType,
45
+ entryType: this.#entryType,
45
46
  startTime,
46
47
  duration
47
48
  }
48
49
 
49
- if (!this.eventFilter(event)) {
50
+ if (!this.#eventFilter(event)) {
50
51
  return
51
52
  }
52
53
 
53
54
  const context = (ctx.currentStore?.span || this.activeSpan)?.context()
54
- event._ddSpanId = context?.toSpanId()
55
- event._ddRootSpanId = context?._trace.started[0]?.context().toSpanId() || event._ddSpanId
55
+ event._ddSpanId = context?.toBigIntSpanId()
56
+ event._ddRootSpanId = context?._trace.started[0]?.context().toBigIntSpanId() || event._ddSpanId
56
57
 
57
- this.eventHandler(this.extendEvent(event, startEvent))
58
+ this.#eventHandler(this.extendEvent(event, ctx))
58
59
  }
59
60
 
60
61
  ignoreEvent () {
@@ -273,10 +273,11 @@ class EventSerializer {
273
273
  new Label({ key: this.timestampLabelKey, num: dateOffset + BigInt(Math.round(endTime * MS_TO_NS)) })
274
274
  ]
275
275
  if (_ddSpanId) {
276
- label.push(labelFromStr(this.stringTable, this.spanIdKey, _ddSpanId))
276
+ label.push(
277
+ new Label({ key: this.spanIdKey, num: _ddSpanId }))
277
278
  }
278
279
  if (_ddRootSpanId) {
279
- label.push(labelFromStr(this.stringTable, this.rootSpanIdKey, _ddRootSpanId))
280
+ label.push(new Label({ key: this.rootSpanIdKey, num: _ddRootSpanId }))
280
281
  }
281
282
 
282
283
  const sampleInput = {
@@ -215,10 +215,10 @@ class NativeWallProfiler {
215
215
 
216
216
  _updateContext (context) {
217
217
  if (context.spanId !== null && typeof context.spanId === 'object') {
218
- context.spanId = context.spanId.toString(10)
218
+ context.spanId = context.spanId.toBigInt()
219
219
  }
220
220
  if (context.rootSpanId !== null && typeof context.rootSpanId === 'object') {
221
- context.rootSpanId = context.rootSpanId.toString(10)
221
+ context.rootSpanId = context.rootSpanId.toBigInt()
222
222
  }
223
223
  if (context.webTags !== undefined && context.endpoint === undefined) {
224
224
  // endpoint may not be determined yet, but keep it as fallback
@@ -118,6 +118,7 @@
118
118
  "DD_PLAYWRIGHT_WORKER": ["A"],
119
119
  "DD_PROFILING_CODEHOTSPOTS_ENABLED": ["A"],
120
120
  "DD_PROFILING_CPU_ENABLED": ["A"],
121
+ "DD_PROFILING_DEBUG_SOURCE_MAPS": ["A"],
121
122
  "DD_PROFILING_DEBUG_UPLOAD_COMPRESSION": ["A"],
122
123
  "DD_PROFILING_ENABLED": ["A"],
123
124
  "DD_PROFILING_ENDPOINT_COLLECTION_ENABLED": ["A"],
@@ -127,9 +128,13 @@
127
128
  "DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED": ["A"],
128
129
  "DD_PROFILING_EXPORTERS": ["A"],
129
130
  "DD_PROFILING_HEAP_ENABLED": ["A"],
131
+ "DD_PROFILING_HEAP_SAMPLING_INTERVAL": ["A"],
132
+ "DD_PROFILING_PPROF_PREFIX": ["A"],
130
133
  "DD_PROFILING_PROFILERS": ["A"],
131
134
  "DD_PROFILING_SOURCE_MAP": ["A"],
135
+ "DD_PROFILING_TIMELINE_ENABLED": ["A"],
132
136
  "DD_PROFILING_UPLOAD_PERIOD": ["A"],
137
+ "DD_PROFILING_UPLOAD_TIMEOUT": ["A"],
133
138
  "DD_PROFILING_V8_PROFILER_BUG_WORKAROUND": ["A"],
134
139
  "DD_PROFILING_WALLTIME_ENABLED": ["A"],
135
140
  "DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS": ["A"],
@@ -160,6 +165,7 @@
160
165
  "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED": ["A"],
161
166
  "DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED": ["A"],
162
167
  "DD_TRACE_AEROSPIKE_ENABLED": ["A"],
168
+ "DD_TRACE_AI_ENABLED": ["A"],
163
169
  "DD_TRACE_AGENT_PORT": ["A"],
164
170
  "DD_TRACE_AGENT_PROTOCOL_VERSION": ["A"],
165
171
  "DD_TRACE_AGENT_URL": ["A"],
@@ -14,7 +14,7 @@ function storeConfig (config) {
14
14
  config.tags['runtime-id'],
15
15
  tracerVersion,
16
16
  config.hostname,
17
- config.server || null,
17
+ config.service || null,
18
18
  config.env || null,
19
19
  config.version || null
20
20
  )