dd-trace
Version:
Datadog APM tracing client for JavaScript
174 lines (142 loc) • 4.6 kB
JavaScript
const {
channel,
addHook,
AsyncResource
} = require('./helpers/instrument')
const shimmer = require('../../datadog-shimmer')
const requestStartCh = channel('apm:google-cloud-pubsub:request:start')
const requestFinishCh = channel('apm:google-cloud-pubsub:request:finish')
const requestErrorCh = channel('apm:google-cloud-pubsub:request:error')
const receiveStartCh = channel('apm:google-cloud-pubsub:receive:start')
const receiveFinishCh = channel('apm:google-cloud-pubsub:receive:finish')
const receiveErrorCh = channel('apm:google-cloud-pubsub:receive:error')
const publisherMethods = [
'createTopic',
'updateTopic',
'publish',
'getTopic',
'listTopics',
'listTopicSubscriptions',
'listTopicSnapshots',
'deleteTopic',
'detachSubscription'
]
const schemaServiceMethods = [
'createSchema',
'getSchema',
'listSchemas',
'listSchemaRevisions',
'commitSchema',
'rollbackSchema',
'deleteSchemaRevision',
'deleteSchema',
'validateSchema',
'validateMessage'
]
const subscriberMethods = [
'createSubscription',
'getSubscription',
'updateSubscription',
'listSubscriptions',
'deleteSubscription',
'modifyAckDeadline',
'acknowledge',
'pull',
'streamingPull',
'modifyPushConfig',
'getSnapshot',
'listSnapshots',
'createSnapshot',
'updateSnapshot',
'deleteSnapshot',
'seek'
]
function wrapMethod (method) {
const api = method.name
return function (request) {
if (!requestStartCh.hasSubscribers) return method.apply(this, arguments)
const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
return innerAsyncResource.runInAsyncScope(() => {
const projectId = this.auth._cachedProjectId
const cb = arguments[arguments.length - 1]
requestStartCh.publish({ request, api, projectId })
if (typeof cb === 'function') {
const outerAsyncResource = new AsyncResource('bound-anonymous-fn')
arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => innerAsyncResource.bind(function (error) {
if (error) {
requestErrorCh.publish(error)
}
requestFinishCh.publish()
return outerAsyncResource.runInAsyncScope(() => cb.apply(this, arguments))
}))
return method.apply(this, arguments)
} else {
return method.apply(this, arguments)
.then(
response => {
requestFinishCh.publish()
return response
},
error => {
requestErrorCh.publish(error)
requestFinishCh.publish()
throw error
}
)
}
})
}
}
function massWrap (obj, methods, wrapper) {
for (const method of methods) {
if (typeof obj[method] === 'function') {
shimmer.wrap(obj, method, wrapper)
}
}
}
addHook({ name: '@google-cloud/pubsub', versions: ['>=1.2'] }, (obj) => {
const Subscription = obj.Subscription
shimmer.wrap(Subscription.prototype, 'emit', emit => function (eventName, message) {
if (eventName !== 'message' || !message) return emit.apply(this, arguments)
const asyncResource = new AsyncResource('bound-anonymous-fn')
return asyncResource.runInAsyncScope(() => {
try {
return emit.apply(this, arguments)
} catch (err) {
receiveErrorCh.publish(err)
throw err
}
})
})
return obj
})
addHook({ name: '@google-cloud/pubsub', versions: ['>=1.2'], file: 'build/src/lease-manager.js' }, (obj) => {
const LeaseManager = obj.LeaseManager
shimmer.wrap(LeaseManager.prototype, '_dispense', dispense => function (message) {
if (receiveStartCh.hasSubscribers) {
receiveStartCh.publish({ message })
}
return dispense.apply(this, arguments)
})
shimmer.wrap(LeaseManager.prototype, 'remove', remove => function (message) {
receiveFinishCh.publish({ message })
return remove.apply(this, arguments)
})
shimmer.wrap(LeaseManager.prototype, 'clear', clear => function () {
for (const message of this._messages) {
receiveFinishCh.publish({ message })
}
return clear.apply(this, arguments)
})
return obj
})
addHook({ name: '@google-cloud/pubsub', versions: ['>=1.2'] }, (obj) => {
const { PublisherClient, SchemaServiceClient, SubscriberClient } = obj.v1
massWrap(PublisherClient.prototype, publisherMethods, wrapMethod)
massWrap(SubscriberClient.prototype, subscriberMethods, wrapMethod)
if (SchemaServiceClient) {
massWrap(SchemaServiceClient.prototype, schemaServiceMethods, wrapMethod)
}
return obj
})