dd-trace 3.12.1 → 3.15.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/README.md +5 -5
- package/ci/init.js +3 -1
- package/index.d.ts +100 -1
- package/package.json +5 -4
- package/packages/datadog-instrumentations/src/aws-sdk.js +86 -0
- package/packages/datadog-instrumentations/src/cucumber.js +74 -15
- package/packages/datadog-instrumentations/src/cypress.js +1 -1
- package/packages/datadog-instrumentations/src/fs.js +358 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +24 -23
- package/packages/datadog-instrumentations/src/ldapjs.js +12 -2
- package/packages/datadog-instrumentations/src/mocha.js +10 -7
- package/packages/datadog-instrumentations/src/mongoose.js +1 -1
- package/packages/datadog-instrumentations/src/mysql.js +7 -1
- package/packages/datadog-instrumentations/src/mysql2.js +7 -1
- package/packages/datadog-instrumentations/src/next.js +2 -1
- package/packages/datadog-instrumentations/src/playwright.js +263 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +12 -5
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +29 -24
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +31 -16
- package/packages/datadog-plugin-cucumber/src/index.js +42 -11
- package/packages/datadog-plugin-cypress/src/plugin.js +129 -4
- package/packages/datadog-plugin-cypress/src/support.js +5 -0
- package/packages/datadog-plugin-fs/src/index.js +45 -0
- package/packages/datadog-plugin-hapi/src/index.js +5 -1
- package/packages/datadog-plugin-http/src/server.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +40 -70
- package/packages/datadog-plugin-mocha/src/index.js +44 -64
- package/packages/datadog-plugin-mysql/src/index.js +8 -7
- package/packages/datadog-plugin-playwright/src/index.js +112 -0
- package/packages/datadog-shimmer/src/shimmer.js +28 -11
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/blocking.js +35 -9
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
- package/packages/dd-trace/src/appsec/iast/iast-context.js +6 -2
- package/packages/dd-trace/src/appsec/iast/index.js +3 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +5 -2
- package/packages/dd-trace/src/appsec/index.js +5 -5
- package/packages/dd-trace/src/appsec/recommended.json +320 -184
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +3 -0
- package/packages/dd-trace/src/appsec/reporter.js +14 -14
- package/packages/dd-trace/src/appsec/sdk/index.js +41 -0
- package/packages/dd-trace/src/appsec/sdk/noop.js +17 -0
- package/packages/dd-trace/src/appsec/sdk/set_user.js +30 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +73 -0
- package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +1 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +1 -5
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +48 -11
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +7 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +4 -2
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +5 -3
- package/packages/dd-trace/src/config.js +63 -7
- package/packages/dd-trace/src/encode/0.4.js +1 -1
- package/packages/dd-trace/src/encode/0.5.js +1 -1
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
- package/packages/dd-trace/src/encode/tags-processors.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +10 -3
- package/packages/dd-trace/src/lambda/handler.js +5 -6
- package/packages/dd-trace/src/log/channels.js +47 -0
- package/packages/dd-trace/src/log/index.js +79 -0
- package/packages/dd-trace/src/log/writer.js +124 -0
- package/packages/dd-trace/src/metrics.js +18 -0
- package/packages/dd-trace/src/noop/proxy.js +5 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +188 -36
- package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
- package/packages/dd-trace/src/opentracing/span.js +2 -1
- package/packages/dd-trace/src/opentracing/span_context.js +6 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +72 -12
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -21
- package/packages/dd-trace/src/plugins/util/exec.js +2 -2
- package/packages/dd-trace/src/plugins/util/git.js +16 -1
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +53 -10
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
- package/packages/dd-trace/src/plugins/util/web.js +11 -0
- package/packages/dd-trace/src/profiler.js +3 -0
- package/packages/dd-trace/src/profiling/config.js +8 -3
- package/packages/dd-trace/src/profiling/exporters/file.js +13 -2
- package/packages/dd-trace/src/profiling/profiler.js +23 -6
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -0
- package/packages/dd-trace/src/proxy.js +2 -0
- package/packages/dd-trace/src/span_processor.js +1 -1
- package/packages/dd-trace/src/span_sampler.js +68 -52
- package/packages/dd-trace/src/startup-log.js +3 -6
- package/packages/dd-trace/src/telemetry/index.js +23 -2
- package/packages/dd-trace/src/telemetry/send-data.js +4 -1
- package/packages/dd-trace/src/tracer.js +0 -16
- package/scripts/check-proposal-labels.js +71 -0
- package/packages/dd-trace/src/log.js +0 -143
- /package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
|
@@ -5,9 +5,10 @@ const { version: ddTraceVersion } = require('../../../../package.json')
|
|
|
5
5
|
const id = require('../../../dd-trace/src/id')
|
|
6
6
|
const ENCODING_VERSION = 1
|
|
7
7
|
|
|
8
|
-
const ALLOWED_CONTENT_TYPES = ['test_session_end', 'test_suite_end', 'test']
|
|
8
|
+
const ALLOWED_CONTENT_TYPES = ['test_session_end', 'test_module_end', 'test_suite_end', 'test']
|
|
9
9
|
|
|
10
|
-
const TEST_SUITE_KEYS_LENGTH =
|
|
10
|
+
const TEST_SUITE_KEYS_LENGTH = 12
|
|
11
|
+
const TEST_MODULE_KEYS_LENGTH = 11
|
|
11
12
|
const TEST_SESSION_KEYS_LENGTH = 10
|
|
12
13
|
|
|
13
14
|
const INTAKE_SOFT_LIMIT = 2 * 1024 * 1024 // 2MB
|
|
@@ -46,6 +47,9 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
46
47
|
this._encodeString(bytes, 'test_session_id')
|
|
47
48
|
this._encodeId(bytes, content.trace_id)
|
|
48
49
|
|
|
50
|
+
this._encodeString(bytes, 'test_module_id')
|
|
51
|
+
this._encodeId(bytes, content.parent_id)
|
|
52
|
+
|
|
49
53
|
this._encodeString(bytes, 'test_suite_id')
|
|
50
54
|
this._encodeId(bytes, content.span_id)
|
|
51
55
|
|
|
@@ -67,6 +71,35 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
67
71
|
this._encodeMap(bytes, content.metrics)
|
|
68
72
|
}
|
|
69
73
|
|
|
74
|
+
_encodeTestModule (bytes, content) {
|
|
75
|
+
this._encodeMapPrefix(bytes, TEST_MODULE_KEYS_LENGTH)
|
|
76
|
+
this._encodeString(bytes, 'type')
|
|
77
|
+
this._encodeString(bytes, content.type)
|
|
78
|
+
|
|
79
|
+
this._encodeString(bytes, 'test_session_id')
|
|
80
|
+
this._encodeId(bytes, content.trace_id)
|
|
81
|
+
|
|
82
|
+
this._encodeString(bytes, 'test_module_id')
|
|
83
|
+
this._encodeId(bytes, content.span_id)
|
|
84
|
+
|
|
85
|
+
this._encodeString(bytes, 'error')
|
|
86
|
+
this._encodeNumber(bytes, content.error)
|
|
87
|
+
this._encodeString(bytes, 'name')
|
|
88
|
+
this._encodeString(bytes, content.name)
|
|
89
|
+
this._encodeString(bytes, 'service')
|
|
90
|
+
this._encodeString(bytes, content.service)
|
|
91
|
+
this._encodeString(bytes, 'resource')
|
|
92
|
+
this._encodeString(bytes, content.resource)
|
|
93
|
+
this._encodeString(bytes, 'start')
|
|
94
|
+
this._encodeNumber(bytes, content.start)
|
|
95
|
+
this._encodeString(bytes, 'duration')
|
|
96
|
+
this._encodeNumber(bytes, content.duration)
|
|
97
|
+
this._encodeString(bytes, 'meta')
|
|
98
|
+
this._encodeMap(bytes, content.meta)
|
|
99
|
+
this._encodeString(bytes, 'metrics')
|
|
100
|
+
this._encodeMap(bytes, content.metrics)
|
|
101
|
+
}
|
|
102
|
+
|
|
70
103
|
_encodeTestSession (bytes, content) {
|
|
71
104
|
this._encodeMapPrefix(bytes, TEST_SESSION_KEYS_LENGTH)
|
|
72
105
|
this._encodeString(bytes, 'type')
|
|
@@ -95,8 +128,9 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
95
128
|
|
|
96
129
|
_encodeEventContent (bytes, content) {
|
|
97
130
|
const keysLength = Object.keys(content).length
|
|
131
|
+
|
|
98
132
|
if (content.meta.test_session_id) {
|
|
99
|
-
this._encodeMapPrefix(bytes, keysLength +
|
|
133
|
+
this._encodeMapPrefix(bytes, keysLength + 3)
|
|
100
134
|
} else {
|
|
101
135
|
this._encodeMapPrefix(bytes, keysLength)
|
|
102
136
|
}
|
|
@@ -137,6 +171,10 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
137
171
|
this._encodeId(bytes, id(content.meta.test_session_id, 10))
|
|
138
172
|
delete content.meta.test_session_id
|
|
139
173
|
|
|
174
|
+
this._encodeString(bytes, 'test_module_id')
|
|
175
|
+
this._encodeId(bytes, id(content.meta.test_module_id, 10))
|
|
176
|
+
delete content.meta.test_module_id
|
|
177
|
+
|
|
140
178
|
this._encodeString(bytes, 'test_suite_id')
|
|
141
179
|
this._encodeId(bytes, id(content.meta.test_suite_id, 10))
|
|
142
180
|
delete content.meta.test_suite_id
|
|
@@ -160,6 +198,8 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
160
198
|
this._encodeEventContent(bytes, event.content)
|
|
161
199
|
} else if (event.type === 'test_suite_end') {
|
|
162
200
|
this._encodeTestSuite(bytes, event.content)
|
|
201
|
+
} else if (event.type === 'test_module_end') {
|
|
202
|
+
this._encodeTestModule(bytes, event.content)
|
|
163
203
|
} else if (event.type === 'test_session_end') {
|
|
164
204
|
this._encodeTestSession(bytes, event.content)
|
|
165
205
|
}
|
|
@@ -200,7 +240,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
200
240
|
const rawEvents = trace.map(formatSpan)
|
|
201
241
|
|
|
202
242
|
const testSessionEvents = rawEvents.filter(
|
|
203
|
-
event => event.type === 'test_session_end' || event.type === 'test_suite_end'
|
|
243
|
+
event => event.type === 'test_session_end' || event.type === 'test_suite_end' || event.type === 'test_module_end'
|
|
204
244
|
)
|
|
205
245
|
|
|
206
246
|
const isTestSessionTrace = !!testSessionEvents.length
|
|
@@ -1,56 +1,35 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { AgentEncoder } = require('./0.4')
|
|
3
3
|
const Chunk = require('./chunk')
|
|
4
|
-
const log = require('../log')
|
|
5
4
|
|
|
6
5
|
const FormData = require('../exporters/common/form-data')
|
|
7
6
|
|
|
8
|
-
const COVERAGE_PAYLOAD_VERSION =
|
|
9
|
-
const COVERAGE_KEYS_LENGTH =
|
|
10
|
-
const MAXIMUM_NUM_COVERAGE_FILES = 100
|
|
7
|
+
const COVERAGE_PAYLOAD_VERSION = 2
|
|
8
|
+
const COVERAGE_KEYS_LENGTH = 2
|
|
11
9
|
|
|
12
10
|
class CoverageCIVisibilityEncoder extends AgentEncoder {
|
|
13
11
|
constructor () {
|
|
14
12
|
super(...arguments)
|
|
15
13
|
this._coverageBytes = new Chunk()
|
|
16
14
|
this.form = new FormData()
|
|
17
|
-
this.
|
|
15
|
+
this._coveragesCount = 0
|
|
18
16
|
this.reset()
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
count () {
|
|
22
|
-
return this.
|
|
20
|
+
return this._coveragesCount
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
encode (coverage) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const coverageFilename = `coverage${this.fileIndex++}`
|
|
29
|
-
|
|
30
|
-
this.form.append(
|
|
31
|
-
coverageFilename,
|
|
32
|
-
coverageBuffer,
|
|
33
|
-
{
|
|
34
|
-
filename: `${coverageFilename}.msgpack`,
|
|
35
|
-
contentType: 'application/msgpack'
|
|
36
|
-
}
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
if (this.fileIndex === MAXIMUM_NUM_COVERAGE_FILES) {
|
|
40
|
-
log.debug('Coverage buffer reached the limit, flushing')
|
|
41
|
-
this._writer.flush()
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
this.reset()
|
|
24
|
+
this._coveragesCount++
|
|
25
|
+
this.encodeCodeCoverage(this._coverageBytes, coverage)
|
|
45
26
|
}
|
|
46
27
|
|
|
47
28
|
encodeCodeCoverage (bytes, coverage) {
|
|
48
|
-
this._encodeMapPrefix(bytes,
|
|
49
|
-
this._encodeString(bytes, '
|
|
50
|
-
this._encodeInteger(bytes, COVERAGE_PAYLOAD_VERSION)
|
|
51
|
-
this._encodeString(bytes, 'trace_id')
|
|
29
|
+
this._encodeMapPrefix(bytes, 3)
|
|
30
|
+
this._encodeString(bytes, 'test_session_id')
|
|
52
31
|
this._encodeId(bytes, coverage.traceId)
|
|
53
|
-
this._encodeString(bytes, '
|
|
32
|
+
this._encodeString(bytes, 'test_suite_id')
|
|
54
33
|
this._encodeId(bytes, coverage.spanId)
|
|
55
34
|
this._encodeString(bytes, 'files')
|
|
56
35
|
this._encodeArrayPrefix(bytes, coverage.files)
|
|
@@ -59,12 +38,6 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
|
|
|
59
38
|
this._encodeString(bytes, 'filename')
|
|
60
39
|
this._encodeString(bytes, filename)
|
|
61
40
|
}
|
|
62
|
-
const traceSize = bytes.length
|
|
63
|
-
const buffer = Buffer.allocUnsafe(traceSize)
|
|
64
|
-
|
|
65
|
-
bytes.buffer.copy(buffer, 0, 0, bytes.length)
|
|
66
|
-
|
|
67
|
-
return buffer
|
|
68
41
|
}
|
|
69
42
|
|
|
70
43
|
reset () {
|
|
@@ -72,9 +45,51 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
|
|
|
72
45
|
if (this._coverageBytes) {
|
|
73
46
|
this._coverageBytes.length = 0
|
|
74
47
|
}
|
|
48
|
+
this._coveragesCount = 0
|
|
49
|
+
this._encodePayloadStart(this._coverageBytes)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_encodePayloadStart (bytes) {
|
|
53
|
+
const payload = {
|
|
54
|
+
version: COVERAGE_PAYLOAD_VERSION,
|
|
55
|
+
coverages: []
|
|
56
|
+
}
|
|
57
|
+
this._encodeMapPrefix(bytes, COVERAGE_KEYS_LENGTH)
|
|
58
|
+
this._encodeString(bytes, 'version')
|
|
59
|
+
this._encodeInteger(bytes, payload.version)
|
|
60
|
+
this._encodeString(bytes, 'coverages')
|
|
61
|
+
// Get offset of the coverages list to update the length of the array when calling `makePayload`
|
|
62
|
+
this._coveragesOffset = bytes.length
|
|
63
|
+
bytes.reserve(5)
|
|
64
|
+
bytes.length += 5
|
|
75
65
|
}
|
|
76
66
|
|
|
77
67
|
makePayload () {
|
|
68
|
+
const bytes = this._coverageBytes
|
|
69
|
+
|
|
70
|
+
const coveragesOffset = this._coveragesOffset
|
|
71
|
+
const coveragesCount = this._coveragesCount
|
|
72
|
+
|
|
73
|
+
// update with number of coverages
|
|
74
|
+
bytes.buffer[coveragesOffset] = 0xdd
|
|
75
|
+
bytes.buffer[coveragesOffset + 1] = coveragesCount >> 24
|
|
76
|
+
bytes.buffer[coveragesOffset + 2] = coveragesCount >> 16
|
|
77
|
+
bytes.buffer[coveragesOffset + 3] = coveragesCount >> 8
|
|
78
|
+
bytes.buffer[coveragesOffset + 4] = coveragesCount
|
|
79
|
+
|
|
80
|
+
const traceSize = bytes.length
|
|
81
|
+
const buffer = Buffer.allocUnsafe(traceSize)
|
|
82
|
+
|
|
83
|
+
bytes.buffer.copy(buffer, 0, 0, bytes.length)
|
|
84
|
+
|
|
85
|
+
this.form.append(
|
|
86
|
+
'coverage1',
|
|
87
|
+
buffer,
|
|
88
|
+
{
|
|
89
|
+
filename: `coverage1.msgpack`,
|
|
90
|
+
contentType: 'application/msgpack'
|
|
91
|
+
}
|
|
92
|
+
)
|
|
78
93
|
this.form.append(
|
|
79
94
|
'event',
|
|
80
95
|
// The intake requires a populated dictionary here. Simply having {} is not valid.
|
|
@@ -86,7 +101,7 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
|
|
|
86
101
|
const form = this.form
|
|
87
102
|
|
|
88
103
|
this.form = new FormData()
|
|
89
|
-
this.
|
|
104
|
+
this.reset()
|
|
90
105
|
|
|
91
106
|
return form
|
|
92
107
|
}
|
|
@@ -38,11 +38,12 @@ function truncateToLength (value, maxLength) {
|
|
|
38
38
|
return value
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
// normally the agent truncates the resource and parses it in certain scenarios (e.g. SQL Queries)
|
|
42
|
+
function truncateSpan (span, shouldTruncateResourceName = true) {
|
|
42
43
|
return fromEntries(Object.entries(span).map(([key, value]) => {
|
|
43
44
|
switch (key) {
|
|
44
45
|
case 'resource':
|
|
45
|
-
return ['resource', truncateToLength(value, MAX_RESOURCE_NAME_LENGTH)]
|
|
46
|
+
return ['resource', shouldTruncateResourceName ? truncateToLength(value, MAX_RESOURCE_NAME_LENGTH) : value]
|
|
46
47
|
case 'meta':
|
|
47
48
|
return ['meta', fromEntries(Object.entries(value).map(([metaKey, metaValue]) =>
|
|
48
49
|
[truncateToLength(metaKey, MAX_META_KEY_LENGTH), truncateToLength(metaValue, MAX_META_VALUE_LENGTH)]
|
|
@@ -98,9 +98,16 @@ function request (data, options, callback) {
|
|
|
98
98
|
if (res.statusCode >= 200 && res.statusCode <= 299) {
|
|
99
99
|
callback(null, responseData, res.statusCode)
|
|
100
100
|
} else {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
let errorMessage = ''
|
|
102
|
+
try {
|
|
103
|
+
const fullUrl = new URL(
|
|
104
|
+
options.path,
|
|
105
|
+
options.url || options.hostname || `http://localhost:${options.port}`
|
|
106
|
+
).href
|
|
107
|
+
errorMessage = `Error from ${fullUrl}: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}.`
|
|
108
|
+
} catch (e) {
|
|
109
|
+
// ignore error
|
|
110
|
+
}
|
|
104
111
|
if (responseData) {
|
|
105
112
|
errorMessage += ` Response from the endpoint: "${responseData}"`
|
|
106
113
|
}
|
|
@@ -22,15 +22,14 @@ let __lambdaTimeout
|
|
|
22
22
|
* @param {*} context AWS Lambda context object.
|
|
23
23
|
*/
|
|
24
24
|
function checkTimeout (context) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
25
|
+
const remainingTimeInMillis = context.getRemainingTimeInMillis()
|
|
26
|
+
|
|
27
|
+
let apmFlushDeadline = parseInt(process.env.DD_APM_FLUSH_DEADLINE_MILLISECONDS) || 100
|
|
28
|
+
apmFlushDeadline = apmFlushDeadline < 0 ? 100 : apmFlushDeadline
|
|
30
29
|
|
|
31
30
|
__lambdaTimeout = setTimeout(() => {
|
|
32
31
|
timeoutChannel.publish(undefined)
|
|
33
|
-
}, remainingTimeInMillis -
|
|
32
|
+
}, remainingTimeInMillis - apmFlushDeadline)
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
/**
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const dc = require('diagnostics_channel')
|
|
4
|
+
|
|
5
|
+
const Level = {
|
|
6
|
+
Debug: 'debug',
|
|
7
|
+
Info: 'info',
|
|
8
|
+
Warn: 'warn',
|
|
9
|
+
Error: 'error'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const defaultLevel = Level.Debug
|
|
13
|
+
|
|
14
|
+
class LogChannel extends dc.Channel {
|
|
15
|
+
constructor (name, logLevel) {
|
|
16
|
+
super(`datadog:log:${name}`)
|
|
17
|
+
this.logLevel = logLevel
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// based on: https://github.com/trentm/node-bunyan#levels
|
|
22
|
+
const logChannels = {
|
|
23
|
+
[Level.Debug]: new LogChannel(Level.Debug, 20),
|
|
24
|
+
[Level.Info]: new LogChannel(Level.Info, 30),
|
|
25
|
+
[Level.Warn]: new LogChannel(Level.Warn, 40),
|
|
26
|
+
[Level.Error]: new LogChannel(Level.Error, 50)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getChannelLogLevel (level) {
|
|
30
|
+
let logChannel
|
|
31
|
+
if (level && typeof level === 'string') {
|
|
32
|
+
logChannel = logChannels[level.toLowerCase().trim()] || logChannels[defaultLevel]
|
|
33
|
+
} else {
|
|
34
|
+
logChannel = logChannels[defaultLevel]
|
|
35
|
+
}
|
|
36
|
+
return logChannel.logLevel
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
Level,
|
|
41
|
+
getChannelLogLevel,
|
|
42
|
+
|
|
43
|
+
debugChannel: logChannels[Level.Debug],
|
|
44
|
+
infoChannel: logChannels[Level.Info],
|
|
45
|
+
warnChannel: logChannels[Level.Warn],
|
|
46
|
+
errorChannel: logChannels[Level.Error]
|
|
47
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
|
|
4
|
+
const logWriter = require('./writer')
|
|
5
|
+
|
|
6
|
+
const memoize = func => {
|
|
7
|
+
const cache = {}
|
|
8
|
+
const memoized = function (key) {
|
|
9
|
+
if (!cache[key]) {
|
|
10
|
+
cache[key] = func.apply(this, arguments)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return cache[key]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return memoized
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function processMsg (msg) {
|
|
20
|
+
return typeof msg === 'function' ? msg() : msg
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const log = {
|
|
24
|
+
use (logger) {
|
|
25
|
+
logWriter.use(logger)
|
|
26
|
+
return this
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
toggle (enabled, logLevel) {
|
|
30
|
+
logWriter.toggle(enabled, logLevel)
|
|
31
|
+
return this
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
reset () {
|
|
35
|
+
logWriter.reset()
|
|
36
|
+
this._deprecate = memoize((code, message) => {
|
|
37
|
+
errorChannel.publish(message)
|
|
38
|
+
return true
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
return this
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
debug (message) {
|
|
45
|
+
if (debugChannel.hasSubscribers) {
|
|
46
|
+
debugChannel.publish(processMsg(message))
|
|
47
|
+
}
|
|
48
|
+
return this
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
info (message) {
|
|
52
|
+
if (infoChannel.hasSubscribers) {
|
|
53
|
+
infoChannel.publish(processMsg(message))
|
|
54
|
+
}
|
|
55
|
+
return this
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
warn (message) {
|
|
59
|
+
if (warnChannel.hasSubscribers) {
|
|
60
|
+
warnChannel.publish(processMsg(message))
|
|
61
|
+
}
|
|
62
|
+
return this
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
error (err) {
|
|
66
|
+
if (errorChannel.hasSubscribers) {
|
|
67
|
+
errorChannel.publish(processMsg(err))
|
|
68
|
+
}
|
|
69
|
+
return this
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
deprecate (code, message) {
|
|
73
|
+
return this._deprecate(code, message)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
log.reset()
|
|
78
|
+
|
|
79
|
+
module.exports = log
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { storage } = require('../../../datadog-core')
|
|
4
|
+
const { getChannelLogLevel, debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
|
|
5
|
+
|
|
6
|
+
const defaultLogger = {
|
|
7
|
+
debug: msg => console.debug(msg), /* eslint-disable-line no-console */
|
|
8
|
+
info: msg => console.info(msg), /* eslint-disable-line no-console */
|
|
9
|
+
warn: msg => console.warn(msg), /* eslint-disable-line no-console */
|
|
10
|
+
error: msg => console.error(msg) /* eslint-disable-line no-console */
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let enabled = false
|
|
14
|
+
let logger = defaultLogger
|
|
15
|
+
let logLevel = getChannelLogLevel()
|
|
16
|
+
|
|
17
|
+
function withNoop (fn) {
|
|
18
|
+
const store = storage.getStore()
|
|
19
|
+
|
|
20
|
+
storage.enterWith({ noop: true })
|
|
21
|
+
fn()
|
|
22
|
+
storage.enterWith(store)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function unsubscribeAll () {
|
|
26
|
+
if (debugChannel.hasSubscribers) {
|
|
27
|
+
debugChannel.unsubscribe(onDebug)
|
|
28
|
+
}
|
|
29
|
+
if (infoChannel.hasSubscribers) {
|
|
30
|
+
infoChannel.unsubscribe(onInfo)
|
|
31
|
+
}
|
|
32
|
+
if (warnChannel.hasSubscribers) {
|
|
33
|
+
warnChannel.unsubscribe(onWarn)
|
|
34
|
+
}
|
|
35
|
+
if (errorChannel.hasSubscribers) {
|
|
36
|
+
errorChannel.unsubscribe(onError)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function toggleSubscription (enable) {
|
|
41
|
+
unsubscribeAll()
|
|
42
|
+
|
|
43
|
+
if (enable) {
|
|
44
|
+
if (debugChannel.logLevel >= logLevel) {
|
|
45
|
+
debugChannel.subscribe(onDebug)
|
|
46
|
+
}
|
|
47
|
+
if (infoChannel.logLevel >= logLevel) {
|
|
48
|
+
infoChannel.subscribe(onInfo)
|
|
49
|
+
}
|
|
50
|
+
if (warnChannel.logLevel >= logLevel) {
|
|
51
|
+
warnChannel.subscribe(onWarn)
|
|
52
|
+
}
|
|
53
|
+
if (errorChannel.logLevel >= logLevel) {
|
|
54
|
+
errorChannel.subscribe(onError)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function toggle (enable, level) {
|
|
60
|
+
if (level !== undefined) {
|
|
61
|
+
logLevel = getChannelLogLevel(level)
|
|
62
|
+
}
|
|
63
|
+
enabled = enable
|
|
64
|
+
toggleSubscription(enabled)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function use (newLogger) {
|
|
68
|
+
if (newLogger && newLogger.debug instanceof Function && newLogger.error instanceof Function) {
|
|
69
|
+
logger = newLogger
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function reset () {
|
|
74
|
+
logger = defaultLogger
|
|
75
|
+
enabled = false
|
|
76
|
+
logLevel = getChannelLogLevel()
|
|
77
|
+
toggleSubscription(false)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function onError (err) {
|
|
81
|
+
if (enabled) error(err)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function onWarn (message) {
|
|
85
|
+
if (enabled) warn(message)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function onInfo (message) {
|
|
89
|
+
if (enabled) info(message)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function onDebug (message) {
|
|
93
|
+
if (enabled) debug(message)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function error (err) {
|
|
97
|
+
if (typeof err !== 'object' || !err) {
|
|
98
|
+
err = String(err)
|
|
99
|
+
} else if (!err.stack) {
|
|
100
|
+
err = String(err.message || err)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof err === 'string') {
|
|
104
|
+
err = new Error(err)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
withNoop(() => logger.error(err))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function warn (message) {
|
|
111
|
+
if (!logger.warn) return debug(message)
|
|
112
|
+
withNoop(() => logger.warn(message))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function info (message) {
|
|
116
|
+
if (!logger.info) return debug(message)
|
|
117
|
+
withNoop(() => logger.info(message))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function debug (message) {
|
|
121
|
+
withNoop(() => logger.debug(message))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = { use, toggle, reset, error, warn, info, debug }
|
|
@@ -8,6 +8,7 @@ const os = require('os')
|
|
|
8
8
|
const Client = require('./dogstatsd')
|
|
9
9
|
const log = require('./log')
|
|
10
10
|
const Histogram = require('./histogram')
|
|
11
|
+
const { performance } = require('perf_hooks')
|
|
11
12
|
|
|
12
13
|
const INTERVAL = 10 * 1000
|
|
13
14
|
|
|
@@ -20,6 +21,7 @@ let cpuUsage
|
|
|
20
21
|
let gauges
|
|
21
22
|
let counters
|
|
22
23
|
let histograms
|
|
24
|
+
let elu
|
|
23
25
|
|
|
24
26
|
reset()
|
|
25
27
|
|
|
@@ -259,6 +261,21 @@ function captureHistograms () {
|
|
|
259
261
|
})
|
|
260
262
|
}
|
|
261
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Gathers and reports Event Loop Utilization (ELU) since last run
|
|
266
|
+
*
|
|
267
|
+
* ELU is a measure of how busy the event loop is, like running JavaScript or
|
|
268
|
+
* waiting on *Sync functions. The value is between 0 (idle) and 1 (exhausted).
|
|
269
|
+
*
|
|
270
|
+
* performance.eventLoopUtilization available in Node.js >= v14.10, >= v12.19, >= v16
|
|
271
|
+
*/
|
|
272
|
+
const captureELU = ('eventLoopUtilization' in performance) ? () => {
|
|
273
|
+
// if elu is undefined (first run) the measurement is from start of process
|
|
274
|
+
elu = performance.eventLoopUtilization(elu)
|
|
275
|
+
|
|
276
|
+
client.gauge('runtime.node.event_loop.utilization', elu.utilization)
|
|
277
|
+
} : () => {}
|
|
278
|
+
|
|
262
279
|
function captureCommonMetrics () {
|
|
263
280
|
captureMemoryUsage()
|
|
264
281
|
captureProcess()
|
|
@@ -266,6 +283,7 @@ function captureCommonMetrics () {
|
|
|
266
283
|
captureGauges()
|
|
267
284
|
captureCounters()
|
|
268
285
|
captureHistograms()
|
|
286
|
+
captureELU()
|
|
269
287
|
}
|
|
270
288
|
|
|
271
289
|
function captureNativeMetrics () {
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const NoopTracer = require('./tracer')
|
|
4
|
+
const NoopAppsecSdk = require('../appsec/sdk/noop')
|
|
4
5
|
|
|
5
6
|
const noop = new NoopTracer()
|
|
7
|
+
const noopAppsec = new NoopAppsecSdk()
|
|
6
8
|
|
|
7
9
|
class Tracer {
|
|
8
10
|
constructor () {
|
|
9
11
|
this._tracer = noop
|
|
12
|
+
this.appsec = noopAppsec
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
init () {
|
|
@@ -68,8 +71,8 @@ class Tracer {
|
|
|
68
71
|
return this._tracer.getRumData.apply(this._tracer, arguments)
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
setUser () {
|
|
72
|
-
this.
|
|
74
|
+
setUser (user) {
|
|
75
|
+
this.appsec.setUser(user)
|
|
73
76
|
return this
|
|
74
77
|
}
|
|
75
78
|
}
|