diff --git a/yarn-project/foundation/src/log/pino-logger.ts b/yarn-project/foundation/src/log/pino-logger.ts index a4ed349522bb..2cbaddb83d61 100644 --- a/yarn-project/foundation/src/log/pino-logger.ts +++ b/yarn-project/foundation/src/log/pino-logger.ts @@ -1,6 +1,7 @@ import { createColors } from 'colorette'; import isNode from 'detect-node'; -import { type LoggerOptions, pino } from 'pino'; +import { pino } from 'pino'; +import pretty from 'pino-pretty'; import { inspect } from 'util'; import { compactArray } from '../collection/array.js'; @@ -67,24 +68,25 @@ function isLevelEnabled(logger: pino.Logger<'verbose', boolean>, level: LogLevel const defaultLogLevel = process.env.NODE_ENV === 'test' ? 'silent' : 'info'; const [logLevel, logFilters] = parseEnv(process.env.LOG_LEVEL, defaultLogLevel); -// Transport options for pretty logging to stdout via pino-pretty. +// Transport options for pretty logging to stderr via pino-pretty. const useColor = true; const { bold, reset } = createColors({ useColor }); -const prettyTransport: LoggerOptions['transport'] = { +const pinoPrettyOpts = { + destination: 2, + sync: true, + colorize: useColor, + ignore: 'module,pid,hostname,trace_id,span_id,trace_flags', + messageFormat: `${bold('{module}')} ${reset('{msg}')}`, + customLevels: 'fatal:60,error:50,warn:40,info:30,verbose:25,debug:20,trace:10', + customColors: 'fatal:bgRed,error:red,warn:yellow,info:green,verbose:magenta,debug:blue,trace:gray', +}; +const prettyTransport: pino.TransportSingleOptions = { target: 'pino-pretty', - options: { - destination: 2, - sync: true, - colorize: useColor, - ignore: 'module,pid,hostname,trace_id,span_id,trace_flags', - messageFormat: `${bold('{module}')} ${reset('{msg}')}`, - customLevels: 'fatal:60,error:50,warn:40,info:30,verbose:25,debug:20,trace:10', - customColors: 'fatal:bgRed,error:red,warn:yellow,info:green,verbose:magenta,debug:blue,trace:gray', - }, + options: pinoPrettyOpts, }; // Transport for vanilla stdio logging as JSON. -const stdioTransport: LoggerOptions['transport'] = { +const stdioTransport: pino.TransportSingleOptions = { target: 'pino/file', options: { destination: 2 }, }; @@ -103,27 +105,31 @@ const levels = { // would mean that all child loggers created before the telemetry-client is initialized would not have // this transport configured. Note that the target is defined as the export in the telemetry-client, // since pino will load this transport separately on a worker thread, to minimize disruption to the main loop. - -const otelTransport: LoggerOptions['transport'] = { +const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT; +const otelTransport: pino.TransportSingleOptions = { target: '@aztec/telemetry-client/otel-pino-stream', options: { levels, messageKey: 'msg' }, }; -// In nodejs, create a new pino instance with an stdout transport (either vanilla or json), and optionally -// an OTLP transport if the OTLP endpoint is provided. Note that transports are initialized in a worker thread. -// On the browser, we just log to the console. -const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT; -const logger = isNode - ? pino( - pinoOpts, - pino.transport({ - targets: compactArray([ - ['1', 'true', 'TRUE'].includes(process.env.LOG_JSON ?? '') ? stdioTransport : prettyTransport, - process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT ? otelTransport : undefined, - ]), - }), - ) - : pino({ ...pinoOpts, browser: { asObject: false } }); +function makeLogger() { + if (!isNode) { + // We are on the browser + return pino({ ...pinoOpts, browser: { asObject: false } }); + } else if (process.env.JEST_WORKER_ID) { + // We are on jest, we need sync logging + return pino(pinoOpts, pretty({ ...pinoPrettyOpts })); + } else { + // Regular nodejs with transports on worker thread, using pino-pretty for console logging if LOG_JSON + // is not set, and an optional OTLP transport if the OTLP endpoint is provided. + const targets: pino.TransportSingleOptions[] = compactArray([ + ['1', 'true', 'TRUE'].includes(process.env.LOG_JSON ?? '') ? stdioTransport : prettyTransport, + otlpEndpoint ? otelTransport : undefined, + ]); + return pino(pinoOpts, pino.transport({ targets })); + } +} + +const logger = makeLogger(); // Log the logger configuration. logger.verbose(