Files
vendoo/lib/structured-logger.mjs
T
Masterluke77andGitHub 6f48827f4d Vendoo 1.41.2 – Git Ignore Boundary & Module Tracking Hotfix (#18)
* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix

* fix: track native source modules with root-anchored runtime ignores
2026-07-09 17:09:00 +02:00

49 lines
2.4 KiB
JavaScript

import { randomUUID } from 'node:crypto';
const startedAt = new Date().toISOString();
const telemetry = {
total: 0, active: 0, errors: 0, blocked: 0,
by_status: {}, by_method: {}, last_error_at: null, last_blocked_at: null,
recent: [],
};
function safePath(req) { return String(req.path || req.url || '').split('?')[0].slice(0, 300); }
function enabled() { return !/^(0|false|no)$/i.test(String(process.env.VENDOO_JSON_LOGS || 'true')); }
export function recordSecurityBlock(reason) {
telemetry.blocked += 1;
telemetry.last_blocked_at = new Date().toISOString();
if (enabled()) console.warn(JSON.stringify({ level: 'warn', event: 'security.blocked', reason, time: telemetry.last_blocked_at }));
}
export function requestContextMiddleware(req, res, next) {
const requestId = String(req.get('x-vendoo-request-id') || randomUUID()).replace(/[^a-zA-Z0-9._:-]/g, '').slice(0, 100) || randomUUID();
const correlationId = String(req.get('x-correlation-id') || requestId).replace(/[^a-zA-Z0-9._:-]/g, '').slice(0, 100) || requestId;
const started = process.hrtime.bigint();
req.requestId = requestId;
req.correlationId = correlationId;
res.setHeader('X-Vendoo-Request-ID', requestId);
res.setHeader('X-Correlation-ID', correlationId);
telemetry.total += 1; telemetry.active += 1;
telemetry.by_method[req.method] = (telemetry.by_method[req.method] || 0) + 1;
res.on('finish', () => {
telemetry.active = Math.max(0, telemetry.active - 1);
const durationMs = Number(process.hrtime.bigint() - started) / 1e6;
const status = String(res.statusCode);
telemetry.by_status[status] = (telemetry.by_status[status] || 0) + 1;
if (res.statusCode >= 500) { telemetry.errors += 1; telemetry.last_error_at = new Date().toISOString(); }
const entry = {
time: new Date().toISOString(), request_id: requestId, correlation_id: correlationId,
method: req.method, path: safePath(req), status: res.statusCode,
duration_ms: Math.round(durationMs * 10) / 10, user_id: req.user?.id || null,
};
telemetry.recent.unshift(entry); telemetry.recent = telemetry.recent.slice(0, 50);
if (enabled()) console.log(JSON.stringify({ level: res.statusCode >= 500 ? 'error' : 'info', event: 'http.request', ...entry }));
});
next();
}
export function getRequestTelemetry() {
return { started_at: startedAt, ...telemetry, recent: telemetry.recent.map(item => ({ ...item })) };
}