dd-trace 5.40.0 → 5.41.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.
- package/LICENSE-3rdparty.csv +1 -0
- package/package.json +4 -3
- package/packages/datadog-plugin-graphql/src/parse.js +1 -3
- package/packages/datadog-plugin-mongodb-core/src/index.js +4 -1
- package/packages/dd-trace/src/config.js +112 -18
- package/packages/dd-trace/src/config_stable.js +100 -0
- package/packages/dd-trace/src/format.js +0 -1
- package/packages/dd-trace/src/llmobs/plugins/base.js +3 -0
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +3 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -0
- package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -0
- package/packages/dd-trace/src/llmobs/sdk.js +5 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +12 -0
- package/packages/dd-trace/src/log/index.js +26 -13
- package/packages/dd-trace/src/plugins/util/git.js +22 -10
- package/packages/dd-trace/src/plugins/util/web.js +3 -2
- package/packages/dd-trace/src/tagger.js +7 -14
- package/packages/dd-trace/src/util.js +10 -1
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -37,6 +37,7 @@ dev,@eslint/eslintrc,MIT,Copyright OpenJS Foundation and other contributors, <ww
|
|
|
37
37
|
dev,@eslint/js,MIT,Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
|
38
38
|
dev,@msgpack/msgpack,ISC,Copyright 2019 The MessagePack Community
|
|
39
39
|
dev,@stylistic/eslint-plugin-js,MIT,Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
|
40
|
+
dev,application-config-path,MIT,Copyright (c) 2015, 2023 Linus Unnebäck
|
|
40
41
|
dev,autocannon,MIT,Copyright 2016 Matteo Collina
|
|
41
42
|
dev,aws-sdk,Apache 2.0,Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
42
43
|
dev,axios,MIT,Copyright 2014-present Matt Zabriskie
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.41.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"node": ">=18"
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"@datadog/libdatadog": "^0.
|
|
85
|
+
"@datadog/libdatadog": "^0.5.0",
|
|
86
86
|
"@datadog/native-appsec": "8.4.0",
|
|
87
87
|
"@datadog/native-iast-rewriter": "2.8.0",
|
|
88
88
|
"@datadog/native-iast-taint-tracking": "3.3.0",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"crypto-randomuuid": "^1.0.0",
|
|
96
96
|
"dc-polyfill": "^0.1.4",
|
|
97
97
|
"ignore": "^5.2.4",
|
|
98
|
-
"import-in-the-middle": "1.
|
|
98
|
+
"import-in-the-middle": "1.13.1",
|
|
99
99
|
"istanbul-lib-coverage": "3.2.0",
|
|
100
100
|
"jest-docblock": "^29.7.0",
|
|
101
101
|
"koalas": "^1.0.2",
|
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
"@msgpack/msgpack": "^3.0.0-beta3",
|
|
123
123
|
"@stylistic/eslint-plugin-js": "^3.0.1",
|
|
124
124
|
"@types/node": "^16.0.0",
|
|
125
|
+
"application-config-path": "^1.0.0",
|
|
125
126
|
"autocannon": "^4.5.2",
|
|
126
127
|
"aws-sdk": "^2.1446.0",
|
|
127
128
|
"axios": "^1.7.4",
|
|
@@ -25,7 +25,10 @@ class MongodbCorePlugin extends DatabasePlugin {
|
|
|
25
25
|
'out.port': options.port
|
|
26
26
|
}
|
|
27
27
|
})
|
|
28
|
-
|
|
28
|
+
const comment = this.injectDbmComment(span, ops.comment, service)
|
|
29
|
+
if (comment) {
|
|
30
|
+
ops.comment = comment
|
|
31
|
+
}
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
getPeerService (tags) {
|
|
@@ -11,7 +11,7 @@ const tagger = require('./tagger')
|
|
|
11
11
|
const get = require('../../datadog-core/src/utils/src/get')
|
|
12
12
|
const has = require('../../datadog-core/src/utils/src/has')
|
|
13
13
|
const set = require('../../datadog-core/src/utils/src/set')
|
|
14
|
-
const { isTrue, isFalse } = require('./util')
|
|
14
|
+
const { isTrue, isFalse, normalizeProfilingEnabledValue } = require('./util')
|
|
15
15
|
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags')
|
|
16
16
|
const { getGitMetadataFromGitProperties, removeUserSensitiveInfo } = require('./git_properties')
|
|
17
17
|
const { updateConfig } = require('./telemetry')
|
|
@@ -236,6 +236,12 @@ function reformatSpanSamplingRules (rules) {
|
|
|
236
236
|
|
|
237
237
|
class Config {
|
|
238
238
|
constructor (options = {}) {
|
|
239
|
+
if (!isInServerlessEnvironment()) {
|
|
240
|
+
// Bail out early if we're in a serverless environment, stable config isn't supported
|
|
241
|
+
const StableConfig = require('./config_stable')
|
|
242
|
+
this.stableConfig = new StableConfig()
|
|
243
|
+
}
|
|
244
|
+
|
|
239
245
|
options = {
|
|
240
246
|
...options,
|
|
241
247
|
appsec: options.appsec != null ? options.appsec : options.experimental?.appsec,
|
|
@@ -244,13 +250,24 @@ class Config {
|
|
|
244
250
|
|
|
245
251
|
// Configure the logger first so it can be used to warn about other configs
|
|
246
252
|
const logConfig = log.getConfig()
|
|
247
|
-
this.debug =
|
|
253
|
+
this.debug = log.isEnabled(
|
|
254
|
+
this.stableConfig?.fleetEntries?.DD_TRACE_DEBUG,
|
|
255
|
+
this.stableConfig?.localEntries?.DD_TRACE_DEBUG
|
|
256
|
+
)
|
|
248
257
|
this.logger = coalesce(options.logger, logConfig.logger)
|
|
249
|
-
this.logLevel =
|
|
250
|
-
|
|
258
|
+
this.logLevel = log.getLogLevel(
|
|
259
|
+
options.logLevel,
|
|
260
|
+
this.stableConfig?.fleetEntries?.DD_TRACE_LOG_LEVEL,
|
|
261
|
+
this.stableConfig?.localEntries?.DD_TRACE_LOG_LEVEL
|
|
262
|
+
)
|
|
251
263
|
log.use(this.logger)
|
|
252
264
|
log.toggle(this.debug, this.logLevel)
|
|
253
265
|
|
|
266
|
+
// Process stable config warnings, if any
|
|
267
|
+
for (const warning of this.stableConfig?.warnings ?? []) {
|
|
268
|
+
log.warn(warning)
|
|
269
|
+
}
|
|
270
|
+
|
|
254
271
|
checkIfBothOtelAndDdEnvVarSet()
|
|
255
272
|
|
|
256
273
|
const DD_API_KEY = coalesce(
|
|
@@ -337,7 +354,9 @@ class Config {
|
|
|
337
354
|
}
|
|
338
355
|
|
|
339
356
|
this._applyDefaults()
|
|
357
|
+
this._applyLocalStableConfig()
|
|
340
358
|
this._applyEnvironment()
|
|
359
|
+
this._applyFleetStableConfig()
|
|
341
360
|
this._applyOptions(options)
|
|
342
361
|
this._applyCalculated()
|
|
343
362
|
this._applyRemote({})
|
|
@@ -576,6 +595,45 @@ class Config {
|
|
|
576
595
|
this._setValue(defaults, 'trace.dynamoDb.tablePrimaryKeys', undefined)
|
|
577
596
|
}
|
|
578
597
|
|
|
598
|
+
_applyLocalStableConfig () {
|
|
599
|
+
const obj = setHiddenProperty(this, '_localStableConfig', {})
|
|
600
|
+
this._applyStableConfig(this.stableConfig?.localEntries ?? {}, obj)
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
_applyFleetStableConfig () {
|
|
604
|
+
const obj = setHiddenProperty(this, '_fleetStableConfig', {})
|
|
605
|
+
this._applyStableConfig(this.stableConfig?.fleetEntries ?? {}, obj)
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
_applyStableConfig (config, obj) {
|
|
609
|
+
const {
|
|
610
|
+
DD_APPSEC_ENABLED,
|
|
611
|
+
DD_APPSEC_SCA_ENABLED,
|
|
612
|
+
DD_DATA_STREAMS_ENABLED,
|
|
613
|
+
DD_DYNAMIC_INSTRUMENTATION_ENABLED,
|
|
614
|
+
DD_ENV,
|
|
615
|
+
DD_IAST_ENABLED,
|
|
616
|
+
DD_LOGS_INJECTION,
|
|
617
|
+
DD_PROFILING_ENABLED,
|
|
618
|
+
DD_RUNTIME_METRICS_ENABLED,
|
|
619
|
+
DD_SERVICE,
|
|
620
|
+
DD_VERSION
|
|
621
|
+
} = config
|
|
622
|
+
|
|
623
|
+
this._setBoolean(obj, 'appsec.enabled', DD_APPSEC_ENABLED)
|
|
624
|
+
this._setBoolean(obj, 'appsec.sca.enabled', DD_APPSEC_SCA_ENABLED)
|
|
625
|
+
this._setBoolean(obj, 'dsmEnabled', DD_DATA_STREAMS_ENABLED)
|
|
626
|
+
this._setBoolean(obj, 'dynamicInstrumentation.enabled', DD_DYNAMIC_INSTRUMENTATION_ENABLED)
|
|
627
|
+
this._setString(obj, 'env', DD_ENV)
|
|
628
|
+
this._setBoolean(obj, 'iast.enabled', DD_IAST_ENABLED)
|
|
629
|
+
this._setBoolean(obj, 'logInjection', DD_LOGS_INJECTION)
|
|
630
|
+
const profilingEnabled = normalizeProfilingEnabledValue(DD_PROFILING_ENABLED)
|
|
631
|
+
this._setString(obj, 'profiling.enabled', profilingEnabled)
|
|
632
|
+
this._setBoolean(obj, 'runtimeMetrics', DD_RUNTIME_METRICS_ENABLED)
|
|
633
|
+
this._setString(obj, 'service', DD_SERVICE)
|
|
634
|
+
this._setString(obj, 'version', DD_VERSION)
|
|
635
|
+
}
|
|
636
|
+
|
|
579
637
|
_applyEnvironment () {
|
|
580
638
|
const {
|
|
581
639
|
AWS_LAMBDA_FUNCTION_NAME,
|
|
@@ -715,8 +773,8 @@ class Config {
|
|
|
715
773
|
const env = setHiddenProperty(this, '_env', {})
|
|
716
774
|
setHiddenProperty(this, '_envUnprocessed', {})
|
|
717
775
|
|
|
718
|
-
tagger.add(tags, OTEL_RESOURCE_ATTRIBUTES
|
|
719
|
-
tagger.add(tags, DD_TAGS)
|
|
776
|
+
tagger.add(tags, parseSpaceSeparatedTags(handleOtel(OTEL_RESOURCE_ATTRIBUTES)))
|
|
777
|
+
tagger.add(tags, parseSpaceSeparatedTags(DD_TAGS))
|
|
720
778
|
tagger.add(tags, DD_TRACE_TAGS)
|
|
721
779
|
tagger.add(tags, DD_TRACE_GLOBAL_TAGS)
|
|
722
780
|
|
|
@@ -831,16 +889,13 @@ class Config {
|
|
|
831
889
|
this._envUnprocessed.peerServiceMapping = DD_TRACE_PEER_SERVICE_MAPPING
|
|
832
890
|
}
|
|
833
891
|
this._setString(env, 'port', DD_TRACE_AGENT_PORT)
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
892
|
+
const profilingEnabled = normalizeProfilingEnabledValue(
|
|
893
|
+
coalesce(
|
|
894
|
+
DD_EXPERIMENTAL_PROFILING_ENABLED,
|
|
895
|
+
DD_PROFILING_ENABLED,
|
|
896
|
+
this._isInServerlessEnvironment() ? 'false' : undefined
|
|
897
|
+
)
|
|
838
898
|
)
|
|
839
|
-
const profilingEnabled = isTrue(profilingEnabledEnv)
|
|
840
|
-
? 'true'
|
|
841
|
-
: isFalse(profilingEnabledEnv)
|
|
842
|
-
? 'false'
|
|
843
|
-
: profilingEnabledEnv === 'auto' ? 'auto' : undefined
|
|
844
899
|
this._setString(env, 'profiling.enabled', profilingEnabled)
|
|
845
900
|
this._setString(env, 'profiling.exporters', DD_PROFILING_EXPORTERS)
|
|
846
901
|
this._setBoolean(env, 'profiling.sourceMap', DD_PROFILING_SOURCE_MAP && !isFalse(DD_PROFILING_SOURCE_MAP))
|
|
@@ -1347,9 +1402,33 @@ class Config {
|
|
|
1347
1402
|
// eslint-disable-next-line @stylistic/js/max-len
|
|
1348
1403
|
// https://github.com/DataDog/dd-go/blob/prod/trace/apps/tracer-telemetry-intake/telemetry-payload/static/config_norm_rules.json
|
|
1349
1404
|
_merge () {
|
|
1350
|
-
const containers = [
|
|
1351
|
-
|
|
1352
|
-
|
|
1405
|
+
const containers = [
|
|
1406
|
+
this._remote,
|
|
1407
|
+
this._options,
|
|
1408
|
+
this._fleetStableConfig,
|
|
1409
|
+
this._env,
|
|
1410
|
+
this._localStableConfig,
|
|
1411
|
+
this._calculated,
|
|
1412
|
+
this._defaults
|
|
1413
|
+
]
|
|
1414
|
+
const origins = [
|
|
1415
|
+
'remote_config',
|
|
1416
|
+
'code',
|
|
1417
|
+
'fleet_stable_config',
|
|
1418
|
+
'env_var',
|
|
1419
|
+
'local_stable_config',
|
|
1420
|
+
'calculated',
|
|
1421
|
+
'default'
|
|
1422
|
+
]
|
|
1423
|
+
const unprocessedValues = [
|
|
1424
|
+
this._remoteUnprocessed,
|
|
1425
|
+
this._optsUnprocessed,
|
|
1426
|
+
{},
|
|
1427
|
+
this._envUnprocessed,
|
|
1428
|
+
{},
|
|
1429
|
+
{},
|
|
1430
|
+
{}
|
|
1431
|
+
]
|
|
1353
1432
|
const changes = []
|
|
1354
1433
|
|
|
1355
1434
|
for (const name in this._defaults) {
|
|
@@ -1394,6 +1473,21 @@ class Config {
|
|
|
1394
1473
|
}
|
|
1395
1474
|
}
|
|
1396
1475
|
|
|
1476
|
+
function handleOtel (tagString) {
|
|
1477
|
+
return tagString
|
|
1478
|
+
?.replace(/(^|,)deployment\.environment=/, '$1env:')
|
|
1479
|
+
.replace(/(^|,)service\.name=/, '$1service:')
|
|
1480
|
+
.replace(/(^|,)service\.version=/, '$1version:')
|
|
1481
|
+
.replace(/=/g, ':')
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
function parseSpaceSeparatedTags (tagString) {
|
|
1485
|
+
if (tagString && !tagString.includes(',')) {
|
|
1486
|
+
tagString = tagString.replace(/\s+/g, ',')
|
|
1487
|
+
}
|
|
1488
|
+
return tagString
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1397
1491
|
function maybeInt (number) {
|
|
1398
1492
|
const parsed = parseInt(number)
|
|
1399
1493
|
return isNaN(parsed) ? undefined : parsed
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const os = require('os')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
|
|
4
|
+
class StableConfig {
|
|
5
|
+
constructor () {
|
|
6
|
+
this.warnings = [] // Logger hasn't been initialized yet, so we can't use log.warn
|
|
7
|
+
this.localEntries = {}
|
|
8
|
+
this.fleetEntries = {}
|
|
9
|
+
this.wasm_loaded = false
|
|
10
|
+
|
|
11
|
+
const { localConfigPath, fleetConfigPath } = this._getStableConfigPaths()
|
|
12
|
+
if (!fs.existsSync(localConfigPath) && !fs.existsSync(fleetConfigPath)) {
|
|
13
|
+
// Bail out early if files don't exist to avoid unnecessary library loading
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const localConfig = this._readConfigFromPath(localConfigPath)
|
|
18
|
+
const fleetConfig = this._readConfigFromPath(fleetConfigPath)
|
|
19
|
+
if (!localConfig && !fleetConfig) {
|
|
20
|
+
// Bail out early if files are empty or we can't read them to avoid unnecessary library loading
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Note: we don't enforce loading because there may be cases where the library is not available and we
|
|
25
|
+
// want to avoid breaking the application. In those cases, we will not have the file-based configuration.
|
|
26
|
+
let libdatadog
|
|
27
|
+
try {
|
|
28
|
+
libdatadog = require('@datadog/libdatadog')
|
|
29
|
+
this.wasm_loaded = true
|
|
30
|
+
} catch (e) {
|
|
31
|
+
this.warnings.push('Can\'t load libdatadog library')
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const libconfig = libdatadog.maybeLoad('library_config')
|
|
36
|
+
if (libconfig === undefined) {
|
|
37
|
+
this.warnings.push('Can\'t load library_config library')
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const configurator = new libconfig.JsConfigurator()
|
|
43
|
+
configurator.set_envp(Object.entries(process.env).map(([key, value]) => `${key}=${value}`))
|
|
44
|
+
configurator.set_args(process.argv)
|
|
45
|
+
configurator.get_configuration(localConfig.toString(), fleetConfig.toString()).forEach((entry) => {
|
|
46
|
+
if (entry.source === 'local_stable_config') {
|
|
47
|
+
this.localEntries[entry.name] = entry.value
|
|
48
|
+
} else if (entry.source === 'fleet_stable_config') {
|
|
49
|
+
this.fleetEntries[entry.name] = entry.value
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
} catch (e) {
|
|
53
|
+
this.warnings.push(`Error parsing configuration from file: ${e.message}`)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_readConfigFromPath (path) {
|
|
58
|
+
try {
|
|
59
|
+
return fs.readFileSync(path, 'utf8')
|
|
60
|
+
} catch (err) {
|
|
61
|
+
if (err.code !== 'ENOENT') {
|
|
62
|
+
this.warnings.push(`Error reading config file at ${path}. ${err.code}: ${err.message}`)
|
|
63
|
+
}
|
|
64
|
+
return '' // Always return a string to avoid undefined.toString() errors
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_getStableConfigPaths () {
|
|
69
|
+
let localConfigPath = ''
|
|
70
|
+
let fleetConfigPath = ''
|
|
71
|
+
switch (os.type().toLowerCase()) {
|
|
72
|
+
case 'linux':
|
|
73
|
+
localConfigPath = '/etc/datadog-agent/application_monitoring.yaml'
|
|
74
|
+
fleetConfigPath = '/etc/datadog-agent/managed/datadog-agent/stable/application_monitoring.yaml'
|
|
75
|
+
break
|
|
76
|
+
case 'darwin':
|
|
77
|
+
localConfigPath = '/opt/datadog-agent/etc/application_monitoring.yaml'
|
|
78
|
+
fleetConfigPath = '/opt/datadog-agent/etc/managed/datadog-agent/stable/application_monitoring.yaml'
|
|
79
|
+
break
|
|
80
|
+
case 'win32':
|
|
81
|
+
localConfigPath = 'C:\\ProgramData\\Datadog\\application_monitoring.yaml'
|
|
82
|
+
fleetConfigPath = 'C:\\ProgramData\\Datadog\\managed\\datadog-agent\\stable\\application_monitoring.yaml'
|
|
83
|
+
break
|
|
84
|
+
default:
|
|
85
|
+
break
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Allow overriding the paths for testing
|
|
89
|
+
if (process.env.DD_TEST_LOCAL_CONFIG_PATH !== undefined) {
|
|
90
|
+
localConfigPath = process.env.DD_TEST_LOCAL_CONFIG_PATH
|
|
91
|
+
}
|
|
92
|
+
if (process.env.DD_TEST_FLEET_CONFIG_PATH !== undefined) {
|
|
93
|
+
fleetConfigPath = process.env.DD_TEST_FLEET_CONFIG_PATH
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { localConfigPath, fleetConfigPath }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = StableConfig
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const log = require('../../log')
|
|
4
4
|
const { storage: llmobsStorage } = require('../storage')
|
|
5
|
+
const telemetry = require('../telemetry')
|
|
5
6
|
|
|
6
7
|
const TracingPlugin = require('../../plugins/tracing')
|
|
7
8
|
const LLMObsTagger = require('../tagger')
|
|
@@ -36,6 +37,8 @@ class LLMObsPlugin extends TracingPlugin {
|
|
|
36
37
|
// register options may not be set for operations we do not trace with llmobs
|
|
37
38
|
// ie OpenAI fine tuning jobs, file jobs, etc.
|
|
38
39
|
if (registerOptions) {
|
|
40
|
+
telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: this.constructor.id })
|
|
41
|
+
|
|
39
42
|
ctx.llmobs = {} // initialize context-based namespace
|
|
40
43
|
llmobsStorage.enterWith({ span })
|
|
41
44
|
ctx.llmobs.parent = parent
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const BaseLLMObsPlugin = require('./base')
|
|
2
2
|
const { storage } = require('../../../../datadog-core')
|
|
3
3
|
const llmobsStore = storage('llmobs')
|
|
4
|
+
const telemetry = require('../telemetry')
|
|
4
5
|
|
|
5
6
|
const {
|
|
6
7
|
extractRequestParams,
|
|
@@ -46,6 +47,8 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
setLLMObsTags ({ request, span, response, modelProvider, modelName }) {
|
|
50
|
+
telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: 'bedrock' })
|
|
51
|
+
|
|
49
52
|
const parent = llmobsStore.getStore()?.span
|
|
50
53
|
this._tagger.registerLLMObsSpan(span, {
|
|
51
54
|
parent,
|
|
@@ -21,6 +21,7 @@ const LlmHandler = require('./handlers/llm')
|
|
|
21
21
|
const EmbeddingHandler = require('./handlers/embedding')
|
|
22
22
|
|
|
23
23
|
class LangChainLLMObsPlugin extends LLMObsPlugin {
|
|
24
|
+
static get id () { return 'langchain' }
|
|
24
25
|
static get prefix () {
|
|
25
26
|
return 'tracing:apm:langchain:invoke'
|
|
26
27
|
}
|
|
@@ -14,6 +14,7 @@ const Span = require('../opentracing/span')
|
|
|
14
14
|
|
|
15
15
|
const tracerVersion = require('../../../../package.json').version
|
|
16
16
|
const logger = require('../log')
|
|
17
|
+
const telemetry = require('./telemetry')
|
|
17
18
|
|
|
18
19
|
const LLMObsTagger = require('./tagger')
|
|
19
20
|
|
|
@@ -88,6 +89,8 @@ class LLMObs extends NoopLLMObs {
|
|
|
88
89
|
|
|
89
90
|
const kind = validateKind(options.kind) // will throw if kind is undefined or not an expected kind
|
|
90
91
|
|
|
92
|
+
telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: false, kind })
|
|
93
|
+
|
|
91
94
|
// name is required for spans generated with `trace`
|
|
92
95
|
// while `kind` is required, this should never throw (as otherwise it would have thrown above)
|
|
93
96
|
const name = options.name || kind
|
|
@@ -133,6 +136,8 @@ class LLMObs extends NoopLLMObs {
|
|
|
133
136
|
const llmobs = this
|
|
134
137
|
|
|
135
138
|
function wrapped () {
|
|
139
|
+
telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: false, kind })
|
|
140
|
+
|
|
136
141
|
const span = llmobs._tracer.scope().active()
|
|
137
142
|
const fnArgs = arguments
|
|
138
143
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const telemetryMetrics = require('../telemetry/metrics')
|
|
4
|
+
const llmobsMetrics = telemetryMetrics.manager.namespace('mlobs')
|
|
5
|
+
|
|
6
|
+
function incrementLLMObsSpanStartCount (tags, value = 1) {
|
|
7
|
+
llmobsMetrics.count('span.start', tags).inc(value)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
incrementLLMObsSpanStartCount
|
|
12
|
+
}
|
|
@@ -105,23 +105,36 @@ const log = {
|
|
|
105
105
|
|
|
106
106
|
deprecate (code, message) {
|
|
107
107
|
return this._deprecate(code, message)
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
isEnabled (fleetStableConfigValue = undefined, localStableConfigValue = undefined) {
|
|
111
|
+
return isTrue(coalesce(
|
|
112
|
+
fleetStableConfigValue,
|
|
113
|
+
process.env?.DD_TRACE_DEBUG,
|
|
114
|
+
process.env?.OTEL_LOG_LEVEL === 'debug' || undefined,
|
|
115
|
+
localStableConfigValue,
|
|
116
|
+
config.enabled
|
|
117
|
+
))
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
getLogLevel (
|
|
121
|
+
optionsValue = undefined,
|
|
122
|
+
fleetStableConfigValue = undefined,
|
|
123
|
+
localStableConfigValue = undefined
|
|
124
|
+
) {
|
|
125
|
+
return coalesce(
|
|
126
|
+
optionsValue,
|
|
127
|
+
fleetStableConfigValue,
|
|
128
|
+
process.env?.DD_TRACE_LOG_LEVEL,
|
|
129
|
+
process.env?.OTEL_LOG_LEVEL,
|
|
130
|
+
localStableConfigValue,
|
|
131
|
+
config.logLevel
|
|
132
|
+
)
|
|
108
133
|
}
|
|
109
134
|
}
|
|
110
135
|
|
|
111
136
|
log.reset()
|
|
112
137
|
|
|
113
|
-
|
|
114
|
-
process.env.DD_TRACE_DEBUG,
|
|
115
|
-
process.env.OTEL_LOG_LEVEL === 'debug',
|
|
116
|
-
config.enabled
|
|
117
|
-
))
|
|
118
|
-
|
|
119
|
-
const logLevel = coalesce(
|
|
120
|
-
process.env.DD_TRACE_LOG_LEVEL,
|
|
121
|
-
process.env.OTEL_LOG_LEVEL,
|
|
122
|
-
config.logLevel
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
log.toggle(enabled, logLevel)
|
|
138
|
+
log.toggle(log.isEnabled(), log.getLogLevel())
|
|
126
139
|
|
|
127
140
|
module.exports = log
|
|
@@ -328,22 +328,34 @@ function getGitMetadata (ciMetadata) {
|
|
|
328
328
|
committerDate
|
|
329
329
|
] = sanitizedExec('git', ['show', '-s', '--format=%an,%ae,%aI,%cn,%ce,%cI']).split(',')
|
|
330
330
|
|
|
331
|
-
|
|
332
|
-
[GIT_REPOSITORY_URL]:
|
|
333
|
-
filterSensitiveInfoFromRepository(repositoryUrl || sanitizedExec('git', ['ls-remote', '--get-url'])),
|
|
331
|
+
const tags = {
|
|
334
332
|
[GIT_COMMIT_MESSAGE]:
|
|
335
333
|
commitMessage || sanitizedExec('git', ['show', '-s', '--format=%s']),
|
|
336
|
-
[GIT_COMMIT_AUTHOR_DATE]: authorDate,
|
|
337
|
-
[GIT_COMMIT_AUTHOR_NAME]: ciAuthorName || authorName,
|
|
338
|
-
[GIT_COMMIT_AUTHOR_EMAIL]: ciAuthorEmail || authorEmail,
|
|
339
|
-
[GIT_COMMIT_COMMITTER_DATE]: committerDate,
|
|
340
|
-
[GIT_COMMIT_COMMITTER_NAME]: committerName,
|
|
341
|
-
[GIT_COMMIT_COMMITTER_EMAIL]: committerEmail,
|
|
342
334
|
[GIT_BRANCH]: branch || sanitizedExec('git', ['rev-parse', '--abbrev-ref', 'HEAD']),
|
|
343
335
|
[GIT_COMMIT_SHA]: commitSHA || sanitizedExec('git', ['rev-parse', 'HEAD']),
|
|
344
|
-
[GIT_TAG]: tag,
|
|
345
336
|
[CI_WORKSPACE_PATH]: ciWorkspacePath || sanitizedExec('git', ['rev-parse', '--show-toplevel'])
|
|
346
337
|
}
|
|
338
|
+
|
|
339
|
+
const entries = [
|
|
340
|
+
GIT_REPOSITORY_URL,
|
|
341
|
+
filterSensitiveInfoFromRepository(repositoryUrl || sanitizedExec('git', ['ls-remote', '--get-url'])),
|
|
342
|
+
GIT_COMMIT_AUTHOR_DATE, authorDate,
|
|
343
|
+
GIT_COMMIT_AUTHOR_NAME, ciAuthorName || authorName,
|
|
344
|
+
GIT_COMMIT_AUTHOR_EMAIL, ciAuthorEmail || authorEmail,
|
|
345
|
+
GIT_COMMIT_COMMITTER_DATE, committerDate,
|
|
346
|
+
GIT_COMMIT_COMMITTER_NAME, committerName,
|
|
347
|
+
GIT_COMMIT_COMMITTER_EMAIL, committerEmail,
|
|
348
|
+
GIT_TAG, tag
|
|
349
|
+
]
|
|
350
|
+
|
|
351
|
+
for (let i = 0; i < entries.length; i += 2) {
|
|
352
|
+
const value = entries[i + 1]
|
|
353
|
+
if (value) {
|
|
354
|
+
tags[entries[i]] = value
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return tags
|
|
347
359
|
}
|
|
348
360
|
|
|
349
361
|
module.exports = {
|
|
@@ -475,8 +475,9 @@ function addRequestTags (context, spanType) {
|
|
|
475
475
|
function addResponseTags (context) {
|
|
476
476
|
const { req, res, paths, span, inferredProxySpan } = context
|
|
477
477
|
|
|
478
|
-
|
|
479
|
-
|
|
478
|
+
const route = paths.join('')
|
|
479
|
+
if (route) {
|
|
480
|
+
span.setTag(HTTP_ROUTE, route)
|
|
480
481
|
}
|
|
481
482
|
|
|
482
483
|
span.addTags({
|
|
@@ -6,13 +6,7 @@ const ERROR_MESSAGE = constants.ERROR_MESSAGE
|
|
|
6
6
|
const ERROR_STACK = constants.ERROR_STACK
|
|
7
7
|
const ERROR_TYPE = constants.ERROR_TYPE
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
'deployment.environment': 'env',
|
|
11
|
-
'service.name': 'service',
|
|
12
|
-
'service.version': 'version'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function add (carrier, keyValuePairs, parseOtelTags = false) {
|
|
9
|
+
function add (carrier, keyValuePairs) {
|
|
16
10
|
if (!carrier || !keyValuePairs) return
|
|
17
11
|
|
|
18
12
|
if (Array.isArray(keyValuePairs)) {
|
|
@@ -22,14 +16,13 @@ function add (carrier, keyValuePairs, parseOtelTags = false) {
|
|
|
22
16
|
if (typeof keyValuePairs === 'string') {
|
|
23
17
|
const segments = keyValuePairs.split(',')
|
|
24
18
|
for (const segment of segments) {
|
|
25
|
-
const separatorIndex =
|
|
26
|
-
if (separatorIndex === -1) continue
|
|
27
|
-
|
|
28
|
-
let key = segment.slice(0, separatorIndex)
|
|
29
|
-
const value = segment.slice(separatorIndex + 1)
|
|
19
|
+
const separatorIndex = segment.indexOf(':')
|
|
30
20
|
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
let value = ''
|
|
22
|
+
let key = segment
|
|
23
|
+
if (separatorIndex !== -1) {
|
|
24
|
+
key = segment.slice(0, separatorIndex)
|
|
25
|
+
value = segment.slice(separatorIndex + 1)
|
|
33
26
|
}
|
|
34
27
|
|
|
35
28
|
carrier[key.trim()] = value.trim()
|
|
@@ -79,11 +79,20 @@ function hasOwn (object, prop) {
|
|
|
79
79
|
return Object.prototype.hasOwnProperty.call(object, prop)
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
function normalizeProfilingEnabledValue (configValue) {
|
|
83
|
+
return isTrue(configValue)
|
|
84
|
+
? 'true'
|
|
85
|
+
: isFalse(configValue)
|
|
86
|
+
? 'false'
|
|
87
|
+
: configValue === 'auto' ? 'auto' : undefined
|
|
88
|
+
}
|
|
89
|
+
|
|
82
90
|
module.exports = {
|
|
83
91
|
isTrue,
|
|
84
92
|
isFalse,
|
|
85
93
|
isError,
|
|
86
94
|
globMatch,
|
|
87
95
|
calculateDDBasePath,
|
|
88
|
-
hasOwn
|
|
96
|
+
hasOwn,
|
|
97
|
+
normalizeProfilingEnabledValue
|
|
89
98
|
}
|