dd-trace
Version:
Datadog APM tracing client for JavaScript
95 lines (78 loc) • 2.55 kB
JavaScript
const { channel, addHook, AsyncResource } = require('./helpers/instrument')
const shimmer = require('../../datadog-shimmer')
const rrtypes = {
resolveAny: 'ANY',
resolve4: 'A',
resolve6: 'AAAA',
resolveCname: 'CNAME',
resolveMx: 'MX',
resolveNs: 'NS',
resolveTxt: 'TXT',
resolveSrv: 'SRV',
resolvePtr: 'PTR',
resolveNaptr: 'NAPTR',
resolveSoa: 'SOA'
}
const rrtypeMap = new WeakMap()
addHook({ name: 'dns' }, dns => {
dns.lookup = wrap('apm:dns:lookup', dns.lookup, 2)
dns.lookupService = wrap('apm:dns:lookup_service', dns.lookupService, 3)
dns.resolve = wrap('apm:dns:resolve', dns.resolve, 2)
dns.reverse = wrap('apm:dns:reverse', dns.reverse, 2)
patchResolveShorthands(dns)
if (dns.Resolver) {
dns.Resolver.prototype.resolve = wrap('apm:dns:resolve', dns.Resolver.prototype.resolve, 2)
dns.Resolver.prototype.reverse = wrap('apm:dns:reverse', dns.Resolver.prototype.reverse, 2)
patchResolveShorthands(dns.Resolver.prototype)
}
return dns
})
function patchResolveShorthands (prototype) {
Object.keys(rrtypes)
.filter(method => !!prototype[method])
.forEach(method => {
rrtypeMap.set(prototype[method], rrtypes[method])
prototype[method] = wrap('apm:dns:resolve', prototype[method], 2, rrtypes[method])
})
}
function wrap (prefix, fn, expectedArgs, rrtype) {
const startCh = channel(prefix + ':start')
const endCh = channel(prefix + ':end')
const asyncEndCh = channel(prefix + ':async-end')
const errorCh = channel(prefix + ':error')
const wrapped = function () {
const cb = AsyncResource.bind(arguments[arguments.length - 1])
if (
!startCh.hasSubscribers ||
arguments.length < expectedArgs ||
typeof cb !== 'function'
) {
return fn.apply(this, arguments)
}
const startArgs = Array.from(arguments)
startArgs.pop() // gets rid of the callback
if (rrtype) {
startArgs.push(rrtype)
}
startCh.publish(startArgs)
arguments[arguments.length - 1] = function (error, result) {
if (error) {
errorCh.publish(error)
}
asyncEndCh.publish(result)
cb.apply(this, arguments)
}
try {
return fn.apply(this, arguments)
// TODO deal with promise versions when we support `dns/promises`
} catch (error) {
error.stack // trigger getting the stack at the original throwing point
errorCh.publish(error)
throw error
} finally {
endCh.publish(undefined)
}
}
return shimmer.wrap(fn, wrapped)
}