import pino, { Logger as PinoLogger } from 'pino'; import type { LoggerService } from './logger-service'; import { config } from '../../config'; export class PinoLoggerService implements LoggerService { private readonly logger: PinoLogger; constructor(name?: string, parent?: PinoLogger) { if (parent) { this.logger = parent.child({ name }); } else { // In Next.js, especially in the Edge runtime or during instrumentation, // pino transports (which use worker threads) can cause issues. // We disable transport in production and during instrumentation. const useTransport = config.isDevelopment && typeof window === 'undefined'; this.logger = pino({ name: name || 'app', level: config.logging.level, transport: useTransport ? { target: 'pino-pretty', options: { colorize: true, }, } : undefined, }); } } trace(msg: string, ...args: any[]) { // @ts-expect-error - pino types can be strict this.logger.trace(msg, ...args); } debug(msg: string, ...args: any[]) { // @ts-expect-error - pino types can be strict this.logger.debug(msg, ...args); } info(msg: string, ...args: any[]) { // @ts-expect-error - pino types can be strict this.logger.info(msg, ...args); } warn(msg: string, ...args: any[]) { // @ts-expect-error - pino types can be strict this.logger.warn(msg, ...args); } error(msg: string, ...args: any[]) { // @ts-expect-error - pino types can be strict this.logger.error(msg, ...args); } fatal(msg: string, ...args: any[]) { // @ts-expect-error - pino types can be strict this.logger.fatal(msg, ...args); } child(bindings: Record): LoggerService { const childPino = this.logger.child(bindings); const service = new PinoLoggerService(); // @ts-expect-error - accessing private member for child creation service.logger = childPino; return service; } }