dd-trace 2.9.1 → 2.12.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 (59) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/index.d.ts +3 -3
  3. package/package.json +7 -8
  4. package/packages/datadog-core/src/storage/async_hooks.js +4 -4
  5. package/packages/datadog-core/src/storage/async_resource.js +14 -4
  6. package/packages/datadog-instrumentations/index.js +5 -0
  7. package/packages/datadog-instrumentations/src/connect.js +3 -0
  8. package/packages/datadog-instrumentations/src/couchbase.js +166 -61
  9. package/packages/datadog-instrumentations/src/fastify.js +5 -3
  10. package/packages/datadog-instrumentations/src/graphql.js +366 -0
  11. package/packages/datadog-instrumentations/src/grpc/client.js +250 -0
  12. package/packages/datadog-instrumentations/src/grpc/server.js +144 -0
  13. package/packages/{datadog-plugin-grpc/src/kinds.js → datadog-instrumentations/src/grpc/types.js} +0 -0
  14. package/packages/datadog-instrumentations/src/grpc.js +4 -0
  15. package/packages/datadog-instrumentations/src/http/client.js +1 -1
  16. package/packages/datadog-instrumentations/src/http2/client.js +67 -0
  17. package/packages/datadog-instrumentations/src/http2/server.js +3 -0
  18. package/packages/datadog-instrumentations/src/http2.js +4 -0
  19. package/packages/datadog-instrumentations/src/jest.js +14 -14
  20. package/packages/datadog-instrumentations/src/koa.js +12 -3
  21. package/packages/datadog-instrumentations/src/microgateway-core.js +66 -0
  22. package/packages/datadog-instrumentations/src/mocha.js +198 -62
  23. package/packages/datadog-instrumentations/src/next.js +140 -0
  24. package/packages/datadog-instrumentations/src/restify.js +4 -8
  25. package/packages/datadog-instrumentations/src/router.js +3 -0
  26. package/packages/datadog-instrumentations/src/tedious.js +1 -1
  27. package/packages/datadog-plugin-couchbase/src/index.js +8 -10
  28. package/packages/datadog-plugin-graphql/src/index.js +123 -412
  29. package/packages/datadog-plugin-graphql/src/resolve.js +122 -0
  30. package/packages/datadog-plugin-grpc/src/client.js +54 -283
  31. package/packages/datadog-plugin-grpc/src/index.js +31 -3
  32. package/packages/datadog-plugin-grpc/src/server.js +50 -145
  33. package/packages/datadog-plugin-http/src/client.js +10 -7
  34. package/packages/datadog-plugin-http/src/server.js +3 -8
  35. package/packages/datadog-plugin-http2/src/client.js +72 -120
  36. package/packages/datadog-plugin-http2/src/index.js +32 -3
  37. package/packages/datadog-plugin-http2/src/server.js +6 -214
  38. package/packages/datadog-plugin-jest/src/util.js +13 -1
  39. package/packages/datadog-plugin-microgateway-core/src/index.js +14 -145
  40. package/packages/datadog-plugin-mocha/src/index.js +88 -39
  41. package/packages/datadog-plugin-next/src/index.js +56 -168
  42. package/packages/datadog-plugin-router/src/index.js +41 -13
  43. package/packages/dd-trace/src/config.js +3 -2
  44. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +111 -15
  45. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  46. package/packages/dd-trace/src/opentracing/span.js +6 -3
  47. package/packages/dd-trace/src/plugin_manager.js +59 -22
  48. package/packages/dd-trace/src/plugins/plugin.js +3 -1
  49. package/packages/dd-trace/src/plugins/util/test.js +35 -1
  50. package/packages/dd-trace/src/plugins/util/web.js +22 -24
  51. package/packages/dd-trace/src/profiling/config.js +10 -2
  52. package/packages/dd-trace/src/profiling/exporters/agent.js +2 -3
  53. package/packages/dd-trace/src/profiling/exporters/form-data.js +53 -0
  54. package/packages/dd-trace/src/profiling/index.js +2 -0
  55. package/packages/dd-trace/src/profiling/profiler.js +6 -1
  56. package/packages/dd-trace/src/profiling/profilers/cpu.js +126 -0
  57. package/packages/dd-trace/src/startup-log.js +1 -1
  58. package/packages/dd-trace/src/telemetry.js +1 -1
  59. package/packages/dd-trace/lib/version.js +0 -1
