fase(23): observability and health probes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user