Skip to content

Commit

Permalink
Express 5 Instrumentation (#4913)
Browse files Browse the repository at this point in the history
Co-authored-by: William Conti <william.conti@datadoghq.com>
Co-authored-by: simon-id <simon.id@datadoghq.com>
  • Loading branch information
3 people authored Dec 10, 2024
1 parent 4e9b1ff commit b04ced4
Show file tree
Hide file tree
Showing 21 changed files with 397 additions and 171 deletions.
42 changes: 38 additions & 4 deletions packages/datadog-instrumentations/src/express.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ function wrapResponseRender (render) {

addHook({ name: 'express', versions: ['>=4'] }, express => {
shimmer.wrap(express.application, 'handle', wrapHandle)
shimmer.wrap(express.Router, 'use', wrapRouterMethod)
shimmer.wrap(express.Router, 'route', wrapRouterMethod)

shimmer.wrap(express.response, 'json', wrapResponseJson)
shimmer.wrap(express.response, 'jsonp', wrapResponseJson)
Expand All @@ -69,6 +67,20 @@ addHook({ name: 'express', versions: ['>=4'] }, express => {
return express
})

addHook({ name: 'express', versions: ['4'] }, express => {
shimmer.wrap(express.Router, 'use', wrapRouterMethod)
shimmer.wrap(express.Router, 'route', wrapRouterMethod)

return express
})

addHook({ name: 'express', versions: ['>=5.0.0'] }, express => {
shimmer.wrap(express.Router.prototype, 'use', wrapRouterMethod)
shimmer.wrap(express.Router.prototype, 'route', wrapRouterMethod)

return express
})

const queryParserReadCh = channel('datadog:query:read:finish')

function publishQueryParsedAndNext (req, res, next) {
Expand All @@ -88,7 +100,7 @@ function publishQueryParsedAndNext (req, res, next) {

addHook({
name: 'express',
versions: ['>=4'],
versions: ['4'],
file: 'lib/middleware/query.js'
}, query => {
return shimmer.wrapFunction(query, query => function () {
Expand Down Expand Up @@ -129,7 +141,29 @@ addHook({ name: 'express', versions: ['>=4.0.0 <4.3.0'] }, express => {
return express
})

addHook({ name: 'express', versions: ['>=4.3.0'] }, express => {
addHook({ name: 'express', versions: ['>=4.3.0 <5.0.0'] }, express => {
shimmer.wrap(express.Router, 'process_params', wrapProcessParamsMethod(2))
return express
})

const queryReadCh = channel('datadog:express:query:finish')

addHook({ name: 'express', file: ['lib/request.js'], versions: ['>=5.0.0'] }, request => {
const requestDescriptor = Object.getOwnPropertyDescriptor(request, 'query')

shimmer.wrap(requestDescriptor, 'get', function (originalGet) {
return function wrappedGet () {
const query = originalGet.apply(this, arguments)

if (queryReadCh.hasSubscribers && query) {
queryReadCh.publish({ query })
}

return query
}
})

Object.defineProperty(request, 'query', requestDescriptor)

return request
})
1 change: 0 additions & 1 deletion packages/datadog-instrumentations/src/helpers/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ module.exports = {
protobufjs: () => require('../protobufjs'),
pug: () => require('../pug'),
q: () => require('../q'),
qs: () => require('../qs'),
redis: () => require('../redis'),
restify: () => require('../restify'),
rhea: () => require('../rhea'),
Expand Down
24 changes: 0 additions & 24 deletions packages/datadog-instrumentations/src/qs.js

This file was deleted.

98 changes: 97 additions & 1 deletion packages/datadog-instrumentations/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,107 @@ function createWrapRouterMethod (name) {

const wrapRouterMethod = createWrapRouterMethod('router')

addHook({ name: 'router', versions: ['>=1'] }, Router => {
addHook({ name: 'router', versions: ['>=1 <2'] }, Router => {
shimmer.wrap(Router.prototype, 'use', wrapRouterMethod)
shimmer.wrap(Router.prototype, 'route', wrapRouterMethod)

return Router
})

const queryParserReadCh = channel('datadog:query:read:finish')

addHook({ name: 'router', versions: ['>=2'] }, Router => {
const WrappedRouter = shimmer.wrapFunction(Router, function (originalRouter) {
return function wrappedMethod () {
const router = originalRouter.apply(this, arguments)

shimmer.wrap(router, 'handle', function wrapHandle (originalHandle) {
return function wrappedHandle (req, res, next) {
const abortController = new AbortController()

if (queryParserReadCh.hasSubscribers && req) {
queryParserReadCh.publish({ req, res, query: req.query, abortController })

if (abortController.signal.aborted) return
}

return originalHandle.apply(this, arguments)
}
})

return router
}
})

shimmer.wrap(WrappedRouter.prototype, 'use', wrapRouterMethod)
shimmer.wrap(WrappedRouter.prototype, 'route', wrapRouterMethod)

return WrappedRouter
})

const routerParamStartCh = channel('datadog:router:param:start')
const visitedParams = new WeakSet()

function wrapHandleRequest (original) {
return function wrappedHandleRequest (req, res, next) {
if (routerParamStartCh.hasSubscribers && Object.keys(req.params).length && !visitedParams.has(req.params)) {
visitedParams.add(req.params)

const abortController = new AbortController()

routerParamStartCh.publish({
req,
res,
params: req?.params,
abortController
})

if (abortController.signal.aborted) return
}

return original.apply(this, arguments)
}
}

addHook({
name: 'router', file: 'lib/layer.js', versions: ['>=2']
}, Layer => {
shimmer.wrap(Layer.prototype, 'handleRequest', wrapHandleRequest)
return Layer
})

function wrapParam (original) {
return function wrappedProcessParams () {
arguments[1] = shimmer.wrapFunction(arguments[1], (originalFn) => {
return function wrappedFn (req, res) {
if (routerParamStartCh.hasSubscribers && Object.keys(req.params).length && !visitedParams.has(req.params)) {
visitedParams.add(req.params)

const abortController = new AbortController()

routerParamStartCh.publish({
req,
res,
params: req?.params,
abortController
})

if (abortController.signal.aborted) return
}

return originalFn.apply(this, arguments)
}
})

return original.apply(this, arguments)
}
}

addHook({
name: 'router', versions: ['>=2']
}, router => {
shimmer.wrap(router.prototype, 'param', wrapParam)
return router
})

module.exports = { createWrapRouterMethod }
2 changes: 1 addition & 1 deletion packages/datadog-instrumentations/test/express.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ withVersions('express', 'express', version => {
})

before((done) => {
const express = require('../../../versions/express').get()
const express = require(`../../../versions/express@${version}`).get()
const app = express()
app.get('/', (req, res) => {
requestBody()
Expand Down
Loading

0 comments on commit b04ced4

Please sign in to comment.