@@ -1,149 +1,81 @@
1
1
  'use strict'
2
2
 
3
- // TODO: either instrument all or none of the render functions
4
-
3
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
+ const { storage } = require('../../datadog-core')
5
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
6
6
 
7
- const contexts = new WeakMap()
8
-
9
- function createWrapHandleRequest (tracer, config) {
10
- return function wrapHandleRequest (handleRequest) {
11
- return function handleRequestWithTrace (req, res, pathname, query) {
12
- return trace(tracer, config, req, res, () => handleRequest.apply(this, arguments))
13
- }
7
+ class NextPlugin extends Plugin {
8
+ static get name () {
9
+ return 'next'
14
10
  }
15
- }
16
-
17
- function createWrapHandleApiRequest (tracer, config) {
18
- return function wrapHandleApiRequest (handleApiRequest) {
19
- return function handleApiRequestWithTrace (req, res, pathname, query) {
20
- return trace(tracer, config, req, res, () => {
21
- const promise = handleApiRequest.apply(this, arguments)
22
-
23
- return promise.then(handled => {
24
- if (!handled) return handled
25
11
 
26
- const page = getPageFromPath(pathname, this.dynamicRoutes)
27
-
28
- addPage(req, page)
29
-
30
- return handled
31
- })
12
+ constructor (...args) {
13
+ super(...args)
14
+
15
+ this._requests = new WeakMap()
16
+
17
+ this.addSub('apm:next:request:start', ({ req, res }) => {
18
+ const store = storage.getStore()
19
+ const childOf = store ? store.span : store
20
+ const span = this.tracer.startSpan('next.request', {
21
+ childOf,
22
+ tags: {
23
+ 'service.name': this.config.service || this.tracer._service,
24
+ 'resource.name': req.method,
25
+ 'span.type': 'web',
26
+ 'span.kind': 'server',
27
+ 'http.method': req.method
28
+ }
32
29
  })
33
- }
34
- }
35
- }
36
30
 
37
- function createWrapRenderToResponse (tracer, config) {
38
- return function wrapRenderToResponse (renderToResponse) {
39
- return function renderToResponseWithTrace (ctx) {
40
- return trace(tracer, config, ctx.req, ctx.res, () => renderToResponse.apply(this, arguments))
41
- }
42
- }
43
- }
31
+ analyticsSampler.sample(span, this.config.measured, true)
44
32
 
45
- function createWrapRenderErrorToResponse (tracer, config) {
46
- return function wrapRenderErrorToResponse (renderErrorToResponse) {
47
- return function renderErrorToResponseWithTrace (ctx) {
48
- return trace(tracer, config, ctx.req, ctx.res, () => renderErrorToResponse.apply(this, arguments))
49
- }
50
- }
51
- }
33
+ this.enter(span, store)
52
34
 
53
- function createWrapRenderToHTML (tracer, config) {
54
- return function wrapRenderToHTML (renderToHTML) {
55
- return function renderToHTMLWithTrace (req, res, pathname, query, parsedUrl) {
56
- return trace(tracer, config, req, res, () => renderToHTML.apply(this, arguments))
57
- }
58
- }
59
- }
35
+ this._requests.set(span, req)
36
+ })
60
37
 
61
- function createWrapRenderErrorToHTML (tracer, config) {
62
- return function wrapRenderErrorToHTML (renderErrorToHTML) {
63
- return function renderErrorToHTMLWithTrace (err, req, res, pathname, query) {
64
- return trace(tracer, config, req, res, () => renderErrorToHTML.apply(this, arguments))
65
- }
66
- }
67
- }
38
+ this.addSub('apm:next:request:error', this.addError)
68
39
 
69
- function createWrapFindPageComponents (tracer, config) {
70
- return function wrapFindPageComponents (findPageComponents) {
71
- return function findPageComponentsWithTrace (pathname, query) {
72
- const result = findPageComponents.apply(this, arguments)
73
- const span = tracer.scope().active()
74
- const req = span && span._nextReq
40
+ this.addSub('apm:next:request:finish', ({ req, res }) => {
41
+ const store = storage.getStore()
75
42
 
76
- if (result) {
77
- addPage(req, pathname)
78
- }
43
+ if (!store) return
79
44
 
80
- return result
81
- }
82
- }
83
- }
84
-
85
- function getPageFromPath (page, dynamicRoutes = []) {
86
- for (const dynamicRoute of dynamicRoutes) {
87
- if (dynamicRoute.page.startsWith('/api') && dynamicRoute.match(page)) {
88
- return dynamicRoute.page
89
- }
90
- }
91
-
92
- return page
93
- }
94
-
95
- function trace (tracer, config, req, res, handler) {
96
- const scope = tracer.scope()
97
- const context = contexts.get(req)
98
-
99
- if (context) return scope.activate(context.span, handler)
100
-
101
- const childOf = scope.active()
102
- const tags = {
103
- 'service.name': config.service || tracer._service,
104
- 'resource.name': req.method,
105
- 'span.type': 'web',
106
- 'span.kind': 'server',
107
- 'http.method': req.method
108
- }
109
- const span = tracer.startSpan('next.request', { childOf, tags })
45
+ const span = store.span
46
+ const error = span.context()._tags['error']
110
47
 
111
- analyticsSampler.sample(span, config.measured, true)
48
+ if (!this.config.validateStatus(res.statusCode) && !error) {
49
+ span.setTag('error', true)
50
+ }
112
51
 
113
- contexts.set(req, { span })
52
+ span.addTags({
53
+ 'http.status_code': res.statusCode
54
+ })
114
55
 
115
- const promise = scope.activate(span, handler)
56
+ this.config.hooks.request(span, req, res)
116
57
 
117
- // HACK: Store the request object on the span for findPageComponents.
118
- // TODO: Use CLS when it will be available in core.
119
- span._nextReq = req
58
+ span.finish()
59
+ })
120
60
 
121
- return promise.then(
122
- result => finish(span, config, req, res, result),
123
- err => finish(span, config, req, res, null, err)
124
- )
125
- }
61
+ this.addSub('apm:next:page:load', ({ page }) => {
62
+ const store = storage.getStore()
126
63
 
127
- function addPage (req, page) {
128
- const context = contexts.get(req)
64
+ if (!store) return
129
65
 
130
- if (!context) return
131
-
132
- context.span.addTags({
133
- 'resource.name': `${req.method} ${page}`.trim(),
134
- 'next.page': page
135
- })
136
- }
66
+ const span = store.span
67
+ const req = this._requests.get(span)
137
68
 
138
- function finish (span, config, req, res, result, err) {
139
- span.setTag('error', err || !config.validateStatus(res.statusCode))
140
- span.addTags({
141
- 'http.status_code': res.statusCode
142
- })
143
- config.hooks.request(span, req, res)
144
- span.finish()
69
+ span.addTags({
70
+ 'resource.name': `${req.method} ${page}`.trim(),
71
+ 'next.page': page
72
+ })
73
+ })
74
+ }
145
75
 
146
- return result || err
76
+ configure (config) {
77
+ return super.configure(normalizeConfig(config))
78
+ }
147
79
  }
148
80
 
149
81
  function normalizeConfig (config) {
@@ -162,48 +94,4 @@ function getHooks (config) {
162
94
  return { request }
163
95
  }
164
96
 
165
- module.exports = [
166
- {
167
- name: 'next',
168
- versions: ['>=9.5 <11.1'],
169
- file: 'dist/next-server/server/next-server.js',
170
- patch ({ default: Server }, tracer, config) {
171
- config = normalizeConfig(config)
172
-
173
- this.wrap(Server.prototype, 'handleRequest', createWrapHandleRequest(tracer, config))
174
- this.wrap(Server.prototype, 'handleApiRequest', createWrapHandleApiRequest(tracer, config))
175
- this.wrap(Server.prototype, 'renderToHTML', createWrapRenderToHTML(tracer, config))
176
- this.wrap(Server.prototype, 'renderErrorToHTML', createWrapRenderErrorToHTML(tracer, config))
177
- this.wrap(Server.prototype, 'findPageComponents', createWrapFindPageComponents(tracer, config))
178
- },
179
- unpatch ({ default: Server }) {
180
- this.unwrap(Server.prototype, 'handleRequest')
181
- this.unwrap(Server.prototype, 'handleApiRequest')
182
- this.unwrap(Server.prototype, 'renderToHTML')
183
- this.unwrap(Server.prototype, 'renderErrorToHTML')
184
- this.unwrap(Server.prototype, 'findPageComponents')
185
- }
186
- },
187
-
188
- {
189
- name: 'next',
190
- versions: ['>=11.1'],
191
- file: 'dist/server/next-server.js',
192
- patch ({ default: Server }, tracer, config) {
193
- config = normalizeConfig(config)
194
-
195
- this.wrap(Server.prototype, 'handleRequest', createWrapHandleRequest(tracer, config))
196
- this.wrap(Server.prototype, 'handleApiRequest', createWrapHandleApiRequest(tracer, config))
197
- this.wrap(Server.prototype, 'renderToResponse', createWrapRenderToResponse(tracer, config))
198
- this.wrap(Server.prototype, 'renderErrorToResponse', createWrapRenderErrorToResponse(tracer, config))
199
- this.wrap(Server.prototype, 'findPageComponents', createWrapFindPageComponents(tracer, config))
200
- },
201
- unpatch ({ default: Server }) {
202
- this.unwrap(Server.prototype, 'handleRequest')
203
- this.unwrap(Server.prototype, 'handleApiRequest')
204
- this.unwrap(Server.prototype, 'renderToResponse')
205
- this.unwrap(Server.prototype, 'renderErrorToResponse')
206
- this.unwrap(Server.prototype, 'findPageComponents')
207
- }
208
- }
209
- ]
97
+ module.exports = NextPlugin
@@ -16,11 +16,15 @@ class RouterPlugin extends WebPlugin {
16
16
  this._contexts = new WeakMap()
17
17
 
18
18
  this.addSub(`apm:${this.constructor.name}:middleware:enter`, ({ req, name, route }) => {
19
- const store = storage.getStore()
20
- const context = this._createContext(req, route)
21
- const span = this._getMiddlewareSpan(context, store, name)
19
+ const childOf = this._getActive(req)
20
+ const span = this._getMiddlewareSpan(name, childOf)
21
+ const context = this._createContext(req, route, childOf)
22
+
23
+ if (childOf !== span) {
24
+ context.middleware.push(span)
25
+ }
22
26
 
23
- this.enter(span, store)
27
+ this.enter(span)
24
28
 
25
29
  web.patch(req)
26
30
  web.setRoute(req, context.route)
@@ -32,13 +36,25 @@ class RouterPlugin extends WebPlugin {
32
36
  if (!context) return
33
37
 
34
38
  context.stack.pop()
39
+ })
35
40
 
36
- if (context.middleware.length > 0) {
37
- context.middleware.pop().finish()
38
- }
41
+ this.addSub(`apm:${this.constructor.name}:middleware:exit`, ({ req }) => {
42
+ const context = this._contexts.get(req)
43
+
44
+ if (!context || context.middleware.length === 0) return
45
+
46
+ context.middleware.pop().finish()
39
47
  })
40
48
 
41
- this.addSub(`apm:${this.constructor.name}:middleware:error`, this.addError)
49
+ this.addSub(`apm:${this.constructor.name}:middleware:error`, err => {
50
+ const store = storage.getStore()
51
+
52
+ web.addError(store.req, err)
53
+
54
+ if (this.config.middleware) {
55
+ this.addError(err)
56
+ }
57
+ })
42
58
 
43
59
  this.addSub(`apm:http:server:request:finish`, ({ req }) => {
44
60
  const context = this._contexts.get(req)
@@ -53,9 +69,22 @@ class RouterPlugin extends WebPlugin {
53
69
  })
54
70
  }
55
71
 
56
- _getMiddlewareSpan (context, store, name) {
57
- const childOf = store && store.span
72
+ _getActive (req) {
73
+ const context = this._contexts.get(req)
74
+
75
+ if (!context) return this._getStoreSpan()
76
+ if (context.middleware.length === 0) return context.span
77
+
78
+ return context.middleware[context.middleware.length - 1]
79
+ }
80
+
81
+ _getStoreSpan () {
82
+ const store = storage.getStore()
58
83
 
84
+ return store && store.span
85
+ }
86
+
87
+ _getMiddlewareSpan (name, childOf) {
59
88
  if (this.config.middleware === false) {
60
89
  return childOf
61
90
  }
@@ -67,14 +96,12 @@ class RouterPlugin extends WebPlugin {
67
96
  }
68
97
  })
69
98
 
70
- context.middleware.push(span)
71
-
72
99
  analyticsSampler.sample(span, this.config.measured)
73
100
 
74
101
  return span
75
102
  }
76
103
 
77
- _createContext (req, route) {
104
+ _createContext (req, route, span) {
78
105
  let context = this._contexts.get(req)
79
106
 
80
107
  if (!route || route === '/' || route === '*') {
@@ -92,6 +119,7 @@ class RouterPlugin extends WebPlugin {
92
119
  }
93
120
  } else {
94
121
  context = {
122
+ span,
95
123
  stack: [route],
96
124
  route,
97
125
  middleware: []
@@ -93,7 +93,7 @@ class Config {
93
93
  )
94
94
  const DD_TRACE_TELEMETRY_ENABLED = coalesce(
95
95
  process.env.DD_TRACE_TELEMETRY_ENABLED,
96
- true
96
+ !process.env.AWS_LAMBDA_FUNCTION_NAME
97
97
  )
98
98
  const DD_TRACE_DEBUG = coalesce(
99
99
  process.env.DD_TRACE_DEBUG,
@@ -237,7 +237,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
237
237
  }
238
238
  this.lookup = options.lookup
239
239
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
240
- this.telemetryEnabled = isTrue(DD_TRACE_TELEMETRY_ENABLED)
240
+ // Disabled for CI Visibility's agentless
241
+ this.telemetryEnabled = DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_TRACE_TELEMETRY_ENABLED)
241
242
  this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
242
243
  this.appsec = {
243
244
  enabled: isTrue(DD_APPSEC_ENABLED),
@@ -3,13 +3,25 @@ const { truncateSpan, normalizeSpan } = require('./tags-processors')
3
3
  const Chunk = require('./chunk')
4
4
  const { AgentEncoder } = require('./0.4')
5
5
  const { version: ddTraceVersion } = require('../../../../package.json')
6
+ const id = require('../../../dd-trace/src/id')
6
7
 
7
8
  const ENCODING_VERSION = 1
8
9
 
10
+ const ALLOWED_CONTENT_TYPES = ['test_session_end', 'test_suite_end', 'test']
11
+
12
+ const TEST_SUITE_KEYS_LENGTH = 11
13
+ const TEST_SESSION_KEYS_LENGTH = 10
14
+
15
+ const CHUNK_SIZE = 4 * 1024 * 1024 // 4MB
16
+
9
17
  function formatSpan (span) {
18
+ let encodingVersion = ENCODING_VERSION
19
+ if (span.type === 'test' && span.meta && span.meta.test_session_id) {
20
+ encodingVersion = 2
21
+ }
10
22
  return {
11
- type: span.type === 'test' ? 'test' : 'span',
12
- version: ENCODING_VERSION,
23
+ type: ALLOWED_CONTENT_TYPES.includes(span.type) ? span.type : 'span',
24
+ version: encodingVersion,
13
25
  content: normalizeSpan(truncateSpan(span))
14
26
  }
15
27
  }
@@ -21,8 +33,8 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
21
33
  this.runtimeId = runtimeId
22
34
  this.service = service
23
35
  this.env = env
24
- this._traceBytes = new Chunk()
25
- this._stringBytes = new Chunk()
36
+ this._traceBytes = new Chunk(CHUNK_SIZE)
37
+ this._stringBytes = new Chunk(CHUNK_SIZE)
26
38
  this._stringCount = 0
27
39
  this._stringMap = {}
28
40
 
@@ -33,8 +45,69 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
33
45
  this.reset()
34
46
  }
35
47
 
48
+ _encodeTestSuite (bytes, content) {
49
+ this._encodeMapPrefix(bytes, TEST_SUITE_KEYS_LENGTH)
50
+ this._encodeString(bytes, 'type')
51
+ this._encodeString(bytes, content.type)
52
+
53
+ this._encodeString(bytes, 'test_session_id')
54
+ this._encodeId(bytes, content.trace_id)
55
+
56
+ this._encodeString(bytes, 'test_suite_id')
57
+ this._encodeId(bytes, content.span_id)
58
+
59
+ this._encodeString(bytes, 'error')
60
+ this._encodeNumber(bytes, content.error)
61
+ this._encodeString(bytes, 'name')
62
+ this._encodeString(bytes, content.name)
63
+ this._encodeString(bytes, 'service')
64
+ this._encodeString(bytes, content.service)
65
+ this._encodeString(bytes, 'resource')
66
+ this._encodeString(bytes, content.resource)
67
+ this._encodeString(bytes, 'start')
68
+ this._encodeNumber(bytes, content.start)
69
+ this._encodeString(bytes, 'duration')
70
+ this._encodeNumber(bytes, content.duration)
71
+ this._encodeString(bytes, 'meta')
72
+ this._encodeMap(bytes, content.meta)
73
+ this._encodeString(bytes, 'metrics')
74
+ this._encodeMap(bytes, content.metrics)
75
+ }
76
+
77
+ _encodeTestSession (bytes, content) {
78
+ this._encodeMapPrefix(bytes, TEST_SESSION_KEYS_LENGTH)
79
+ this._encodeString(bytes, 'type')
80
+ this._encodeString(bytes, content.type)
81
+
82
+ this._encodeString(bytes, 'test_session_id')
83
+ this._encodeId(bytes, content.trace_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
+
36
103
  _encodeEventContent (bytes, content) {
37
- this._encodeMapPrefix(bytes, content)
104
+ const keysLength = Object.keys(content).length
105
+ if (content.meta.test_session_id) {
106
+ this._encodeMapPrefix(bytes, keysLength + 2)
107
+ } else {
108
+ this._encodeMapPrefix(bytes, keysLength)
109
+ }
110
+
38
111
  if (content.type) {
39
112
  this._encodeString(bytes, 'type')
40
113
  this._encodeString(bytes, content.type)
@@ -57,6 +130,24 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
57
130
  this._encodeNumber(bytes, content.start)
58
131
  this._encodeString(bytes, 'duration')
59
132
  this._encodeNumber(bytes, content.duration)
133
+ /**
134
+ * We include `test_session_id` and `test_suite_id`
135
+ * in the root of the event by passing them via the `meta` dict.
136
+ * This is to avoid changing the span format in packages/dd-trace/src/format.js,
137
+ * which can have undesired side effects in other products.
138
+ * But `test_session_id` and `test_suite_id` are *not* supposed to be in `meta`,
139
+ * so we delete them before enconding the dictionary.
140
+ * TODO: find a better way to do this.
141
+ */
142
+ if (content.meta.test_session_id) {
143
+ this._encodeString(bytes, 'test_session_id')
144
+ this._encodeId(bytes, id(content.meta.test_session_id))
145
+ delete content.meta.test_session_id
146
+
147
+ this._encodeString(bytes, 'test_suite_id')
148
+ this._encodeId(bytes, id(content.meta.test_suite_id))
149
+ delete content.meta.test_suite_id
150
+ }
60
151
  this._encodeString(bytes, 'meta')
61
152
  this._encodeMap(bytes, content.meta)
62
153
  this._encodeString(bytes, 'metrics')
@@ -64,7 +155,7 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
64
155
  }
65
156
 
66
157
  _encodeEvent (bytes, event) {
67
- this._encodeMapPrefix(bytes, event)
158
+ this._encodeMapPrefix(bytes, Object.keys(event).length)
68
159
  this._encodeString(bytes, 'type')
69
160
  this._encodeString(bytes, event.type)
70
161
 
@@ -72,7 +163,13 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
72
163
  this._encodeNumber(bytes, event.version)
73
164
 
74
165
  this._encodeString(bytes, 'content')
75
- this._encodeEventContent(bytes, event.content)
166
+ if (event.type === 'span' || event.type === 'test') {
167
+ this._encodeEventContent(bytes, event.content)
168
+ } else if (event.type === 'test_suite_end') {
169
+ this._encodeTestSuite(bytes, event.content)
170
+ } else if (event.type === 'test_session_end') {
171
+ this._encodeTestSession(bytes, event.content)
172
+ }
76
173
  }
77
174
 
78
175
  _encodeNumber (bytes, value) {
@@ -107,18 +204,17 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
107
204
  buffer[offset + 8] = lo
108
205
  }
109
206
 
110
- _encodeMapPrefix (bytes, map) {
111
- const keys = Object.keys(map)
207
+ _encodeMapPrefix (bytes, keysLength) {
112
208
  const buffer = bytes.buffer
113
209
  const offset = bytes.length
114
210
 
115
211
  bytes.reserve(5)
116
212
  bytes.length += 5
117
213
  buffer[offset] = 0xdf
118
- buffer[offset + 1] = keys.length >> 24
119
- buffer[offset + 2] = keys.length >> 16
120
- buffer[offset + 3] = keys.length >> 8
121
- buffer[offset + 4] = keys.length
214
+ buffer[offset + 1] = keysLength >> 24
215
+ buffer[offset + 2] = keysLength >> 16
216
+ buffer[offset + 3] = keysLength >> 8
217
+ buffer[offset + 4] = keysLength
122
218
  }
123
219
 
124
220
  _encode (bytes, trace) {
@@ -171,11 +267,11 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
171
267
  payload.metadata['*']['runtime-id'] = this.runtimeId
172
268
  }
173
269
 
174
- this._encodeMapPrefix(bytes, payload)
270
+ this._encodeMapPrefix(bytes, Object.keys(payload).length)
175
271
  this._encodeString(bytes, 'version')
176
272
  this._encodeNumber(bytes, payload.version)
177
273
  this._encodeString(bytes, 'metadata')
178
- this._encodeMapPrefix(bytes, payload.metadata)
274
+ this._encodeMapPrefix(bytes, Object.keys(payload.metadata).length)
179
275
  this._encodeString(bytes, '*')
180
276
  this._encodeMap(bytes, payload.metadata['*'])
181
277
  this._encodeString(bytes, 'events')
@@ -4,7 +4,7 @@ const request = require('../common/request')
4
4
  const { startupLog } = require('../../startup-log')
5
5
  const metrics = require('../../metrics')
6
6
  const log = require('../../log')
7
- const tracerVersion = require('../../../lib/version')
7
+ const tracerVersion = require('../../../../../package.json').version
8
8
  const BaseWriter = require('../common/writer')
9
9
 
10
10
  const METRIC_PREFIX = 'datadog.tracer.node.exporter.agent'
@@ -13,7 +13,10 @@ const metrics = require('../metrics')
13
13
  const log = require('../log')
14
14
  const { storage } = require('../../../datadog-core')
15
15
 
16
- const { DD_TRACE_EXPERIMENTAL_STATE_TRACKING } = process.env
16
+ const {
17
+ DD_TRACE_EXPERIMENTAL_STATE_TRACKING,
18
+ DD_TRACE_EXPERIMENTAL_SPAN_COUNTS
19
+ } = process.env
17
20
 
18
21
  const unfinishedRegistry = createRegistry('unfinished')
19
22
  const finishedRegistry = createRegistry('finished')
@@ -41,7 +44,7 @@ class DatadogSpan extends Span {
41
44
 
42
45
  this._startTime = fields.startTime || this._getTime()
43
46
 
44
- if (this._debug && unfinishedRegistry) {
47
+ if (DD_TRACE_EXPERIMENTAL_SPAN_COUNTS && finishedRegistry) {
45
48
  metrics.increment('runtime.node.spans.unfinished')
46
49
  metrics.increment('runtime.node.spans.unfinished.by.name', `span_name:${operationName}`)
47
50
 
@@ -137,7 +140,7 @@ class DatadogSpan extends Span {
137
140
  }
138
141
  }
139
142
 
140
- if (this._debug && finishedRegistry) {
143
+ if (DD_TRACE_EXPERIMENTAL_SPAN_COUNTS && finishedRegistry) {
141
144
  metrics.decrement('runtime.node.spans.unfinished')
142
145
  metrics.decrement('runtime.node.spans.unfinished.by.name', `span_name:${this._name}`)
143
146
  metrics.increment('runtime.node.spans.finished')