fase(23): observability and health probes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
debian
2026-03-08 06:10:24 -04:00
parent ddb4f66036
commit 629eafecd8
5 changed files with 34 additions and 15 deletions

View File

@@ -49,17 +49,27 @@ export class RateLimitError extends AppError {
}
}
type ExtendedReq = Request & {
log?: {
warn(obj: Record<string, unknown>, msg: string): void;
error(obj: Record<string, unknown>, msg: string): void;
};
user?: { id: string; email: string; role: string };
};
export function globalErrorHandler(
err: Error,
req: Request,
res: Response,
_next: NextFunction,
): void {
const logger = (req as Request & { log?: { warn: Function; error: Function } }).log;
const authReq = req as ExtendedReq;
const logger = authReq.log;
const userId = authReq.user?.id;
if (err instanceof AppError && err.isOperational) {
if (logger) {
logger.warn({ err, statusCode: err.statusCode }, err.message);
logger.warn({ err, statusCode: err.statusCode, userId }, err.message);
}
const body: Record<string, unknown> = { error: err.message, code: err.code };
if (err instanceof ValidationError && err.details !== undefined) {
@@ -70,7 +80,7 @@ export function globalErrorHandler(
}
if (logger) {
logger.error({ err }, 'Unhandled error');
logger.error({ err, userId }, 'Unhandled error');
} else {
console.error('Unhandled error', err);
}

View File

@@ -93,6 +93,9 @@ import { createServer } from './api/server';
import { SocketGateway } from './realtime/SocketGateway';
async function bootstrap(): Promise<void> {
// Startup probe — measure total boot time
const startupAt = Date.now();
// 1. Config
const config = loadConfig();
@@ -247,7 +250,8 @@ async function bootstrap(): Promise<void> {
await new Promise<void>((resolve) => {
httpServer.listen(config.port, config.host, resolve);
});
logger.info({ port: config.port, host: config.host }, 'ABE server ready');
const startupMs = Date.now() - startupAt;
logger.info({ port: config.port, host: config.host, startupMs }, 'ABE server ready');
// 14. Graceful shutdown
let shuttingDown = false;