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.
Files changed (42) hide show
  1. package/index.d.ts +50 -0
  2. package/package.json +1 -1
  3. package/packages/datadog-instrumentations/src/fs.js +350 -4
  4. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  5. package/packages/datadog-instrumentations/src/jest.js +11 -1
  6. package/packages/datadog-instrumentations/src/mocha.js +3 -2
  7. package/packages/datadog-instrumentations/src/mysql.js +7 -1
  8. package/packages/datadog-instrumentations/src/mysql2.js +7 -1
  9. package/packages/datadog-instrumentations/src/playwright.js +236 -0
  10. package/packages/datadog-plugin-fs/src/index.js +37 -574
  11. package/packages/datadog-plugin-jest/src/index.js +45 -23
  12. package/packages/datadog-plugin-mocha/src/index.js +34 -6
  13. package/packages/datadog-plugin-mysql/src/index.js +8 -7
  14. package/packages/datadog-plugin-playwright/src/index.js +171 -0
  15. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +1 -1
  16. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  17. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +60 -0
  18. package/packages/dd-trace/src/appsec/index.js +1 -1
  19. package/packages/dd-trace/src/appsec/recommended.json +247 -112
  20. package/packages/dd-trace/src/appsec/sdk/index.js +23 -0
  21. package/packages/dd-trace/src/appsec/sdk/noop.js +11 -0
  22. package/packages/dd-trace/src/appsec/sdk/track_event.js +74 -0
  23. package/packages/dd-trace/src/appsec/sdk/utils.js +10 -0
  24. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
  25. package/packages/dd-trace/src/config.js +7 -0
  26. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -4
  27. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +52 -37
  28. package/packages/dd-trace/src/log/channels.js +47 -0
  29. package/packages/dd-trace/src/log/index.js +79 -0
  30. package/packages/dd-trace/src/log/writer.js +108 -0
  31. package/packages/dd-trace/src/noop/proxy.js +3 -0
  32. package/packages/dd-trace/src/plugins/index.js +1 -0
  33. package/packages/dd-trace/src/plugins/util/ci.js +13 -21
  34. package/packages/dd-trace/src/{appsec → plugins/util}/ip_blocklist.js +0 -0
  35. package/packages/dd-trace/src/{appsec → plugins/util}/ip_extractor.js +1 -1
  36. package/packages/dd-trace/src/plugins/util/test.js +27 -10
  37. package/packages/dd-trace/src/plugins/util/user-provided-git.js +2 -7
  38. package/packages/dd-trace/src/plugins/util/web.js +11 -0
  39. package/packages/dd-trace/src/proxy.js +2 -0
  40. package/packages/dd-trace/src/startup-log.js +1 -1
  41. package/scripts/check-proposal-labels.js +71 -0
  42. 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,11 @@
1
+ 'use strict'
2
+
3
+ class NoopAppsecSdk {
4
+ trackUserLoginSuccessEvent () {}
5
+
6
+ trackUserLoginFailureEvent () {}
7
+
8
+ trackCustomEvent () {}
9
+ }
10
+
11
+ module.exports = NoopAppsecSdk
@@ -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
+ }
@@ -0,0 +1,10 @@
1
+ 'use strict'
2
+
3
+ function getRootSpan (tracer) {
4
+ const span = tracer.scope().active()
5
+ return span && span.context()._trace.started[0]
6
+ }
7
+
8
+ module.exports = {
9
+ getRootSpan
10
+ }
@@ -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 = 11
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 + 2)
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 = 1
9
- const COVERAGE_KEYS_LENGTH = 4
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.fileIndex = 1
15
+ this._coveragesCount = 0
18
16
  this.reset()
19
17
  }
20
18
 
21
19
  count () {
22
- return this.fileIndex - 1
20
+ return this._coveragesCount
23
21
  }
24
22
 
25
23
  encode (coverage) {
26
- const bytes = this._coverageBytes
27
- const coverageBuffer = this.encodeCodeCoverage(bytes, coverage)
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, COVERAGE_KEYS_LENGTH)
49
- this._encodeString(bytes, 'version')
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, 'span_id')
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.fileIndex = 1
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') },