From d4d1ea9b163b4c5d8db8f386324941b90c320578 Mon Sep 17 00:00:00 2001 From: Tanuj Soni Date: Tue, 8 Oct 2024 16:25:14 +0530 Subject: [PATCH 1/3] Add requestLogger middleware --- src/config.ts | 2 ++ src/middlewares/requestLogger.ts | 15 +++++++++++++++ src/server.ts | 4 ++++ 3 files changed, 21 insertions(+) create mode 100644 src/middlewares/requestLogger.ts diff --git a/src/config.ts b/src/config.ts index e6c4b0da..d372286f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -66,6 +66,7 @@ type Config = { adaptiveRejection: boolean filterDeadNodesFromArchiver: boolean verbose: boolean + enableRequestLogger: boolean firstLineLogs: boolean verboseRequestWithRetry: boolean verboseAALG: boolean @@ -165,6 +166,7 @@ export const CONFIG: Config = { adaptiveRejection: true, filterDeadNodesFromArchiver: false, verbose: false, + enableRequestLogger: true, verboseRequestWithRetry: false, verboseAALG: false, firstLineLogs: true, // default is true and turn off for prod for perf diff --git a/src/middlewares/requestLogger.ts b/src/middlewares/requestLogger.ts new file mode 100644 index 00000000..5e8e9260 --- /dev/null +++ b/src/middlewares/requestLogger.ts @@ -0,0 +1,15 @@ +import { Request, Response, NextFunction } from 'express' +const requestLogger = (req: Request, res: Response, next: NextFunction): void => { + const originalSend = res.send + res.send = function (body) { + if (res.statusCode !== 200) { + console.log('RequestLogger:>> Request Method: ', req.method) + console.log('RequestLogger:>> Request Body: ', req.body) + console.log('RequestLogger:>> Response Status Code: ', res.statusCode) + console.log('RequestLogger:>> Response Body: ', body) + } + return originalSend.call(this, body) + } + next() +} +export default requestLogger diff --git a/src/server.ts b/src/server.ts index 2e886a33..37545c2b 100644 --- a/src/server.ts +++ b/src/server.ts @@ -35,6 +35,7 @@ import { nestedCountersInstance } from './utils/nestedCounters' import { methodWhitelist } from './middlewares/methodWhitelist' import { isDebugModeMiddlewareLow, rateLimitedDebugAuth } from './middlewares/debugMiddleware' import { isIPv4 } from 'net'; +import requestLogger from './middlewares/requestLogger' setDefaultResultOrder('ipv4first') @@ -90,6 +91,9 @@ app.set('trust proxy', false) app.use(cors({ methods: ['POST'] })) app.use(express.json()) app.use(cookieParser()) +if (config.enableRequestLogger) { + app.use(requestLogger) +} app.use(function (req, res, next) { res.setHeader('X-Content-Type-Options', 'nosniff') res.setHeader( From c92391baf04c2e48633344a428f397d7125ff7a4 Mon Sep 17 00:00:00 2001 From: Tanuj Soni Date: Tue, 8 Oct 2024 16:49:01 +0530 Subject: [PATCH 2/3] Refactor requestLogger middleware --- src/middlewares/requestLogger.ts | 36 +++++++++++++++++++++++++------- src/server.ts | 4 +--- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/middlewares/requestLogger.ts b/src/middlewares/requestLogger.ts index 5e8e9260..23b5f771 100644 --- a/src/middlewares/requestLogger.ts +++ b/src/middlewares/requestLogger.ts @@ -1,14 +1,34 @@ import { Request, Response, NextFunction } from 'express' +import { CONFIG as config } from '../config' const requestLogger = (req: Request, res: Response, next: NextFunction): void => { - const originalSend = res.send - res.send = function (body) { - if (res.statusCode !== 200) { - console.log('RequestLogger:>> Request Method: ', req.method) - console.log('RequestLogger:>> Request Body: ', req.body) - console.log('RequestLogger:>> Response Status Code: ', res.statusCode) - console.log('RequestLogger:>> Response Body: ', body) + if (config.enableRequestLogger) { + const reqTime = Date.now() + const originalSend = res.send + res.send = function (body) { + const resTime = Date.now() + const respTimeStamp = new Date(resTime).toISOString() + const senderIp = req.ip + const userAgent = req.headers['user-agent'] || 'Unknown' + + console.log( + `RequestLogger:>> Request URL: ${req.originalUrl}` + + ` Response Status Code: ${res.statusCode}` + + ` Sender IP: ${senderIp}` + + ` Request Timestamp: ${new Date(reqTime).toISOString()}` + + ` Response Timestamp: ${respTimeStamp}` + + ` Request Method: ${req.method}` + + ` Response Time: ${resTime - reqTime}ms` + + ` User Agent: ${userAgent}` + ) + + if (res.statusCode !== 200) { + console.log( + `RequestLogger:>> Request Body: ${JSON.stringify(req.body)}` + + ` Response Body: ${JSON.stringify(body)}` + ) + } + return originalSend.call(this, body) } - return originalSend.call(this, body) } next() } diff --git a/src/server.ts b/src/server.ts index 37545c2b..26242b7f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -91,9 +91,7 @@ app.set('trust proxy', false) app.use(cors({ methods: ['POST'] })) app.use(express.json()) app.use(cookieParser()) -if (config.enableRequestLogger) { - app.use(requestLogger) -} +app.use(requestLogger) app.use(function (req, res, next) { res.setHeader('X-Content-Type-Options', 'nosniff') res.setHeader( From 211c1cb8dd90797919a69b9df7dda02d1a84162d Mon Sep 17 00:00:00 2001 From: Tanuj Soni Date: Wed, 9 Oct 2024 10:20:54 +0530 Subject: [PATCH 3/3] Update requestLogger to capture res from all the res.* calls --- src/middlewares/requestLogger.ts | 81 ++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/src/middlewares/requestLogger.ts b/src/middlewares/requestLogger.ts index 23b5f771..bf2c99a1 100644 --- a/src/middlewares/requestLogger.ts +++ b/src/middlewares/requestLogger.ts @@ -1,35 +1,86 @@ import { Request, Response, NextFunction } from 'express' import { CONFIG as config } from '../config' + const requestLogger = (req: Request, res: Response, next: NextFunction): void => { if (config.enableRequestLogger) { const reqTime = Date.now() - const originalSend = res.send + const senderIp = req.ip + const userAgent = req.headers['user-agent'] || 'Unknown' + + const responseChunks: Buffer[] = [] + + const originalWrite = res.write.bind(res) + res.write = function ( + chunk: any, + encodingOrCallback?: BufferEncoding | ((error: Error | null | undefined) => void), + callback?: (error: Error | null | undefined) => void + ) { + responseChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)) + + if (typeof encodingOrCallback === 'function') { + return originalWrite(chunk, encodingOrCallback) + } else { + return originalWrite(chunk, encodingOrCallback as BufferEncoding, callback) + } + } + + const originalEnd = res.end.bind(res) + res.end = function (chunk?: any, ...args: any[]) { + const responseBody = Buffer.concat(responseChunks).toString('utf8') + res.locals.responseBody = responseBody + return originalEnd(chunk, ...args) + } + + const originalJson = res.json.bind(res) + res.json = function (body) { + res.locals.responseBody = body + return originalJson(body) + } + + const originalSend = res.send.bind(res) res.send = function (body) { + res.locals.responseBody = body + return originalSend(body) + } + + res.on('finish', () => { const resTime = Date.now() - const respTimeStamp = new Date(resTime).toISOString() - const senderIp = req.ip - const userAgent = req.headers['user-agent'] || 'Unknown' console.log( - `RequestLogger:>> Request URL: ${req.originalUrl}` + - ` Response Status Code: ${res.statusCode}` + - ` Sender IP: ${senderIp}` + - ` Request Timestamp: ${new Date(reqTime).toISOString()}` + - ` Response Timestamp: ${respTimeStamp}` + - ` Request Method: ${req.method}` + - ` Response Time: ${resTime - reqTime}ms` + + `Request URL: ${req.originalUrl} ||` + + ` Response Status Code: ${res.statusCode} ||` + + ` Sender IP: ${senderIp} ||` + + ` Request Timestamp: ${new Date(reqTime).toISOString()} ||` + + ` Response Timestamp: ${new Date(resTime).toISOString()} ||` + + ` Request Method: ${req.method} ||` + + ` Response Time: ${resTime - reqTime}ms ||` + ` User Agent: ${userAgent}` ) + const responseBody = res.locals.responseBody if (res.statusCode !== 200) { console.log( - `RequestLogger:>> Request Body: ${JSON.stringify(req.body)}` + - ` Response Body: ${JSON.stringify(body)}` + `Request Failed with ${res.statusCode} ||` + + `Request Body: ${JSON.stringify(req.body)} ||` + + ` Response Body: ${res.locals.responseBody}` ) + } else if (responseBody) { + try { + const parsedBody = JSON.parse(responseBody) + if (parsedBody && 'error' in parsedBody) { + console.log( + `RPC Request Failed with Error ||` + + ` Request Body: ${JSON.stringify(req.body)} ||` + + ` Response Body: ${res.locals.responseBody}` + ) + } + } catch (e) { + // Silently fail if parsing fails, no logging here + } } - return originalSend.call(this, body) - } + }) } next() } + export default requestLogger