Skip to content

chore(tracing): remove async storage from mongo plugins #5812

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 35 additions & 47 deletions packages/datadog-instrumentations/src/mongodb-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

const {
channel,
addHook,
AsyncResource
addHook
} = require('./helpers/instrument')
const shimmer = require('../../datadog-shimmer')

Expand Down Expand Up @@ -58,22 +57,6 @@ addHook({ name: 'mongodb-core', versions: ['~3.1.10'], file: 'lib/wireprotocol/2
return WireProtocol
})

addHook({ name: 'mongodb', versions: ['>=3.5.4 <4.11.0'], file: 'lib/utils.js' }, util => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems weird that this hook was removed but not replaced with anything. Do you know why it is no longer needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been following a pattern for these changes. Since we don't call channel.publish here, AFAIK we do not need this wrapper hook anymore since it only deals with binding the asyncresource to the callback. Going to refer to @rochdev since honestly im not sure why this was ever needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically still needed as it basically patches non-native promise implementations that can be used by mongodb. Since we're also instrumenting the library and not just a generic promise implementation it could be replaced with a channel, but I think it's safe to just leave it here as-is for now as it's not nesting async resources.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, ive reverted the change and kept the function here.

shimmer.wrap(util, 'maybePromise', maybePromise => function (parent, callback, fn) {
const asyncResource = new AsyncResource('bound-anonymous-fn')
const callbackIndex = arguments.length - 2

callback = arguments[callbackIndex]

if (typeof callback === 'function') {
arguments[callbackIndex] = asyncResource.bind(callback)
}

return maybePromise.apply(this, arguments)
})
return util
})

function wrapWp (wp) {
shimmer.wrap(wp, 'command', command => wrapUnifiedCommand(command, 'command'))
shimmer.wrap(wp, 'insert', insert => wrapUnifiedCommand(insert, 'insert', 'insert'))
Expand Down Expand Up @@ -148,61 +131,66 @@ function wrapCommand (command, operation, name) {
return wrapped
}

function instrument (operation, command, ctx, args, server, ns, ops, options = {}) {
function instrument (operation, command, mongoCtx, args, server, ns, ops, options = {}) {
const name = options.name || (ops && Object.keys(ops)[0])
const index = args.length - 1
let callback = args[index]
const callback = args[index]

if (typeof callback !== 'function') return command.apply(ctx, args)
if (typeof callback !== 'function') return command.apply(mongoCtx, args)

const serverInfo = server && server.s && server.s.options
const callbackResource = new AsyncResource('bound-anonymous-fn')
const asyncResource = new AsyncResource('bound-anonymous-fn')

callback = callbackResource.bind(callback)

return asyncResource.runInAsyncScope(() => {
startCh.publish({ ns, ops, options: serverInfo, name })

args[index] = shimmer.wrapFunction(callback, callback => asyncResource.bind(function (err, res) {
const ctx = {
ns,
ops,
options: serverInfo,
name
}
return startCh.runStores(ctx, () => {
args[index] = shimmer.wrapFunction(callback, callback => function (err, res) {
if (err) {
errorCh.publish(err)
ctx.error = err
errorCh.publish(ctx)
}

finishCh.publish()

if (callback) {
return callback.apply(this, arguments)
}
}))
return callback ? finishCh.runStores(ctx, callback, this, ...arguments) : finishCh.publish(ctx)
})

try {
return command.apply(ctx, args)
return command.apply(mongoCtx, args)
} catch (err) {
errorCh.publish(err)
ctx.error = err
errorCh.publish(ctx)

throw err
}
})
}

function instrumentPromise (operation, command, ctx, args, server, ns, ops, options = {}) {
function instrumentPromise (operation, command, mongoCtx, args, server, ns, ops, options = {}) {
const name = options.name || (ops && Object.keys(ops)[0])

const serverInfo = server && server.s && server.s.options
const asyncResource = new AsyncResource('bound-anonymous-fn')

return asyncResource.runInAsyncScope(() => {
startCh.publish({ ns, ops, options: serverInfo, name })
const ctx = {
ns,
ops,
options: serverInfo,
name
}

const promise = command.apply(ctx, args)
return startCh.runStores(ctx, () => {
const promise = command.apply(mongoCtx, args)

return promise.then(function (res) {
finishCh.publish()
return res
ctx.result = res
return finishCh.runStores(ctx, () => {
return res
})
}, function (err) {
errorCh.publish(err)
finishCh.publish()
ctx.error = err
errorCh.publish(ctx)
finishCh.publish(ctx)

throw err
})
Expand Down
22 changes: 9 additions & 13 deletions packages/datadog-instrumentations/src/mongodb.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ require('./mongodb-core')

const {
channel,
addHook,
AsyncResource
addHook
} = require('./helpers/instrument')
const shimmer = require('../../datadog-shimmer')

Expand Down Expand Up @@ -41,19 +40,16 @@ addHook({ name: 'mongodb', versions: ['>=3.3 <5', '5', '>=6'] }, mongodb => {
return method.apply(this, arguments)
}

const asyncResource = new AsyncResource('bound-anonymous-fn')

return asyncResource.runInAsyncScope(() => {
const filters = [arguments[0]]
if (useTwoArguments) {
filters.push(arguments[1])
}
const ctx = {
filters: [arguments[0]],
methodName
}

startCh.publish({
filters,
methodName
})
if (useTwoArguments) {
ctx.filters.push(arguments[1])
}

return startCh.runStores(ctx, () => {
return method.apply(this, arguments)
})
}
Expand Down
8 changes: 6 additions & 2 deletions packages/datadog-plugin-mongodb-core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class MongodbCorePlugin extends DatabasePlugin {
)
}

start ({ ns, ops, options = {}, name }) {
bindStart (ctx) {
const { ns, ops, options = {}, name } = ctx

// heartbeat commands can be disabled if this.config.heartbeatEnabled is false
if (!this.config.heartbeatEnabled && isHeartbeat(ops, this.config)) {
return
Expand All @@ -44,11 +46,13 @@ class MongodbCorePlugin extends DatabasePlugin {
'out.host': options.host,
'out.port': options.port
}
})
}, ctx)
const comment = this.injectDbmComment(span, ops.comment, service)
if (comment) {
ops.comment = comment
}

return ctx.currentStore
}

getPeerService (tags) {
Expand Down
Loading