Skip to content

Commit 6df1607

Browse files
committed
add monitoring logs for ui
1 parent 0c0e04c commit 6df1607

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

ui/vite.config.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,116 @@ import { defineConfig, loadEnv } from 'vite';
22
import tsConfigPaths from 'vite-tsconfig-paths';
33
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
44
import viteReact from '@vitejs/plugin-react';
5+
import { unsealData } from 'iron-session';
6+
import { decodeJwt } from 'jose';
7+
import type { Plugin } from 'vite';
8+
9+
// Request logging utilities
10+
async function extractUserInfoFromRequest(req: any): Promise<{ userId: string; orgId: string }> {
11+
try {
12+
const cookieName = process.env.WORKOS_COOKIE_NAME || 'wos-session';
13+
const cookiePassword = process.env.WORKOS_COOKIE_PASSWORD;
14+
15+
if (!cookiePassword) {
16+
return { userId: 'anonymous', orgId: 'anonymous' };
17+
}
18+
19+
const cookieHeader = req.headers?.cookie || req.getHeader?.('cookie');
20+
if (!cookieHeader) {
21+
return { userId: 'anonymous', orgId: 'anonymous' };
22+
}
23+
24+
const cookies = cookieHeader.split(';').reduce((acc: Record<string, string>, cookie: string) => {
25+
const [key, value] = cookie.trim().split('=');
26+
acc[key] = decodeURIComponent(value);
27+
return acc;
28+
}, {});
29+
30+
const sessionCookie = cookies[cookieName];
31+
if (!sessionCookie) {
32+
return { userId: 'anonymous', orgId: 'anonymous' };
33+
}
34+
35+
const session = await unsealData(sessionCookie, {
36+
password: cookiePassword,
37+
}) as { user?: { id?: string }; accessToken?: string };
38+
39+
if (!session?.user?.id || !session?.accessToken) {
40+
return { userId: 'anonymous', orgId: 'anonymous' };
41+
}
42+
43+
// Decode JWT to get organization ID
44+
let orgId = 'anonymous';
45+
try {
46+
const decoded = decodeJwt<{ org_id?: string }>(session.accessToken);
47+
orgId = decoded.org_id || 'anonymous';
48+
} catch (error) {
49+
// If JWT decode fails, just use anonymous
50+
}
51+
52+
return { userId: session.user.id, orgId };
53+
} catch (error) {
54+
return { userId: 'anonymous', orgId: 'anonymous' };
55+
}
56+
}
57+
58+
function logRequestInit(method: string, path: string, requestId: string, userId: string, orgId: string) {
59+
console.log(JSON.stringify({
60+
event: 'request_initialized',
61+
method,
62+
path,
63+
requestId,
64+
userId,
65+
orgId,
66+
}));
67+
}
68+
69+
function logResponse(method: string, path: string, requestId: string, latency: number, statusCode: number) {
70+
console.log(JSON.stringify({
71+
event: 'response_sent',
72+
method,
73+
path,
74+
requestId,
75+
latency,
76+
statusCode,
77+
}));
78+
}
79+
80+
// Logging middleware plugin
81+
function requestLoggingPlugin(): Plugin {
82+
return {
83+
name: 'request-logging',
84+
configureServer(server) {
85+
server.middlewares.use(async (req, res, next) => {
86+
const existingRequestId = req.headers['x-request-id'];
87+
const requestId = Array.isArray(existingRequestId)
88+
? existingRequestId[0]
89+
: existingRequestId || `ssr-${Math.random().toString(36).slice(2, 10)}`;
90+
const requestStart = Date.now();
91+
92+
const pathname = req.url?.split('?')[0] || '/';
93+
const method = req.method || 'GET';
94+
95+
// Extract user ID and org ID and log request initialization
96+
const { userId, orgId } = await extractUserInfoFromRequest(req);
97+
logRequestInit(method, pathname, requestId, userId, orgId);
98+
99+
// Set request ID header
100+
req.headers['x-request-id'] = requestId;
101+
102+
// Capture original end function to log response
103+
const originalEnd = res.end.bind(res);
104+
res.end = function(...args: any[]) {
105+
const latency = Date.now() - requestStart;
106+
logResponse(method, pathname, requestId, latency, res.statusCode || 200);
107+
return originalEnd(...args);
108+
};
109+
110+
next();
111+
});
112+
},
113+
};
114+
}
5115

6116
export default defineConfig(({ mode }) => {
7117

@@ -25,6 +135,7 @@ export default defineConfig(({ mode }) => {
25135
tsConfigPaths({
26136
projects: ['./tsconfig.json'],
27137
}),
138+
requestLoggingPlugin(),
28139
tanstackStart(),
29140
viteReact(),
30141
// cloudflare({ viteEnvironment: { name: 'ssr' } }),

0 commit comments

Comments
 (0)