diff --git a/Dockerfile_ui b/Dockerfile_ui index 7d3167a5a..215757560 100644 --- a/Dockerfile_ui +++ b/Dockerfile_ui @@ -22,12 +22,14 @@ RUN --mount=type=cache,target=/root/.npm \ ########### Runtime: minimal production image ########### FROM node:22-alpine AS runner +ARG COMMIT_SHA WORKDIR /app # Set env before install so some libs can optimize for production ENV NODE_ENV=production ENV PORT=3030 ENV HOST=0.0.0.0 +ENV COMMIT_SHA=${COMMIT_SHA} # Install only production deps COPY ui/package.json ui/package-lock.json ./ diff --git a/ui/request-logging.js b/ui/request-logging.js index 192ce9565..6ffc807c4 100644 --- a/ui/request-logging.js +++ b/ui/request-logging.js @@ -61,7 +61,7 @@ export function logRequestInit(method, path, requestId, userId, orgId) { })); } -export function logResponse(method, path, requestId, latency, statusCode) { +export function logResponse(method, path, requestId, latency, statusCode, commitSha) { console.log(JSON.stringify({ event: 'response_sent', method, @@ -69,6 +69,7 @@ export function logResponse(method, path, requestId, latency, statusCode) { requestId, latency, statusCode, + commitSha: commitSha || 'unknown', })); } diff --git a/ui/server-start.js b/ui/server-start.js index 197a281d2..593a09d27 100644 --- a/ui/server-start.js +++ b/ui/server-start.js @@ -15,6 +15,7 @@ const __dirname = fileURLToPath(new URL('.', import.meta.url)); const PORT = process.env.PORT || 3030; const HOST = process.env.HOST || '0.0.0.0'; const REQUEST_TIMEOUT = 60 * 1000; // 60s timeout for requests +const COMMIT_SHA = process.env.COMMIT_SHA || 'unknown'; // Configure global fetch with connection pooling for much better performance // Without this, every fetch creates a new TCP connection (DNS + handshake overhead) @@ -110,7 +111,7 @@ const server = createServer(async (req, res) => { // Set request timeout req.setTimeout(REQUEST_TIMEOUT, () => { - console.error(`⏱️ Request timeout (${REQUEST_TIMEOUT}ms): ${req.method} ${req.url} [${requestId}]`); + console.error(`⏱️ Request timeout (${REQUEST_TIMEOUT}ms): ${req.method} ${req.url} [${requestId}] [commitSha: ${COMMIT_SHA}]`); if (!res.headersSent) { res.writeHead(408, { 'Content-Type': 'text/plain' }); res.end('Request Timeout'); @@ -140,7 +141,7 @@ const server = createServer(async (req, res) => { // Log response for static files try { const latency = Date.now() - requestStart; - logResponse(method, pathname, requestId, latency, 200); + logResponse(method, pathname, requestId, latency, 200, COMMIT_SHA); } catch (err) { console.error(`Response logging error [${requestId}]:`, err); } @@ -177,9 +178,9 @@ const server = createServer(async (req, res) => { // Log slow SSR requests if (ssrTime > 2000) { - console.debug(`🔥 VERY SLOW SSR: ${req.method} ${pathname} took ${ssrTime}ms [${requestId}]`); + console.debug(`🔥 VERY SLOW SSR: ${req.method} ${pathname} took ${ssrTime}ms [${requestId}] [commitSha: ${COMMIT_SHA}]`); } else if (ssrTime > 1000) { - console.debug(`⚠️ SLOW SSR: ${req.method} ${pathname} took ${ssrTime}ms [${requestId}]`); + console.debug(`⚠️ SLOW SSR: ${req.method} ${pathname} took ${ssrTime}ms [${requestId}] [commitSha: ${COMMIT_SHA}]`); } // Convert Web Standard Response to Node.js response @@ -270,7 +271,7 @@ const server = createServer(async (req, res) => { // Log response after sending try { const latency = Date.now() - requestStart; - logResponse(method, pathname, requestId, latency, res.statusCode); + logResponse(method, pathname, requestId, latency, res.statusCode, COMMIT_SHA); } catch (err) { console.error(`Response logging error [${requestId}]:`, err); } @@ -284,7 +285,7 @@ const server = createServer(async (req, res) => { // Log error response try { const latency = Date.now() - requestStart; - logResponse(method, pathname, requestId, latency, res.statusCode || 500); + logResponse(method, pathname, requestId, latency, res.statusCode || 500, COMMIT_SHA); } catch (err) { console.error(`Error response logging error [${requestId}]:`, err); }