dd-trace 5.25.0 → 5.26.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 +2 -0
- package/index.d.ts +10 -8
- package/init.js +60 -47
- package/package.json +5 -2
- package/packages/datadog-core/index.js +1 -3
- package/packages/datadog-core/src/storage.js +21 -0
- package/packages/datadog-instrumentations/src/express.js +1 -1
- package/packages/datadog-instrumentations/src/handlebars.js +40 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/jest.js +6 -2
- package/packages/datadog-instrumentations/src/pug.js +23 -0
- package/packages/datadog-instrumentations/src/router.js +2 -3
- package/packages/datadog-plugin-amqplib/src/consumer.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +5 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +9 -7
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +34 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +10 -9
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +59 -45
- package/packages/datadog-plugin-cypress/src/support.js +1 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -1
- package/packages/datadog-plugin-grpc/src/server.js +2 -1
- package/packages/datadog-plugin-http/src/client.js +42 -1
- package/packages/datadog-plugin-http2/src/client.js +26 -1
- package/packages/datadog-plugin-jest/src/index.js +2 -1
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -1
- package/packages/datadog-plugin-mocha/src/index.js +1 -1
- package/packages/datadog-plugin-moleculer/src/server.js +2 -2
- package/packages/datadog-plugin-rhea/src/consumer.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +2 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +50 -27
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +33 -16
- package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +18 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +6 -6
- package/packages/dd-trace/src/appsec/recommended.json +353 -155
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +0 -7
- package/packages/dd-trace/src/appsec/reporter.js +1 -0
- package/packages/dd-trace/src/config.js +13 -4
- package/packages/dd-trace/src/constants.js +6 -1
- package/packages/dd-trace/src/crashtracking/crashtracker.js +98 -0
- package/packages/dd-trace/src/crashtracking/index.js +15 -0
- package/packages/dd-trace/src/crashtracking/noop.js +8 -0
- package/packages/dd-trace/src/llmobs/sdk.js +1 -1
- package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
- package/packages/dd-trace/src/llmobs/writers/spans/base.js +3 -0
- package/packages/dd-trace/src/log/index.js +10 -13
- package/packages/dd-trace/src/log/log.js +52 -0
- package/packages/dd-trace/src/log/writer.js +50 -19
- package/packages/dd-trace/src/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +15 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +35 -22
- package/packages/dd-trace/src/opentracing/span.js +14 -0
- package/packages/dd-trace/src/opentracing/span_context.js +1 -0
- package/packages/dd-trace/src/plugins/tracing.js +3 -3
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +121 -0
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +0 -1
- package/packages/dd-trace/src/plugins/util/web.js +39 -11
- package/packages/dd-trace/src/proxy.js +5 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +16 -11
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -8
- package/packages/dd-trace/src/telemetry/metrics.js +6 -1
- package/packages/dd-trace/src/util.js +16 -1
- package/version.js +4 -2
- /package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/{code-injection-sensitive-analyzer.js → tainted-range-based-sensitive-analyzer.js} +0 -0
|
@@ -11,7 +11,7 @@ module.exports = {
|
|
|
11
11
|
ASM_CUSTOM_RULES: 1n << 8n,
|
|
12
12
|
ASM_CUSTOM_BLOCKING_RESPONSE: 1n << 9n,
|
|
13
13
|
ASM_TRUSTED_IPS: 1n << 10n,
|
|
14
|
-
ASM_API_SECURITY_SAMPLE_RATE: 1n << 11n,
|
|
14
|
+
ASM_API_SECURITY_SAMPLE_RATE: 1n << 11n, // deprecated
|
|
15
15
|
APM_TRACING_SAMPLE_RATE: 1n << 12n,
|
|
16
16
|
APM_TRACING_LOGS_INJECTION: 1n << 13n,
|
|
17
17
|
APM_TRACING_HTTP_HEADER_TAGS: 1n << 14n,
|
|
@@ -4,7 +4,6 @@ const Activation = require('../activation')
|
|
|
4
4
|
|
|
5
5
|
const RemoteConfigManager = require('./manager')
|
|
6
6
|
const RemoteConfigCapabilities = require('./capabilities')
|
|
7
|
-
const apiSecuritySampler = require('../api_security_sampler')
|
|
8
7
|
|
|
9
8
|
let rc
|
|
10
9
|
|
|
@@ -24,18 +23,12 @@ function enable (config, appsec) {
|
|
|
24
23
|
rc.updateCapabilities(RemoteConfigCapabilities.ASM_ACTIVATION, true)
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
if (config.appsec.apiSecurity?.enabled) {
|
|
28
|
-
rc.updateCapabilities(RemoteConfigCapabilities.ASM_API_SECURITY_SAMPLE_RATE, true)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
26
|
rc.setProductHandler('ASM_FEATURES', (action, rcConfig) => {
|
|
32
27
|
if (!rcConfig) return
|
|
33
28
|
|
|
34
29
|
if (activation === Activation.ONECLICK) {
|
|
35
30
|
enableOrDisableAppsec(action, rcConfig, config, appsec)
|
|
36
31
|
}
|
|
37
|
-
|
|
38
|
-
apiSecuritySampler.setRequestSampling(rcConfig.api_security?.request_sample_rate)
|
|
39
32
|
})
|
|
40
33
|
}
|
|
41
34
|
|
|
@@ -444,7 +444,7 @@ class Config {
|
|
|
444
444
|
const defaults = setHiddenProperty(this, '_defaults', {})
|
|
445
445
|
|
|
446
446
|
this._setValue(defaults, 'appsec.apiSecurity.enabled', true)
|
|
447
|
-
this._setValue(defaults, 'appsec.apiSecurity.
|
|
447
|
+
this._setValue(defaults, 'appsec.apiSecurity.sampleDelay', 30)
|
|
448
448
|
this._setValue(defaults, 'appsec.blockedTemplateGraphql', undefined)
|
|
449
449
|
this._setValue(defaults, 'appsec.blockedTemplateHtml', undefined)
|
|
450
450
|
this._setValue(defaults, 'appsec.blockedTemplateJson', undefined)
|
|
@@ -467,6 +467,7 @@ class Config {
|
|
|
467
467
|
this._setValue(defaults, 'ciVisibilityTestSessionName', '')
|
|
468
468
|
this._setValue(defaults, 'clientIpEnabled', false)
|
|
469
469
|
this._setValue(defaults, 'clientIpHeader', null)
|
|
470
|
+
this._setValue(defaults, 'crashtracking.enabled', false)
|
|
470
471
|
this._setValue(defaults, 'codeOriginForSpans.enabled', false)
|
|
471
472
|
this._setValue(defaults, 'dbmPropagationMode', 'disabled')
|
|
472
473
|
this._setValue(defaults, 'dogstatsd.hostname', '127.0.0.1')
|
|
@@ -513,6 +514,7 @@ class Config {
|
|
|
513
514
|
this._setValue(defaults, 'isTestDynamicInstrumentationEnabled', false)
|
|
514
515
|
this._setValue(defaults, 'logInjection', false)
|
|
515
516
|
this._setValue(defaults, 'lookup', undefined)
|
|
517
|
+
this._setValue(defaults, 'inferredProxyServicesEnabled', false)
|
|
516
518
|
this._setValue(defaults, 'memcachedCommandEnabled', false)
|
|
517
519
|
this._setValue(defaults, 'openAiLogsEnabled', false)
|
|
518
520
|
this._setValue(defaults, 'openaiSpanCharLimit', 128)
|
|
@@ -569,7 +571,7 @@ class Config {
|
|
|
569
571
|
AWS_LAMBDA_FUNCTION_NAME,
|
|
570
572
|
DD_AGENT_HOST,
|
|
571
573
|
DD_API_SECURITY_ENABLED,
|
|
572
|
-
|
|
574
|
+
DD_API_SECURITY_SAMPLE_DELAY,
|
|
573
575
|
DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING,
|
|
574
576
|
DD_APPSEC_ENABLED,
|
|
575
577
|
DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON,
|
|
@@ -585,6 +587,7 @@ class Config {
|
|
|
585
587
|
DD_APPSEC_RASP_ENABLED,
|
|
586
588
|
DD_APPSEC_TRACE_RATE_LIMIT,
|
|
587
589
|
DD_APPSEC_WAF_TIMEOUT,
|
|
590
|
+
DD_CRASHTRACKING_ENABLED,
|
|
588
591
|
DD_CODE_ORIGIN_FOR_SPANS_ENABLED,
|
|
589
592
|
DD_DATA_STREAMS_ENABLED,
|
|
590
593
|
DD_DBM_PROPAGATION_MODE,
|
|
@@ -675,6 +678,7 @@ class Config {
|
|
|
675
678
|
DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
|
|
676
679
|
DD_TRACING_ENABLED,
|
|
677
680
|
DD_VERSION,
|
|
681
|
+
DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED,
|
|
678
682
|
OTEL_METRICS_EXPORTER,
|
|
679
683
|
OTEL_PROPAGATORS,
|
|
680
684
|
OTEL_RESOURCE_ATTRIBUTES,
|
|
@@ -696,7 +700,7 @@ class Config {
|
|
|
696
700
|
DD_API_SECURITY_ENABLED && isTrue(DD_API_SECURITY_ENABLED),
|
|
697
701
|
DD_EXPERIMENTAL_API_SECURITY_ENABLED && isTrue(DD_EXPERIMENTAL_API_SECURITY_ENABLED)
|
|
698
702
|
))
|
|
699
|
-
this.
|
|
703
|
+
this._setValue(env, 'appsec.apiSecurity.sampleDelay', maybeFloat(DD_API_SECURITY_SAMPLE_DELAY))
|
|
700
704
|
this._setValue(env, 'appsec.blockedTemplateGraphql', maybeFile(DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON))
|
|
701
705
|
this._setValue(env, 'appsec.blockedTemplateHtml', maybeFile(DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML))
|
|
702
706
|
this._envUnprocessed['appsec.blockedTemplateHtml'] = DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML
|
|
@@ -728,6 +732,7 @@ class Config {
|
|
|
728
732
|
this._setValue(env, 'baggageMaxItems', DD_TRACE_BAGGAGE_MAX_ITEMS)
|
|
729
733
|
this._setBoolean(env, 'clientIpEnabled', DD_TRACE_CLIENT_IP_ENABLED)
|
|
730
734
|
this._setString(env, 'clientIpHeader', DD_TRACE_CLIENT_IP_HEADER)
|
|
735
|
+
this._setBoolean(env, 'crashtracking.enabled', DD_CRASHTRACKING_ENABLED)
|
|
731
736
|
this._setBoolean(env, 'codeOriginForSpans.enabled', DD_CODE_ORIGIN_FOR_SPANS_ENABLED)
|
|
732
737
|
this._setString(env, 'dbmPropagationMode', DD_DBM_PROPAGATION_MODE)
|
|
733
738
|
this._setString(env, 'dogstatsd.hostname', DD_DOGSTATSD_HOSTNAME)
|
|
@@ -862,6 +867,7 @@ class Config {
|
|
|
862
867
|
: !!OTEL_PROPAGATORS)
|
|
863
868
|
this._setBoolean(env, 'tracing', DD_TRACING_ENABLED)
|
|
864
869
|
this._setString(env, 'version', DD_VERSION || tags.version)
|
|
870
|
+
this._setBoolean(env, 'inferredProxyServicesEnabled', DD_TRACE_INFERRED_PROXY_SERVICES_ENABLED)
|
|
865
871
|
}
|
|
866
872
|
|
|
867
873
|
_applyOptions (options) {
|
|
@@ -874,7 +880,6 @@ class Config {
|
|
|
874
880
|
tagger.add(tags, options.tags)
|
|
875
881
|
|
|
876
882
|
this._setBoolean(opts, 'appsec.apiSecurity.enabled', options.appsec.apiSecurity?.enabled)
|
|
877
|
-
this._setUnit(opts, 'appsec.apiSecurity.requestSampling', options.appsec.apiSecurity?.requestSampling)
|
|
878
883
|
this._setValue(opts, 'appsec.blockedTemplateGraphql', maybeFile(options.appsec.blockedTemplateGraphql))
|
|
879
884
|
this._setValue(opts, 'appsec.blockedTemplateHtml', maybeFile(options.appsec.blockedTemplateHtml))
|
|
880
885
|
this._optsUnprocessed['appsec.blockedTemplateHtml'] = options.appsec.blockedTemplateHtml
|
|
@@ -980,6 +985,7 @@ class Config {
|
|
|
980
985
|
this._setBoolean(opts, 'traceId128BitGenerationEnabled', options.traceId128BitGenerationEnabled)
|
|
981
986
|
this._setBoolean(opts, 'traceId128BitLoggingEnabled', options.traceId128BitLoggingEnabled)
|
|
982
987
|
this._setString(opts, 'version', options.version || tags.version)
|
|
988
|
+
this._setBoolean(opts, 'inferredProxyServicesEnabled', options.inferredProxyServicesEnabled)
|
|
983
989
|
|
|
984
990
|
// For LLMObs, we want the environment variable to take precedence over the options.
|
|
985
991
|
// This is reliant on environment config being set before options.
|
|
@@ -1134,6 +1140,9 @@ class Config {
|
|
|
1134
1140
|
if (iastEnabled || ['auto', 'true'].includes(profilingEnabled) || injectionIncludesProfiler) {
|
|
1135
1141
|
this._setBoolean(calc, 'telemetry.logCollection', true)
|
|
1136
1142
|
}
|
|
1143
|
+
if (this._env.injectionEnabled?.length > 0) {
|
|
1144
|
+
this._setBoolean(calc, 'crashtracking.enabled', true)
|
|
1145
|
+
}
|
|
1137
1146
|
}
|
|
1138
1147
|
|
|
1139
1148
|
_applyRemote (options) {
|
|
@@ -46,5 +46,10 @@ module.exports = {
|
|
|
46
46
|
SCHEMA_OPERATION: 'schema.operation',
|
|
47
47
|
SCHEMA_NAME: 'schema.name',
|
|
48
48
|
GRPC_CLIENT_ERROR_STATUSES: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
|
|
49
|
-
GRPC_SERVER_ERROR_STATUSES: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
|
|
49
|
+
GRPC_SERVER_ERROR_STATUSES: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
|
|
50
|
+
S3_PTR_KIND: 'aws.s3.object',
|
|
51
|
+
SPAN_POINTER_DIRECTION: Object.freeze({
|
|
52
|
+
UPSTREAM: 'u',
|
|
53
|
+
DOWNSTREAM: 'd'
|
|
54
|
+
})
|
|
50
55
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Load binding first to not import other modules if it throws
|
|
4
|
+
const libdatadog = require('@datadog/libdatadog')
|
|
5
|
+
const binding = libdatadog.load('crashtracker')
|
|
6
|
+
|
|
7
|
+
const log = require('../log')
|
|
8
|
+
const { URL } = require('url')
|
|
9
|
+
const pkg = require('../../../../package.json')
|
|
10
|
+
|
|
11
|
+
class Crashtracker {
|
|
12
|
+
constructor () {
|
|
13
|
+
this._started = false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
configure (config) {
|
|
17
|
+
if (!this._started) return
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
binding.updateConfig(this._getConfig(config))
|
|
21
|
+
binding.updateMetadata(this._getMetadata(config))
|
|
22
|
+
} catch (e) {
|
|
23
|
+
log.error(e)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
start (config) {
|
|
28
|
+
if (this._started) return this.configure(config)
|
|
29
|
+
|
|
30
|
+
this._started = true
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
binding.init(
|
|
34
|
+
this._getConfig(config),
|
|
35
|
+
this._getReceiverConfig(config),
|
|
36
|
+
this._getMetadata(config)
|
|
37
|
+
)
|
|
38
|
+
} catch (e) {
|
|
39
|
+
log.error(e)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// TODO: Send only configured values when defaults are fixed.
|
|
44
|
+
_getConfig (config) {
|
|
45
|
+
const { hostname = '127.0.0.1', port = 8126 } = config
|
|
46
|
+
const url = config.url || new URL(`http://${hostname}:${port}`)
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
additional_files: [],
|
|
50
|
+
create_alt_stack: true,
|
|
51
|
+
use_alt_stack: true,
|
|
52
|
+
endpoint: {
|
|
53
|
+
// TODO: Use the string directly when deserialization is fixed.
|
|
54
|
+
url: {
|
|
55
|
+
scheme: url.protocol.slice(0, -1),
|
|
56
|
+
authority: url.protocol === 'unix'
|
|
57
|
+
? Buffer.from(url.pathname).toString('hex')
|
|
58
|
+
: url.host,
|
|
59
|
+
path_and_query: ''
|
|
60
|
+
},
|
|
61
|
+
timeout_ms: 3000
|
|
62
|
+
},
|
|
63
|
+
timeout_ms: 0,
|
|
64
|
+
// TODO: Use `EnabledWithSymbolsInReceiver` instead for Linux when fixed.
|
|
65
|
+
resolve_frames: 'EnabledWithInprocessSymbols'
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_getMetadata (config) {
|
|
70
|
+
const tags = Object.keys(config.tags).map(key => `${key}:${config.tags[key]}`)
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
library_name: pkg.name,
|
|
74
|
+
library_version: pkg.version,
|
|
75
|
+
family: 'nodejs',
|
|
76
|
+
tags: [
|
|
77
|
+
...tags,
|
|
78
|
+
'is_crash:true',
|
|
79
|
+
'language:javascript',
|
|
80
|
+
`library_version:${pkg.version}`,
|
|
81
|
+
'runtime:nodejs',
|
|
82
|
+
'severity:crash'
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_getReceiverConfig () {
|
|
88
|
+
return {
|
|
89
|
+
args: [],
|
|
90
|
+
env: [],
|
|
91
|
+
path_to_receiver_binary: libdatadog.find('crashtracker-receiver', true),
|
|
92
|
+
stderr_filename: null,
|
|
93
|
+
stdout_filename: null
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = new Crashtracker()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { isMainThread } = require('worker_threads')
|
|
4
|
+
const log = require('../log')
|
|
5
|
+
|
|
6
|
+
if (isMainThread) {
|
|
7
|
+
try {
|
|
8
|
+
module.exports = require('./crashtracker')
|
|
9
|
+
} catch (e) {
|
|
10
|
+
log.warn(e.message)
|
|
11
|
+
module.exports = require('./noop')
|
|
12
|
+
}
|
|
13
|
+
} else {
|
|
14
|
+
module.exports = require('./noop')
|
|
15
|
+
}
|
|
@@ -6,6 +6,8 @@ const { DROPPED_IO_COLLECTION_ERROR } = require('../../constants/tags')
|
|
|
6
6
|
const BaseWriter = require('../base')
|
|
7
7
|
const logger = require('../../../log')
|
|
8
8
|
|
|
9
|
+
const tracerVersion = require('../../../../../../package.json').version
|
|
10
|
+
|
|
9
11
|
class LLMObsSpanWriter extends BaseWriter {
|
|
10
12
|
constructor (options) {
|
|
11
13
|
super({
|
|
@@ -32,6 +34,7 @@ class LLMObsSpanWriter extends BaseWriter {
|
|
|
32
34
|
makePayload (events) {
|
|
33
35
|
return {
|
|
34
36
|
'_dd.stage': 'raw',
|
|
37
|
+
'_dd.tracer_version': tracerVersion,
|
|
35
38
|
event_type: this._eventType,
|
|
36
39
|
spans: events
|
|
37
40
|
}
|
|
@@ -4,6 +4,7 @@ const coalesce = require('koalas')
|
|
|
4
4
|
const { isTrue } = require('../util')
|
|
5
5
|
const { debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
|
|
6
6
|
const logWriter = require('./writer')
|
|
7
|
+
const { Log } = require('./log')
|
|
7
8
|
|
|
8
9
|
const memoize = func => {
|
|
9
10
|
const cache = {}
|
|
@@ -18,10 +19,6 @@ const memoize = func => {
|
|
|
18
19
|
return memoized
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
function processMsg (msg) {
|
|
22
|
-
return typeof msg === 'function' ? msg() : msg
|
|
23
|
-
}
|
|
24
|
-
|
|
25
22
|
const config = {
|
|
26
23
|
enabled: false,
|
|
27
24
|
logger: undefined,
|
|
@@ -52,37 +49,37 @@ const log = {
|
|
|
52
49
|
reset () {
|
|
53
50
|
logWriter.reset()
|
|
54
51
|
this._deprecate = memoize((code, message) => {
|
|
55
|
-
errorChannel.publish(message)
|
|
52
|
+
errorChannel.publish(Log.parse(message))
|
|
56
53
|
return true
|
|
57
54
|
})
|
|
58
55
|
|
|
59
56
|
return this
|
|
60
57
|
},
|
|
61
58
|
|
|
62
|
-
debug (
|
|
59
|
+
debug (...args) {
|
|
63
60
|
if (debugChannel.hasSubscribers) {
|
|
64
|
-
debugChannel.publish(
|
|
61
|
+
debugChannel.publish(Log.parse(...args))
|
|
65
62
|
}
|
|
66
63
|
return this
|
|
67
64
|
},
|
|
68
65
|
|
|
69
|
-
info (
|
|
66
|
+
info (...args) {
|
|
70
67
|
if (infoChannel.hasSubscribers) {
|
|
71
|
-
infoChannel.publish(
|
|
68
|
+
infoChannel.publish(Log.parse(...args))
|
|
72
69
|
}
|
|
73
70
|
return this
|
|
74
71
|
},
|
|
75
72
|
|
|
76
|
-
warn (
|
|
73
|
+
warn (...args) {
|
|
77
74
|
if (warnChannel.hasSubscribers) {
|
|
78
|
-
warnChannel.publish(
|
|
75
|
+
warnChannel.publish(Log.parse(...args))
|
|
79
76
|
}
|
|
80
77
|
return this
|
|
81
78
|
},
|
|
82
79
|
|
|
83
|
-
error (
|
|
80
|
+
error (...args) {
|
|
84
81
|
if (errorChannel.hasSubscribers) {
|
|
85
|
-
errorChannel.publish(
|
|
82
|
+
errorChannel.publish(Log.parse(...args))
|
|
86
83
|
}
|
|
87
84
|
return this
|
|
88
85
|
},
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { format } = require('util')
|
|
4
|
+
|
|
5
|
+
class Log {
|
|
6
|
+
constructor (message, args, cause, delegate) {
|
|
7
|
+
this.message = message
|
|
8
|
+
this.args = args
|
|
9
|
+
this.cause = cause
|
|
10
|
+
this.delegate = delegate
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get formatted () {
|
|
14
|
+
const { message, args } = this
|
|
15
|
+
|
|
16
|
+
let formatted = message
|
|
17
|
+
if (message && args && args.length) {
|
|
18
|
+
formatted = format(message, ...args)
|
|
19
|
+
}
|
|
20
|
+
return formatted
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static parse (...args) {
|
|
24
|
+
let message, cause, delegate
|
|
25
|
+
|
|
26
|
+
const lastArg = args[args.length - 1]
|
|
27
|
+
if (lastArg && typeof lastArg === 'object' && lastArg.stack) { // lastArg instanceof Error?
|
|
28
|
+
cause = args.pop()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const firstArg = args.shift()
|
|
32
|
+
if (firstArg) {
|
|
33
|
+
if (typeof firstArg === 'string') {
|
|
34
|
+
message = firstArg
|
|
35
|
+
} else if (typeof firstArg === 'object') {
|
|
36
|
+
message = String(firstArg.message || firstArg)
|
|
37
|
+
} else if (typeof firstArg === 'function') {
|
|
38
|
+
delegate = firstArg
|
|
39
|
+
} else {
|
|
40
|
+
message = String(firstArg)
|
|
41
|
+
}
|
|
42
|
+
} else if (!cause) {
|
|
43
|
+
message = String(firstArg)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return new Log(message, args, cause, delegate)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
Log
|
|
52
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { storage } = require('../../../datadog-core')
|
|
4
4
|
const { LogChannel } = require('./channels')
|
|
5
|
+
const { Log } = require('./log')
|
|
5
6
|
const defaultLogger = {
|
|
6
7
|
debug: msg => console.debug(msg), /* eslint-disable-line no-console */
|
|
7
8
|
info: msg => console.info(msg), /* eslint-disable-line no-console */
|
|
@@ -22,7 +23,7 @@ function withNoop (fn) {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
function unsubscribeAll () {
|
|
25
|
-
logChannel.unsubscribe({ debug, info, warn, error })
|
|
26
|
+
logChannel.unsubscribe({ debug: onDebug, info: onInfo, warn: onWarn, error: onError })
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
function toggleSubscription (enable, level) {
|
|
@@ -30,7 +31,7 @@ function toggleSubscription (enable, level) {
|
|
|
30
31
|
|
|
31
32
|
if (enable) {
|
|
32
33
|
logChannel = new LogChannel(level)
|
|
33
|
-
logChannel.subscribe({ debug, info, warn, error })
|
|
34
|
+
logChannel.subscribe({ debug: onDebug, info: onInfo, warn: onWarn, error: onError })
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -51,32 +52,62 @@ function reset () {
|
|
|
51
52
|
toggleSubscription(false)
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
function
|
|
55
|
-
if (typeof err
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
function getErrorLog (err) {
|
|
56
|
+
if (err && typeof err.delegate === 'function') {
|
|
57
|
+
const result = err.delegate()
|
|
58
|
+
return Array.isArray(result) ? Log.parse(...result) : Log.parse(result)
|
|
59
|
+
} else {
|
|
60
|
+
return err
|
|
59
61
|
}
|
|
62
|
+
}
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
function onError (err) {
|
|
65
|
+
const { formatted, cause } = getErrorLog(err)
|
|
66
|
+
|
|
67
|
+
// calling twice logger.error() because Error cause is only available in nodejs v16.9.0
|
|
68
|
+
// TODO: replace it with Error(message, { cause }) when cause has broad support
|
|
69
|
+
if (formatted) withNoop(() => logger.error(new Error(formatted)))
|
|
70
|
+
if (cause) withNoop(() => logger.error(cause))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function onWarn (log) {
|
|
74
|
+
const { formatted, cause } = getErrorLog(log)
|
|
75
|
+
if (formatted) withNoop(() => logger.warn(formatted))
|
|
76
|
+
if (cause) withNoop(() => logger.warn(cause))
|
|
77
|
+
}
|
|
64
78
|
|
|
65
|
-
|
|
79
|
+
function onInfo (log) {
|
|
80
|
+
const { formatted, cause } = getErrorLog(log)
|
|
81
|
+
if (formatted) withNoop(() => logger.info(formatted))
|
|
82
|
+
if (cause) withNoop(() => logger.info(cause))
|
|
66
83
|
}
|
|
67
84
|
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
withNoop(() => logger.
|
|
85
|
+
function onDebug (log) {
|
|
86
|
+
const { formatted, cause } = getErrorLog(log)
|
|
87
|
+
if (formatted) withNoop(() => logger.debug(formatted))
|
|
88
|
+
if (cause) withNoop(() => logger.debug(cause))
|
|
71
89
|
}
|
|
72
90
|
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
91
|
+
function error (...args) {
|
|
92
|
+
onError(Log.parse(...args))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function warn (...args) {
|
|
96
|
+
const log = Log.parse(...args)
|
|
97
|
+
if (!logger.warn) return onDebug(log)
|
|
98
|
+
|
|
99
|
+
onWarn(log)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function info (...args) {
|
|
103
|
+
const log = Log.parse(...args)
|
|
104
|
+
if (!logger.info) return onDebug(log)
|
|
105
|
+
|
|
106
|
+
onInfo(log)
|
|
76
107
|
}
|
|
77
108
|
|
|
78
|
-
function debug (
|
|
79
|
-
|
|
109
|
+
function debug (...args) {
|
|
110
|
+
onDebug(Log.parse(...args))
|
|
80
111
|
}
|
|
81
112
|
|
|
82
113
|
module.exports = { use, toggle, reset, error, warn, info, debug }
|
|
@@ -14,6 +14,7 @@ const { SERVICE_NAME, RESOURCE_NAME } = require('../../../../ext/tags')
|
|
|
14
14
|
const kinds = require('../../../../ext/kinds')
|
|
15
15
|
|
|
16
16
|
const SpanContext = require('./span_context')
|
|
17
|
+
const id = require('../id')
|
|
17
18
|
|
|
18
19
|
// The one built into OTel rounds so we lose sub-millisecond precision.
|
|
19
20
|
function hrTimeToMilliseconds (time) {
|
|
@@ -217,6 +218,20 @@ class Span {
|
|
|
217
218
|
return this
|
|
218
219
|
}
|
|
219
220
|
|
|
221
|
+
addSpanPointer (ptrKind, ptrDir, ptrHash) {
|
|
222
|
+
const zeroContext = new SpanContext({
|
|
223
|
+
traceId: id('0'),
|
|
224
|
+
spanId: id('0')
|
|
225
|
+
})
|
|
226
|
+
const attributes = {
|
|
227
|
+
'ptr.kind': ptrKind,
|
|
228
|
+
'ptr.dir': ptrDir,
|
|
229
|
+
'ptr.hash': ptrHash,
|
|
230
|
+
'link.kind': 'span-pointer'
|
|
231
|
+
}
|
|
232
|
+
return this.addLink(zeroContext, attributes)
|
|
233
|
+
}
|
|
234
|
+
|
|
220
235
|
setStatus ({ code, message }) {
|
|
221
236
|
if (!this.ended && !this._hasStatus && code) {
|
|
222
237
|
this._hasStatus = true
|
|
@@ -290,50 +290,63 @@ class TextMapPropagator {
|
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
_extractSpanContext (carrier) {
|
|
293
|
-
let
|
|
293
|
+
let context = null
|
|
294
294
|
for (const extractor of this._config.tracePropagationStyle.extract) {
|
|
295
|
-
|
|
296
|
-
if (spanContext !== null) {
|
|
297
|
-
if (this._config.tracePropagationExtractFirst) {
|
|
298
|
-
return spanContext
|
|
299
|
-
}
|
|
300
|
-
if (extractor !== 'tracecontext') {
|
|
301
|
-
continue
|
|
302
|
-
}
|
|
303
|
-
spanContext = this._resolveTraceContextConflicts(
|
|
304
|
-
this._extractTraceparentContext(carrier), spanContext, carrier)
|
|
305
|
-
break
|
|
306
|
-
}
|
|
307
|
-
|
|
295
|
+
let extractedContext = null
|
|
308
296
|
switch (extractor) {
|
|
309
297
|
case 'datadog':
|
|
310
|
-
|
|
298
|
+
extractedContext = this._extractDatadogContext(carrier)
|
|
311
299
|
break
|
|
312
300
|
case 'tracecontext':
|
|
313
|
-
|
|
301
|
+
extractedContext = this._extractTraceparentContext(carrier)
|
|
314
302
|
break
|
|
315
303
|
case 'b3' && this
|
|
316
304
|
._config
|
|
317
305
|
.tracePropagationStyle
|
|
318
306
|
.otelPropagators: // TODO: should match "b3 single header" in next major
|
|
319
307
|
case 'b3 single header': // TODO: delete in major after singular "b3"
|
|
320
|
-
|
|
308
|
+
extractedContext = this._extractB3SingleContext(carrier)
|
|
321
309
|
break
|
|
322
310
|
case 'b3':
|
|
323
311
|
case 'b3multi':
|
|
324
|
-
|
|
312
|
+
extractedContext = this._extractB3MultiContext(carrier)
|
|
325
313
|
break
|
|
326
314
|
default:
|
|
327
|
-
log.warn(`Unknown propagation style: ${extractor}`)
|
|
315
|
+
if (extractor !== 'baggage') log.warn(`Unknown propagation style: ${extractor}`)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (extractedContext === null) { // If the current extractor was invalid, continue to the next extractor
|
|
319
|
+
continue
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (context === null) {
|
|
323
|
+
context = extractedContext
|
|
324
|
+
if (this._config.tracePropagationExtractFirst) {
|
|
325
|
+
return context
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
// If extractor is tracecontext, add tracecontext specific information to the context
|
|
329
|
+
if (extractor === 'tracecontext') {
|
|
330
|
+
context = this._resolveTraceContextConflicts(
|
|
331
|
+
this._extractTraceparentContext(carrier), context, carrier)
|
|
332
|
+
}
|
|
333
|
+
if (extractedContext._traceId && extractedContext._spanId &&
|
|
334
|
+
extractedContext.toTraceId(true) !== context.toTraceId(true)) {
|
|
335
|
+
const link = {
|
|
336
|
+
context: extractedContext,
|
|
337
|
+
attributes: { reason: 'terminated_context', context_headers: extractor }
|
|
338
|
+
}
|
|
339
|
+
context._links.push(link)
|
|
340
|
+
}
|
|
328
341
|
}
|
|
329
342
|
|
|
330
343
|
if (this._config.tracePropagationStyle.extract.includes('baggage') && carrier.baggage) {
|
|
331
|
-
|
|
332
|
-
this._extractBaggageItems(carrier,
|
|
344
|
+
context = context || new DatadogSpanContext()
|
|
345
|
+
this._extractBaggageItems(carrier, context)
|
|
333
346
|
}
|
|
334
347
|
}
|
|
335
348
|
|
|
336
|
-
return
|
|
349
|
+
return context || this._extractSqsdContext(carrier)
|
|
337
350
|
}
|
|
338
351
|
|
|
339
352
|
_extractDatadogContext (carrier) {
|