diff --git a/yarn-project/foundation/package.json b/yarn-project/foundation/package.json index 97aa9dae7e41..d284594f165d 100644 --- a/yarn-project/foundation/package.json +++ b/yarn-project/foundation/package.json @@ -132,6 +132,7 @@ }, "devDependencies": { "@jest/globals": "^29.5.0", + "@libp2p/interface": "1.3.1", "@types/bn.js": "^5.1.3", "@types/debug": "^4.1.7", "@types/detect-node": "^2.0.0", diff --git a/yarn-project/foundation/src/log/index.ts b/yarn-project/foundation/src/log/index.ts index 8e61bc817825..dcc425e972c2 100644 --- a/yarn-project/foundation/src/log/index.ts +++ b/yarn-project/foundation/src/log/index.ts @@ -3,3 +3,4 @@ export * from './debug.js'; export * from './pino-logger.js'; export * from './log_history.js'; export * from './log_fn.js'; +export * from './libp2p_logger.js'; diff --git a/yarn-project/foundation/src/log/libp2p_logger.ts b/yarn-project/foundation/src/log/libp2p_logger.ts new file mode 100644 index 000000000000..b90de4c6db01 --- /dev/null +++ b/yarn-project/foundation/src/log/libp2p_logger.ts @@ -0,0 +1,48 @@ +import { type ComponentLogger, type Logger } from '@libp2p/interface'; + +import { getLogLevelFromFilters } from './log-filters.js'; +import { logFilters, logger } from './pino-logger.js'; + +/** + * Creates a libp2p compatible logger that wraps our pino logger. + * This adapter implements the ComponentLogger interface required by libp2p. + */ +export function createLibp2pComponentLogger(namespace: string): ComponentLogger { + return { + forComponent: (component: string) => createLibp2pLogger(`${namespace}:${component}`), + }; +} + +function createLibp2pLogger(component: string): Logger { + // Create a direct pino logger instance for libp2p that supports string interpolation + const log = logger.child({ module: component }, { level: getLogLevelFromFilters(logFilters, component) }); + + // Default log level is trace as this is super super noisy + const logFn = (message: string, ...args: unknown[]) => { + log.trace(message, ...args); + }; + + return Object.assign(logFn, { + enabled: log.isLevelEnabled('debug'), + error(message: string, ...args: unknown[]) { + // We write error outputs as debug as they are often expected, e.g. connection errors can happen in happy paths + log.debug(message, ...args); + }, + + debug(message: string, ...args: unknown[]) { + log.debug(message, ...args); + }, + + info(message: string, ...args: unknown[]) { + log.info(message, ...args); + }, + + warn(message: string, ...args: unknown[]) { + log.warn(message, ...args); + }, + + trace(message: string, ...args: unknown[]) { + log.trace(message, ...args); + }, + }); +} diff --git a/yarn-project/foundation/src/log/pino-logger.ts b/yarn-project/foundation/src/log/pino-logger.ts index 38991a706cd6..8b5a3232c209 100644 --- a/yarn-project/foundation/src/log/pino-logger.ts +++ b/yarn-project/foundation/src/log/pino-logger.ts @@ -11,23 +11,14 @@ import { getLogLevelFromFilters, parseEnv } from './log-filters.js'; import { type LogLevel } from './log-levels.js'; import { type LogData, type LogFn } from './log_fn.js'; -export function createLogger(module: string, fixedTerms = {}): Logger { +export function createLogger(module: string): Logger { module = logNameHandlers.reduce((moduleName, handler) => handler(moduleName), module.replace(/^aztec:/, '')); const pinoLogger = logger.child({ module }, { level: getLogLevelFromFilters(logFilters, module) }); - // Only perform copy of data if fixed terms are provided - const hasFixedTerms = Object.keys(fixedTerms).length > 0; - // We check manually for isLevelEnabled to avoid calling processLogData unnecessarily. // Note that isLevelEnabled is missing from the browser version of pino. const logFn = (level: LogLevel, msg: string, data?: unknown) => - isLevelEnabled(pinoLogger, level) && - pinoLogger[level]( - hasFixedTerms - ? processLogData({ ...fixedTerms, ...(data ?? {}) } as LogData) - : processLogData((data as LogData) ?? {}), - msg, - ); + isLevelEnabled(pinoLogger, level) && pinoLogger[level](processLogData((data as LogData) ?? {}), msg); return { silent: () => {}, @@ -92,7 +83,7 @@ function isLevelEnabled(logger: pino.Logger<'verbose', boolean>, level: LogLevel // Load log levels from environment variables. const defaultLogLevel = process.env.NODE_ENV === 'test' ? 'silent' : 'info'; -const [logLevel, logFilters] = parseEnv(process.env.LOG_LEVEL, defaultLogLevel); +export const [logLevel, logFilters] = parseEnv(process.env.LOG_LEVEL, defaultLogLevel); // Define custom logging levels for pino. const customLevels = { verbose: 25 }; @@ -178,7 +169,7 @@ function makeLogger() { } } -const logger = makeLogger(); +export const logger = makeLogger(); // Log the logger configuration. logger.verbose( diff --git a/yarn-project/p2p/src/services/libp2p/libp2p_logger.ts b/yarn-project/p2p/src/services/libp2p/libp2p_logger.ts deleted file mode 100644 index 02dc823c6632..000000000000 --- a/yarn-project/p2p/src/services/libp2p/libp2p_logger.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { createLogger } from '@aztec/foundation/log'; - -import { type ComponentLogger, type Logger } from '@libp2p/interface'; - -/** - * Creates a libp2p compatible logger that wraps our pino logger. - * This adapter implements the ComponentLogger interface required by libp2p. - */ -export function createLibp2pComponentLogger(namespace: string, fixedTerms = {}): ComponentLogger { - return { - forComponent: (component: string) => createLibp2pLogger(`${namespace}:${component}`, fixedTerms), - }; -} - -function createLibp2pLogger(component: string, fixedTerms = {}): Logger { - const logger = createLogger(component, fixedTerms); - - // Default log level is trace as this is super super noisy - const logFn = (formatter: any, ...args: any[]) => { - // Handle %p format specifier by manually replacing with args - if (typeof formatter === 'string' && args.length > 0) { - // Handle %p, %a, %s and %d format specifiers - const parts = formatter.split(/(%p|%a|%s|%d)/); - let result = parts[0]; - let argIndex = 0; - - for (let i = 1; i < parts.length; i += 2) { - if (argIndex < args.length) { - result += String(args[argIndex]) + (parts[i + 1] || ''); - argIndex++; - } - } - - formatter = result; - // Only keep non-format args as data - args = args.slice(argIndex); - } - - // Handle object args by spreading them, but only if they weren't used in formatting - if (args.length === 1 && typeof args[0] === 'object') { - logger.trace(formatter, args[0]); - } else if (args.length > 0) { - // If we have remaining args after formatting, pass them as data - logger.trace(formatter, { _args: args }); - } else { - logger.trace(formatter); - } - }; - - return Object.assign(logFn, { - enabled: logger.isLevelEnabled('debug'), - - error(...args: any[]) { - const [msg, ...rest] = args; - logger.error(msg as string, ...rest); - }, - - debug(...args: any[]) { - const [msg, ...rest] = args; - logger.debug(msg as string, ...rest); - }, - - info(...args: any[]) { - const [msg, ...rest] = args; - logger.info(msg as string, ...rest); - }, - - warn(...args: any[]) { - const [msg, ...rest] = args; - logger.warn(msg as string, ...rest); - }, - - trace(...args: any[]) { - const [msg, ...rest] = args; - logger.trace(msg as string, ...rest); - }, - }); -} diff --git a/yarn-project/p2p/src/services/libp2p/libp2p_service.ts b/yarn-project/p2p/src/services/libp2p/libp2p_service.ts index d679b2a989d7..45a5697d29be 100644 --- a/yarn-project/p2p/src/services/libp2p/libp2p_service.ts +++ b/yarn-project/p2p/src/services/libp2p/libp2p_service.ts @@ -19,7 +19,7 @@ import { } from '@aztec/circuit-types'; import { Fr } from '@aztec/circuits.js'; import { type EpochCacheInterface } from '@aztec/epoch-cache'; -import { createLogger } from '@aztec/foundation/log'; +import { createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log'; import { SerialQueue } from '@aztec/foundation/queue'; import { RunningPromise } from '@aztec/foundation/running-promise'; import type { AztecAsyncKVStore } from '@aztec/kv-store'; @@ -65,7 +65,6 @@ import { pingHandler, reqRespBlockHandler, reqRespTxHandler, statusHandler } fro import { ReqResp } from '../reqresp/reqresp.js'; import type { P2PService, PeerDiscoveryService } from '../service.js'; import { GossipSubEvent } from '../types.js'; -import { createLibp2pComponentLogger } from './libp2p_logger.js'; interface MessageValidator { validator: { @@ -268,8 +267,7 @@ export class LibP2PService extends WithTracer implement connectionManager: components.connectionManager, }), }, - // Fix the peer id in libp2p logs so we can see the source of the log - logger: createLibp2pComponentLogger(logger.module, { sourcePeerId: peerId }), + logger: createLibp2pComponentLogger(logger.module), }); return new LibP2PService( diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 948ec03aacf0..48bb0b62a28c 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -759,6 +759,7 @@ __metadata: "@aztec/bb.js": "portal:../../barretenberg/ts" "@jest/globals": "npm:^29.5.0" "@koa/cors": "npm:^5.0.0" + "@libp2p/interface": "npm:1.3.1" "@noble/curves": "npm:^1.2.0" "@types/bn.js": "npm:^5.1.3" "@types/debug": "npm:^4.1.7"