diff --git a/yarn-project/aztec.js/webpack.config.js b/yarn-project/aztec.js/webpack.config.js index d377a5fa0563..3ba9561af4e1 100644 --- a/yarn-project/aztec.js/webpack.config.js +++ b/yarn-project/aztec.js/webpack.config.js @@ -61,6 +61,7 @@ export default { fs: false, path: false, url: false, + tty: false, worker_threads: false, buffer: require.resolve('buffer/'), util: require.resolve('util/'), diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index f8732bff89b1..cf8c8e076361 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -114,4 +114,4 @@ "engines": { "node": ">=18" } -} \ No newline at end of file +} diff --git a/yarn-project/cli-wallet/package.json b/yarn-project/cli-wallet/package.json index e33bf41c8058..7973038a447f 100644 --- a/yarn-project/cli-wallet/package.json +++ b/yarn-project/cli-wallet/package.json @@ -100,4 +100,4 @@ "engines": { "node": ">=18" } -} \ No newline at end of file +} diff --git a/yarn-project/end-to-end/package.json b/yarn-project/end-to-end/package.json index 047609c40157..71530defd744 100644 --- a/yarn-project/end-to-end/package.json +++ b/yarn-project/end-to-end/package.json @@ -156,4 +156,4 @@ "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", "rootDir": "./src" } -} \ No newline at end of file +} diff --git a/yarn-project/end-to-end/src/shared/browser.ts b/yarn-project/end-to-end/src/shared/browser.ts index ea9dde82e564..50e09adf0225 100644 --- a/yarn-project/end-to-end/src/shared/browser.ts +++ b/yarn-project/end-to-end/src/shared/browser.ts @@ -6,6 +6,7 @@ import * as AztecJs from '@aztec/aztec.js'; import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; import { contractArtifactToBuffer } from '@aztec/types/abi'; +import getPort from 'get-port'; import { type Server } from 'http'; import Koa from 'koa'; import serve from 'koa-static'; @@ -77,16 +78,18 @@ export const browserTestSuite = ( app = new Koa(); app.use(serve(path.resolve(__dirname, './web'))); + const debuggingPort = await getPort({ port: 9222 }); browser = await launch({ executablePath: process.env.CHROME_BIN, headless: true, + debuggingPort, args: [ '--no-sandbox', '--headless', '--disable-gpu', '--disable-dev-shm-usage', '--disable-software-rasterizer', - '--remote-debugging-port=9222', + `--remote-debugging-port=${debuggingPort}`, ], }); page = await browser.newPage(); diff --git a/yarn-project/end-to-end/webpack.config.js b/yarn-project/end-to-end/webpack.config.js index 88f6bb5178c1..3ae5808f82fe 100644 --- a/yarn-project/end-to-end/webpack.config.js +++ b/yarn-project/end-to-end/webpack.config.js @@ -60,6 +60,7 @@ export default { fs: false, path: false, url: false, + tty: false, worker_threads: false, buffer: require.resolve('buffer/'), util: require.resolve('util/'), diff --git a/yarn-project/foundation/src/log/pino-logger.ts b/yarn-project/foundation/src/log/pino-logger.ts index ca5ac46a2628..57adc0902a12 100644 --- a/yarn-project/foundation/src/log/pino-logger.ts +++ b/yarn-project/foundation/src/log/pino-logger.ts @@ -1,4 +1,5 @@ import { bold, reset } from 'colorette'; +import isNode from 'detect-node'; import { type LoggerOptions, pino } from 'pino'; import { inspect } from 'util'; @@ -16,8 +17,9 @@ export function createDebugLogger(module: string): DebugLogger { ); // 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?: LogData) => - pinoLogger.isLevelEnabled(level) && pinoLogger[level](processLogData(data ?? {}), msg); + isLevelEnabled(pinoLogger, level) && pinoLogger[level](processLogData(data ?? {}), msg); return { silent: () => {}, @@ -37,7 +39,7 @@ export function createDebugLogger(module: string): DebugLogger { /** Log as trace. Use for when we want to denial-of-service any recipient of the logs. */ trace: (msg: string, data?: LogData) => logFn('trace', msg, data), level: pinoLogger.level as LogLevel, - isLevelEnabled: pinoLogger.isLevelEnabled.bind(pinoLogger), + isLevelEnabled: (level: LogLevel) => isLevelEnabled(pinoLogger, level), }; } @@ -54,6 +56,13 @@ function processLogData(data: LogData): LogData { return logDataHandlers.reduce((accum, handler) => handler(accum), data); } +// Patch isLevelEnabled missing from pino/browser. +function isLevelEnabled(logger: pino.Logger<'verbose', boolean>, level: LogLevel): boolean { + return typeof logger.isLevelEnabled === 'function' + ? logger.isLevelEnabled(level) + : logger.levels.values[level] >= logger.levels.values[logger.level]; +} + // Load log levels from environment variables. const defaultLogLevel = process.env.NODE_ENV === 'test' ? 'silent' : 'info'; const [logLevel, logFilters] = parseEnv(process.env.LOG_LEVEL, defaultLogLevel); @@ -76,36 +85,51 @@ const stdoutTransport: LoggerOptions['transport'] = { options: { destination: 1 }, }; +// Define custom logging levels for pino. +const customLevels = { verbose: 25 }; +const pinoOpts = { customLevels, useOnlyCustomLevels: false, level: logLevel }; +const levels = { + labels: { ...pino.levels.labels, ...Object.fromEntries(Object.entries(customLevels).map(e => e.reverse())) }, + values: { ...pino.levels.values, ...customLevels }, +}; + // Transport for OpenTelemetry logging. While defining this here is an abstraction leakage since this // should live in the telemetry-client, it is necessary to ensure that the logger is initialized with // the correct transport. Tweaking transports of a live pino instance is tricky, and creating a new instance // 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 customLevels = { verbose: 25 }; -const { levels } = pino({ customLevels, useOnlyCustomLevels: false }); + const otelTransport: LoggerOptions['transport'] = { target: '@aztec/telemetry-client/otel-pino-stream', options: { levels, messageKey: 'msg' }, }; -// 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. +// 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 = pino( - { customLevels, useOnlyCustomLevels: false, level: logLevel }, - pino.transport({ - targets: compactArray([ - ['1', 'true', 'TRUE'].includes(process.env.LOG_JSON ?? '') ? stdoutTransport : prettyTransport, - process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT ? otelTransport : undefined, - ]), - }), -); - +const logger = isNode + ? pino( + pinoOpts, + pino.transport({ + targets: compactArray([ + ['1', 'true', 'TRUE'].includes(process.env.LOG_JSON ?? '') ? stdoutTransport : prettyTransport, + process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT ? otelTransport : undefined, + ]), + }), + ) + : pino({ ...pinoOpts, browser: { asObject: false } }); + +// Log the logger configuration. logger.info( - { module: 'logger', ...logFilters.reduce((accum, [module, level]) => ({ ...accum, [`log.${module}`]: level }), {}) }, - `Logger initialized with level ${logLevel}` + (otlpEndpoint ? ` with OTLP exporter to ${otlpEndpoint}` : ''), + { + module: 'logger', + ...logFilters.reduce((accum, [module, level]) => ({ ...accum, [`log.${module}`]: level }), {}), + }, + isNode + ? `Logger initialized with level ${logLevel}` + (otlpEndpoint ? ` with OTLP exporter to ${otlpEndpoint}` : '') + : `Browser console logger initialized with level ${logLevel}`, ); /** Log function that accepts an exception object */ diff --git a/yarn-project/ivc-integration/webpack.config.js b/yarn-project/ivc-integration/webpack.config.js index 679267bc82cc..93ad59791671 100644 --- a/yarn-project/ivc-integration/webpack.config.js +++ b/yarn-project/ivc-integration/webpack.config.js @@ -30,6 +30,9 @@ export default { ], resolve: { plugins: [new ResolveTypeScriptPlugin()], + fallback: { + tty: false, + } }, devServer: { hot: false, diff --git a/yarn-project/kv-store/package.json b/yarn-project/kv-store/package.json index 96073106a080..f42e02ff7863 100644 --- a/yarn-project/kv-store/package.json +++ b/yarn-project/kv-store/package.json @@ -79,4 +79,4 @@ "engines": { "node": ">=18" } -} \ No newline at end of file +} diff --git a/yarn-project/prover-client/package.json b/yarn-project/prover-client/package.json index 08b6b59a46d8..2c01d5617c0f 100644 --- a/yarn-project/prover-client/package.json +++ b/yarn-project/prover-client/package.json @@ -104,4 +104,4 @@ "engines": { "node": ">=18" } -} \ No newline at end of file +} diff --git a/yarn-project/txe/package.json b/yarn-project/txe/package.json index ebae6269f3c6..0fa9709f348e 100644 --- a/yarn-project/txe/package.json +++ b/yarn-project/txe/package.json @@ -93,4 +93,4 @@ "engines": { "node": ">=18" } -} \ No newline at end of file +}