Skip to content

Commit 59c8ea4

Browse files
authored
[core] Ensure Explicit Timeouts from Underlying Request Socket are Recorded as Errors When Using Node 20 (#3853)
* req.socket timeouts recorded as errors node 20 * check for process.send
1 parent 9c71b30 commit 59c8ea4

File tree

5 files changed

+54
-5
lines changed

5 files changed

+54
-5
lines changed

packages/datadog-instrumentations/src/http/client.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,29 @@ function patch (http, methodName) {
6969
try {
7070
const req = request.call(this, options, callback)
7171
const emit = req.emit
72-
const setTimeout = req.setTimeout
72+
73+
const requestSetTimeout = req.setTimeout
7374

7475
ctx.req = req
7576

7677
// tracked to accurately discern custom request socket timeout
7778
let customRequestTimeout = false
79+
7880
req.setTimeout = function () {
7981
customRequestTimeout = true
80-
return setTimeout.apply(this, arguments)
82+
return requestSetTimeout.apply(this, arguments)
8183
}
8284

85+
req.on('socket', socket => {
86+
if (socket) {
87+
const socketSetTimeout = socket.setTimeout
88+
socket.setTimeout = function () {
89+
customRequestTimeout = true
90+
return socketSetTimeout.apply(this, arguments)
91+
}
92+
}
93+
})
94+
8395
req.emit = function (eventName, arg) {
8496
switch (eventName) {
8597
case 'response': {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class HttpClientPlugin extends ClientPlugin {
121121
} else {
122122
// conditions for no error:
123123
// 1. not using a custom agent instance with custom timeout specified
124-
// 2. no invocation of `req.setTimeout`
124+
// 2. no invocation of `req.setTimeout` or `socket.setTimeout`
125125
if (!args.options.agent?.options.timeout && !customRequestTimeout) return
126126

127127
span.setTag('error', 1)

packages/datadog-plugin-http/test/client.spec.js

+33
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,39 @@ describe('Plugin', () => {
900900
})
901901
})
902902
}).timeout(10000)
903+
904+
it('should record error if req.socket.setTimeout is used with Node 20', done => {
905+
const app = express()
906+
907+
app.get('/user', async (req, res) => {
908+
await new Promise(resolve => {
909+
setTimeout(resolve, 6 * 1000)
910+
})
911+
res.status(200).send()
912+
})
913+
914+
getPort().then(port => {
915+
agent
916+
.use(traces => {
917+
expect(traces[0][0]).to.have.property('error', 1)
918+
})
919+
.then(done)
920+
.catch(done)
921+
922+
appListener = server(app, port, async () => {
923+
const req = http.request(`${protocol}://localhost:${port}/user`, res => {
924+
res.on('data', () => { })
925+
})
926+
927+
req.on('error', () => {})
928+
req.on('socket', socket => {
929+
socket.setTimeout(5000)// match default timeout
930+
})
931+
932+
req.end()
933+
})
934+
})
935+
}).timeout(10000)
903936
}
904937

905938
it('should only record a request once', done => {

packages/datadog-plugin-http/test/integration-test/server.mjs

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ const server = http.createServer(async (req, res) => {
1010
}
1111
}).listen(0, () => {
1212
const port = server.address().port
13-
process.send({ port })
13+
if (process.send) {
14+
process.send({ port })
15+
}
1416
})

packages/datadog-plugin-http2/test/integration-test/server.mjs

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ const server = http2.createServer((req, res) => {
77

88
server.listen(0, () => {
99
const port = server.address().port
10-
process.send({ port })
10+
if (process.send) {
11+
process.send({ port })
12+
}
1113
})

0 commit comments

Comments
 (0)