fix: don't log Puppeteer logs to file unless requested (#2743)

Currently we unconditionally log all MCP and Puppeteer logs to the
files.
This adds regression test using mocks to simplify testings. 

Closes https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/2734
Closes https://github.com/ChromeDevTools/chrome-devtools-mcp/pull/2706
Fixes https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/2731
This commit is contained in:
Nikolay Vitkov
2026-09-14 11:45:24 +00:00
committed by GitHub
parent d9a8cb6ec2
commit 4fbfbc4fd9
7 changed files with 85 additions and 12 deletions
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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`
+2 -2
View File
@@ -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": "*"
}
}
}
+3 -1
View File
@@ -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:*'}
: {}),
},
});
+1 -1
View File
@@ -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',
+9 -6
View File
@@ -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));
};
};
+68
View File
@@ -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'));
});
});