@@ -3,6 +3,7 @@ import geoip from "geoip-lite";
33import { UAParser } from "ua-parser-js" ;
44import { db } from "../db" ;
55import { requestLogs } from "@shared/schema" ;
6+ import { emitAdminRequestUpdate } from "../socket" ;
67
78// Helper to mask IP addresses for privacy when visibility is restricted
89function maskIp ( ip : string ) : string {
@@ -27,7 +28,13 @@ function maskIp(ip: string): string {
2728export function requestLogger ( req : Request , res : Response , next : NextFunction ) {
2829 const start = Date . now ( ) ;
2930
30- res . on ( "finish" , ( ) => {
31+ const originalEnd = res . end ;
32+ let logged = false ;
33+
34+ const performLog = async ( statusCode : number ) => {
35+ if ( logged ) return ;
36+ logged = true ;
37+
3138 const responseTimeMs = Date . now ( ) - start ;
3239
3340 // Get IP respecting proxy headers
@@ -78,32 +85,56 @@ export function requestLogger(req: Request, res: Response, next: NextFunction) {
7885 const userId = req . user ?. id || null ;
7986 const sessionId = req . sessionID || "" ;
8087
81- // Insert async (don't await to avoid blocking the event loop)
82- db . insert ( requestLogs ) . values ( {
83- userId,
84- sessionId,
85- method : req . method ,
86- path : req . originalUrl || req . path ,
87- statusCode : res . statusCode ,
88- responseTimeMs,
89- ipAddress : finalIpAddress ,
90- userAgent,
91- device,
92- browser,
93- os,
94- geoCountry,
95- geoRegion,
96- geoCity,
97- geoLat,
98- geoLng,
99- } ) . returning ( )
100- . then ( ( [ log ] ) => {
101- if ( log ) emitAdminRequestUpdate ( log ) ;
102- } )
103- . catch ( err => {
104- console . error ( "[RequestLogger] Failed to insert log:" , err ) ;
88+ try {
89+ const [ log ] = await db . insert ( requestLogs ) . values ( {
90+ userId,
91+ sessionId,
92+ method : req . method ,
93+ path : req . originalUrl || req . path ,
94+ statusCode,
95+ responseTimeMs,
96+ ipAddress : finalIpAddress ,
97+ userAgent,
98+ device,
99+ browser,
100+ os,
101+ geoCountry,
102+ geoRegion,
103+ geoCity,
104+ geoLat,
105+ geoLng,
106+ } ) . returning ( ) ;
107+
108+ if ( log ) emitAdminRequestUpdate ( log ) ;
109+ } catch ( err ) {
110+ console . error ( "[RequestLogger] Failed to insert log:" , err ) ;
111+ }
112+ } ;
113+
114+ // @ts -ignore
115+ res . end = function ( chunk ?: any , encodingOrCb ?: any , cb ?: any ) {
116+ let encoding : string | undefined ;
117+ let callback : ( ( ) => void ) | undefined ;
118+
119+ if ( typeof encodingOrCb === "function" ) {
120+ callback = encodingOrCb ;
121+ encoding = undefined ;
122+ } else {
123+ encoding = encodingOrCb ;
124+ callback = cb ;
125+ }
126+
127+ // Capture the status code before ending
128+ const statusCode = res . statusCode ;
129+
130+ // Run the logging before we close the stream.
131+ // This ensures Vercel doesn't kill the lambda before the DB insert completes.
132+ performLog ( statusCode )
133+ . finally ( ( ) => {
134+ // Now actually end the response
135+ originalEnd . call ( res , chunk , encoding , callback ) ;
105136 } ) ;
106- } ) ;
137+ } ;
107138
108139 next ( ) ;
109140}
0 commit comments