Files
backend/src/common/logging/structured-logger.service.ts
T
codex-bot 966a1f793a
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 9s
Backend verify / verify (push) Failing after 5m39s
feat: log unhandled errors and pretty dev output (WealthLedger/backend#120) (#126)
feat: log unhandled errors and pretty dev output (#120)
2026-10-24 15:06:34 +03:00

71 lines
1.6 KiB
TypeScript

import { Injectable, OnApplicationShutdown } from '@nestjs/common';
import { PinoLogger } from 'nestjs-pino';
type LogLevel = 'debug' | 'error' | 'info' | 'warn';
type LogContext = Record<string, boolean | number | string | undefined>;
const allowedFields = new Set([
'asOf',
'attempts',
'brokerageAccountId',
'channelState',
'clientRequestId',
'code',
'count',
'durationMs',
'environment',
'errorName',
'errorStack',
'found',
'grpcCode',
'headersReceived',
'invalidFields',
'method',
'networkMs',
'operation',
'queueWaitMs',
'requestId',
'route',
'service',
'status',
'trackingId',
'userId',
]);
@Injectable()
export class StructuredLogger implements OnApplicationShutdown {
constructor(private readonly pino: PinoLogger) {}
info(message: string, context?: LogContext): void {
this.write('info', message, context);
}
event(level: LogLevel, message: string, context?: LogContext): void {
this.write(level, message, context);
}
onApplicationShutdown(): void {
this.info('application.stopped');
}
private write(
level: LogLevel,
message: string,
context: LogContext = {},
): void {
// eslint-disable-next-line security/detect-object-injection -- The log level is restricted to the internal LogLevel union.
this.pino[level](
this.safeContext(context),
message,
);
}
private safeContext(context: LogContext): LogContext {
return Object.fromEntries(
Object.entries(context).filter(
([key, value]) => allowedFields.has(key) && value !== undefined,
),
);
}
}