refactor: change type of logger (#2165)

This change aligns most of our logger allowing them to be omitted when
needed meaning code inside the args will not be executed unconditionally
- example `logger?.(JSON.stringy(X))`.

Currently only changes the type, while in a follow up I will remove the
`debug` package and update the file logs.
This commit is contained in:
Nikolay Vitkov
2026-06-02 11:29:48 +02:00
committed by GitHub
parent 692b28adac
commit bf0574da8c
24 changed files with 100 additions and 97 deletions
+10 -10
View File
@@ -27,7 +27,6 @@ import {
type Browser,
type BrowserContext,
type ConsoleMessage,
type Debugger,
type HTTPRequest,
type Page,
type ScreenRecorder,
@@ -41,6 +40,7 @@ import {listPages} from './tools/pages.js';
import {CLOSE_PAGE_ERROR} from './tools/ToolDefinition.js';
import type {Context, SupportedExtensions} from './tools/ToolDefinition.js';
import type {TraceResult} from './trace-processing/parse.js';
import type {Logger} from './types.js';
import type {
EmulationSettings,
GeolocationOptions,
@@ -67,7 +67,7 @@ const NAVIGATION_TIMEOUT = 10_000;
export class McpContext implements Context {
browser: Browser;
logger: Debugger;
logger: Logger;
// Maps LLM-provided isolatedContext name → Puppeteer BrowserContext.
#isolatedContexts = new Map<string, BrowserContext>();
@@ -102,7 +102,7 @@ export class McpContext implements Context {
private constructor(
browser: Browser,
logger: Debugger,
logger: Logger,
options: McpContextOptions,
locatorClass: typeof Locator,
) {
@@ -153,7 +153,7 @@ export class McpContext implements Context {
static async from(
browser: Browser,
logger: Debugger,
logger: Logger,
opts: McpContextOptions,
/* Let tests use unbundled Locator class to avoid overly strict checks within puppeteer that fail when mixing bundled and unbundled class instances */
locatorClass: typeof Locator = Locator,
@@ -236,7 +236,7 @@ export class McpContext implements Context {
resolveCdpRequestId(page: McpPage, cdpRequestId: string): number | undefined {
if (!cdpRequestId) {
this.logger('no network request');
this.logger?.('no network request');
return;
}
const request = this.#networkCollector.find(page.pptrPage, request => {
@@ -244,7 +244,7 @@ export class McpContext implements Context {
return request.id === cdpRequestId;
});
if (!request) {
this.logger('no network request for ' + cdpRequestId);
this.logger?.('no network request for ' + cdpRequestId);
return;
}
return this.#networkCollector.getIdForResource(request);
@@ -591,7 +591,7 @@ export class McpContext implements Context {
this.#mcpPages.set(page, mcpPage);
// We emulate a focused page for all pages to support multi-agent workflows.
void page.emulateFocusedPage(true).catch(error => {
this.logger('Error turning on focused page emulation', error);
this.logger?.('Error turning on focused page emulation', error);
});
}
mcpPage.isolatedContextName = isolatedContextNames.get(page);
@@ -655,7 +655,7 @@ export class McpContext implements Context {
page = await target.asPage();
this.#extensionPages.set(target, page);
} catch (e) {
this.logger('Failed to get page for extension target', e);
this.logger?.('Failed to get page for extension target', e);
}
}
}
@@ -696,7 +696,7 @@ export class McpContext implements Context {
}
async detectOpenDevToolsWindows() {
this.logger('Detecting open DevTools windows');
this.logger?.('Detecting open DevTools windows');
const {pages} = await this.#getAllPages();
await Promise.all(
@@ -769,7 +769,7 @@ export class McpContext implements Context {
await fs.writeFile(filePath, data);
return {filename: filePath};
} catch (err) {
this.logger(err);
this.logger?.(err);
throw new Error('Could not save a file', {cause: err});
}
}
+8 -8
View File
@@ -283,7 +283,7 @@ export class McpPage implements ContextPage {
for (const handle of oldHandles) {
await handle
.dispose()
.catch(e => logger('Failed to dispose old handle', e));
.catch(e => logger?.('Failed to dispose old handle', e));
}
}
@@ -291,14 +291,14 @@ export class McpPage implements ContextPage {
elementHandles.map(async (elementHandle, index) => {
const backendNodeId = await elementHandle.backendNodeId();
if (!backendNodeId) {
logger(
logger?.(
`No backendNodeId for stashed DOM element with index ${index}`,
);
return `stashed-${index}`;
}
const cdpElementId = this.resolveCdpElementId(backendNodeId);
if (!cdpElementId) {
logger(
logger?.(
`Could not get cdpElementId for backend node ${backendNodeId}`,
);
return `stashed-${index}`;
@@ -371,12 +371,12 @@ export class McpPage implements ContextPage {
resolveCdpElementId(cdpBackendNodeId: number): string | undefined {
if (!cdpBackendNodeId) {
logger('no cdpBackendNodeId');
logger?.('no cdpBackendNodeId');
return;
}
const snapshot = this.textSnapshot;
if (!snapshot) {
logger('no text snapshot');
logger?.('no text snapshot');
return;
}
// TODO: index by backendNodeId instead.
@@ -395,10 +395,10 @@ export class McpPage implements ContextPage {
async getDevToolsData(): Promise<DevToolsData> {
try {
logger('Getting DevTools UI data');
logger?.('Getting DevTools UI data');
const devtoolsPage = this.devToolsPage;
if (!devtoolsPage) {
logger('No DevTools page detected');
logger?.('No DevTools page detected');
return {};
}
const {cdpRequestId, cdpBackendNodeId} = await devtoolsPage.evaluate(
@@ -421,7 +421,7 @@ export class McpPage implements ContextPage {
);
return {cdpBackendNodeId, cdpRequestId};
} catch (err) {
logger('error getting devtools data', err);
logger?.('error getting devtools data', err);
}
return {};
}
+4 -4
View File
@@ -92,7 +92,7 @@ export class PageCollector<T> {
}
this.addPage(page);
} catch (err) {
logger('Error getting a page for a target onTargetCreated', err);
logger?.('Error getting a page for a target onTargetCreated', err);
}
};
@@ -104,7 +104,7 @@ export class PageCollector<T> {
}
this.cleanupPageDestroyed(page);
} catch (err) {
logger('Error getting a page for a target onTargetDestroyed', err);
logger?.('Error getting a page for a target onTargetDestroyed', err);
}
};
@@ -335,7 +335,7 @@ class PageEventSubscriber {
inspectorIssue,
)[0];
if (!issue) {
logger('No issue mapping for for the issue: ', inspectorIssue.code);
logger?.('No issue mapping for for the issue: ', inspectorIssue.code);
return;
}
@@ -353,7 +353,7 @@ class PageEventSubscriber {
},
);
} catch (error) {
logger('Error creating a new issue', error);
logger?.('Error creating a new issue', error);
}
};
}
+1 -1
View File
@@ -262,7 +262,7 @@ export class TextSnapshot {
collect(node);
}
} catch (e) {
logger(
logger?.(
`Failed to collect descendants for backend node ${backendNodeId}`,
e,
);
+3 -3
View File
@@ -208,11 +208,11 @@ export class ToolHandler {
const startTime = Date.now();
let success = false;
try {
logger(
logger?.(
`${this.tool.name} request: ${JSON.stringify(params, null, ' ')}`,
);
const context = await this.getContext();
logger(`${this.tool.name} context: resolved`);
logger?.(`${this.tool.name} context: resolved`);
await context.detectOpenDevToolsWindows();
const response = this.serverArgs.slim
? new SlimMcpResponse(this.serverArgs)
@@ -277,7 +277,7 @@ export class ToolHandler {
}
return result;
} catch (err) {
logger(`${this.tool.name} error:`, err, err?.stack);
logger?.(`${this.tool.name} error:`, err, err?.stack);
let errorText = err && 'message' in err ? err.message : String(err);
if ('cause' in err && err.cause) {
errorText += `\nCause: ${err.cause.message}`;
+2 -2
View File
@@ -162,7 +162,7 @@ export class WaitForHelper {
}
return;
})
.catch(error => logger(error));
.catch(error => logger?.(error));
try {
await action();
@@ -183,7 +183,7 @@ export class WaitForHelper {
// the correct context
await this.waitForStableDom();
} catch (error) {
logger(error);
logger?.(error);
} finally {
this.#abortController.abort();
}
+5 -5
View File
@@ -29,7 +29,7 @@ const logFile = args.logFile ? saveLogsToFile(args.logFile) : undefined;
if (process.env['CHROME_DEVTOOLS_MCP_CRASH_ON_UNCAUGHT'] !== 'true') {
process.on('unhandledRejection', (reason, promise) => {
logger('Unhandled promise rejection', promise, reason);
logger?.('Unhandled promise rejection', promise, reason);
});
}
@@ -43,13 +43,13 @@ async function shutdown(reason: string): Promise<void> {
return;
}
shuttingDown = true;
logger(`Shutting down (${reason})`);
logger?.(`Shutting down (${reason})`);
// Backstop in case browser teardown hangs (e.g. unresponsive Chrome,
// slow beforeunload handlers, many tabs). Exits 0 because we still
// honored the shutdown request; the log line preserves observability.
// Unref'd so it doesn't keep the loop alive on the clean path.
setTimeout(() => {
logger('Shutdown timeout exceeded, forcing exit');
logger?.('Shutdown timeout exceeded, forcing exit');
process.exit(0);
}, 10000).unref();
await closeBrowser();
@@ -71,13 +71,13 @@ process.on('SIGHUP', () => {
void shutdown('SIGHUP');
});
logger(`Starting Chrome DevTools MCP Server v${VERSION}`);
logger?.(`Starting Chrome DevTools MCP Server v${VERSION}`);
const {server} = await createMcpServer(args, {
logFile,
});
const transport = new StdioServerTransport();
await server.connect(transport);
logger('Chrome DevTools MCP Server connected');
logger?.('Chrome DevTools MCP Server connected');
logDisclaimers(args);
void ClearcutLogger.get()?.logDailyActiveIfNeeded();
void ClearcutLogger.get()?.logServerStart(computeFlagUsage(args, cliOptions));
+4 -4
View File
@@ -119,7 +119,7 @@ export async function ensureBrowserConnected(options: {
);
}
logger('Connecting Puppeteer to ', JSON.stringify(connectOptions));
logger?.('Connecting Puppeteer to ', JSON.stringify(connectOptions));
try {
// Assign mode before browser so a concurrent closeBrowser() never sees
// `browser` set with `browserMode` still undefined (would fall through
@@ -135,7 +135,7 @@ export async function ensureBrowserConnected(options: {
},
);
}
logger('Connected Puppeteer');
logger?.('Connected Puppeteer');
return browser;
}
@@ -296,12 +296,12 @@ export async function closeBrowser(): Promise<void> {
}
if (mode === 'launched') {
await b.close().catch(err => {
logger('Failed to close browser', err);
logger?.('Failed to close browser', err);
});
return;
}
await b.disconnect().catch(err => {
logger('Failed to disconnect from browser', err);
logger?.('Failed to disconnect from browser', err);
});
}
+7 -7
View File
@@ -69,7 +69,7 @@ function waitForFile(filePath: string, removed = false) {
export async function startDaemon(mcpArgs: string[] = [], sessionId: string) {
if (isDaemonRunning(sessionId)) {
logger('Daemon is already running');
logger?.('Daemon is already running');
return;
}
@@ -79,7 +79,7 @@ export async function startDaemon(mcpArgs: string[] = [], sessionId: string) {
fs.unlinkSync(pidFilePath);
}
logger('Starting daemon...', ...mcpArgs);
logger?.('Starting daemon...', ...mcpArgs);
const child = spawn(process.execPath, [DAEMON_SCRIPT_PATH, ...mcpArgs], {
detached: true,
stdio: 'ignore',
@@ -116,27 +116,27 @@ export async function sendCommand(
const transport = new PipeTransport(socket, socket);
transport.onmessage = async (message: string) => {
clearTimeout(timer);
logger('onmessage', message);
logger?.('onmessage', message);
resolve(JSON.parse(message));
};
socket.on('error', error => {
clearTimeout(timer);
logger('Socket error:', error);
logger?.('Socket error:', error);
reject(error);
});
socket.on('close', () => {
clearTimeout(timer);
logger('Socket closed:');
logger?.('Socket closed:');
reject(new Error('Socket closed'));
});
logger('Sending message', command);
logger?.('Sending message', command);
transport.send(JSON.stringify(command));
});
}
export async function stopDaemon(sessionId: string) {
if (!isDaemonRunning(sessionId)) {
logger('Daemon is not running');
logger?.('Daemon is not running');
return;
}
+12 -12
View File
@@ -31,9 +31,9 @@ import {
} from './utils.js';
const sessionId = process.env.CHROME_DEVTOOLS_MCP_SESSION_ID || '';
logger(`Daemon sessionId: ${sessionId}`);
logger?.(`Daemon sessionId: ${sessionId}`);
if (isDaemonRunning(sessionId)) {
logger('Another daemon process is running.');
logger?.('Another daemon process is running.');
process.exit(1);
}
const pidFilePath = getPidFilePath(sessionId);
@@ -113,7 +113,7 @@ try {
}
}
}
logger(`Writing ${process.pid.toString()} to ${pidFilePath}`);
logger?.(`Writing ${process.pid.toString()} to ${pidFilePath}`);
const socketPath = getSocketPath(sessionId);
@@ -225,13 +225,13 @@ async function startSocketServer() {
server = createServer(socket => {
const transport = new PipeTransport(socket, socket);
transport.onmessage = async (message: string) => {
logger('onmessage', message);
logger?.('onmessage', message);
const response = await handleRequest(JSON.parse(message));
transport.send(JSON.stringify(response));
socket.end();
};
socket.on('error', error => {
logger('Socket error:', error);
logger?.('Socket error:', error);
});
});
@@ -255,7 +255,7 @@ async function startSocketServer() {
);
server.on('error', error => {
logger('Server error:', error);
logger?.('Server error:', error);
reject(error);
});
});
@@ -267,12 +267,12 @@ async function cleanup() {
try {
await mcpClient?.close();
} catch (error) {
logger('Error closing MCP client:', error);
logger?.('Error closing MCP client:', error);
}
try {
await mcpTransport?.close();
} catch (error) {
logger('Error closing MCP transport:', error);
logger?.('Error closing MCP transport:', error);
}
if (server) {
await new Promise<void>(resolve => {
@@ -286,7 +286,7 @@ async function cleanup() {
// ignore errors
}
}
logger(`unlinking ${pidFilePath}`);
logger?.(`unlinking ${pidFilePath}`);
if (fs.existsSync(pidFilePath)) {
fs.unlinkSync(pidFilePath);
}
@@ -306,14 +306,14 @@ process.on('SIGHUP', () => {
// Handle uncaught errors
process.on('uncaughtException', error => {
logger('Uncaught exception:', error);
logger?.('Uncaught exception:', error);
});
process.on('unhandledRejection', error => {
logger('Unhandled rejection:', error);
logger?.('Unhandled rejection:', error);
});
// Start the server
const started = startSocketServer().catch(error => {
logger('Failed to start daemon server:', error);
logger?.('Failed to start daemon server:', error);
process.exit(1);
});
+2 -2
View File
@@ -77,13 +77,13 @@ export function getPidFilePath(sessionId: string) {
export function getDaemonPid(sessionId: string) {
try {
const pidFile = getPidFilePath(sessionId);
logger(`Daemon pid file ${pidFile} sessionId=${sessionId}`);
logger?.(`Daemon pid file ${pidFile} sessionId=${sessionId}`);
if (!fs.existsSync(pidFile)) {
return null;
}
const pidContent = fs.readFileSync(pidFile, 'utf-8');
const pid = parseInt(pidContent.trim(), 10);
logger(`Daemon pid: ${pid}`);
logger?.(`Daemon pid: ${pid}`);
if (isNaN(pid)) {
return null;
}
+4 -4
View File
@@ -156,7 +156,7 @@ export class IssueFormatter {
const markdownDescription = this.#issue.getDescription();
const filename = markdownDescription?.file;
if (!filename) {
logger(`no description found for issue:` + this.#issue.code());
logger?.(`no description found for issue:` + this.#issue.code());
return undefined;
}
@@ -166,7 +166,7 @@ export class IssueFormatter {
const rawMarkdown = ISSUE_UTILS.getIssueDescription(filename);
if (!rawMarkdown) {
logger(`no markdown ${filename} found for issue:` + this.#issue.code());
logger?.(`no markdown ${filename} found for issue:` + this.#issue.code());
return undefined;
}
@@ -180,12 +180,12 @@ export class IssueFormatter {
const title =
DevTools.MarkdownIssueDescription.findTitleFromMarkdownAst(markdownAst);
if (!title) {
logger('cannot read issue title from ' + filename);
logger?.('cannot read issue title from ' + filename);
return undefined;
}
return title;
} catch {
logger('error parsing markdown for issue ' + this.#issue.code());
logger?.('error parsing markdown for issue ' + this.#issue.code());
return undefined;
}
}
+1 -1
View File
@@ -69,7 +69,7 @@ export async function createMcpServer(
);
context?.setRoots(roots.roots);
} catch (e) {
logger('Failed to list roots', e);
logger?.('Failed to list roots', e);
}
};
+2 -1
View File
@@ -7,6 +7,7 @@
import fs from 'node:fs';
import {debug} from './third_party/index.js';
import type {Logger} from './types.js';
const mcpDebugNamespace = 'mcp:log';
@@ -44,4 +45,4 @@ export function flushLogs(
});
}
export const logger = debug(mcpDebugNamespace);
export const logger: Logger = debug(mcpDebugNamespace) as Logger;
+1 -1
View File
@@ -176,7 +176,7 @@ export class ClearcutLogger {
await this.#persistence.saveState(state);
}
} catch (err) {
logger('Error in logDailyActiveIfNeeded:', err);
logger?.('Error in logDailyActiveIfNeeded:', err);
}
}
+4 -4
View File
@@ -59,10 +59,10 @@ export class WatchdogClient {
});
this.#childProcess.unref();
this.#childProcess.on('error', err => {
logger('Watchdog process error:', err);
logger?.('Watchdog process error:', err);
});
this.#childProcess.on('exit', (code, signal) => {
logger(`Watchdog exited with code ${code} and signal ${signal}`);
logger?.(`Watchdog exited with code ${code} and signal ${signal}`);
});
}
@@ -76,10 +76,10 @@ export class WatchdogClient {
const line = JSON.stringify(message) + '\n';
this.#childProcess.stdin.write(line);
} catch (err) {
logger('Failed to write to watchdog stdin', err);
logger?.('Failed to write to watchdog stdin', err);
}
} else {
logger('Watchdog stdin not available, dropping message');
logger?.('Watchdog stdin not available, dropping message');
}
}
}
+2 -2
View File
@@ -67,7 +67,7 @@ export class FilePersistence implements Persistence {
const content = await fs.readFile(filePath, 'utf-8');
return JSON.parse(content) as LocalState;
} catch (error) {
logger(`Failed to read telemetry state from ${filePath}:`, error);
logger?.(`Failed to read telemetry state from ${filePath}:`, error);
void ClearcutLogger.get()?.logServerError({
errorCode: ErrorCode.ERROR_CODE_PERSISTENCE_FILE_READ_FAILED,
});
@@ -84,7 +84,7 @@ export class FilePersistence implements Persistence {
await fs.writeFile(filePath, JSON.stringify(state, null, 2), 'utf-8');
} catch (error) {
// Ignore errors during state saving to avoid crashing the server
logger(`Failed to save telemetry state to ${filePath}:`, error);
logger?.(`Failed to save telemetry state to ${filePath}:`, error);
void ClearcutLogger.get()?.logServerError({
errorCode: ErrorCode.ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED,
});
+10 -10
View File
@@ -76,7 +76,7 @@ export class ClearcutSender {
app_version: this.#appVersion,
os_type: this.#osType,
};
logger('Enqueing telemetry event', JSON.stringify(eventToSend, null, 2));
logger?.('Enqueing telemetry event', JSON.stringify(eventToSend, null, 2));
this.#addToBuffer(eventToSend);
if (!this.#timerStarted) {
@@ -101,9 +101,9 @@ export class ClearcutSender {
this.#finalFlush(),
new Promise(resolve => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),
]);
logger('Final flush completed');
logger?.('Final flush completed');
} catch (error) {
logger('Final flush failed:', error);
logger?.('Final flush failed:', error);
}
}
@@ -136,7 +136,7 @@ export class ClearcutSender {
);
}
} else if (result.isPermanentError) {
logger(
logger?.(
'Permanent error, dropped batch of',
eventsToSend.length,
'events',
@@ -149,7 +149,7 @@ export class ClearcutSender {
} catch (error) {
// Safety catch for unexpected errors, requeue events
this.#buffer = [...eventsToSend, ...this.#buffer];
logger('Flush failed unexpectedly:', error);
logger?.('Flush failed unexpectedly:', error);
} finally {
this.#isFlushing = false;
this.#scheduleFlush(nextDelayMs);
@@ -159,7 +159,7 @@ export class ClearcutSender {
#addToBuffer(event: ChromeDevToolsMcpExtension): void {
if (this.#buffer.length >= MAX_BUFFER_SIZE) {
this.#buffer.shift();
logger('Telemetry buffer overflow: dropped oldest event');
logger?.('Telemetry buffer overflow: dropped oldest event');
}
this.#buffer.push({
event,
@@ -168,13 +168,13 @@ export class ClearcutSender {
}
#scheduleFlush(delayMs: number): void {
logger(`Scheduling flush in ${delayMs}`);
logger?.(`Scheduling flush in ${delayMs}`);
if (this.#flushTimer) {
clearTimeout(this.#flushTimer);
}
this.#flushTimer = setTimeout(() => {
this.#flush().catch(err => {
logger('Flush error:', err);
logger?.('Flush error:', err);
});
}, delayMs);
}
@@ -184,7 +184,7 @@ export class ClearcutSender {
isPermanentError?: boolean;
nextRequestWaitMs?: number;
}> {
logger(`Sending batch of ${events.length}`);
logger?.(`Sending batch of ${events.length}`);
const requestBody: LogRequest = {
log_source: LOG_SOURCE,
request_time_ms: Date.now().toString(),
@@ -227,7 +227,7 @@ export class ClearcutSender {
return {success: false};
}
logger('Telemetry permanent error:', status);
logger?.('Telemetry permanent error:', status);
return {success: false, isPermanentError: true};
} catch {
clearTimeout(timeoutId);
+5 -5
View File
@@ -100,7 +100,7 @@ function main() {
});
};
logger(
logger?.(
'Watchdog started',
JSON.stringify(
{
@@ -129,15 +129,15 @@ function main() {
}
isShuttingDown = true;
logger(`Parent death detected (${reason}). Sending shutdown event...`);
logger?.(`Parent death detected (${reason}). Sending shutdown event...`);
sender
.sendShutdownEvent()
.then(() => {
logger('Shutdown event sent. Exiting.');
logger?.('Shutdown event sent. Exiting.');
exit(0);
})
.catch(err => {
logger('Failed to send shutdown event', err);
logger?.('Failed to send shutdown event', err);
exit(1);
});
}
@@ -162,7 +162,7 @@ function main() {
sender.enqueueEvent(msg.payload);
}
} catch (err) {
logger('Failed to parse IPC message', err);
logger?.('Failed to parse IPC message', err);
}
});
}
+1 -1
View File
@@ -34,7 +34,7 @@ const submitKeySchema = zod
);
function handleActionError(error: unknown, uid: string) {
logger('failed to act using a locator', error);
logger?.('failed to act using a locator', error);
throw new Error(
`Failed to interact with the element with uid ${uid}. The element did not become interactive within the configured timeout.`,
{
+5 -5
View File
@@ -40,7 +40,7 @@ async function navigateWithInterception(
if (isAllowed) {
void interceptedRequest.continue();
} else {
logger(`Blocking request to: ${requestUrl}`);
logger?.(`Blocking request to: ${requestUrl}`);
void interceptedRequest.abort('blockedbyclient');
}
};
@@ -49,7 +49,7 @@ async function navigateWithInterception(
if (allowList) {
page.pptrPage.off('request', requestHandler);
await page.pptrPage.setRequestInterception(false).catch(error => {
logger(`Failed to disable request interception`, error);
logger?.(`Failed to disable request interception`, error);
});
}
};
@@ -372,7 +372,7 @@ export const navigatePage = definePageTool(args => {
await page.pptrPage
.removeScriptToEvaluateOnNewDocument(initScriptId)
.catch(error => {
logger(`Failed to remove init script`, error);
logger?.(`Failed to remove init script`, error);
});
}
}
@@ -456,7 +456,7 @@ export const handleDialog = definePageTool({
await dialog.accept(request.params.promptText);
} catch (err) {
// Likely already handled by the user outside of MCP.
logger(err);
logger?.(err);
}
response.appendResponseLine('Successfully accepted the dialog');
break;
@@ -466,7 +466,7 @@ export const handleDialog = definePageTool({
await dialog.dismiss();
} catch (err) {
// Likely already handled.
logger(err);
logger?.(err);
}
response.appendResponseLine('Successfully dismissed the dialog');
break;
+4 -4
View File
@@ -234,7 +234,7 @@ async function stopTracingAndAppendOutput(
/** We tell CrUXManager to fetch data so it's available when DevTools.PerformanceTraceFormatter is invoked */
async function populateCruxData(result: TraceResult): Promise<void> {
logger('populateCruxData called');
logger?.('populateCruxData called');
const cruxManager = DevTools.CrUXManager.CrUXManager.instance();
// go/jtfbx. Yes, we're aware this API key is public. ;)
cruxManager.setEndpointForTesting(
@@ -254,17 +254,17 @@ async function populateCruxData(result: TraceResult): Promise<void> {
const urlSet = new Set(urls);
if (urlSet.size === 0) {
logger('No URLs found for CrUX data');
logger?.('No URLs found for CrUX data');
return;
}
logger(
logger?.(
`Fetching CrUX data for ${urlSet.size} URLs: ${Array.from(urlSet).join(', ')}`,
);
const cruxData = await Promise.all(
Array.from(urlSet).map(async url => {
const data = await cruxManager.getFieldDataForPage(url);
logger(`CrUX data for ${url}: ${data ? 'found' : 'not found'}`);
logger?.(`CrUX data for ${url}: ${data ? 'found' : 'not found'}`);
return data;
}),
);
+1 -1
View File
@@ -67,7 +67,7 @@ export async function parseRawTraceBuffer(
};
} catch (e) {
const errorText = e instanceof Error ? e.message : JSON.stringify(e);
logger(`Unexpected error parsing trace: ${errorText}`);
logger?.(`Unexpected error parsing trace: ${errorText}`);
return {
error: errorText,
};
+2
View File
@@ -33,3 +33,5 @@ export interface EmulationSettings {
viewport?: Viewport;
extraHttpHeaders?: Record<string, string>;
}
export type Logger = ((...args: unknown[]) => void) | undefined;