Skip to content

Commit 75c2867

Browse files
authored
remove async storage from http2 server instrumentation (#5947)
* remove async storage from http2 instrumentation
1 parent 5875fec commit 75c2867

File tree

9 files changed

+268
-213
lines changed

9 files changed

+268
-213
lines changed

packages/datadog-instrumentations/src/http2/server.js

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55

66
const {
77
channel,
8-
addHook,
9-
AsyncResource
8+
addHook
109
} = require('../helpers/instrument')
1110
const shimmer = require('../../../datadog-shimmer')
1211

1312
const startServerCh = channel('apm:http2:server:request:start')
1413
const errorServerCh = channel('apm:http2:server:request:error')
15-
const finishServerCh = channel('apm:http2:server:request:finish')
14+
const emitCh = channel('apm:http2:server:response:emit')
1615

1716
const names = ['http2', 'node:http2']
1817

@@ -30,18 +29,14 @@ function wrapCreateServer (createServer) {
3029
}
3130
}
3231

33-
function wrapResponseEmit (emit) {
34-
const asyncResource = new AsyncResource('bound-anonymous-fn')
32+
function wrapResponseEmit (emit, ctx) {
3533
return function (eventName, event) {
36-
return asyncResource.runInAsyncScope(() => {
37-
if (eventName === 'close' && finishServerCh.hasSubscribers) {
38-
finishServerCh.publish({ req: this.req })
39-
}
40-
41-
return emit.apply(this, arguments)
42-
})
34+
ctx.req = this.req
35+
ctx.eventName = eventName
36+
return emitCh.runStores(ctx, emit, this, ...arguments)
4337
}
4438
}
39+
4540
function wrapEmit (emit) {
4641
return function (eventName, req, res) {
4742
if (!startServerCh.hasSubscribers) {
@@ -51,18 +46,17 @@ function wrapEmit (emit) {
5146
if (eventName === 'request') {
5247
res.req = req
5348

54-
const asyncResource = new AsyncResource('bound-anonymous-fn')
55-
return asyncResource.runInAsyncScope(() => {
56-
startServerCh.publish({ req, res })
57-
58-
shimmer.wrap(res, 'emit', wrapResponseEmit)
49+
const ctx = { req, res }
50+
return startServerCh.runStores(ctx, () => {
51+
shimmer.wrap(res, 'emit', emit => wrapResponseEmit(emit, ctx))
5952

6053
try {
6154
return emit.apply(this, arguments)
62-
} catch (err) {
63-
errorServerCh.publish(err)
55+
} catch (error) {
56+
ctx.error = error
57+
errorServerCh.publish(ctx)
6458

65-
throw err
59+
throw error
6660
}
6761
})
6862
}

packages/datadog-plugin-child_process/test/index.spec.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ describe('Child process plugin', () => {
5252
expect(tracerStub.startSpan).to.have.been.calledOnceWithExactly(
5353
'command_execution',
5454
{
55+
startTime: undefined,
5556
childOf: undefined,
5657
tags: {
5758
component: 'subprocess',
@@ -75,6 +76,7 @@ describe('Child process plugin', () => {
7576
expect(tracerStub.startSpan).to.have.been.calledOnceWithExactly(
7677
'command_execution',
7778
{
79+
startTime: undefined,
7880
childOf: undefined,
7981
tags: {
8082
component: 'subprocess',
@@ -100,6 +102,7 @@ describe('Child process plugin', () => {
100102
expect(tracerStub.startSpan).to.have.been.calledOnceWithExactly(
101103
'command_execution',
102104
{
105+
startTime: undefined,
103106
childOf: undefined,
104107
tags: {
105108
component: 'subprocess',
@@ -126,6 +129,7 @@ describe('Child process plugin', () => {
126129
expect(tracerStub.startSpan).to.have.been.calledOnceWithExactly(
127130
'command_execution',
128131
{
132+
startTime: undefined,
129133
childOf: undefined,
130134
tags: {
131135
component: 'subprocess',
@@ -153,6 +157,7 @@ describe('Child process plugin', () => {
153157
expect(tracerStub.startSpan).to.have.been.calledOnceWithExactly(
154158
'command_execution',
155159
{
160+
startTime: undefined,
156161
childOf: undefined,
157162
tags: {
158163
component: 'subprocess',
@@ -180,6 +185,7 @@ describe('Child process plugin', () => {
180185
expect(tracerStub.startSpan).to.have.been.calledOnceWithExactly(
181186
'command_execution',
182187
{
188+
startTime: undefined,
183189
childOf: undefined,
184190
tags: {
185191
component: 'subprocess',

packages/datadog-plugin-http/src/server.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ class HttpServerPlugin extends ServerPlugin {
1111
return 'http'
1212
}
1313

14+
static get prefix () {
15+
return 'apm:http:server:request'
16+
}
17+
1418
constructor (...args) {
1519
super(...args)
1620
this._parentStore = undefined
1721
this.addTraceSub('exit', message => this.exit(message))
1822
}
1923

20-
addTraceSub (eventName, handler) {
21-
this.addSub(`apm:${this.constructor.id}:server:${this.operation}:${eventName}`, handler)
22-
}
23-
2424
start ({ req, res, abortController }) {
2525
const store = storage('legacy').getStore()
2626
const span = web.startSpan(

packages/datadog-plugin-http2/src/server.js

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,26 @@
33
// Plugin temporarily disabled. See https://github.com/DataDog/dd-trace-js/issues/312
44

55
const ServerPlugin = require('../../dd-trace/src/plugins/server')
6-
const { storage } = require('../../datadog-core')
76
const web = require('../../dd-trace/src/plugins/util/web')
87
const { COMPONENT } = require('../../dd-trace/src/constants')
98

109
class Http2ServerPlugin extends ServerPlugin {
10+
constructor (tracer, config) {
11+
super(tracer, config)
12+
this.addBind('apm:http2:server:response:emit', this.bindEmit)
13+
}
14+
1115
static get id () {
1216
return 'http2'
1317
}
1418

15-
addTraceSub (eventName, handler) {
16-
this.addSub(`apm:${this.constructor.id}:server:${this.operation}:${eventName}`, handler)
19+
static get prefix () {
20+
return 'apm:http2:server:request'
1721
}
1822

19-
start ({ req, res }) {
20-
const store = storage('legacy').getStore()
23+
bindStart (ctx) {
24+
const { req, res } = ctx
25+
2126
const span = web.startSpan(
2227
this.tracer,
2328
{
@@ -26,28 +31,38 @@ class Http2ServerPlugin extends ServerPlugin {
2631
},
2732
req,
2833
res,
29-
this.operationName()
34+
this.operationName(),
35+
ctx
3036
)
3137

3238
span.setTag(COMPONENT, this.constructor.id)
3339
span._integrationName = this.constructor.id
3440

35-
this.enter(span, { ...store, req, res })
41+
ctx.currentStore.req = req
42+
ctx.currentStore.res = res
3643

3744
const context = web.getContext(req)
3845

3946
if (!context.instrumented) {
4047
context.res.writeHead = web.wrapWriteHead(context)
4148
context.instrumented = true
4249
}
50+
51+
return ctx.currentStore
4352
}
4453

45-
finish ({ req }) {
54+
bindEmit (ctx) {
55+
if (ctx.eventName !== 'close') return ctx.currentStore
56+
57+
const { req } = ctx
58+
4659
const context = web.getContext(req)
4760

4861
if (!context || !context.res) return // Not created by a http.Server instance.
4962

5063
web.finishAll(context)
64+
65+
return ctx.currentStore
5166
}
5267

5368
error (error) {

packages/dd-trace/src/plugins/plugin.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ module.exports = class Plugin {
6060
}
6161

6262
get tracer () {
63-
return this._tracer._tracer
63+
return this._tracer?._tracer || this._tracer
6464
}
6565

6666
enter (span, store) {

packages/dd-trace/src/plugins/tracing.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,28 +103,45 @@ class TracingPlugin extends Plugin {
103103
}
104104

105105
startSpan (name, options = {}, enterOrCtx = true) {
106-
let { childOf, integrationName, kind, meta, metrics, service, resource, type } = options
106+
// TODO: modularize this code to a helper function
107+
let {
108+
component = this.component,
109+
childOf,
110+
integrationName,
111+
kind,
112+
meta,
113+
metrics,
114+
service,
115+
startTime,
116+
resource,
117+
type
118+
} = options
119+
120+
const tracer = options.tracer || this.tracer
121+
const config = options.config || this.config
122+
107123
const store = storage('legacy').getStore()
108124
if (store && childOf === undefined) {
109125
childOf = store.span
110126
}
111127

112-
const span = this.tracer.startSpan(name, {
128+
const span = tracer.startSpan(name, {
129+
startTime,
113130
childOf,
114131
tags: {
115-
[COMPONENT]: this.component,
116-
'service.name': service || this.tracer._service,
132+
[COMPONENT]: component,
133+
'service.name': service || meta?.service || tracer._service,
117134
'resource.name': resource,
118135
'span.kind': kind,
119136
'span.type': type,
120137
...meta,
121138
...metrics
122139
},
123-
integrationName: integrationName || this.component,
140+
integrationName: integrationName || component,
124141
links: childOf?._links
125142
})
126143

127-
analyticsSampler.sample(span, this.config.measured)
144+
analyticsSampler.sample(span, config.measured)
128145

129146
// TODO: Remove this after migration to TracingChannel is done.
130147
if (enterOrCtx === true) {

packages/dd-trace/src/plugins/util/inferred_proxy.js

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const supportedProxies = {
2222
}
2323
}
2424

25-
function createInferredProxySpan (headers, childOf, tracer, context) {
25+
function createInferredProxySpan (headers, childOf, tracer, reqCtx, traceCtx, config, startSpanHelper) {
2626
if (!headers) {
2727
return null
2828
}
@@ -41,26 +41,22 @@ function createInferredProxySpan (headers, childOf, tracer, context) {
4141

4242
log.debug('Successfully extracted inferred span info %s for proxy:', proxyContext, proxyContext.proxySystemName)
4343

44-
const span = tracer.startSpan(
45-
proxySpanInfo.spanName,
46-
{
47-
childOf,
48-
type: 'web',
49-
startTime: proxyContext.requestTime,
50-
integrationName: proxySpanInfo.component,
51-
tags: {
52-
service: proxyContext.domainName || tracer._config.service,
53-
component: proxySpanInfo.component,
54-
[SPAN_TYPE]: 'web',
55-
[HTTP_METHOD]: proxyContext.method,
56-
[HTTP_URL]: proxyContext.domainName + proxyContext.path,
57-
stage: proxyContext.stage
58-
}
44+
const span = startSpanHelper(tracer, proxySpanInfo.spanName, {
45+
childOf,
46+
type: 'web',
47+
startTime: proxyContext.requestTime,
48+
integrationName: proxySpanInfo.component,
49+
meta: {
50+
service: proxyContext.domainName || tracer._config.service,
51+
component: proxySpanInfo.component,
52+
[SPAN_TYPE]: 'web',
53+
[HTTP_METHOD]: proxyContext.method,
54+
[HTTP_URL]: proxyContext.domainName + proxyContext.path,
55+
stage: proxyContext.stage
5956
}
60-
)
57+
}, traceCtx, config)
6158

62-
tracer.scope().activate(span)
63-
context.inferredProxySpan = span
59+
reqCtx.inferredProxySpan = span
6460
childOf = span
6561

6662
log.debug('Successfully created inferred proxy span.')

0 commit comments

Comments
 (0)