dd-trace 1.6.0 → 1.7.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/NOTICE ADDED
@@ -0,0 +1,4 @@
1
+ Datadog dd-trace-js
2
+ Copyright 2016-Present Datadog, Inc.
3
+
4
+ This product includes software developed at Datadog, Inc. (https://www.datadoghq.com/).
package/ci/init.js CHANGED
@@ -1,7 +1,11 @@
1
1
  const tracer = require('../packages/dd-trace')
2
+ const { ORIGIN_KEY } = require('../packages/dd-trace/src/constants')
2
3
 
3
4
  tracer.init({
4
- startupLogs: false
5
+ startupLogs: false,
6
+ tags: {
7
+ [ORIGIN_KEY]: 'ciapp-test'
8
+ }
5
9
  })
6
10
 
7
11
  tracer.use('fs', false)
package/ci/jest/env.js CHANGED
@@ -1,8 +1,12 @@
1
1
  const tracer = require('../../packages/dd-trace')
2
+ const { ORIGIN_KEY } = require('../../packages/dd-trace/src/constants')
2
3
 
3
4
  tracer.init({
4
5
  startupLogs: false,
5
- flushInterval: 400000
6
+ flushInterval: 400000,
7
+ tags: {
8
+ [ORIGIN_KEY]: 'ciapp-test'
9
+ }
6
10
  })
7
11
 
8
12
  tracer.use('fs', false)
package/index.d.ts CHANGED
@@ -792,7 +792,7 @@ declare namespace plugins {
792
792
  * This plugin automatically instruments the
793
793
  * [cucumber](https://www.npmjs.com/package/@cucumber/cucumber) module.
794
794
  */
795
- interface cucumber extends Instrumentation {}
795
+ interface cucumber extends Integration {}
796
796
 
797
797
  /**
798
798
  * This plugin automatically instruments the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -10,6 +10,7 @@
10
10
  "bench": "node benchmark",
11
11
  "bench:profiler": "node benchmark/profiler",
12
12
  "bench:e2e": "SERVICES=mongo yarn services && cd benchmark/e2e && node benchmark-run.js --duration=30",
13
+ "bench:e2e:ci-visibility": "node benchmark/e2e-ci/benchmark-run.js",
13
14
  "type:doc": "cd docs && yarn && yarn build",
14
15
  "type:test": "cd docs && yarn && yarn test",
15
16
  "lint": "node scripts/check_licenses.js && eslint . && yarn audit --groups dependencies",
@@ -103,8 +103,8 @@ module.exports = [
103
103
  name: '@cucumber/cucumber',
104
104
  versions: ['7.0.0 - 7.2.1'],
105
105
  file: 'lib/runtime/pickle_runner.js',
106
- patch (PickleRunner, tracer) {
107
- const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber')
106
+ patch (PickleRunner, tracer, config) {
107
+ const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber', config)
108
108
  const sourceRoot = process.cwd()
109
109
  const pl = PickleRunner.default
110
110
  this.wrap(
@@ -127,8 +127,8 @@ module.exports = [
127
127
  name: '@cucumber/cucumber',
128
128
  versions: ['>=7.3.0'],
129
129
  file: 'lib/runtime/test_case_runner.js',
130
- patch (TestCaseRunner, tracer) {
131
- const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber')
130
+ patch (TestCaseRunner, tracer, config) {
131
+ const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber', config)
132
132
  const sourceRoot = process.cwd()
133
133
  const pl = TestCaseRunner.default
134
134
  this.wrap(
@@ -4,6 +4,7 @@ const {
4
4
  TEST_SUITE,
5
5
  TEST_STATUS,
6
6
  TEST_FRAMEWORK_VERSION,
7
+ TEST_IS_RUM_ACTIVE,
7
8
  getTestEnvironmentMetadata,
8
9
  CI_APP_ORIGIN,
9
10
  getTestParentSpan
@@ -66,19 +67,28 @@ module.exports = (on, config) => {
66
67
  }
67
68
  })
68
69
  }
69
- return null
70
+ return activeSpan ? activeSpan._spanContext._traceId.toString(10) : null
70
71
  },
71
72
  'dd:afterEach': (test) => {
72
- const { state, error } = test
73
+ const { state, error, isRUMActive } = test
73
74
  if (activeSpan) {
74
75
  activeSpan.setTag(TEST_STATUS, CYPRESS_STATUS_TO_TEST_STATUS[state])
75
76
  if (error) {
76
77
  activeSpan.setTag('error', error)
77
78
  }
79
+ if (isRUMActive) {
80
+ activeSpan.setTag(TEST_IS_RUM_ACTIVE, true)
81
+ }
78
82
  activeSpan.finish()
79
83
  }
80
84
  activeSpan = null
81
85
  return null
86
+ },
87
+ 'dd:addTags': (tags) => {
88
+ if (activeSpan) {
89
+ activeSpan.addTags(tags)
90
+ }
91
+ return null
82
92
  }
83
93
  })
84
94
  }
@@ -3,15 +3,30 @@ beforeEach(() => {
3
3
  cy.task('dd:beforeEach', {
4
4
  testName: Cypress.mocha.getRunner().suite.ctx.currentTest.fullTitle(),
5
5
  testSuite: Cypress.mocha.getRootSuite().file
6
+ }).then(traceId => {
7
+ Cypress.env('traceId', traceId)
6
8
  })
7
9
  })
8
10
 
11
+ after(() => {
12
+ cy.window().then(win => {
13
+ win.dispatchEvent(new Event('beforeunload'))
14
+ })
15
+ })
16
+
17
+
9
18
  afterEach(() => {
10
- const currentTest = Cypress.mocha.getRunner().suite.ctx.currentTest
11
- cy.task('dd:afterEach', {
12
- testName: currentTest.fullTitle(),
13
- testSuite: Cypress.mocha.getRootSuite().file,
14
- state: currentTest.state,
15
- error: currentTest.err
19
+ cy.window().then(win => {
20
+ const currentTest = Cypress.mocha.getRunner().suite.ctx.currentTest
21
+ const testInfo = {
22
+ testName: currentTest.fullTitle(),
23
+ testSuite: Cypress.mocha.getRootSuite().file,
24
+ state: currentTest.state,
25
+ error: currentTest.err,
26
+ }
27
+ if (win.DD_RUM) {
28
+ testInfo.isRUMActive = true
29
+ }
30
+ cy.task('dd:afterEach', testInfo)
16
31
  })
17
32
  })
@@ -238,8 +238,8 @@ module.exports = [
238
238
  {
239
239
  name: 'jest-environment-node',
240
240
  versions: ['>=24.8.0'],
241
- patch: function (NodeEnvironment, tracer) {
242
- const testEnvironmentMetadata = getTestEnvironmentMetadata('jest')
241
+ patch: function (NodeEnvironment, tracer, config) {
242
+ const testEnvironmentMetadata = getTestEnvironmentMetadata('jest', config)
243
243
 
244
244
  this.wrap(NodeEnvironment.prototype, 'teardown', createWrapTeardown(tracer, this))
245
245
 
@@ -257,8 +257,8 @@ module.exports = [
257
257
  {
258
258
  name: 'jest-environment-jsdom',
259
259
  versions: ['>=24.8.0'],
260
- patch: function (JsdomEnvironment, tracer) {
261
- const testEnvironmentMetadata = getTestEnvironmentMetadata('jest')
260
+ patch: function (JsdomEnvironment, tracer, config) {
261
+ const testEnvironmentMetadata = getTestEnvironmentMetadata('jest', config)
262
262
 
263
263
  this.wrap(JsdomEnvironment.prototype, 'teardown', createWrapTeardown(tracer, this))
264
264
 
@@ -169,8 +169,8 @@ module.exports = [
169
169
  name: 'jest-jasmine2',
170
170
  versions: ['>=24.8.0'],
171
171
  file: 'build/jasmineAsyncInstall.js',
172
- patch: function (jasmineAsyncInstallExport, tracer) {
173
- const testEnvironmentMetadata = getTestEnvironmentMetadata('jest')
172
+ patch: function (jasmineAsyncInstallExport, tracer, config) {
173
+ const testEnvironmentMetadata = getTestEnvironmentMetadata('jest', config)
174
174
  return this.wrapExport(
175
175
  jasmineAsyncInstallExport.default,
176
176
  createWrapJasmineAsyncInstall(tracer, this, testEnvironmentMetadata)(jasmineAsyncInstallExport.default)
@@ -122,6 +122,7 @@ function getAllTestsInSuite (root) {
122
122
  function createWrapRunTests (tracer, testEnvironmentMetadata, sourceRoot) {
123
123
  return function wrapRunTests (runTests) {
124
124
  return function runTestsWithTrace () {
125
+ this.once('end', () => tracer._exporter._writer.flush())
125
126
  runTests.apply(this, arguments)
126
127
  const suite = arguments[0]
127
128
  const tests = getAllTestsInSuite(suite)
@@ -239,8 +240,8 @@ module.exports = [
239
240
  name: 'mocha',
240
241
  versions: ['>=5.2.0'],
241
242
  file: 'lib/runner.js',
242
- patch (Runner, tracer) {
243
- const testEnvironmentMetadata = getTestEnvironmentMetadata('mocha')
243
+ patch (Runner, tracer, config) {
244
+ const testEnvironmentMetadata = getTestEnvironmentMetadata('mocha', config)
244
245
  const sourceRoot = process.cwd()
245
246
  this.wrap(Runner.prototype, 'runTests', createWrapRunTests(tracer, testEnvironmentMetadata, sourceRoot))
246
247
  this.wrap(Runner.prototype, 'runTest', createWrapRunTest(tracer, testEnvironmentMetadata, sourceRoot))
@@ -1 +1 @@
1
- module.exports = '1.6.0'
1
+ module.exports = '1.7.0'
@@ -10,5 +10,10 @@ module.exports = {
10
10
  SAMPLING_RULE_DECISION: '_dd.rule_psr',
11
11
  SAMPLING_LIMIT_DECISION: '_dd.limit_psr',
12
12
  SAMPLING_AGENT_DECISION: '_dd.agent_psr',
13
- DATADOG_LAMBDA_EXTENSION_PATH: '/opt/extensions/datadog-agent'
13
+ SAMPLING_MECHANISM_DEFAULT: 0,
14
+ SAMPLING_MECHANISM_AGENT: 1,
15
+ SAMPLING_MECHANISM_RULE: 3,
16
+ SAMPLING_MECHANISM_MANUAL: 4,
17
+ DATADOG_LAMBDA_EXTENSION_PATH: '/opt/extensions/datadog-agent',
18
+ UPSTREAM_SERVICES_KEY: '_dd.p.upstream_services'
14
19
  }
@@ -25,6 +25,7 @@ function format (span) {
25
25
 
26
26
  extractError(formatted, span)
27
27
  extractRootTags(formatted, span)
28
+ extractChunkTags(formatted, span)
28
29
  extractTags(formatted, span)
29
30
 
30
31
  return formatted
@@ -112,6 +113,17 @@ function extractRootTags (trace, span) {
112
113
  addTag({}, trace.metrics, SAMPLING_AGENT_DECISION, context._trace[SAMPLING_AGENT_DECISION])
113
114
  }
114
115
 
116
+ function extractChunkTags (trace, span) {
117
+ const context = span.context()
118
+ const isLocalRoot = span === context._trace.started[0]
119
+
120
+ if (!isLocalRoot) return
121
+
122
+ for (const key in context._trace.tags) {
123
+ addTag(trace.meta, trace.metrics, key, context._trace.tags[key])
124
+ }
125
+ }
126
+
115
127
  function extractError (trace, span) {
116
128
  const error = span.context()._tags['error']
117
129
  if (isError(error)) {
@@ -11,6 +11,7 @@ const spanKey = 'x-datadog-parent-id'
11
11
  const originKey = 'x-datadog-origin'
12
12
  const samplingKey = 'x-datadog-sampling-priority'
13
13
  const sampleKey = 'x-datadog-sampled'
14
+ const tagsKey = 'x-datadog-tags'
14
15
  const baggagePrefix = 'ot-baggage-'
15
16
  const b3TraceKey = 'x-b3-traceid'
16
17
  const b3TraceExpr = /^([0-9a-f]{16}){1,2}$/i
@@ -41,6 +42,7 @@ class TextMapPropagator {
41
42
  this._injectSamplingPriority(spanContext, carrier)
42
43
  this._injectBaggageItems(spanContext, carrier)
43
44
  this._injectB3(spanContext, carrier)
45
+ this._injectTags(spanContext, carrier)
44
46
 
45
47
  log.debug(() => `Inject into carrier: ${JSON.stringify(pick(carrier, logKeys))}.`)
46
48
  }
@@ -53,6 +55,7 @@ class TextMapPropagator {
53
55
  this._extractOrigin(carrier, spanContext)
54
56
  this._extractBaggageItems(carrier, spanContext)
55
57
  this._extractSamplingPriority(carrier, spanContext)
58
+ this._extractTags(carrier, spanContext)
56
59
 
57
60
  log.debug(() => `Extract from carrier: ${JSON.stringify(pick(carrier, logKeys))}.`)
58
61
 
@@ -81,6 +84,25 @@ class TextMapPropagator {
81
84
  })
82
85
  }
83
86
 
87
+ _injectTags (spanContext, carrier) {
88
+ const trace = spanContext._trace
89
+ const tags = []
90
+
91
+ for (const key in trace.tags) {
92
+ if (!key.startsWith('_dd.p.')) continue
93
+
94
+ tags.push(`${key}=${trace.tags[key]}`)
95
+ }
96
+
97
+ const header = tags.join(',')
98
+
99
+ if (header.length <= 512) {
100
+ carrier[tagsKey] = header
101
+ } else {
102
+ trace.tags['_dd.propagation_error:max_size'] = 1
103
+ }
104
+ }
105
+
84
106
  _injectB3 (spanContext, carrier) {
85
107
  if (!this._config.experimental.b3) return
86
108
 
@@ -241,6 +263,18 @@ class TextMapPropagator {
241
263
  }
242
264
  }
243
265
 
266
+ _extractTags (carrier, spanContext) {
267
+ if (!carrier[tagsKey]) return
268
+
269
+ const pairs = carrier[tagsKey].split(',')
270
+
271
+ for (const pair of pairs) {
272
+ const [key, value] = pair.split('=')
273
+
274
+ spanContext._trace.tags[key] = value
275
+ }
276
+ }
277
+
244
278
  _isSampled (sampled, debug) {
245
279
  if (debug || sampled === '1') {
246
280
  return true
@@ -22,7 +22,8 @@ class DatadogSpanContext extends SpanContext {
22
22
  this._noop = props.noop || null
23
23
  this._trace = props.trace || {
24
24
  started: [],
25
- finished: []
25
+ finished: [],
26
+ tags: {}
26
27
  }
27
28
  }
28
29
 
@@ -24,6 +24,7 @@ const TEST_SUITE = 'test.suite'
24
24
  const TEST_STATUS = 'test.status'
25
25
  const TEST_PARAMETERS = 'test.parameters'
26
26
  const TEST_SKIP_REASON = 'test.skip_reason'
27
+ const TEST_IS_RUM_ACTIVE = 'test.is_rum_active'
27
28
 
28
29
  const ERROR_TYPE = 'error.type'
29
30
  const ERROR_MESSAGE = 'error.msg'
@@ -43,6 +44,7 @@ module.exports = {
43
44
  TEST_STATUS,
44
45
  TEST_PARAMETERS,
45
46
  TEST_SKIP_REASON,
47
+ TEST_IS_RUM_ACTIVE,
46
48
  ERROR_TYPE,
47
49
  ERROR_MESSAGE,
48
50
  ERROR_STACK,
@@ -54,7 +56,7 @@ module.exports = {
54
56
  getTestSuitePath
55
57
  }
56
58
 
57
- function getTestEnvironmentMetadata (testFramework) {
59
+ function getTestEnvironmentMetadata (testFramework, config) {
58
60
  // TODO: eventually these will come from the tracer (generally available)
59
61
  const ciMetadata = getCIMetadata()
60
62
  const {
@@ -83,13 +85,17 @@ function getTestEnvironmentMetadata (testFramework) {
83
85
 
84
86
  const runtimeAndOSMetadata = getRuntimeAndOSMetadata()
85
87
 
86
- return {
88
+ const metadata = {
87
89
  [TEST_FRAMEWORK]: testFramework,
88
90
  ...gitMetadata,
89
91
  ...ciMetadata,
90
92
  ...userProvidedGitMetadata,
91
93
  ...runtimeAndOSMetadata
92
94
  }
95
+ if (config && config.service) {
96
+ metadata['service.name'] = config.service
97
+ }
98
+ return metadata
93
99
  }
94
100
 
95
101
  function getTestParametersString (parametersByTestName, testName) {
@@ -1,14 +1,20 @@
1
1
  'use strict'
2
2
 
3
+ const coalesce = require('koalas')
3
4
  const RateLimiter = require('./rate_limiter')
4
5
  const Sampler = require('./sampler')
5
6
  const ext = require('../../../ext')
6
7
  const { setSamplingRules } = require('./startup-log')
7
8
 
8
9
  const {
10
+ SAMPLING_MECHANISM_DEFAULT,
11
+ SAMPLING_MECHANISM_AGENT,
12
+ SAMPLING_MECHANISM_RULE,
13
+ SAMPLING_MECHANISM_MANUAL,
9
14
  SAMPLING_RULE_DECISION,
10
15
  SAMPLING_LIMIT_DECISION,
11
- SAMPLING_AGENT_DECISION
16
+ SAMPLING_AGENT_DECISION,
17
+ UPSTREAM_SERVICES_KEY
12
18
  } = require('./constants')
13
19
 
14
20
  const SERVICE_NAME = ext.tags.SERVICE_NAME
@@ -21,6 +27,9 @@ const AUTO_KEEP = ext.priority.AUTO_KEEP
21
27
  const USER_KEEP = ext.priority.USER_KEEP
22
28
  const DEFAULT_KEY = 'service:,env:'
23
29
 
30
+ const defaultSampler = new Sampler(AUTO_KEEP)
31
+ const serviceNames = new Map()
32
+
24
33
  class PrioritySampler {
25
34
  constructor (env, { sampleRate, rateLimit = 100, rules = [] } = {}) {
26
35
  this._env = env
@@ -50,12 +59,14 @@ class PrioritySampler {
50
59
 
51
60
  if (this.validate(tag)) {
52
61
  context._sampling.priority = tag
62
+ context._sampling.mechanism = SAMPLING_MECHANISM_MANUAL
63
+ } else if (auto) {
64
+ context._sampling.priority = this._getPriorityFromAuto(root)
65
+ } else {
53
66
  return
54
67
  }
55
68
 
56
- if (auto) {
57
- context._sampling.priority = this._getPriorityFromAuto(root)
58
- }
69
+ this._addUpstreamService(root)
59
70
  }
60
71
 
61
72
  update (rates) {
@@ -68,7 +79,7 @@ class PrioritySampler {
68
79
  samplers[key] = sampler
69
80
  }
70
81
 
71
- samplers[DEFAULT_KEY] = samplers[DEFAULT_KEY] || new Sampler(AUTO_KEEP)
82
+ samplers[DEFAULT_KEY] = samplers[DEFAULT_KEY] || defaultSampler
72
83
 
73
84
  this._samplers = samplers
74
85
  }
@@ -116,6 +127,7 @@ class PrioritySampler {
116
127
 
117
128
  _getPriorityByRule (context, rule) {
118
129
  context._trace[SAMPLING_RULE_DECISION] = rule.sampleRate
130
+ context._sampling.mechanism = SAMPLING_MECHANISM_RULE
119
131
 
120
132
  return rule.sampler.isSampled(context) && this._isSampledByRateLimit(context) ? USER_KEEP : USER_REJECT
121
133
  }
@@ -134,9 +146,44 @@ class PrioritySampler {
134
146
 
135
147
  context._trace[SAMPLING_AGENT_DECISION] = sampler.rate()
136
148
 
149
+ if (sampler === defaultSampler) {
150
+ context._sampling.mechanism = SAMPLING_MECHANISM_DEFAULT
151
+ } else {
152
+ context._sampling.mechanism = SAMPLING_MECHANISM_AGENT
153
+ }
154
+
137
155
  return sampler.isSampled(context) ? AUTO_KEEP : AUTO_REJECT
138
156
  }
139
157
 
158
+ _addUpstreamService (span) {
159
+ const context = span.context()
160
+ const trace = context._trace
161
+ const service = this._toBase64(context._tags['service.name'])
162
+ const priority = context._sampling.priority
163
+ const mechanism = context._sampling.mechanism
164
+ const rate = Math.ceil(coalesce(
165
+ context._trace[SAMPLING_RULE_DECISION],
166
+ context._trace[SAMPLING_AGENT_DECISION]
167
+ ) * 10000) / 10000
168
+ const group = `${service}|${priority}|${mechanism}|${rate}`
169
+ const groups = trace.tags[UPSTREAM_SERVICES_KEY]
170
+ ? `${trace.tags[UPSTREAM_SERVICES_KEY]};${group}`
171
+ : group
172
+
173
+ trace.tags[UPSTREAM_SERVICES_KEY] = groups
174
+ }
175
+
176
+ _toBase64 (serviceName) {
177
+ let encoded = serviceNames.get(serviceName)
178
+
179
+ if (!encoded) {
180
+ encoded = Buffer.from(serviceName).toString('base64')
181
+ serviceNames.set(serviceName, encoded)
182
+ }
183
+
184
+ return encoded
185
+ }
186
+
140
187
  _normalizeRules (rules, sampleRate) {
141
188
  return rules
142
189
  .concat({ sampleRate })
@@ -55,7 +55,6 @@ class AgentExporter {
55
55
  }
56
56
 
57
57
  export ({ profiles, start, end, tags }) {
58
- const form = new FormData()
59
58
  const types = Object.keys(profiles)
60
59
 
61
60
  const fields = [
@@ -75,10 +74,6 @@ class AgentExporter {
75
74
  ...Object.entries(tags).map(([key, value]) => ['tags[]', `${key}:${value}`])
76
75
  ]
77
76
 
78
- for (const [key, value] of fields) {
79
- form.append(key, value)
80
- }
81
-
82
77
  this._logger.debug(() => {
83
78
  const body = fields.map(([key, value]) => ` ${key}: ${value}`).join('\n')
84
79
  return `Building agent export report: ${'\n' + body}`
@@ -93,36 +88,14 @@ class AgentExporter {
93
88
  return `Adding ${type} profile to agent export: ` + bytes
94
89
  })
95
90
 
96
- form.append(`types[${index}]`, type)
97
- form.append(`data[${index}]`, buffer, {
91
+ fields.push([`types[${index}]`, type])
92
+ fields.push([`data[${index}]`, buffer, {
98
93
  filename: `${type}.pb.gz`,
99
94
  contentType: 'application/octet-stream',
100
95
  knownLength: buffer.length
101
- })
102
- }
103
-
104
- const options = {
105
- method: 'POST',
106
- path: '/profiling/v1/input',
107
- headers: form.getHeaders()
108
- }
109
-
110
- if (containerId) {
111
- options.headers['Datadog-Container-ID'] = containerId
96
+ }])
112
97
  }
113
98
 
114
- if (this._url.protocol === 'unix:') {
115
- options.socketPath = this._url.pathname
116
- } else {
117
- options.protocol = this._url.protocol
118
- options.hostname = this._url.hostname
119
- options.port = this._url.port
120
- }
121
-
122
- this._logger.debug(() => {
123
- return `Submitting agent report to: ${JSON.stringify(options)}`
124
- })
125
-
126
99
  return new Promise((resolve, reject) => {
127
100
  const operation = retry.operation({
128
101
  randomize: true,
@@ -131,8 +104,36 @@ class AgentExporter {
131
104
  })
132
105
 
133
106
  operation.attempt((attempt) => {
134
- const timeout = this._backoffTime * Math.pow(2, attempt)
135
- sendRequest({ ...options, timeout }, form, (err, response) => {
107
+ const form = new FormData()
108
+
109
+ for (const [key, value, options] of fields) {
110
+ form.append(key, value, options)
111
+ }
112
+
113
+ const options = {
114
+ method: 'POST',
115
+ path: '/profiling/v1/input',
116
+ headers: form.getHeaders(),
117
+ timeout: this._backoffTime * Math.pow(2, attempt)
118
+ }
119
+
120
+ if (containerId) {
121
+ options.headers['Datadog-Container-ID'] = containerId
122
+ }
123
+
124
+ if (this._url.protocol === 'unix:') {
125
+ options.socketPath = this._url.pathname
126
+ } else {
127
+ options.protocol = this._url.protocol
128
+ options.hostname = this._url.hostname
129
+ options.port = this._url.port
130
+ }
131
+
132
+ this._logger.debug(() => {
133
+ return `Submitting profiler agent report attempt #${attempt} to: ${JSON.stringify(options)}`
134
+ })
135
+
136
+ sendRequest(options, form, (err, response) => {
136
137
  if (operation.retry(err)) {
137
138
  this._logger.error(`Error from the agent: ${err.message}`)
138
139
  return