Skip to content

Commit ed619b6

Browse files
authored
cherry-pick(#27162): fix(tracing): bump trace version to V5, migrate V4 traces to consoleMessage.args (#27193)
This moves the fix in #27095 from `modernize` to `appendEvent`. The reason is that `trace V4` is used both for older traces that do not have `consoleMessage.args` and the new ones with `args`. Since we do not call `modernize` for traces of the same version, the original fix does not help in this case. Fixes #27144.
1 parent abf9df3 commit ed619b6

File tree

11 files changed

+341
-92
lines changed

11 files changed

+341
-92
lines changed

packages/playwright-core/src/server/trace/recorder/tracing.ts

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import { Snapshotter } from './snapshotter';
4343
import { yazl } from '../../../zipBundle';
4444
import type { ConsoleMessage } from '../../console';
4545

46-
const version: trace.VERSION = 4;
46+
const version: trace.VERSION = 5;
4747

4848
export type TracerOptions = {
4949
name?: string;
@@ -429,24 +429,12 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
429429
}
430430

431431
private _onConsoleMessage(message: ConsoleMessage) {
432-
const object: trace.ConsoleMessageTraceEvent = {
433-
type: 'object',
434-
class: 'ConsoleMessage',
435-
guid: message.guid,
436-
initializer: {
437-
type: message.type(),
438-
text: message.text(),
439-
args: message.args().map(a => ({ preview: a.toString(), value: a.rawValue() })),
440-
location: message.location(),
441-
},
442-
};
443-
this._appendTraceEvent(object);
444-
445-
const event: trace.EventTraceEvent = {
446-
type: 'event',
447-
class: 'BrowserContext',
448-
method: 'console',
449-
params: { message: { guid: message.guid } },
432+
const event: trace.ConsoleMessageTraceEvent = {
433+
type: 'console',
434+
messageType: message.type(),
435+
text: message.text(),
436+
args: message.args().map(a => ({ preview: a.toString(), value: a.rawValue() })),
437+
location: message.location(),
450438
time: monotonicTime(),
451439
pageId: message.page().guid,
452440
};
@@ -478,7 +466,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
478466
private _appendTraceEvent(event: trace.TraceEvent) {
479467
const visited = visitTraceEvent(event, this._state!.traceSha1s);
480468
// Do not flush (console) events, they are too noisy, unless we are in ui mode (live).
481-
const flush = this._state!.options.live || (event.type !== 'event' && event.type !== 'object');
469+
const flush = this._state!.options.live || (event.type !== 'event' && event.type !== 'console');
482470
this._fs.appendFile(this._state!.traceFile, JSON.stringify(visited) + '\n', flush);
483471
}
484472

packages/trace-viewer/src/entries.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,8 @@ export type ContextEntry = {
3434
pages: PageEntry[];
3535
resources: ResourceSnapshot[];
3636
actions: trace.ActionTraceEvent[];
37-
events: trace.EventTraceEvent[];
37+
events: (trace.EventTraceEvent | trace.ConsoleMessageTraceEvent)[];
3838
stdio: trace.StdioTraceEvent[];
39-
initializers: { [key: string]: trace.ConsoleMessageTraceEvent['initializer'] };
4039
hasSource: boolean;
4140
};
4241

@@ -65,7 +64,6 @@ export function createEmptyContext(): ContextEntry {
6564
actions: [],
6665
events: [],
6766
stdio: [],
68-
initializers: {},
6967
hasSource: false
7068
};
7169
}

packages/trace-viewer/src/traceModel.ts

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import type * as trace from '@trace/trace';
1818
import type * as traceV3 from './versions/traceV3';
19+
import type * as traceV4 from './versions/traceV4';
1920
import { parseClientSideCallMetadata } from '../../../packages/playwright-core/src/utils/isomorphic/traceUtils';
2021
import type { ContextEntry, PageEntry } from './entries';
2122
import { createEmptyContext } from './entries';
@@ -39,6 +40,7 @@ export class TraceModel {
3940
private _attachments = new Map<string, trace.AfterActionTraceEventAttachment>();
4041
private _resourceToContentType = new Map<string, string>();
4142
private _jsHandles = new Map<string, { preview: string }>();
43+
private _consoleObjects = new Map<string, { type: string, text: string, location: { url: string, lineNumber: number, columnNumber: number }, args?: { preview: string, value: string }[] }>();
4244

4345
constructor() {
4446
}
@@ -114,6 +116,7 @@ export class TraceModel {
114116

115117
this._snapshotStorage!.finalize();
116118
this._jsHandles.clear();
119+
this._consoleObjects.clear();
117120
}
118121

119122
async hasEntry(filename: string): Promise<boolean> {
@@ -209,8 +212,8 @@ export class TraceModel {
209212
contextEntry!.stdio.push(event);
210213
break;
211214
}
212-
case 'object': {
213-
contextEntry!.initializers[event.guid] = event.initializer;
215+
case 'console': {
216+
contextEntry!.events.push(event);
214217
break;
215218
}
216219
case 'resource-snapshot':
@@ -235,12 +238,15 @@ export class TraceModel {
235238
}
236239
}
237240

238-
private _modernize(event: any): trace.TraceEvent {
241+
private _modernize(event: any): trace.TraceEvent | null {
239242
if (this._version === undefined)
240243
return event;
241-
const lastVersion: trace.VERSION = 4;
242-
for (let version = this._version; version < lastVersion; ++version)
244+
const lastVersion: trace.VERSION = 5;
245+
for (let version = this._version; version < lastVersion; ++version) {
243246
event = (this as any)[`_modernize_${version}_to_${version + 1}`].call(this, event);
247+
if (!event)
248+
return null;
249+
}
244250
return event;
245251
}
246252

@@ -286,7 +292,7 @@ export class TraceModel {
286292
return event;
287293
}
288294

289-
_modernize_3_to_4(event: traceV3.TraceEvent): trace.TraceEvent | null {
295+
_modernize_3_to_4(event: traceV3.TraceEvent): traceV4.TraceEvent | null {
290296
if (event.type !== 'action' && event.type !== 'event') {
291297
return event as traceV3.ContextCreatedTraceEvent |
292298
traceV3.ScreencastFrameTraceEvent |
@@ -299,23 +305,12 @@ export class TraceModel {
299305
return null;
300306

301307
if (event.type === 'event') {
302-
if (metadata.method === '__create__' && metadata.type === 'JSHandle')
303-
this._jsHandles.set(metadata.params.guid, metadata.params.initializer);
304308
if (metadata.method === '__create__' && metadata.type === 'ConsoleMessage') {
305309
return {
306310
type: 'object',
307311
class: metadata.type,
308312
guid: metadata.params.guid,
309-
initializer: {
310-
...metadata.params.initializer,
311-
args: metadata.params.initializer.args?.map((arg: any) => {
312-
if (arg.guid) {
313-
const handle = this._jsHandles.get(arg.guid);
314-
return { preview: handle?.preview || '', value: '' };
315-
}
316-
return { preview: '', value: '' };
317-
})
318-
},
313+
initializer: metadata.params.initializer,
319314
};
320315
}
321316
return {
@@ -348,6 +343,47 @@ export class TraceModel {
348343
pageId: metadata.pageId,
349344
};
350345
}
346+
347+
_modernize_4_to_5(event: traceV4.TraceEvent): trace.TraceEvent | null {
348+
if (event.type === 'event' && event.method === '__create__' && event.class === 'JSHandle')
349+
this._jsHandles.set(event.params.guid, event.params.initializer);
350+
if (event.type === 'object') {
351+
// We do not expect any other 'object' events.
352+
if (event.class !== 'ConsoleMessage')
353+
return null;
354+
// Older traces might have `args` inherited from the protocol initializer - guid of JSHandle,
355+
// but might also have modern `args` with preview and value.
356+
const args: { preview: string, value: string }[] = (event.initializer as any).args?.map((arg: any) => {
357+
if (arg.guid) {
358+
const handle = this._jsHandles.get(arg.guid);
359+
return { preview: handle?.preview || '', value: '' };
360+
}
361+
return { preview: arg.preview || '', value: arg.value || '' };
362+
});
363+
this._consoleObjects.set(event.guid, {
364+
type: event.initializer.type,
365+
text: event.initializer.text,
366+
location: event.initializer.location,
367+
args,
368+
});
369+
return null;
370+
}
371+
if (event.type === 'event' && event.method === 'console') {
372+
const consoleMessage = this._consoleObjects.get(event.params.message?.guid || '');
373+
if (!consoleMessage)
374+
return null;
375+
return {
376+
type: 'console',
377+
time: event.time,
378+
pageId: event.pageId,
379+
messageType: consoleMessage.type,
380+
text: consoleMessage.text,
381+
args: consoleMessage.args,
382+
location: consoleMessage.location,
383+
};
384+
}
385+
return event;
386+
}
351387
}
352388

353389
function stripEncodingFromContentType(contentType: string) {

packages/trace-viewer/src/ui/consoleTab.tsx

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import type * as channels from '@protocol/channels';
1818
import * as React from 'react';
1919
import './consoleTab.css';
20-
import * as modelUtil from './modelUtil';
20+
import type * as modelUtil from './modelUtil';
2121
import { ListView } from '@web/components/listView';
2222
import type { Boundaries } from '../geometry';
2323
import { msToString } from '@web/uiUtils';
@@ -51,29 +51,23 @@ export function useConsoleTabModel(model: modelUtil.MultiTraceModel | undefined,
5151
return { entries: [] };
5252
const entries: ConsoleEntry[] = [];
5353
for (const event of model.events) {
54-
if (event.method !== 'console' && event.method !== 'pageError')
55-
continue;
56-
if (event.method === 'console') {
57-
const { guid } = event.params.message;
58-
const browserMessage = modelUtil.context(event).initializers[guid];
59-
if (browserMessage) {
60-
const body = browserMessage.args && browserMessage.args.length ? format(browserMessage.args) : formatAnsi(browserMessage.text);
61-
const url = browserMessage.location.url;
62-
const filename = url ? url.substring(url.lastIndexOf('/') + 1) : '<anonymous>';
63-
const location = `${filename}:${browserMessage.location.lineNumber}`;
64-
65-
entries.push({
66-
browserMessage: {
67-
body,
68-
location,
69-
},
70-
isError: modelUtil.context(event).initializers[guid]?.type === 'error',
71-
isWarning: modelUtil.context(event).initializers[guid]?.type === 'warning',
72-
timestamp: event.time,
73-
});
74-
}
54+
if (event.type === 'console') {
55+
const body = event.args && event.args.length ? format(event.args) : formatAnsi(event.text);
56+
const url = event.location.url;
57+
const filename = url ? url.substring(url.lastIndexOf('/') + 1) : '<anonymous>';
58+
const location = `${filename}:${event.location.lineNumber}`;
59+
60+
entries.push({
61+
browserMessage: {
62+
body,
63+
location,
64+
},
65+
isError: event.messageType === 'error',
66+
isWarning: event.messageType === 'warning',
67+
timestamp: event.time,
68+
});
7569
}
76-
if (event.method === 'pageError') {
70+
if (event.type === 'event' && event.method === 'pageError') {
7771
entries.push({
7872
browserError: event.params.error,
7973
isError: true,

packages/trace-viewer/src/ui/modelUtil.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import type { Language } from '@isomorphic/locatorGenerators';
1818
import type { ResourceSnapshot } from '@trace/snapshot';
1919
import type * as trace from '@trace/trace';
20-
import type { ActionTraceEvent, EventTraceEvent } from '@trace/trace';
20+
import type { ActionTraceEvent } from '@trace/trace';
2121
import type { ContextEntry, PageEntry } from '../entries';
2222

2323
const contextSymbol = Symbol('context');
@@ -58,7 +58,7 @@ export class MultiTraceModel {
5858
readonly options: trace.BrowserContextEventOptions;
5959
readonly pages: PageEntry[];
6060
readonly actions: ActionTraceEventInContext[];
61-
readonly events: trace.EventTraceEvent[];
61+
readonly events: (trace.EventTraceEvent | trace.ConsoleMessageTraceEvent)[];
6262
readonly stdio: trace.StdioTraceEvent[];
6363
readonly hasSource: boolean;
6464
readonly sdkLanguage: Language | undefined;
@@ -83,7 +83,7 @@ export class MultiTraceModel {
8383
this.endTime = contexts.map(c => c.endTime).reduce((prev, cur) => Math.max(prev, cur), Number.MIN_VALUE);
8484
this.pages = ([] as PageEntry[]).concat(...contexts.map(c => c.pages));
8585
this.actions = mergeActions(contexts);
86-
this.events = ([] as EventTraceEvent[]).concat(...contexts.map(c => c.events));
86+
this.events = ([] as (trace.EventTraceEvent | trace.ConsoleMessageTraceEvent)[]).concat(...contexts.map(c => c.events));
8787
this.stdio = ([] as trace.StdioTraceEvent[]).concat(...contexts.map(c => c.stdio));
8888
this.hasSource = contexts.some(c => c.hasSource);
8989
this.resources = [...contexts.map(c => c.resources)].flat();
@@ -203,7 +203,7 @@ export function idForAction(action: ActionTraceEvent) {
203203
return `${action.pageId || 'none'}:${action.callId}`;
204204
}
205205

206-
export function context(action: ActionTraceEvent | EventTraceEvent): ContextEntry {
206+
export function context(action: ActionTraceEvent | trace.EventTraceEvent): ContextEntry {
207207
return (action as any)[contextSymbol];
208208
}
209209

@@ -218,24 +218,22 @@ export function prevInList(action: ActionTraceEvent): ActionTraceEvent {
218218
export function stats(action: ActionTraceEvent): { errors: number, warnings: number } {
219219
let errors = 0;
220220
let warnings = 0;
221-
const c = context(action);
222221
for (const event of eventsForAction(action)) {
223-
if (event.method === 'console') {
224-
const { guid } = event.params.message;
225-
const type = c.initializers[guid]?.type;
222+
if (event.type === 'console') {
223+
const type = event.messageType;
226224
if (type === 'warning')
227225
++warnings;
228226
else if (type === 'error')
229227
++errors;
230228
}
231-
if (event.method === 'pageError')
229+
if (event.type === 'event' && event.method === 'pageError')
232230
++errors;
233231
}
234232
return { errors, warnings };
235233
}
236234

237-
export function eventsForAction(action: ActionTraceEvent): EventTraceEvent[] {
238-
let result: EventTraceEvent[] = (action as any)[eventsSymbol];
235+
export function eventsForAction(action: ActionTraceEvent): (trace.EventTraceEvent | trace.ConsoleMessageTraceEvent)[] {
236+
let result: (trace.EventTraceEvent | trace.ConsoleMessageTraceEvent)[] = (action as any)[eventsSymbol];
239237
if (result)
240238
return result;
241239

0 commit comments

Comments
 (0)