dd-trace 4.51.1 → 4.53.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 +8 -2
- package/ci/init.js +16 -0
- package/index.d.ts +31 -13
- package/init.js +4 -66
- package/initialize.mjs +13 -10
- package/loader-hook.mjs +4 -0
- package/package.json +16 -11
- package/packages/datadog-core/src/storage.js +39 -2
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
- package/packages/datadog-instrumentations/src/cucumber.js +29 -3
- package/packages/datadog-instrumentations/src/express.js +38 -4
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/hooks.js +0 -1
- package/packages/datadog-instrumentations/src/helpers/register.js +3 -4
- package/packages/datadog-instrumentations/src/http/client.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +27 -8
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -1
- package/packages/datadog-instrumentations/src/mysql2.js +13 -8
- package/packages/datadog-instrumentations/src/next.js +7 -4
- package/packages/datadog-instrumentations/src/passport-http.js +2 -14
- package/packages/datadog-instrumentations/src/passport-local.js +2 -14
- package/packages/datadog-instrumentations/src/passport-utils.js +43 -19
- package/packages/datadog-instrumentations/src/pg.js +6 -6
- package/packages/datadog-instrumentations/src/playwright.js +17 -4
- package/packages/datadog-instrumentations/src/router.js +97 -1
- package/packages/datadog-instrumentations/src/sequelize.js +9 -4
- package/packages/datadog-instrumentations/src/url.js +4 -0
- package/packages/datadog-instrumentations/src/vitest.js +27 -2
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +8 -3
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +154 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/util.js +92 -0
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +39 -4
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +3 -3
- package/packages/datadog-plugin-grpc/src/client.js +2 -2
- package/packages/datadog-plugin-grpc/src/util.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +39 -4
- package/packages/datadog-plugin-langchain/src/handlers/language_models/chat_model.js +1 -1
- package/packages/datadog-plugin-langchain/src/handlers/language_models/llm.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +36 -2
- package/packages/datadog-plugin-oracledb/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +34 -2
- package/packages/datadog-shimmer/src/shimmer.js +8 -4
- package/packages/dd-trace/src/appsec/addresses.js +3 -0
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/blocked_templates.js +1 -1
- package/packages/dd-trace/src/appsec/blocking.js +1 -1
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +4 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +10 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +4 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +4 -0
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +8 -21
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +2 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +64 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -8
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +7 -11
- package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +2 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +32 -37
- package/packages/dd-trace/src/appsec/index.js +18 -13
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +2 -2
- package/packages/dd-trace/src/appsec/rasp/utils.js +1 -1
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +1 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +25 -1
- package/packages/dd-trace/src/appsec/remote_config/manager.js +2 -2
- package/packages/dd-trace/src/appsec/reporter.js +3 -1
- package/packages/dd-trace/src/appsec/sdk/set_user.js +2 -2
- package/packages/dd-trace/src/appsec/sdk/track_event.js +37 -24
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -4
- package/packages/dd-trace/src/appsec/telemetry.js +10 -0
- package/packages/dd-trace/src/appsec/user_tracking.js +168 -0
- package/packages/dd-trace/src/appsec/waf/index.js +2 -2
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +2 -3
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/azure_metadata.js +4 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +5 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +39 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -9
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -2
- package/packages/dd-trace/src/config.js +24 -32
- package/packages/dd-trace/src/constants.js +1 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +3 -2
- package/packages/dd-trace/src/datastreams/processor.js +4 -6
- package/packages/dd-trace/src/datastreams/writer.js +6 -5
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +80 -0
- package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
- package/packages/dd-trace/src/debugger/devtools_client/defaults.js +6 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +63 -8
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +10 -67
- package/packages/dd-trace/src/debugger/devtools_client/send.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/status.js +4 -4
- package/packages/dd-trace/src/debugger/index.js +14 -10
- package/packages/dd-trace/src/dogstatsd.js +2 -2
- package/packages/dd-trace/src/encode/0.4.js +23 -78
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +0 -32
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +1 -2
- package/packages/dd-trace/src/encode/span-stats.js +0 -30
- package/packages/dd-trace/src/exporters/agent/writer.js +3 -3
- package/packages/dd-trace/src/exporters/common/request.js +1 -1
- package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -1
- package/packages/dd-trace/src/flare/index.js +1 -1
- package/packages/dd-trace/src/guardrails/index.js +64 -0
- package/packages/dd-trace/src/guardrails/log.js +32 -0
- package/packages/dd-trace/src/guardrails/telemetry.js +78 -0
- package/packages/dd-trace/src/guardrails/util.js +10 -0
- package/packages/dd-trace/src/lambda/runtime/ritm.js +2 -2
- package/packages/dd-trace/src/llmobs/storage.js +2 -3
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -2
- package/packages/dd-trace/src/{encode → msgpack}/chunk.js +8 -5
- package/packages/dd-trace/src/msgpack/encoder.js +309 -0
- package/packages/dd-trace/src/msgpack/index.js +6 -0
- package/packages/dd-trace/src/opentelemetry/context_manager.js +2 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +12 -9
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/tracer.js +2 -2
- package/packages/dd-trace/src/plugin_manager.js +4 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +47 -4
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -1
- package/packages/dd-trace/src/plugins/util/git.js +7 -7
- package/packages/dd-trace/src/plugins/util/test.js +36 -3
- package/packages/dd-trace/src/plugins/util/web.js +2 -2
- package/packages/dd-trace/src/profiling/config.js +3 -0
- package/packages/dd-trace/src/profiling/exporters/agent.js +9 -68
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +76 -0
- package/packages/dd-trace/src/profiling/exporters/file.js +8 -4
- package/packages/dd-trace/src/profiling/profiler.js +62 -10
- package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +22 -12
- package/packages/dd-trace/src/profiling/profilers/events.js +47 -8
- package/packages/dd-trace/src/profiling/profilers/wall.js +2 -17
- package/packages/dd-trace/src/profiling/webspan-utils.js +23 -0
- package/packages/dd-trace/src/proxy.js +7 -2
- package/packages/dd-trace/src/runtime_metrics.js +107 -4
- package/packages/dd-trace/src/serverless.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +1 -1
- package/packages/dd-trace/src/span_processor.js +10 -10
- package/packages/dd-trace/src/tagger.js +1 -1
- package/packages/dd-trace/src/telemetry/index.js +1 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +10 -2
- package/packages/dd-trace/src/telemetry/send-data.js +2 -2
- package/packages/dd-trace/src/util.js +5 -16
- package/packages/datadog-instrumentations/src/qs.js +0 -24
- package/packages/dd-trace/src/appsec/iast/iast-log.js +0 -86
- package/packages/dd-trace/src/appsec/passport.js +0 -110
- package/packages/dd-trace/src/telemetry/init-telemetry.js +0 -75
|
@@ -181,8 +181,13 @@ class Tracer extends NoopProxy {
|
|
|
181
181
|
)
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
|
+
|
|
185
|
+
if (config.isTestDynamicInstrumentationEnabled) {
|
|
186
|
+
const testVisibilityDynamicInstrumentation = require('./ci-visibility/dynamic-instrumentation')
|
|
187
|
+
testVisibilityDynamicInstrumentation.start()
|
|
188
|
+
}
|
|
184
189
|
} catch (e) {
|
|
185
|
-
log.error(e)
|
|
190
|
+
log.error('Error initialising tracer', e)
|
|
186
191
|
}
|
|
187
192
|
|
|
188
193
|
return this
|
|
@@ -193,7 +198,7 @@ class Tracer extends NoopProxy {
|
|
|
193
198
|
try {
|
|
194
199
|
return require('./profiler').start(config)
|
|
195
200
|
} catch (e) {
|
|
196
|
-
log.error(e)
|
|
201
|
+
log.error('Error starting profiler', e)
|
|
197
202
|
}
|
|
198
203
|
}
|
|
199
204
|
|
|
@@ -7,11 +7,19 @@ const os = require('os')
|
|
|
7
7
|
const { DogStatsDClient } = require('./dogstatsd')
|
|
8
8
|
const log = require('./log')
|
|
9
9
|
const Histogram = require('./histogram')
|
|
10
|
-
const { performance } = require('perf_hooks')
|
|
10
|
+
const { performance, PerformanceObserver } = require('perf_hooks')
|
|
11
11
|
|
|
12
|
+
const { NODE_MAJOR, NODE_MINOR } = require('../../../version')
|
|
12
13
|
const INTERVAL = 10 * 1000
|
|
13
14
|
|
|
15
|
+
// Node >=16 has PerformanceObserver with `gc` type, but <16.7 had a critical bug.
|
|
16
|
+
// See: https://github.com/nodejs/node/issues/39548
|
|
17
|
+
const hasGCObserver = NODE_MAJOR >= 18 || (NODE_MAJOR === 16 && NODE_MINOR >= 7)
|
|
18
|
+
const hasGCProfiler = NODE_MAJOR >= 20 || (NODE_MAJOR === 18 && NODE_MINOR >= 15)
|
|
19
|
+
|
|
14
20
|
let nativeMetrics = null
|
|
21
|
+
let gcObserver = null
|
|
22
|
+
let gcProfiler = null
|
|
15
23
|
|
|
16
24
|
let interval
|
|
17
25
|
let client
|
|
@@ -24,15 +32,20 @@ let elu
|
|
|
24
32
|
|
|
25
33
|
reset()
|
|
26
34
|
|
|
27
|
-
module.exports = {
|
|
35
|
+
const runtimeMetrics = module.exports = {
|
|
28
36
|
start (config) {
|
|
29
37
|
const clientConfig = DogStatsDClient.generateClientConfig(config)
|
|
30
38
|
|
|
31
39
|
try {
|
|
32
40
|
nativeMetrics = require('@datadog/native-metrics')
|
|
33
|
-
|
|
41
|
+
|
|
42
|
+
if (hasGCObserver) {
|
|
43
|
+
nativeMetrics.start('loop') // Only add event loop watcher and not GC.
|
|
44
|
+
} else {
|
|
45
|
+
nativeMetrics.start()
|
|
46
|
+
}
|
|
34
47
|
} catch (e) {
|
|
35
|
-
log.error(e)
|
|
48
|
+
log.error('Error starting native metrics', e)
|
|
36
49
|
nativeMetrics = null
|
|
37
50
|
}
|
|
38
51
|
|
|
@@ -40,6 +53,9 @@ module.exports = {
|
|
|
40
53
|
|
|
41
54
|
time = process.hrtime()
|
|
42
55
|
|
|
56
|
+
startGCObserver()
|
|
57
|
+
startGCProfiler()
|
|
58
|
+
|
|
43
59
|
if (nativeMetrics) {
|
|
44
60
|
interval = setInterval(() => {
|
|
45
61
|
captureCommonMetrics()
|
|
@@ -138,6 +154,10 @@ function reset () {
|
|
|
138
154
|
counters = {}
|
|
139
155
|
histograms = {}
|
|
140
156
|
nativeMetrics = null
|
|
157
|
+
gcObserver && gcObserver.disconnect()
|
|
158
|
+
gcObserver = null
|
|
159
|
+
gcProfiler && gcProfiler.stop()
|
|
160
|
+
gcProfiler = null
|
|
141
161
|
}
|
|
142
162
|
|
|
143
163
|
function captureCpuUsage () {
|
|
@@ -202,6 +222,29 @@ function captureHeapSpace () {
|
|
|
202
222
|
client.gauge('runtime.node.heap.physical_size.by.space', stats[i].physical_space_size, tags)
|
|
203
223
|
}
|
|
204
224
|
}
|
|
225
|
+
function captureGCMetrics () {
|
|
226
|
+
if (!gcProfiler) return
|
|
227
|
+
|
|
228
|
+
const profile = gcProfiler.stop()
|
|
229
|
+
const pauseAll = new Histogram()
|
|
230
|
+
const pause = {}
|
|
231
|
+
|
|
232
|
+
for (const stat of profile.statistics) {
|
|
233
|
+
const type = stat.gcType.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase()
|
|
234
|
+
|
|
235
|
+
pause[type] = pause[type] || new Histogram()
|
|
236
|
+
pause[type].record(stat.cost)
|
|
237
|
+
pauseAll.record(stat.cost)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
histogram('runtime.node.gc.pause', pauseAll)
|
|
241
|
+
|
|
242
|
+
for (const type in pause) {
|
|
243
|
+
histogram('runtime.node.gc.pause.by.type', pause[type], [`gc_type:${type}`])
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
gcProfiler.start()
|
|
247
|
+
}
|
|
205
248
|
|
|
206
249
|
function captureGauges () {
|
|
207
250
|
Object.keys(gauges).forEach(name => {
|
|
@@ -256,6 +299,7 @@ function captureCommonMetrics () {
|
|
|
256
299
|
captureCounters()
|
|
257
300
|
captureHistograms()
|
|
258
301
|
captureELU()
|
|
302
|
+
captureGCMetrics()
|
|
259
303
|
}
|
|
260
304
|
|
|
261
305
|
function captureNativeMetrics () {
|
|
@@ -297,6 +341,11 @@ function captureNativeMetrics () {
|
|
|
297
341
|
function histogram (name, stats, tags) {
|
|
298
342
|
tags = [].concat(tags)
|
|
299
343
|
|
|
344
|
+
// Stats can contain garbage data when a value was never recorded.
|
|
345
|
+
if (stats.count === 0) {
|
|
346
|
+
stats = { max: 0, min: 0, sum: 0, avg: 0, median: 0, p95: 0, count: 0 }
|
|
347
|
+
}
|
|
348
|
+
|
|
300
349
|
client.gauge(`${name}.min`, stats.min, tags)
|
|
301
350
|
client.gauge(`${name}.max`, stats.max, tags)
|
|
302
351
|
client.increment(`${name}.sum`, stats.sum, tags)
|
|
@@ -306,3 +355,57 @@ function histogram (name, stats, tags) {
|
|
|
306
355
|
client.gauge(`${name}.median`, stats.median, tags)
|
|
307
356
|
client.gauge(`${name}.95percentile`, stats.p95, tags)
|
|
308
357
|
}
|
|
358
|
+
|
|
359
|
+
function startGCObserver () {
|
|
360
|
+
if (gcObserver || hasGCProfiler || !hasGCObserver) return
|
|
361
|
+
|
|
362
|
+
gcObserver = new PerformanceObserver(list => {
|
|
363
|
+
for (const entry of list.getEntries()) {
|
|
364
|
+
const type = gcType(entry.detail?.kind || entry.kind)
|
|
365
|
+
|
|
366
|
+
runtimeMetrics.histogram('runtime.node.gc.pause.by.type', entry.duration, `gc_type:${type}`)
|
|
367
|
+
runtimeMetrics.histogram('runtime.node.gc.pause', entry.duration)
|
|
368
|
+
}
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
gcObserver.observe({ type: 'gc' })
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function startGCProfiler () {
|
|
375
|
+
if (gcProfiler || !hasGCProfiler) return
|
|
376
|
+
|
|
377
|
+
gcProfiler = new v8.GCProfiler()
|
|
378
|
+
gcProfiler.start()
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function gcType (kind) {
|
|
382
|
+
if (NODE_MAJOR >= 22) {
|
|
383
|
+
switch (kind) {
|
|
384
|
+
case 1: return 'scavenge'
|
|
385
|
+
case 2: return 'minor_mark_sweep'
|
|
386
|
+
case 4: return 'mark_sweep_compact' // Deprecated, might be removed soon.
|
|
387
|
+
case 8: return 'incremental_marking'
|
|
388
|
+
case 16: return 'process_weak_callbacks'
|
|
389
|
+
case 31: return 'all'
|
|
390
|
+
}
|
|
391
|
+
} else if (NODE_MAJOR >= 18) {
|
|
392
|
+
switch (kind) {
|
|
393
|
+
case 1: return 'scavenge'
|
|
394
|
+
case 2: return 'minor_mark_compact'
|
|
395
|
+
case 4: return 'mark_sweep_compact'
|
|
396
|
+
case 8: return 'incremental_marking'
|
|
397
|
+
case 16: return 'process_weak_callbacks'
|
|
398
|
+
case 31: return 'all'
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
switch (kind) {
|
|
402
|
+
case 1: return 'scavenge'
|
|
403
|
+
case 2: return 'mark_sweep_compact'
|
|
404
|
+
case 4: return 'incremental_marking'
|
|
405
|
+
case 8: return 'process_weak_callbacks'
|
|
406
|
+
case 15: return 'all'
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return 'unknown'
|
|
411
|
+
}
|
|
@@ -23,7 +23,7 @@ function maybeStartServerlessMiniAgent (config) {
|
|
|
23
23
|
try {
|
|
24
24
|
require('child_process').spawn(rustBinaryPath, { stdio: 'inherit' })
|
|
25
25
|
} catch (err) {
|
|
26
|
-
log.error(
|
|
26
|
+
log.error('Error spawning mini agent process: %s', err.message)
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -87,22 +87,22 @@ class SpanProcessor {
|
|
|
87
87
|
const id = context.toSpanId()
|
|
88
88
|
|
|
89
89
|
if (finished.has(span)) {
|
|
90
|
-
log.error(
|
|
90
|
+
log.error('Span was already finished in the same trace: %s', span)
|
|
91
91
|
} else {
|
|
92
92
|
finished.add(span)
|
|
93
93
|
|
|
94
94
|
if (finishedIds.has(id)) {
|
|
95
|
-
log.error(
|
|
95
|
+
log.error('Another span with the same ID was already finished in the same trace: %s', span)
|
|
96
96
|
} else {
|
|
97
97
|
finishedIds.add(id)
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
if (context._trace !== trace) {
|
|
101
|
-
log.error(
|
|
101
|
+
log.error('A span was finished in the wrong trace: %s', span)
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
if (finishedSpans.has(span)) {
|
|
105
|
-
log.error(
|
|
105
|
+
log.error('Span was already finished in a different trace: %s', span)
|
|
106
106
|
} else {
|
|
107
107
|
finishedSpans.add(span)
|
|
108
108
|
}
|
|
@@ -114,35 +114,35 @@ class SpanProcessor {
|
|
|
114
114
|
const id = context.toSpanId()
|
|
115
115
|
|
|
116
116
|
if (started.has(span)) {
|
|
117
|
-
log.error(
|
|
117
|
+
log.error('Span was already started in the same trace: %s', span)
|
|
118
118
|
} else {
|
|
119
119
|
started.add(span)
|
|
120
120
|
|
|
121
121
|
if (startedIds.has(id)) {
|
|
122
|
-
log.error(
|
|
122
|
+
log.error('Another span with the same ID was already started in the same trace: %s', span)
|
|
123
123
|
} else {
|
|
124
124
|
startedIds.add(id)
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
if (context._trace !== trace) {
|
|
128
|
-
log.error(
|
|
128
|
+
log.error('A span was started in the wrong trace: %s', span)
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
if (startedSpans.has(span)) {
|
|
132
|
-
log.error(
|
|
132
|
+
log.error('Span was already started in a different trace: %s', span)
|
|
133
133
|
} else {
|
|
134
134
|
startedSpans.add(span)
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
if (!finished.has(span)) {
|
|
139
|
-
log.error(
|
|
139
|
+
log.error('Span started in one trace but was finished in another trace: %s', span)
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
for (const span of trace.finished) {
|
|
144
144
|
if (!started.has(span)) {
|
|
145
|
-
log.error(
|
|
145
|
+
log.error('Span finished in one trace but was started in another trace: %s', span)
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
}
|
|
@@ -137,6 +137,7 @@ function appClosing () {
|
|
|
137
137
|
sendData(config, application, host, reqType, payload)
|
|
138
138
|
// We flush before shutting down.
|
|
139
139
|
metricsManager.send(config, application, host)
|
|
140
|
+
telemetryLogger.send(config, application, host)
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
function onBeforeExit () {
|
|
@@ -40,6 +40,7 @@ function onErrorLog (msg) {
|
|
|
40
40
|
|
|
41
41
|
const telLog = {
|
|
42
42
|
level: 'ERROR',
|
|
43
|
+
count: 1,
|
|
43
44
|
|
|
44
45
|
// existing log.error(err) without message will be reported as 'Generic Error'
|
|
45
46
|
message: message ?? 'Generic Error'
|
|
@@ -47,8 +48,7 @@ function onErrorLog (msg) {
|
|
|
47
48
|
|
|
48
49
|
if (cause) {
|
|
49
50
|
telLog.stack_trace = cause.stack
|
|
50
|
-
|
|
51
|
-
telLog.message = `${errorType}: ${telLog.message}`
|
|
51
|
+
telLog.errorType = cause.constructor.name
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
onLog(telLog)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const log = require('../../log')
|
|
4
4
|
const { calculateDDBasePath } = require('../../util')
|
|
5
5
|
|
|
6
|
-
const logs = new Map()
|
|
6
|
+
const logs = new Map() // hash -> log
|
|
7
7
|
|
|
8
8
|
// NOTE: Is this a reasonable number?
|
|
9
9
|
let maxEntries = 10000
|
|
@@ -47,8 +47,14 @@ function sanitize (logEntry) {
|
|
|
47
47
|
.filter((line, index) => (isDDCode && index < firstIndex) || line.includes(ddBasePath))
|
|
48
48
|
.map(line => line.replace(ddBasePath, ''))
|
|
49
49
|
|
|
50
|
+
if (!isDDCode && logEntry.errorType && stackLines.length) {
|
|
51
|
+
stackLines = [`${logEntry.errorType}: redacted`, ...stackLines]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
delete logEntry.errorType
|
|
55
|
+
|
|
50
56
|
logEntry.stack_trace = stackLines.join(EOL)
|
|
51
|
-
if (logEntry.stack_trace === '' && !logEntry.message) {
|
|
57
|
+
if (logEntry.stack_trace === '' && (!logEntry.message || logEntry.message === 'Generic Error')) {
|
|
52
58
|
// If entire stack was removed and there is no message we'd rather not log it at all.
|
|
53
59
|
return null
|
|
54
60
|
}
|
|
@@ -75,6 +81,8 @@ const logCollector = {
|
|
|
75
81
|
if (!logs.has(hash)) {
|
|
76
82
|
logs.set(hash, logEntry)
|
|
77
83
|
return true
|
|
84
|
+
} else {
|
|
85
|
+
logs.get(hash).count++
|
|
78
86
|
}
|
|
79
87
|
} catch (e) {
|
|
80
88
|
log.error('Unable to add log to logCollector: %s', e.message)
|
|
@@ -57,7 +57,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
|
|
|
57
57
|
try {
|
|
58
58
|
url = url || new URL(getAgentlessTelemetryEndpoint(config.site))
|
|
59
59
|
} catch (err) {
|
|
60
|
-
log.error(err)
|
|
60
|
+
log.error('Telemetry endpoint url is invalid', err)
|
|
61
61
|
// No point to do the request if the URL is invalid
|
|
62
62
|
return cb(err, { payload, reqType })
|
|
63
63
|
}
|
|
@@ -100,7 +100,7 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
|
|
|
100
100
|
path: '/api/v2/apmtelemetry'
|
|
101
101
|
}
|
|
102
102
|
if (backendUrl) {
|
|
103
|
-
request(data, backendOptions, (error) => { log.error(error) })
|
|
103
|
+
request(data, backendOptions, (error) => { log.error('Error sending telemetry data', error) })
|
|
104
104
|
} else {
|
|
105
105
|
log.error('Invalid Telemetry URL')
|
|
106
106
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const crypto = require('crypto')
|
|
4
3
|
const path = require('path')
|
|
5
4
|
|
|
6
5
|
function isTrue (str) {
|
|
@@ -25,6 +24,8 @@ function isError (value) {
|
|
|
25
24
|
|
|
26
25
|
// Matches a glob pattern to a given subject string
|
|
27
26
|
function globMatch (pattern, subject) {
|
|
27
|
+
if (typeof pattern === 'string') pattern = pattern.toLowerCase()
|
|
28
|
+
if (typeof subject === 'string') subject = subject.toLowerCase()
|
|
28
29
|
let px = 0 // [p]attern inde[x]
|
|
29
30
|
let sx = 0 // [s]ubject inde[x]
|
|
30
31
|
let nextPx = 0
|
|
@@ -64,6 +65,8 @@ function globMatch (pattern, subject) {
|
|
|
64
65
|
return true
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
// TODO: this adds stack traces relative to packages/
|
|
69
|
+
// shouldn't paths be relative to the root of dd-trace?
|
|
67
70
|
function calculateDDBasePath (dirname) {
|
|
68
71
|
const dirSteps = dirname.split(path.sep)
|
|
69
72
|
const packagesIndex = dirSteps.lastIndexOf('packages')
|
|
@@ -74,25 +77,11 @@ function hasOwn (object, prop) {
|
|
|
74
77
|
return Object.prototype.hasOwnProperty.call(object, prop)
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
/**
|
|
78
|
-
* Generates a unique hash from an array of strings by joining them with | before hashing.
|
|
79
|
-
* Used to uniquely identify AWS requests for span pointers.
|
|
80
|
-
* @param {string[]} components - Array of strings to hash
|
|
81
|
-
* @returns {string} A 32-character hash uniquely identifying the components
|
|
82
|
-
*/
|
|
83
|
-
function generatePointerHash (components) {
|
|
84
|
-
// If passing S3's ETag as a component, make sure any quotes have already been removed!
|
|
85
|
-
const dataToHash = components.join('|')
|
|
86
|
-
const hash = crypto.createHash('sha256').update(dataToHash).digest('hex')
|
|
87
|
-
return hash.substring(0, 32)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
80
|
module.exports = {
|
|
91
81
|
isTrue,
|
|
92
82
|
isFalse,
|
|
93
83
|
isError,
|
|
94
84
|
globMatch,
|
|
95
85
|
calculateDDBasePath,
|
|
96
|
-
hasOwn
|
|
97
|
-
generatePointerHash
|
|
86
|
+
hasOwn
|
|
98
87
|
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
-
const shimmer = require('../../datadog-shimmer')
|
|
5
|
-
|
|
6
|
-
const qsParseCh = channel('datadog:qs:parse:finish')
|
|
7
|
-
|
|
8
|
-
function wrapParse (originalParse) {
|
|
9
|
-
return function () {
|
|
10
|
-
const qsParsedObj = originalParse.apply(this, arguments)
|
|
11
|
-
if (qsParseCh.hasSubscribers && qsParsedObj) {
|
|
12
|
-
qsParseCh.publish({ qs: qsParsedObj })
|
|
13
|
-
}
|
|
14
|
-
return qsParsedObj
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
addHook({
|
|
19
|
-
name: 'qs',
|
|
20
|
-
versions: ['>=1']
|
|
21
|
-
}, qs => {
|
|
22
|
-
shimmer.wrap(qs, 'parse', wrapParse)
|
|
23
|
-
return qs
|
|
24
|
-
})
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const dc = require('dc-polyfill')
|
|
4
|
-
const log = require('../../log')
|
|
5
|
-
|
|
6
|
-
const telemetryLog = dc.channel('datadog:telemetry:log')
|
|
7
|
-
|
|
8
|
-
function getTelemetryLog (data, level) {
|
|
9
|
-
try {
|
|
10
|
-
data = typeof data === 'function' ? data() : data
|
|
11
|
-
|
|
12
|
-
let message
|
|
13
|
-
if (typeof data !== 'object' || !data) {
|
|
14
|
-
message = String(data)
|
|
15
|
-
} else {
|
|
16
|
-
message = String(data.message || data)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const logEntry = {
|
|
20
|
-
message,
|
|
21
|
-
level
|
|
22
|
-
}
|
|
23
|
-
if (data.stack) {
|
|
24
|
-
logEntry.stack_trace = data.stack
|
|
25
|
-
}
|
|
26
|
-
return logEntry
|
|
27
|
-
} catch (e) {
|
|
28
|
-
log.error(e)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const iastLog = {
|
|
33
|
-
debug (data) {
|
|
34
|
-
log.debug(data)
|
|
35
|
-
return this
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
info (data) {
|
|
39
|
-
log.info(data)
|
|
40
|
-
return this
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
warn (data) {
|
|
44
|
-
log.warn(data)
|
|
45
|
-
return this
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
error (data) {
|
|
49
|
-
log.error(data)
|
|
50
|
-
return this
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
publish (data, level) {
|
|
54
|
-
if (telemetryLog.hasSubscribers) {
|
|
55
|
-
telemetryLog.publish(getTelemetryLog(data, level))
|
|
56
|
-
}
|
|
57
|
-
return this
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
debugAndPublish (data) {
|
|
61
|
-
this.debug(data)
|
|
62
|
-
return this.publish(data, 'DEBUG')
|
|
63
|
-
},
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* forward 'INFO' log level to 'DEBUG' telemetry log level
|
|
67
|
-
* see also {@link ../../telemetry/logs#isLevelEnabled } method
|
|
68
|
-
*/
|
|
69
|
-
infoAndPublish (data) {
|
|
70
|
-
this.info(data)
|
|
71
|
-
return this.publish(data, 'DEBUG')
|
|
72
|
-
},
|
|
73
|
-
|
|
74
|
-
warnAndPublish (data) {
|
|
75
|
-
this.warn(data)
|
|
76
|
-
return this.publish(data, 'WARN')
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
errorAndPublish (data) {
|
|
80
|
-
this.error(data)
|
|
81
|
-
// publish is done automatically by log.error()
|
|
82
|
-
return this
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
module.exports = iastLog
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const log = require('../log')
|
|
4
|
-
const { trackEvent } = require('./sdk/track_event')
|
|
5
|
-
const { setUserTags } = require('./sdk/set_user')
|
|
6
|
-
|
|
7
|
-
const UUID_PATTERN = '^[0-9A-F]{8}-[0-9A-F]{4}-[1-5][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$'
|
|
8
|
-
const regexUsername = new RegExp(UUID_PATTERN, 'i')
|
|
9
|
-
|
|
10
|
-
const SDK_USER_EVENT_PATTERN = '^_dd\\.appsec\\.events\\.users\\.[\\W\\w+]+\\.sdk$'
|
|
11
|
-
const regexSdkEvent = new RegExp(SDK_USER_EVENT_PATTERN, 'i')
|
|
12
|
-
|
|
13
|
-
function isSdkCalled (tags) {
|
|
14
|
-
let called = false
|
|
15
|
-
|
|
16
|
-
if (tags !== null && typeof tags === 'object') {
|
|
17
|
-
called = Object.entries(tags).some(([key, value]) => regexSdkEvent.test(key) && value === 'true')
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return called
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// delete this function later if we know it's always credential.username
|
|
24
|
-
function getLogin (credentials) {
|
|
25
|
-
const type = credentials && credentials.type
|
|
26
|
-
let login
|
|
27
|
-
if (type === 'local' || type === 'http') {
|
|
28
|
-
login = credentials.username
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return login
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function parseUser (login, passportUser, mode) {
|
|
35
|
-
const user = {
|
|
36
|
-
'usr.id': login
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (!user['usr.id']) {
|
|
40
|
-
return user
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (passportUser) {
|
|
44
|
-
// Guess id
|
|
45
|
-
if (passportUser.id) {
|
|
46
|
-
user['usr.id'] = passportUser.id
|
|
47
|
-
} else if (passportUser._id) {
|
|
48
|
-
user['usr.id'] = passportUser._id
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (mode === 'extended') {
|
|
52
|
-
if (login) {
|
|
53
|
-
user['usr.login'] = login
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (passportUser.email) {
|
|
57
|
-
user['usr.email'] = passportUser.email
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Guess username
|
|
61
|
-
if (passportUser.username) {
|
|
62
|
-
user['usr.username'] = passportUser.username
|
|
63
|
-
} else if (passportUser.name) {
|
|
64
|
-
user['usr.username'] = passportUser.name
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (mode === 'safe') {
|
|
70
|
-
// Remove PII in safe mode
|
|
71
|
-
if (!regexUsername.test(user['usr.id'])) {
|
|
72
|
-
user['usr.id'] = ''
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return user
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function passportTrackEvent (credentials, passportUser, rootSpan, mode) {
|
|
80
|
-
const tags = rootSpan && rootSpan.context() && rootSpan.context()._tags
|
|
81
|
-
|
|
82
|
-
if (isSdkCalled(tags)) {
|
|
83
|
-
// Don't overwrite tags set by SDK callings
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
const user = parseUser(getLogin(credentials), passportUser, mode)
|
|
87
|
-
|
|
88
|
-
if (user['usr.id'] === undefined) {
|
|
89
|
-
log.warn('No user ID found in authentication instrumentation')
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (passportUser) {
|
|
94
|
-
// If a passportUser object is published then the login succeded
|
|
95
|
-
const userTags = {}
|
|
96
|
-
Object.entries(user).forEach(([k, v]) => {
|
|
97
|
-
const attr = k.split('.', 2)[1]
|
|
98
|
-
userTags[attr] = v
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
setUserTags(userTags, rootSpan)
|
|
102
|
-
trackEvent('users.login.success', null, 'passportTrackEvent', rootSpan, mode)
|
|
103
|
-
} else {
|
|
104
|
-
trackEvent('users.login.failure', user, 'passportTrackEvent', rootSpan, mode)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
module.exports = {
|
|
109
|
-
passportTrackEvent
|
|
110
|
-
}
|