dd-trace 1.5.0 → 1.5.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -56,13 +56,13 @@
56
56
  "node": ">=12"
57
57
  },
58
58
  "dependencies": {
59
- "@datadog/native-metrics": "^1.0.0",
60
- "@datadog/pprof": "^0.1.3",
59
+ "@datadog/native-metrics": "^1.0.1",
60
+ "@datadog/pprof": "^0.3.0",
61
61
  "@datadog/sketches-js": "^1.0.4",
62
62
  "@types/node": "^10.12.18",
63
63
  "crypto-randomuuid": "^1.0.0",
64
64
  "form-data": "^3.0.0",
65
- "import-in-the-middle": "^1.1.1",
65
+ "import-in-the-middle": "^1.1.2",
66
66
  "koalas": "^1.0.2",
67
67
  "limiter": "^1.1.4",
68
68
  "lodash.kebabcase": "^4.1.1",
@@ -9,20 +9,17 @@ let tools
9
9
  function createWrapExecute (tracer, config, defaultFieldResolver) {
10
10
  return function wrapExecute (execute) {
11
11
  return function executeWithTrace () {
12
- const args = normalizeArgs(arguments)
12
+ const args = normalizeArgs(arguments, tracer, config, defaultFieldResolver)
13
13
  const schema = args.schema
14
14
  const document = args.document
15
15
  const source = document && document._datadog_source
16
- const fieldResolver = args.fieldResolver || defaultFieldResolver
17
- const contextValue = args.contextValue = args.contextValue || {}
16
+ const contextValue = args.contextValue
18
17
  const operation = getOperation(document, args.operationName)
19
18
 
20
19
  if (contextValue._datadog_graphql) {
21
20
  return execute.apply(this, arguments)
22
21
  }
23
22
 
24
- args.fieldResolver = wrapResolve(fieldResolver, tracer, config)
25
-
26
23
  if (schema) {
27
24
  wrapFields(schema._queryType, tracer, config)
28
25
  wrapFields(schema._mutationType, tracer, config)
@@ -32,7 +29,7 @@ function createWrapExecute (tracer, config, defaultFieldResolver) {
32
29
 
33
30
  contextValue._datadog_graphql = { source, span, fields: {} }
34
31
 
35
- return call(execute, span, this, [args], (err, res) => {
32
+ return call(execute, span, this, arguments, (err, res) => {
36
33
  finishResolvers(contextValue, config)
37
34
 
38
35
  setError(span, err || (res && res.errors && res.errors[0]))
@@ -212,10 +209,19 @@ function getField (contextValue, path) {
212
209
  return contextValue._datadog_graphql.fields[path.join('.')]
213
210
  }
214
211
 
215
- function normalizeArgs (args) {
216
- if (args.length === 1) {
217
- return args[0]
218
- }
212
+ function normalizeArgs (args, tracer, config, defaultFieldResolver) {
213
+ if (args.length !== 1) return normalizePositional(args, tracer, config, defaultFieldResolver)
214
+
215
+ args[0].contextValue = args[0].contextValue || {}
216
+ args[0].fieldResolver = wrapResolve(args[0].fieldResolver || defaultFieldResolver, tracer, config)
217
+
218
+ return args[0]
219
+ }
220
+
221
+ function normalizePositional (args, tracer, config, defaultFieldResolver) {
222
+ args[3] = args[3] || {} // contextValue
223
+ args[6] = wrapResolve(args[6] || defaultFieldResolver, tracer, config) // fieldResolver
224
+ args.length = Math.max(args.length, 7)
219
225
 
220
226
  return {
221
227
  schema: args[0],
@@ -48,7 +48,7 @@ function createWrapMakeClientConstructor (tracer, config) {
48
48
  function wrapPackageDefinition (tracer, config, def) {
49
49
  for (const name in def) {
50
50
  if (def[name].format) continue
51
- if (def[name].service) {
51
+ if (def[name].service && def[name].prototype) {
52
52
  wrapClientConstructor(tracer, config, def[name], def[name].service)
53
53
  } else {
54
54
  wrapPackageDefinition(tracer, config, def[name])
@@ -38,6 +38,12 @@ function getTestSpanMetadata (tracer, test, sourceRoot) {
38
38
  function createWrapRunTest (tracer, testEnvironmentMetadata, sourceRoot) {
39
39
  return function wrapRunTest (runTest) {
40
40
  return async function runTestWithTrace () {
41
+ // `runTest` is rerun when retries are configured through `this.retries` and the test fails.
42
+ // This clause prevents rewrapping `this.test.fn` when it has already been wrapped.
43
+ if (this.test._currentRetry !== undefined && this.test._currentRetry !== 0) {
44
+ return runTest.apply(this, arguments)
45
+ }
46
+
41
47
  let specFunction = this.test.fn
42
48
  if (specFunction.length) {
43
49
  specFunction = promisify(specFunction)
@@ -1 +1 @@
1
- module.exports = '1.5.0'
1
+ module.exports = '1.5.1'
@@ -61,13 +61,15 @@ class AgentEncoder {
61
61
  this._encodeArrayPrefix(bytes, trace)
62
62
 
63
63
  for (const span of trace) {
64
+ bytes.reserve(1)
65
+
64
66
  if (span.type) {
65
- bytes.push(0x8c)
67
+ bytes.buffer[bytes.length++] = 0x8c
66
68
 
67
69
  this._encodeString(bytes, 'type')
68
70
  this._encodeString(bytes, span.type)
69
71
  } else {
70
- bytes.push(0x8b)
72
+ bytes.buffer[bytes.length++] = 0x8b
71
73
  }
72
74
 
73
75
  this._encodeString(bytes, 'trace_id')
@@ -107,52 +109,105 @@ class AgentEncoder {
107
109
 
108
110
  _encodeArrayPrefix (bytes, value) {
109
111
  const length = value.length
112
+ const buffer = bytes.buffer
113
+ const offset = bytes.length
114
+
115
+ bytes.reserve(5)
116
+ bytes.length += 5
110
117
 
111
- bytes.push(0xdd, length >> 24, length >> 16, length >> 8, length)
118
+ buffer[offset] = 0xdd
119
+ buffer[offset + 1] = length >> 24
120
+ buffer[offset + 2] = length >> 16
121
+ buffer[offset + 3] = length >> 8
122
+ buffer[offset + 4] = length
112
123
  }
113
124
 
114
125
  _encodeByte (bytes, value) {
115
- bytes.push(value)
126
+ const buffer = bytes.buffer
127
+
128
+ bytes.reserve(1)
129
+
130
+ buffer[bytes.length++] = value
116
131
  }
117
132
 
118
133
  _encodeId (bytes, id) {
134
+ const buffer = bytes.buffer
135
+ const offset = bytes.length
136
+
137
+ bytes.reserve(9)
138
+ bytes.length += 9
139
+
119
140
  id = id.toArray()
120
- bytes.push(0xcf, id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7])
141
+
142
+ buffer[offset] = 0xcf
143
+ buffer[offset + 1] = id[0]
144
+ buffer[offset + 2] = id[1]
145
+ buffer[offset + 3] = id[2]
146
+ buffer[offset + 4] = id[3]
147
+ buffer[offset + 5] = id[4]
148
+ buffer[offset + 6] = id[5]
149
+ buffer[offset + 7] = id[6]
150
+ buffer[offset + 8] = id[7]
121
151
  }
122
152
 
123
153
  _encodeInteger (bytes, value) {
124
- bytes.push(0xce, value >> 24, value >> 16, value >> 8, value)
154
+ const buffer = bytes.buffer
155
+ const offset = bytes.length
156
+
157
+ bytes.reserve(5)
158
+ bytes.length += 5
159
+
160
+ buffer[offset] = 0xce
161
+ buffer[offset + 1] = value >> 24
162
+ buffer[offset + 2] = value >> 16
163
+ buffer[offset + 3] = value >> 8
164
+ buffer[offset + 4] = value
125
165
  }
126
166
 
127
167
  _encodeLong (bytes, value) {
168
+ const buffer = bytes.buffer
169
+ const offset = bytes.length
128
170
  const hi = (value / Math.pow(2, 32)) >> 0
129
171
  const lo = value >>> 0
130
172
 
131
- bytes.push(0xcf, hi >> 24, hi >> 16, hi >> 8, hi, lo >> 24, lo >> 16, lo >> 8, lo)
173
+ bytes.reserve(9)
174
+ bytes.length += 9
175
+
176
+ buffer[offset] = 0xcf
177
+ buffer[offset + 1] = hi >> 24
178
+ buffer[offset + 2] = hi >> 16
179
+ buffer[offset + 3] = hi >> 8
180
+ buffer[offset + 4] = hi
181
+ buffer[offset + 5] = lo >> 24
182
+ buffer[offset + 6] = lo >> 16
183
+ buffer[offset + 7] = lo >> 8
184
+ buffer[offset + 8] = lo
132
185
  }
133
186
 
134
187
  _encodeMap (bytes, value) {
135
- const keys = []
136
- const allKeys = Object.keys(value)
188
+ const keys = Object.keys(value)
189
+ const buffer = bytes.buffer
190
+ const offset = bytes.length
137
191
 
138
- let key = ''
192
+ bytes.reserve(5)
193
+ bytes.length += 5
139
194
 
140
- for (let i = 0, l = allKeys.length; i < l; i++) {
141
- key = allKeys[i]
142
- if (typeof value[key] !== 'function') {
143
- keys.push(key)
144
- }
145
- }
195
+ let length = 0
146
196
 
147
- const length = keys.length
197
+ for (const key of keys) {
198
+ if (typeof value[key] !== 'string' && typeof value[key] !== 'number') return
148
199
 
149
- bytes.push(0xdf, length >> 24, length >> 16, length >> 8, length)
200
+ length++
150
201
 
151
- for (let i = 0; i < length; i++) {
152
- key = keys[i]
153
202
  this._encodeString(bytes, key)
154
203
  this._encodeValue(bytes, value[key])
155
204
  }
205
+
206
+ buffer[offset] = 0xdf
207
+ buffer[offset + 1] = length >> 24
208
+ buffer[offset + 2] = length >> 16
209
+ buffer[offset + 3] = length >> 8
210
+ buffer[offset + 4] = length
156
211
  }
157
212
 
158
213
  _encodeValue (bytes, value) {
@@ -179,15 +234,21 @@ class AgentEncoder {
179
234
  _encodeFloat (bytes, value) {
180
235
  float64Array[0] = value
181
236
 
182
- bytes.push(0xcb)
237
+ const buffer = bytes.buffer
238
+ const offset = bytes.length
239
+
240
+ bytes.reserve(9)
241
+ bytes.length += 9
242
+
243
+ buffer[offset] = 0xcb
183
244
 
184
245
  if (bigEndian) {
185
246
  for (let i = 0; i <= 7; i++) {
186
- bytes.push(uInt8Float64Array[i])
247
+ buffer[offset + i + 1] = uInt8Float64Array[i]
187
248
  }
188
249
  } else {
189
250
  for (let i = 7; i >= 0; i--) {
190
- bytes.push(uInt8Float64Array[i])
251
+ buffer[bytes.length - i - 1] = uInt8Float64Array[i]
191
252
  }
192
253
  }
193
254
  }
@@ -14,26 +14,24 @@ class Chunk {
14
14
  this._minSize = minSize
15
15
  }
16
16
 
17
- push (...bytes) {
18
- this._reserve(bytes.length)
19
-
20
- for (const byte of bytes) {
21
- this.buffer[this.length++] = byte
22
- }
23
- }
24
-
25
17
  write (value) {
26
18
  const length = Buffer.byteLength(value)
27
19
  const offset = this.length
28
20
 
29
21
  if (length < 0x20) { // fixstr
30
- this.push(length | 0xa0)
22
+ this.reserve(length + 1)
23
+ this.length += 1
24
+ this.buffer[offset] = length | 0xa0
31
25
  } else if (length < 0x100000000) { // str 32
32
- this.push(0xdb, length >> 24, length >> 16, length >> 8, length)
26
+ this.reserve(length + 5)
27
+ this.length += 5
28
+ this.buffer[offset] = 0xdb
29
+ this.buffer[offset + 1] = length >> 24
30
+ this.buffer[offset + 2] = length >> 16
31
+ this.buffer[offset + 3] = length >> 8
32
+ this.buffer[offset + 4] = length
33
33
  }
34
34
 
35
- this._reserve(length)
36
-
37
35
  this.length += this.buffer.utf8Write(value, this.length, length)
38
36
 
39
37
  return this.length - offset
@@ -44,13 +42,13 @@ class Chunk {
44
42
  }
45
43
 
46
44
  set (array) {
47
- this._reserve(array.length)
45
+ this.reserve(array.length)
48
46
 
49
47
  this.buffer.set(array, this.length)
50
48
  this.length += array.length
51
49
  }
52
50
 
53
- _reserve (size) {
51
+ reserve (size) {
54
52
  if (this.length + size > this.buffer.length) {
55
53
  this._resize(this._minSize * Math.ceil((this.length + size) / this._minSize))
56
54
  }
@@ -1,17 +1,17 @@
1
1
  'use strict'
2
2
 
3
- const { randomBytes } = require('crypto')
3
+ const { randomFillSync } = require('crypto')
4
4
 
5
5
  const UINT_MAX = 4294967296
6
6
 
7
+ const data = new Uint8Array(8 * 8192)
7
8
  const zeroId = new Uint8Array(8)
8
9
 
9
- // Cryptographically secure local seeds to mitigate Math.random() seed reuse.
10
- const seed = new Uint32Array(randomBytes(8).buffer)
11
-
12
10
  const map = Array.prototype.map
13
11
  const pad = byte => `${byte < 16 ? '0' : ''}${byte.toString(16)}`
14
12
 
13
+ let batch = 0
14
+
15
15
  // Internal representation of a trace or span ID.
16
16
  class Identifier {
17
17
  constructor (value, radix) {
@@ -36,7 +36,7 @@ class Identifier {
36
36
  if (this._buffer.length === 8) {
37
37
  return this._buffer
38
38
  }
39
- return this._buffer.subarray(-8)
39
+ return this._buffer.slice(-8)
40
40
  }
41
41
 
42
42
  toJSON () {
@@ -50,7 +50,7 @@ function createBuffer (value) {
50
50
  if (!value) return pseudoRandom()
51
51
 
52
52
  const size = Math.ceil(value.length / 2)
53
- const buffer = new Uint8Array(size)
53
+ const buffer = new Array(size)
54
54
 
55
55
  for (let i = 0; i < size; i++) {
56
56
  buffer[i] = parseInt(value.substring(i * 2, i * 2 + 2), 16)
@@ -61,7 +61,7 @@ function createBuffer (value) {
61
61
 
62
62
  // Convert a numerical string to a buffer using the specified radix.
63
63
  function fromString (str, raddix) {
64
- const buffer = new Uint8Array(8)
64
+ const buffer = new Array(8)
65
65
  const len = str.length
66
66
 
67
67
  let pos = 0
@@ -126,20 +126,24 @@ function toHexString (buffer) {
126
126
 
127
127
  // Simple pseudo-random 64-bit ID generator.
128
128
  function pseudoRandom () {
129
- const buffer = new Uint8Array(8)
130
-
131
- const hi = randomUInt32(seed[0]) & 0x7FFFFFFF // only positive int64
132
- const lo = randomUInt32(seed[1])
129
+ if (batch === 0) {
130
+ randomFillSync(data)
131
+ }
133
132
 
134
- writeUInt32BE(buffer, hi, 0)
135
- writeUInt32BE(buffer, lo, 4)
133
+ batch = (batch + 1) % 8192
136
134
 
137
- return buffer
138
- }
135
+ const offset = batch * 8
139
136
 
140
- // Generate a random unsigned 32-bit integer.
141
- function randomUInt32 (seed) {
142
- return seed ^ Math.floor(Math.random() * (0xFFFFFFFF + 1))
137
+ return [
138
+ data[offset] & 0x7F, // only positive int64,
139
+ data[offset + 1],
140
+ data[offset + 2],
141
+ data[offset + 3],
142
+ data[offset + 4],
143
+ data[offset + 5],
144
+ data[offset + 6],
145
+ data[offset + 7]
146
+ ]
143
147
  }
144
148
 
145
149
  // Read a buffer to unsigned integer bytes.
@@ -7,10 +7,10 @@ const Loader = require('./loader')
7
7
  const { isTrue } = require('./util')
8
8
  const plugins = require('./plugins')
9
9
 
10
- const disabldPlugins = process.env.DD_TRACE_DISABLED_PLUGINS
10
+ const disabledPlugins = process.env.DD_TRACE_DISABLED_PLUGINS
11
11
 
12
12
  const collectDisabledPlugins = () => {
13
- return new Set(disabldPlugins && disabldPlugins.split(',').map(plugin => plugin.trim()))
13
+ return new Set(disabledPlugins && disabledPlugins.split(',').map(plugin => plugin.trim()))
14
14
  }
15
15
 
16
16
  function cleanEnv (name) {
@@ -119,7 +119,10 @@ function getTestParentSpan (tracer) {
119
119
  */
120
120
  function getTestSuitePath (testSuiteAbsolutePath, sourceRoot) {
121
121
  if (!testSuiteAbsolutePath) {
122
- return testSuiteAbsolutePath
122
+ return sourceRoot
123
123
  }
124
- return path.relative(sourceRoot, testSuiteAbsolutePath).replace(path.sep, '/')
124
+ const testSuitePath = testSuiteAbsolutePath === sourceRoot
125
+ ? testSuiteAbsolutePath : path.relative(sourceRoot, testSuiteAbsolutePath)
126
+
127
+ return testSuitePath.replace(path.sep, '/')
125
128
  }
@@ -181,7 +181,7 @@ const web = {
181
181
 
182
182
  // Extract the parent span from the headers and start a new span as its child
183
183
  startChildSpan (tracer, name, headers) {
184
- const childOf = tracer.extract(FORMAT_HTTP_HEADERS, headers)
184
+ const childOf = tracer.scope().active() || tracer.extract(FORMAT_HTTP_HEADERS, headers)
185
185
  const span = tracer.startSpan(name, { childOf })
186
186
 
187
187
  return span
@@ -4,9 +4,13 @@ const retry = require('retry')
4
4
  const { request } = require('http')
5
5
  const FormData = require('form-data')
6
6
 
7
+ // TODO: avoid using dd-trace internals. Make this a separate module?
8
+ const docker = require('../../exporters/agent/docker')
7
9
  const version = require('../../../lib/version')
8
10
 
9
- function sendRequest (options, body, callback) {
11
+ const containerId = docker.id()
12
+
13
+ function sendRequest (options, form, callback) {
10
14
  const req = request(options, res => {
11
15
  if (res.statusCode >= 400) {
12
16
  const error = new Error(`HTTP Error ${res.statusCode}`)
@@ -17,7 +21,7 @@ function sendRequest (options, body, callback) {
17
21
  }
18
22
  })
19
23
  req.on('error', callback)
20
- if (body) req.write(body)
24
+ if (form) form.pipe(req)
21
25
  req.end()
22
26
  }
23
27
 
@@ -97,13 +101,16 @@ class AgentExporter {
97
101
  })
98
102
  }
99
103
 
100
- const body = form.getBuffer()
101
104
  const options = {
102
105
  method: 'POST',
103
106
  path: '/profiling/v1/input',
104
107
  headers: form.getHeaders()
105
108
  }
106
109
 
110
+ if (containerId) {
111
+ options.headers['Datadog-Container-ID'] = containerId
112
+ }
113
+
107
114
  if (this._url.protocol === 'unix:') {
108
115
  options.socketPath = this._url.pathname
109
116
  } else {
@@ -125,7 +132,7 @@ class AgentExporter {
125
132
 
126
133
  operation.attempt((attempt) => {
127
134
  const timeout = Math.pow(this._backoffTime, attempt)
128
- sendRequest({ ...options, timeout }, body, (err, response) => {
135
+ sendRequest({ ...options, timeout }, form, (err, response) => {
129
136
  if (operation.retry(err)) {
130
137
  this._logger.error(`Error from the agent: ${err.message}`)
131
138
  return
@@ -25,9 +25,7 @@ class NativeCpuProfiler {
25
25
 
26
26
  profile () {
27
27
  if (!this._stop) return
28
- const profile = this._stop()
29
- this._record()
30
- return profile
28
+ return this._stop(true)
31
29
  }
32
30
 
33
31
  encode (profile) {
@@ -46,7 +46,7 @@ class Tracer extends BaseTracer {
46
46
  metrics.start(config)
47
47
  }
48
48
 
49
- // dirty require for now so zero appsec code is executed unless explicitely enabled
49
+ // dirty require for now so zero appsec code is executed unless explicitly enabled
50
50
  if (config.appsec.enabled) {
51
51
  require('./appsec').enable(config)
52
52
  }
package/NOTICE DELETED
@@ -1,4 +0,0 @@
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/).