Skip to content

Commit e48bd75

Browse files
committed
feat(be): request logger middleware
1 parent 1db7a21 commit e48bd75

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

apps/backend/src/app.module.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { ApolloDriver, type ApolloDriverConfig } from "@nestjs/apollo";
22
import { CacheModule } from "@nestjs/cache-manager";
3-
import { Module } from "@nestjs/common";
3+
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
44
import { ConfigModule } from "@nestjs/config";
55
import { GraphQLModule } from "@nestjs/graphql";
66
import { ScheduleModule } from "@nestjs/schedule";
77

88
import { cacheModuleConfig } from "src/config/cache-module.config";
99
import { configModuleConfig } from "src/config/config-module.config";
1010
import { GRAPHQL_PATH } from "src/constants/api";
11+
import { RequestLoggerMiddleware } from "src/middleware/request-logger-middleware";
1112
import { DepartureModule } from "src/modules/departure/departure.module";
1213
import { ImportModule } from "src/modules/import/import.module";
1314
import { LoggerModule } from "src/modules/logger/logger.module";
@@ -38,4 +39,8 @@ import { StopModule } from "src/modules/stop/stop.module";
3839
controllers: [],
3940
providers: [],
4041
})
41-
export class AppModule {}
42+
export class AppModule implements NestModule {
43+
configure(consumer: MiddlewareConsumer) {
44+
consumer.apply(RequestLoggerMiddleware).forRoutes("*");
45+
}
46+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Injectable, NestMiddleware } from "@nestjs/common";
2+
import { NextFunction, Request, Response } from "express";
3+
4+
import { PrismaService } from "src/modules/prisma/prisma.service";
5+
6+
@Injectable()
7+
export class RequestLoggerMiddleware implements NestMiddleware {
8+
constructor(private readonly prisma: PrismaService) {}
9+
10+
async use(req: Request, res: Response, next: NextFunction) {
11+
const start = Date.now();
12+
13+
// Intercept the response to capture the body
14+
const originalSend = res.send;
15+
let responseBody: unknown;
16+
17+
res.send = (body): Response => {
18+
responseBody = body; // Capture the response body
19+
return originalSend.call(res, body); // Call the original `send` method
20+
};
21+
22+
// Attach an event listener to log after the response is sent
23+
res.on("finish", async () => {
24+
const duration = Date.now() - start;
25+
const {
26+
method,
27+
url: path,
28+
headers: { "user-agent": userAgent = null },
29+
} = req;
30+
const { statusCode } = res;
31+
const responseString =
32+
typeof responseBody === "string"
33+
? responseBody
34+
: JSON.stringify(responseBody);
35+
36+
const ignoreResponse = [
37+
"/v1/stop/all",
38+
"/v1/platform/",
39+
"/status",
40+
].some((item) => path.startsWith(item));
41+
42+
try {
43+
// Log the request details to the database
44+
await this.prisma.requestLog.create({
45+
data: {
46+
method,
47+
path,
48+
status: statusCode,
49+
duration,
50+
userAgent,
51+
response: ignoreResponse ? null : responseString,
52+
},
53+
});
54+
} catch (error) {
55+
console.error("Failed to log request:", error);
56+
}
57+
});
58+
59+
next();
60+
}
61+
}

0 commit comments

Comments
 (0)