dd-trace 2.25.1 → 2.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/index.d.ts +50 -0
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/fs.js +350 -4
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/jest.js +11 -1
- package/packages/datadog-instrumentations/src/mocha.js +3 -2
- package/packages/datadog-instrumentations/src/mysql.js +7 -1
- package/packages/datadog-instrumentations/src/mysql2.js +7 -1
- package/packages/datadog-instrumentations/src/playwright.js +236 -0
- package/packages/datadog-plugin-fs/src/index.js +37 -574
- package/packages/datadog-plugin-jest/src/index.js +45 -23
- package/packages/datadog-plugin-mocha/src/index.js +34 -6
- package/packages/datadog-plugin-mysql/src/index.js +8 -7
- package/packages/datadog-plugin-playwright/src/index.js +171 -0
- 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/index.js +1 -1
- package/packages/dd-trace/src/appsec/recommended.json +247 -112
- package/packages/dd-trace/src/appsec/sdk/index.js +23 -0
- package/packages/dd-trace/src/appsec/sdk/noop.js +11 -0
- package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
- package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
- package/packages/dd-trace/src/config.js +7 -0
- 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/log/channels.js +47 -0
- package/packages/dd-trace/src/log/index.js +79 -0
- package/packages/dd-trace/src/log/writer.js +108 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -0
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -21
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
- package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +27 -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/proxy.js +2 -0
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/scripts/check-proposal-labels.js +71 -0
- package/packages/dd-trace/src/log.js +0 -143
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { trackUserLoginSuccessEvent, trackUserLoginFailureEvent, trackCustomEvent } = require('./track_event')
|
|
4
|
+
|
|
5
|
+
class AppsecSdk {
|
|
6
|
+
constructor (tracer) {
|
|
7
|
+
this._tracer = tracer
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
trackUserLoginSuccessEvent (user, metadata) {
|
|
11
|
+
return trackUserLoginSuccessEvent(this._tracer, user, metadata)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
trackUserLoginFailureEvent (userId, exists, metadata) {
|
|
15
|
+
return trackUserLoginFailureEvent(this._tracer, userId, exists, metadata)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
trackCustomEvent (eventName, metadata) {
|
|
19
|
+
return trackCustomEvent(this._tracer, eventName, metadata)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = AppsecSdk
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const log = require('../../log')
|
|
4
|
+
const { getRootSpan } = require('./utils')
|
|
5
|
+
const { MANUAL_KEEP } = require('../../../../../ext/tags')
|
|
6
|
+
|
|
7
|
+
function trackUserLoginSuccessEvent (tracer, user, metadata) {
|
|
8
|
+
// TODO: better user check here and in _setUser() ?
|
|
9
|
+
if (!user || !user.id) {
|
|
10
|
+
log.warn('Invalid user provided to trackUserLoginSuccessEvent')
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const rootSpan = getRootSpan(tracer)
|
|
15
|
+
if (!rootSpan) {
|
|
16
|
+
log.warn('Root span not available in trackUserLoginSuccessEvent')
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// TODO: use sdk._setUser(user, rootSpan) (available in User Blocking PR #2710)
|
|
21
|
+
tracer.setUser(user)
|
|
22
|
+
|
|
23
|
+
trackEvent(tracer, 'users.login.success', metadata, 'trackUserLoginSuccessEvent', rootSpan)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function trackUserLoginFailureEvent (tracer, userId, exists, metadata) {
|
|
27
|
+
if (!userId || typeof userId !== 'string') {
|
|
28
|
+
log.warn('Invalid userId provided to trackUserLoginFailureEvent')
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const fields = {
|
|
33
|
+
'usr.id': userId,
|
|
34
|
+
'usr.exists': exists ? 'true' : 'false',
|
|
35
|
+
...metadata
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
trackEvent(tracer, 'users.login.failure', fields, 'trackUserLoginFailureEvent')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function trackCustomEvent (tracer, eventName, metadata) {
|
|
42
|
+
if (!eventName || typeof eventName !== 'string') {
|
|
43
|
+
log.warn('Invalid eventName provided to trackCustomEvent')
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
trackEvent(tracer, eventName, metadata, 'trackCustomEvent')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function trackEvent (tracer, eventName, fields, sdkMethodName, rootSpan = getRootSpan(tracer)) {
|
|
51
|
+
if (!rootSpan) {
|
|
52
|
+
log.warn(`Root span not available in ${sdkMethodName}`)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const tags = {
|
|
57
|
+
[`appsec.events.${eventName}.track`]: 'true',
|
|
58
|
+
[MANUAL_KEEP]: 'true'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (fields) {
|
|
62
|
+
for (const metadataKey of Object.keys(fields)) {
|
|
63
|
+
tags[`appsec.events.${eventName}.${metadataKey}`] = '' + fields[metadataKey]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
rootSpan.addTags(tags)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
trackUserLoginSuccessEvent,
|
|
72
|
+
trackUserLoginFailureEvent,
|
|
73
|
+
trackCustomEvent
|
|
74
|
+
}
|
|
@@ -10,7 +10,7 @@ const AgentInfoExporter = require('../../exporters/common/agent-info-exporter')
|
|
|
10
10
|
|
|
11
11
|
function getIsTestSessionTrace (trace) {
|
|
12
12
|
return trace.some(span =>
|
|
13
|
-
span.type === 'test_session_end' || span.type === 'test_suite_end'
|
|
13
|
+
span.type === 'test_session_end' || span.type === 'test_suite_end' || span.type === 'test_module_end'
|
|
14
14
|
)
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -178,7 +178,13 @@ class Config {
|
|
|
178
178
|
parseInt(process.env.DD_TRACE_PARTIAL_FLUSH_MIN_SPANS),
|
|
179
179
|
1000
|
|
180
180
|
)
|
|
181
|
+
const DD_TRACE_CLIENT_IP_ENABLED = coalesce(
|
|
182
|
+
options.clientIpEnabled,
|
|
183
|
+
process.env.DD_TRACE_CLIENT_IP_ENABLED && isTrue(process.env.DD_TRACE_CLIENT_IP_ENABLED),
|
|
184
|
+
false
|
|
185
|
+
)
|
|
181
186
|
const DD_TRACE_CLIENT_IP_HEADER = coalesce(
|
|
187
|
+
options.clientIpHeader,
|
|
182
188
|
process.env.DD_TRACE_CLIENT_IP_HEADER,
|
|
183
189
|
null
|
|
184
190
|
)
|
|
@@ -369,6 +375,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
369
375
|
this.flushMinSpans = DD_TRACE_PARTIAL_FLUSH_MIN_SPANS
|
|
370
376
|
this.sampleRate = coalesce(Math.min(Math.max(sampler.sampleRate, 0), 1), 1)
|
|
371
377
|
this.queryStringObfuscation = DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP
|
|
378
|
+
this.clientIpEnabled = DD_TRACE_CLIENT_IP_ENABLED
|
|
372
379
|
this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
|
|
373
380
|
this.plugins = !!coalesce(options.plugins, true)
|
|
374
381
|
this.service = DD_SERVICE
|
|
@@ -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
|
}
|
|
@@ -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,108 @@
|
|
|
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
|
+
debugChannel.unsubscribe(onDebug)
|
|
27
|
+
infoChannel.unsubscribe(onInfo)
|
|
28
|
+
warnChannel.unsubscribe(onWarn)
|
|
29
|
+
errorChannel.unsubscribe(onError)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function toggleSubscription (enable) {
|
|
33
|
+
unsubscribeAll()
|
|
34
|
+
|
|
35
|
+
if (enable) {
|
|
36
|
+
if (debugChannel.logLevel >= logLevel) {
|
|
37
|
+
debugChannel.subscribe(onDebug)
|
|
38
|
+
}
|
|
39
|
+
if (infoChannel.logLevel >= logLevel) {
|
|
40
|
+
infoChannel.subscribe(onInfo)
|
|
41
|
+
}
|
|
42
|
+
if (warnChannel.logLevel >= logLevel) {
|
|
43
|
+
warnChannel.subscribe(onWarn)
|
|
44
|
+
}
|
|
45
|
+
if (errorChannel.logLevel >= logLevel) {
|
|
46
|
+
errorChannel.subscribe(onError)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function toggle (enable, level) {
|
|
52
|
+
if (level !== undefined) {
|
|
53
|
+
logLevel = getChannelLogLevel(level)
|
|
54
|
+
}
|
|
55
|
+
enabled = enable
|
|
56
|
+
toggleSubscription(enabled)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function use (newLogger) {
|
|
60
|
+
if (newLogger && newLogger.debug instanceof Function && newLogger.error instanceof Function) {
|
|
61
|
+
logger = newLogger
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function reset () {
|
|
66
|
+
logger = defaultLogger
|
|
67
|
+
enabled = false
|
|
68
|
+
logLevel = getChannelLogLevel()
|
|
69
|
+
toggleSubscription(false)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function onError (err) {
|
|
73
|
+
if (enabled) {
|
|
74
|
+
if (typeof err !== 'object' || !err) {
|
|
75
|
+
err = String(err)
|
|
76
|
+
} else if (!err.stack) {
|
|
77
|
+
err = String(err.message || err)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (typeof err === 'string') {
|
|
81
|
+
err = new Error(err)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
withNoop(() => logger.error(err))
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function onWarn (message) {
|
|
89
|
+
if (!logger.warn) return onDebug(message)
|
|
90
|
+
if (enabled) {
|
|
91
|
+
withNoop(() => logger.warn(message))
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function onInfo (message) {
|
|
96
|
+
if (!logger.info) return onDebug(message)
|
|
97
|
+
if (enabled) {
|
|
98
|
+
withNoop(() => logger.info(message))
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function onDebug (message) {
|
|
103
|
+
if (enabled) {
|
|
104
|
+
withNoop(() => logger.debug(message))
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = { use, toggle, reset }
|
|
@@ -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 () {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
get '@cucumber/cucumber' () { return require('../../../datadog-plugin-cucumber/src') },
|
|
5
|
+
get '@playwright/test' () { return require('../../../datadog-plugin-playwright/src') },
|
|
5
6
|
get '@elastic/elasticsearch' () { return require('../../../datadog-plugin-elasticsearch/src') },
|
|
6
7
|
get '@elastic/transport' () { return require('../../../datadog-plugin-elasticsearch/src') },
|
|
7
8
|
get '@google-cloud/pubsub' () { return require('../../../datadog-plugin-google-cloud-pubsub/src') },
|