diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6f4f727c..c396ce31 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,7 +114,7 @@ To write debug logs to `log.txt` in the working directory, run with the followin npx @modelcontextprotocol/inspector node ./build/src/bin/chrome-devtools-mcp.js --log-file=/your/desired/path/log.txt ``` -You can use the `DEBUG` environment variable as usual to control categories that are logged. +You can use the `NODE_DEBUG` environment variable as usual to control categories that are logged. ### Updating documentation diff --git a/docs/configuration.md b/docs/configuration.md index 0d395512..99d7a4cb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -96,7 +96,7 @@ The Chrome DevTools MCP server supports the following configuration option: - **Default:** `false` - **`--logFile`/ `--log-file`** - Path to a file to write debug logs to. Set the env variable `DEBUG` to `*` to enable verbose logs. Useful for submitting bug reports. + Path to a file to write debug logs to. Set the env variable `NODE_DEBUG` to `*` to enable verbose logs. Useful for submitting bug reports. - **Type:** string - **Default:** `false` diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 42ee92db..de706901 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -14,7 +14,7 @@ Start the MCP server with debugging enabled and a log file: -- `DEBUG=* npx chrome-devtools-mcp@latest --log-file=/path/to/chrome-devtools-mcp.log` +- `NODE_DEBUG=* npx chrome-devtools-mcp@latest --log-file=/path/to/chrome-devtools-mcp.log` Using `.mcp.json` to debug while using a client: @@ -30,7 +30,7 @@ Using `.mcp.json` to debug while using a client: "/path/to/chrome-devtools-mcp.log" ], "env": { - "DEBUG": "*" + "NODE_DEBUG": "*" } } } diff --git a/scripts/test.js b/scripts/test.js index 0d427847..a18d0b4b 100644 --- a/scripts/test.js +++ b/scripts/test.js @@ -93,7 +93,9 @@ async function runTests(attempt) { CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: true, CHROME_DEVTOOLS_MCP_CRASH_ON_UNCAUGHT: true, CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS: true, - ...(process.env['RUNNER_DEBUG'] === '1' ? {DEBUG: 'puppeteer:*'} : {}), + ...(process.env['RUNNER_DEBUG'] === '1' + ? {NODE_DEBUG: 'puppeteer:*'} + : {}), }, }); diff --git a/src/config/mcp-options.ts b/src/config/mcp-options.ts index fbce4443..832a1c79 100644 --- a/src/config/mcp-options.ts +++ b/src/config/mcp-options.ts @@ -20,7 +20,7 @@ export const mcpOptions = { logFile: { type: 'string', describe: - 'Path to a file to write debug logs to. Set the env variable `DEBUG` to `*` to enable verbose logs. Useful for submitting bug reports.', + 'Path to a file to write debug logs to. Set the env variable `NODE_DEBUG` to `*` to enable verbose logs. Useful for submitting bug reports.', }, viewport: { type: 'string', diff --git a/src/utils/logger.ts b/src/utils/logger.ts index d7748c25..8c00e842 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -50,6 +50,12 @@ export const logger: Logger = (...args: unknown[]) => { }; export const puppeteerLogger = (prefix: string) => { + const dbg = util.debuglog(prefix); + + if (!dbg.enabled) { + return; + } + if (logFileStream) { return (...args: unknown[]) => { logFileStream!.write( @@ -58,10 +64,7 @@ export const puppeteerLogger = (prefix: string) => { }; } - const dbg = util.debuglog(prefix); - return dbg.enabled - ? (...args: unknown[]) => { - dbg('%s %s', new Date().toISOString(), util.format(...args)); - } - : undefined; + return (...args: unknown[]) => { + dbg('%s %s', new Date().toISOString(), util.format(...args)); + }; }; diff --git a/tests/utils/logger.test.ts b/tests/utils/logger.test.ts new file mode 100644 index 00000000..987e7c28 --- /dev/null +++ b/tests/utils/logger.test.ts @@ -0,0 +1,68 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import assert from 'node:assert'; +import fs from 'node:fs'; +import {afterEach, describe, it, mock} from 'node:test'; +import util from 'node:util'; + +import {puppeteerLogger, saveLogsToFile} from '../../src/utils/logger.js'; + +describe('puppeteerLogger', () => { + afterEach(() => { + mock.restoreAll(); + }); + + it('should return undefined if debuglog is not enabled and no log file', () => { + mock.method(util, 'debuglog', () => { + return Object.assign(() => undefined, {enabled: false}); + }); + + const logger = puppeteerLogger('test-prefix'); + assert.strictEqual(logger, undefined); + }); + + it('should return a logger function if debuglog is enabled and no log file', () => { + const dbgMock = Object.assign(mock.fn(), {enabled: true}); + mock.method(util, 'debuglog', () => dbgMock); + + const logger = puppeteerLogger('test-prefix'); + assert.strictEqual(typeof logger, 'function'); + + logger!('hello %s', 'world'); + + assert.strictEqual(dbgMock.mock.calls.length, 1); + assert.strictEqual(dbgMock.mock.calls[0].arguments[0], '%s %s'); + const dateArg = dbgMock.mock.calls[0].arguments[1] as string; + assert.match(dateArg, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/); + assert.strictEqual(dbgMock.mock.calls[0].arguments[2], 'hello world'); + }); + + it('should return a logger function that writes to file if log file is active', () => { + const writeMock = mock.fn(); + const mockStream = { + write: writeMock, + on: mock.fn(), + } as unknown as fs.WriteStream; + + mock.method(fs, 'createWriteStream', () => mockStream); + const dbgMock = Object.assign(mock.fn(), {enabled: true}); + mock.method(util, 'debuglog', () => dbgMock); + + saveLogsToFile('dummy.log'); + + const logger = puppeteerLogger('test-prefix'); + assert.strictEqual(typeof logger, 'function'); + + logger!('hello %s', 'world'); + + assert.strictEqual(writeMock.mock.calls.length, 1); + const writeArg = writeMock.mock.calls[0].arguments[0] as string; + assert.match(writeArg, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z /); + assert.ok(writeArg.includes('test-prefix')); + assert.ok(writeArg.includes('hello world\n')); + }); +});