dd-trace 4.18.0 → 4.22.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 (110) hide show
  1. package/LICENSE-3rdparty.csv +3 -2
  2. package/README.md +3 -3
  3. package/ext/kinds.d.ts +1 -0
  4. package/ext/kinds.js +2 -1
  5. package/ext/tags.d.ts +2 -1
  6. package/ext/tags.js +6 -1
  7. package/index.d.ts +29 -0
  8. package/package.json +11 -10
  9. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  10. package/packages/datadog-esbuild/index.js +1 -20
  11. package/packages/datadog-instrumentations/src/aerospike.js +47 -0
  12. package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
  13. package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
  14. package/packages/datadog-instrumentations/src/graphql.js +18 -4
  15. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  16. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
  17. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
  18. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  19. package/packages/datadog-instrumentations/src/http/client.js +10 -0
  20. package/packages/datadog-instrumentations/src/jest.js +11 -5
  21. package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
  22. package/packages/datadog-instrumentations/src/next.js +18 -6
  23. package/packages/datadog-instrumentations/src/restify.js +14 -1
  24. package/packages/datadog-instrumentations/src/rhea.js +15 -9
  25. package/packages/datadog-plugin-aerospike/src/index.js +113 -0
  26. package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
  27. package/packages/datadog-plugin-http/src/client.js +19 -2
  28. package/packages/datadog-plugin-kafkajs/src/consumer.js +59 -6
  29. package/packages/datadog-plugin-kafkajs/src/producer.js +64 -6
  30. package/packages/datadog-plugin-next/src/index.js +40 -14
  31. package/packages/dd-trace/src/appsec/activation.js +29 -0
  32. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  33. package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
  34. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
  35. package/packages/dd-trace/src/appsec/blocking.js +95 -43
  36. package/packages/dd-trace/src/appsec/channels.js +5 -2
  37. package/packages/dd-trace/src/appsec/graphql.js +146 -0
  38. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  39. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
  40. package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
  41. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  42. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  43. package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
  44. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
  45. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
  46. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
  47. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
  48. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
  49. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
  50. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
  51. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
  52. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
  53. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  54. package/packages/dd-trace/src/appsec/index.js +33 -32
  55. package/packages/dd-trace/src/appsec/recommended.json +1737 -120
  56. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
  57. package/packages/dd-trace/src/appsec/remote_config/index.js +36 -15
  58. package/packages/dd-trace/src/appsec/reporter.js +50 -34
  59. package/packages/dd-trace/src/appsec/rule_manager.js +9 -6
  60. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  61. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
  62. package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
  63. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
  64. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +75 -56
  65. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +22 -6
  66. package/packages/dd-trace/src/config.js +48 -7
  67. package/packages/dd-trace/src/datastreams/processor.js +166 -26
  68. package/packages/dd-trace/src/format.js +6 -1
  69. package/packages/dd-trace/src/id.js +12 -0
  70. package/packages/dd-trace/src/iitm.js +1 -1
  71. package/packages/dd-trace/src/log/channels.js +1 -1
  72. package/packages/dd-trace/src/noop/proxy.js +4 -0
  73. package/packages/dd-trace/src/opentelemetry/span.js +95 -2
  74. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  75. package/packages/dd-trace/src/opentracing/propagation/text_map.js +14 -5
  76. package/packages/dd-trace/src/opentracing/span.js +6 -0
  77. package/packages/dd-trace/src/opentracing/span_context.js +5 -2
  78. package/packages/dd-trace/src/plugin_manager.js +1 -1
  79. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -1
  80. package/packages/dd-trace/src/plugins/database.js +1 -1
  81. package/packages/dd-trace/src/plugins/index.js +1 -0
  82. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  83. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  84. package/packages/dd-trace/src/plugins/util/git.js +4 -3
  85. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  86. package/packages/dd-trace/src/plugins/util/test.js +3 -2
  87. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  88. package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
  89. package/packages/dd-trace/src/profiler.js +5 -3
  90. package/packages/dd-trace/src/profiling/config.js +26 -2
  91. package/packages/dd-trace/src/profiling/profiler.js +17 -10
  92. package/packages/dd-trace/src/profiling/profilers/events.js +264 -0
  93. package/packages/dd-trace/src/profiling/profilers/shared.js +39 -0
  94. package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
  95. package/packages/dd-trace/src/profiling/profilers/wall.js +121 -58
  96. package/packages/dd-trace/src/proxy.js +25 -1
  97. package/packages/dd-trace/src/ritm.js +1 -1
  98. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
  99. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  100. package/packages/dd-trace/src/span_processor.js +4 -0
  101. package/packages/dd-trace/src/spanleak.js +98 -0
  102. package/packages/dd-trace/src/startup-log.js +7 -1
  103. package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
  104. package/packages/dd-trace/src/telemetry/index.js +136 -44
  105. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  106. package/packages/dd-trace/src/telemetry/send-data.js +47 -5
  107. package/packages/dd-trace/src/tracer.js +8 -2
  108. package/scripts/install_plugin_modules.js +11 -3
  109. package/packages/diagnostics_channel/index.js +0 -3
  110. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -236,11 +236,20 @@ class TextMapPropagator {
236
236
  _extractDatadogContext (carrier) {
237
237
  const spanContext = this._extractGenericContext(carrier, traceKey, spanKey, 10)
238
238
 
239
- if (spanContext) {
240
- this._extractOrigin(carrier, spanContext)
241
- this._extractBaggageItems(carrier, spanContext)
242
- this._extractSamplingPriority(carrier, spanContext)
243
- this._extractTags(carrier, spanContext)
239
+ if (!spanContext) return spanContext
240
+
241
+ this._extractOrigin(carrier, spanContext)
242
+ this._extractBaggageItems(carrier, spanContext)
243
+ this._extractSamplingPriority(carrier, spanContext)
244
+ this._extractTags(carrier, spanContext)
245
+
246
+ if (this._config.tracePropagationExtractFirst) return spanContext
247
+
248
+ const tc = this._extractTraceparentContext(carrier)
249
+
250
+ if (tc && spanContext._traceId.equals(tc._traceId)) {
251
+ spanContext._traceparent = tc._traceparent
252
+ spanContext._tracestate = tc._tracestate
244
253
  }
245
254
 
246
255
  return spanContext
@@ -12,6 +12,8 @@ const runtimeMetrics = require('../runtime_metrics')
12
12
  const log = require('../log')
13
13
  const { storage } = require('../../../datadog-core')
14
14
  const telemetryMetrics = require('../telemetry/metrics')
15
+ const { channel } = require('dc-polyfill')
16
+ const spanleak = require('../spanleak')
15
17
 
16
18
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
17
19
 
@@ -30,6 +32,8 @@ const integrationCounters = {
30
32
  span_finished: {}
31
33
  }
32
34
 
35
+ const finishCh = channel('dd-trace:span:finish')
36
+
33
37
  function getIntegrationCounter (event, integration) {
34
38
  const counters = integrationCounters[event]
35
39
 
@@ -87,6 +91,7 @@ class DatadogSpan {
87
91
 
88
92
  unfinishedRegistry.register(this, operationName, this)
89
93
  }
94
+ spanleak.addSpan(this, operationName)
90
95
  }
91
96
 
92
97
  toString () {
@@ -176,6 +181,7 @@ class DatadogSpan {
176
181
  this._duration = finishTime - this._startTime
177
182
  this._spanContext._trace.finished.push(this)
178
183
  this._spanContext._isFinished = true
184
+ finishCh.publish(this)
179
185
  this._processor.process(this)
180
186
  }
181
187
 
@@ -2,6 +2,9 @@
2
2
 
3
3
  const { AUTO_KEEP } = require('../../../../ext/priority')
4
4
 
5
+ // the lowercase, hex encoded upper 64 bits of a 128-bit trace id, if present
6
+ const TRACE_ID_128 = '_dd.p.tid'
7
+
5
8
  class DatadogSpanContext {
6
9
  constructor (props) {
7
10
  props = props || {}
@@ -35,8 +38,8 @@ class DatadogSpanContext {
35
38
 
36
39
  toTraceparent () {
37
40
  const flags = this._sampling.priority >= AUTO_KEEP ? '01' : '00'
38
- const traceId = this._traceId.toBuffer().length <= 8 && this._trace.tags['_dd.p.tid']
39
- ? this._trace.tags['_dd.p.tid'] + this._traceId.toString(16).padStart(16, '0')
41
+ const traceId = this._traceId.toBuffer().length <= 8 && this._trace.tags[TRACE_ID_128]
42
+ ? this._trace.tags[TRACE_ID_128] + this._traceId.toString(16).padStart(16, '0')
40
43
  : this._traceId.toString(16).padStart(32, '0')
41
44
  const spanId = this._spanId.toString(16).padStart(16, '0')
42
45
  const version = (this._traceparent && this._traceparent.version) || '00'
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('../../diagnostics_channel')
3
+ const { channel } = require('dc-polyfill')
4
4
  const { isFalse } = require('./util')
5
5
  const plugins = require('./plugins')
6
6
  const log = require('./log')
@@ -124,7 +124,8 @@ module.exports = class CiPlugin extends Plugin {
124
124
  osArchitecture,
125
125
  runtimeName,
126
126
  runtimeVersion,
127
- branch
127
+ branch,
128
+ testLevel: 'suite'
128
129
  }
129
130
  }
130
131
 
@@ -36,7 +36,7 @@ class DatabasePlugin extends StoragePlugin {
36
36
  const { encodedDddbs, encodedDde, encodedDdps, encodedDdpv } = this.serviceTags
37
37
 
38
38
  return `dddbs='${encodedDddbs}',dde='${encodedDde}',` +
39
- `ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
39
+ `ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
40
40
  }
41
41
 
42
42
  getDbmServiceName (span, tracerService) {
@@ -17,6 +17,7 @@ module.exports = {
17
17
  get '@opensearch-project/opensearch' () { return require('../../../datadog-plugin-opensearch/src') },
18
18
  get '@redis/client' () { return require('../../../datadog-plugin-redis/src') },
19
19
  get '@smithy/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
20
+ get 'aerospike' () { return require('../../../datadog-plugin-aerospike/src') },
20
21
  get 'amqp10' () { return require('../../../datadog-plugin-amqp10/src') },
21
22
  get 'amqplib' () { return require('../../../datadog-plugin-amqplib/src') },
22
23
  get 'aws-sdk' () { return require('../../../datadog-plugin-aws-sdk/src') },
@@ -2,7 +2,7 @@
2
2
 
3
3
  // TODO: move anything related to tracing to TracingPlugin instead
4
4
 
5
- const dc = require('../../../diagnostics_channel')
5
+ const dc = require('dc-polyfill')
6
6
  const { storage } = require('../../../datadog-core')
7
7
 
8
8
  class Subscription {
@@ -1,5 +1,3 @@
1
- const URL = require('url').URL
2
-
3
1
  const {
4
2
  GIT_BRANCH,
5
3
  GIT_COMMIT_SHA,
@@ -24,6 +22,7 @@ const {
24
22
  CI_NODE_LABELS,
25
23
  CI_NODE_NAME
26
24
  } = require('./tags')
25
+ const { filterSensitiveInfoFromRepository } = require('./url')
27
26
 
28
27
  // Receives a string with the form 'John Doe <john.doe@gmail.com>'
29
28
  // and returns { name: 'John Doe', email: 'john.doe@gmail.com' }
@@ -67,20 +66,6 @@ function normalizeRef (ref) {
67
66
  return ref.replace(/origin\/|refs\/heads\/|tags\//gm, '')
68
67
  }
69
68
 
70
- function filterSensitiveInfoFromRepository (repositoryUrl) {
71
- if (repositoryUrl.startsWith('git@')) {
72
- return repositoryUrl
73
- }
74
-
75
- try {
76
- const { protocol, hostname, pathname } = new URL(repositoryUrl)
77
-
78
- return `${protocol}//${hostname}${pathname}`
79
- } catch (e) {
80
- return ''
81
- }
82
- }
83
-
84
69
  function resolveTilde (filePath) {
85
70
  if (!filePath || typeof filePath !== 'string') {
86
71
  return ''
@@ -271,20 +256,22 @@ module.exports = {
271
256
  const ref = GITHUB_HEAD_REF || GITHUB_REF || ''
272
257
  const refKey = ref.includes('tags/') ? GIT_TAG : GIT_BRANCH
273
258
 
259
+ // Both pipeline URL and job URL include GITHUB_SERVER_URL, which can include user credentials,
260
+ // so we pass them through `filterSensitiveInfoFromRepository`.
274
261
  tags = {
275
262
  [CI_PIPELINE_ID]: GITHUB_RUN_ID,
276
263
  [CI_PIPELINE_NAME]: GITHUB_WORKFLOW,
277
264
  [CI_PIPELINE_NUMBER]: GITHUB_RUN_NUMBER,
278
- [CI_PIPELINE_URL]: pipelineURL,
265
+ [CI_PIPELINE_URL]: filterSensitiveInfoFromRepository(pipelineURL),
279
266
  [CI_PROVIDER_NAME]: 'github',
280
267
  [GIT_COMMIT_SHA]: GITHUB_SHA,
281
268
  [GIT_REPOSITORY_URL]: repositoryURL,
282
- [CI_JOB_URL]: jobUrl,
269
+ [CI_JOB_URL]: filterSensitiveInfoFromRepository(jobUrl),
283
270
  [CI_JOB_NAME]: GITHUB_JOB,
284
271
  [CI_WORKSPACE_PATH]: GITHUB_WORKSPACE,
285
272
  [refKey]: ref,
286
273
  [CI_ENV_VARS]: JSON.stringify({
287
- GITHUB_SERVER_URL,
274
+ GITHUB_SERVER_URL: filterSensitiveInfoFromRepository(GITHUB_SERVER_URL),
288
275
  GITHUB_REPOSITORY,
289
276
  GITHUB_RUN_ID,
290
277
  GITHUB_RUN_ATTEMPT
@@ -19,6 +19,7 @@ const {
19
19
  GIT_COMMIT_AUTHOR_NAME,
20
20
  CI_WORKSPACE_PATH
21
21
  } = require('./tags')
22
+ const { filterSensitiveInfoFromRepository } = require('./url')
22
23
 
23
24
  const GIT_REV_LIST_MAX_BUFFER = 8 * 1024 * 1024 // 8MB
24
25
 
@@ -110,7 +111,7 @@ function getLatestCommits () {
110
111
  }
111
112
  }
112
113
 
113
- function getCommitsToUpload (commitsToExclude, commitsToInclude) {
114
+ function getCommitsRevList (commitsToExclude, commitsToInclude) {
114
115
  const commitsToExcludeString = commitsToExclude.map(commit => `^${commit}`)
115
116
 
116
117
  try {
@@ -214,7 +215,7 @@ function getGitMetadata (ciMetadata) {
214
215
 
215
216
  return {
216
217
  [GIT_REPOSITORY_URL]:
217
- repositoryUrl || sanitizedExec('git', ['ls-remote', '--get-url']),
218
+ filterSensitiveInfoFromRepository(repositoryUrl || sanitizedExec('git', ['ls-remote', '--get-url'])),
218
219
  [GIT_COMMIT_MESSAGE]:
219
220
  commitMessage || sanitizedExec('git', ['show', '-s', '--format=%s']),
220
221
  [GIT_COMMIT_AUTHOR_DATE]: authorDate,
@@ -235,7 +236,7 @@ module.exports = {
235
236
  getLatestCommits,
236
237
  getRepositoryUrl,
237
238
  generatePackFilesForCommits,
238
- getCommitsToUpload,
239
+ getCommitsRevList,
239
240
  GIT_REV_LIST_MAX_BUFFER,
240
241
  isShallowRepository,
241
242
  unshallowRepository
@@ -48,8 +48,8 @@ function extractIp (config, req) {
48
48
 
49
49
  let firstPrivateIp
50
50
  if (headers) {
51
- for (let i = 0; i < ipHeaderList.length; i++) {
52
- const firstIp = findFirstIp(headers[ipHeaderList[i]])
51
+ for (const ipHeaderName of ipHeaderList) {
52
+ const firstIp = findFirstIp(headers[ipHeaderName])
53
53
 
54
54
  if (firstIp.public) {
55
55
  return firstIp.public
@@ -59,7 +59,7 @@ function extractIp (config, req) {
59
59
  }
60
60
  }
61
61
 
62
- return firstPrivateIp || (req.socket && req.socket.remoteAddress)
62
+ return firstPrivateIp || req.socket?.remoteAddress
63
63
  }
64
64
 
65
65
  function findFirstIp (str) {
@@ -68,8 +68,8 @@ function findFirstIp (str) {
68
68
 
69
69
  const splitted = str.split(',')
70
70
 
71
- for (let i = 0; i < splitted.length; i++) {
72
- const chunk = splitted[i].trim()
71
+ for (const part of splitted) {
72
+ const chunk = part.trim()
73
73
 
74
74
  // TODO: strip port and interface data ?
75
75
 
@@ -90,5 +90,6 @@ function findFirstIp (str) {
90
90
  }
91
91
 
92
92
  module.exports = {
93
- extractIp
93
+ extractIp,
94
+ ipHeaderList
94
95
  }
@@ -397,8 +397,9 @@ function addIntelligentTestRunnerSpanTags (
397
397
  testModuleSpan.setTag(TEST_ITR_FORCED_RUN, 'true')
398
398
  }
399
399
 
400
- // If suites have been skipped we don't want to report the total coverage, as it will be wrong
401
- if (testCodeCoverageLinesTotal !== undefined && !isSuitesSkipped) {
400
+ // This will not be reported unless the user has manually added code coverage.
401
+ // This is always the case for Mocha and Cucumber, but not for Jest.
402
+ if (testCodeCoverageLinesTotal !== undefined) {
402
403
  testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
403
404
  testModuleSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
404
405
  }
@@ -0,0 +1,26 @@
1
+ const { URL } = require('url')
2
+
3
+ function filterSensitiveInfoFromRepository (repositoryUrl) {
4
+ if (!repositoryUrl) {
5
+ return ''
6
+ }
7
+ if (repositoryUrl.startsWith('git@')) {
8
+ return repositoryUrl
9
+ }
10
+
11
+ // Remove the username from ssh URLs
12
+ if (repositoryUrl.startsWith('ssh://')) {
13
+ const sshRegex = /^(ssh:\/\/)[^@/]*@/
14
+ return repositoryUrl.replace(sshRegex, '$1')
15
+ }
16
+
17
+ try {
18
+ const { protocol, host, pathname } = new URL(repositoryUrl)
19
+
20
+ return `${protocol}//${host}${pathname === '/' ? '' : pathname}`
21
+ } catch (e) {
22
+ return ''
23
+ }
24
+ }
25
+
26
+ module.exports = { filterSensitiveInfoFromRepository }
@@ -13,7 +13,7 @@ const {
13
13
  } = require('./tags')
14
14
 
15
15
  const { normalizeRef } = require('./ci')
16
- const { URL } = require('url')
16
+ const { filterSensitiveInfoFromRepository } = require('./url')
17
17
 
18
18
  function removeEmptyValues (tags) {
19
19
  return Object.keys(tags).reduce((filteredTags, tag) => {
@@ -27,23 +27,11 @@ function removeEmptyValues (tags) {
27
27
  }, {})
28
28
  }
29
29
 
30
- function filterSensitiveInfoFromRepository (repositoryUrl) {
31
- try {
32
- if (repositoryUrl.startsWith('git@')) {
33
- return repositoryUrl
34
- }
35
- const { protocol, hostname, pathname } = new URL(repositoryUrl)
36
-
37
- return `${protocol}//${hostname}${pathname}`
38
- } catch (e) {
39
- return repositoryUrl
40
- }
41
- }
42
-
43
- // The regex is extracted from
30
+ // The regex is inspired by
44
31
  // https://github.com/jonschlinkert/is-git-url/blob/396965ffabf2f46656c8af4c47bef1d69f09292e/index.js#L9C15-L9C87
32
+ // The `.git` suffix is optional in this version
45
33
  function validateGitRepositoryUrl (repoUrl) {
46
- return /(?:git|ssh|https?|git@[-\w.]+):(\/\/)?(.*?)(\.git)(\/?|#[-\d\w._]+?)$/.test(repoUrl)
34
+ return /(?:git|ssh|https?|git@[-\w.]+):(\/\/)?(.*?)(\/?|#[-\d\w._]+?)$/.test(repoUrl)
47
35
  }
48
36
 
49
37
  function validateGitCommitSha (gitCommitSha) {
@@ -8,7 +8,7 @@ process.once('beforeExit', () => { profiler.stop() })
8
8
 
9
9
  module.exports = {
10
10
  start: config => {
11
- const { service, version, env, url, hostname, port, tags } = config
11
+ const { service, version, env, url, hostname, port, tags, repositoryUrl, commitSHA } = config
12
12
  const { enabled, sourceMap, exporters } = config.profiling
13
13
  const logger = {
14
14
  debug: (message) => log.debug(message),
@@ -17,7 +17,7 @@ module.exports = {
17
17
  error: (message) => log.error(message)
18
18
  }
19
19
 
20
- profiler.start({
20
+ return profiler.start({
21
21
  enabled,
22
22
  service,
23
23
  version,
@@ -28,7 +28,9 @@ module.exports = {
28
28
  url,
29
29
  hostname,
30
30
  port,
31
- tags
31
+ tags,
32
+ repositoryUrl,
33
+ commitSHA
32
34
  })
33
35
  },
34
36
 
@@ -9,7 +9,9 @@ const { FileExporter } = require('./exporters/file')
9
9
  const { ConsoleLogger } = require('./loggers/console')
10
10
  const WallProfiler = require('./profilers/wall')
11
11
  const SpaceProfiler = require('./profilers/space')
12
+ const EventsProfiler = require('./profilers/events')
12
13
  const { oomExportStrategies, snapshotKinds } = require('./constants')
14
+ const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../plugins/util/tags')
13
15
  const { tagger } = require('./tagger')
14
16
  const { isFalse, isTrue } = require('../util')
15
17
 
@@ -37,6 +39,7 @@ class Config {
37
39
  DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
38
40
  DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
39
41
  DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES,
42
+ DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED,
40
43
  DD_PROFILING_CODEHOTSPOTS_ENABLED,
41
44
  DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
42
45
  DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED,
@@ -70,6 +73,13 @@ class Config {
70
73
  tagger.parse(options.tags),
71
74
  tagger.parse({ env, host, service, version, functionname })
72
75
  )
76
+
77
+ // Add source code integration tags if available
78
+ if (options.repositoryUrl && options.commitSHA) {
79
+ this.tags[GIT_REPOSITORY_URL] = options.repositoryUrl
80
+ this.tags[GIT_COMMIT_SHA] = options.commitSHA
81
+ }
82
+
73
83
  this.logger = ensureLogger(options.logger)
74
84
  const logger = this.logger
75
85
  function logExperimentalVarDeprecation (shortVarName) {
@@ -126,7 +136,14 @@ class Config {
126
136
 
127
137
  const profilers = options.profilers
128
138
  ? options.profilers
129
- : getProfilers({ DD_PROFILING_HEAP_ENABLED, DD_PROFILING_WALLTIME_ENABLED, DD_PROFILING_PROFILERS })
139
+ : getProfilers({
140
+ DD_PROFILING_HEAP_ENABLED,
141
+ DD_PROFILING_WALLTIME_ENABLED,
142
+ DD_PROFILING_PROFILERS
143
+ })
144
+
145
+ this.timelineEnabled = isTrue(coalesce(options.timelineEnabled,
146
+ DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED, false))
130
147
 
131
148
  this.codeHotspotsEnabled = isTrue(coalesce(options.codeHotspotsEnabled,
132
149
  DD_PROFILING_CODEHOTSPOTS_ENABLED,
@@ -139,7 +156,9 @@ class Config {
139
156
 
140
157
  module.exports = { Config }
141
158
 
142
- function getProfilers ({ DD_PROFILING_HEAP_ENABLED, DD_PROFILING_WALLTIME_ENABLED, DD_PROFILING_PROFILERS }) {
159
+ function getProfilers ({
160
+ DD_PROFILING_HEAP_ENABLED, DD_PROFILING_WALLTIME_ENABLED, DD_PROFILING_PROFILERS
161
+ }) {
143
162
  // First consider "legacy" DD_PROFILING_PROFILERS env variable, defaulting to wall + space
144
163
  // Use a Set to avoid duplicates
145
164
  const profilers = new Set(coalesce(DD_PROFILING_PROFILERS, 'wall,space').split(','))
@@ -240,6 +259,11 @@ function ensureProfilers (profilers, options) {
240
259
  }
241
260
  }
242
261
 
262
+ // Events profiler is a profiler for timeline events
263
+ if (options.timelineEnabled) {
264
+ profilers.push(new EventsProfiler(options))
265
+ }
266
+
243
267
  // Filter out any invalid profilers
244
268
  return profilers.filter(v => v)
245
269
  }
@@ -23,15 +23,19 @@ class Profiler extends EventEmitter {
23
23
  }
24
24
 
25
25
  start (options) {
26
- this._start(options).catch((err) => { if (options.logger) options.logger.error(err) })
27
- return this
26
+ return this._start(options).catch((err) => {
27
+ if (options.logger) {
28
+ options.logger.error(err)
29
+ }
30
+ return false
31
+ })
28
32
  }
29
33
 
30
34
  async _start (options) {
31
- if (this._enabled) return
35
+ if (this._enabled) return true
32
36
 
33
37
  const config = this._config = new Config(options)
34
- if (!config.enabled) return
38
+ if (!config.enabled) return false
35
39
 
36
40
  this._logger = config.logger
37
41
  this._enabled = true
@@ -57,6 +61,7 @@ class Profiler extends EventEmitter {
57
61
  }
58
62
 
59
63
  try {
64
+ const start = new Date()
60
65
  for (const profiler of config.profilers) {
61
66
  // TODO: move this out of Profiler when restoring sourcemap support
62
67
  profiler.start({
@@ -66,10 +71,12 @@ class Profiler extends EventEmitter {
66
71
  this._logger.debug(`Started ${profiler.type} profiler`)
67
72
  }
68
73
 
69
- this._capture(this._timeoutInterval)
74
+ this._capture(this._timeoutInterval, start)
75
+ return true
70
76
  } catch (e) {
71
77
  this._logger.error(e)
72
78
  this._stop()
79
+ return false
73
80
  }
74
81
  }
75
82
 
@@ -110,9 +117,9 @@ class Profiler extends EventEmitter {
110
117
  return this
111
118
  }
112
119
 
113
- _capture (timeout) {
120
+ _capture (timeout, start) {
114
121
  if (!this._enabled) return
115
- this._lastStart = new Date()
122
+ this._lastStart = start
116
123
  if (!this._timer || timeout !== this._timeoutInterval) {
117
124
  this._timer = setTimeout(() => this._collect(snapshotKinds.PERIODIC), timeout)
118
125
  this._timer.unref()
@@ -132,7 +139,7 @@ class Profiler extends EventEmitter {
132
139
  try {
133
140
  // collect profiles synchronously so that profilers can be safely stopped asynchronously
134
141
  for (const profiler of this._config.profilers) {
135
- const profile = profiler.profile()
142
+ const profile = profiler.profile(start, end)
136
143
  if (!profile) continue
137
144
  profiles.push({ profiler, profile })
138
145
  }
@@ -148,7 +155,7 @@ class Profiler extends EventEmitter {
148
155
  })
149
156
  }
150
157
 
151
- this._capture(this._timeoutInterval)
158
+ this._capture(this._timeoutInterval, end)
152
159
  await this._submit(encodedProfiles, start, end, snapshotKind)
153
160
  this._logger.debug('Submitted profiles')
154
161
  } catch (err) {
@@ -195,7 +202,7 @@ class ServerlessProfiler extends Profiler {
195
202
  await super._collect(snapshotKind)
196
203
  } else {
197
204
  this._profiledIntervals += 1
198
- this._capture(this._timeoutInterval)
205
+ this._capture(this._timeoutInterval, new Date())
199
206
  // Don't submit profile until 65 (flushAfterIntervals) intervals have elapsed
200
207
  }
201
208
  }