chore: flush har when recording tracing (#26746)

This commit is contained in:
Pavel Feldman 2023-08-28 17:44:48 -07:00 committed by GitHub
parent 4bbd16d316
commit 99b8ca2be2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 8 deletions

View File

@ -20,6 +20,7 @@ import { Artifact } from '../artifact';
import type { BrowserContext } from '../browserContext';
import type * as har from '@trace/har';
import { HarTracer } from './harTracer';
import type { HarTracerDelegate } from './harTracer';
import type * as channels from '@protocol/channels';
import { yazl } from '../../zipBundle';
import type { ZipFile } from '../../zipBundle';
@ -28,7 +29,7 @@ import type EventEmitter from 'events';
import { createGuid } from '../../utils';
import type { Page } from '../page';
export class HarRecorder {
export class HarRecorder implements HarTracerDelegate {
private _artifact: Artifact;
private _isFlushed: boolean = false;
private _tracer: HarTracer;

View File

@ -182,13 +182,7 @@ export class HarTracer {
return null;
if (!this._options.waitForContentOnStop)
return;
const race = Promise.race([
new Promise<void>(f => target.on('close', () => {
this._barrierPromises.delete(race);
f();
})),
promise
]) as Promise<void>;
const race = target.openScope.safeRace(promise);
this._barrierPromises.add(race);
race.then(() => this._barrierPromises.delete(race));
}

View File

@ -141,6 +141,7 @@ export class Page extends SdkObject {
private _eventsToEmitAfterInitialized: { event: string | symbol, args: any[] }[] = [];
readonly _disconnectedScope = new LongStandingScope();
readonly _crashedScope = new LongStandingScope();
readonly openScope = new LongStandingScope();
readonly _browserContext: BrowserContext;
readonly keyboard: input.Keyboard;
readonly mouse: input.Mouse;
@ -276,6 +277,7 @@ export class Page extends SdkObject {
this.emit(Page.Events.Close);
this._closedPromise.resolve();
this.instrumentation.onPageClose(this);
this.openScope.close('Page closed');
}
_didCrash() {
@ -284,6 +286,7 @@ export class Page extends SdkObject {
this.emit(Page.Events.Crash);
this._crashedScope.close('Page crashed');
this.instrumentation.onPageClose(this);
this.openScope.close('Page closed');
}
_didDisconnect() {
@ -292,6 +295,7 @@ export class Page extends SdkObject {
assert(!this._disconnected, 'Page disconnected twice');
this._disconnected = true;
this._disconnectedScope.close('Page closed');
this.openScope.close('Page closed');
}
async _onFileChooserOpened(handle: dom.ElementHandle) {
@ -711,6 +715,7 @@ export class Worker extends SdkObject {
private _executionContextPromise: Promise<js.ExecutionContext>;
private _executionContextCallback: (value: js.ExecutionContext) => void;
_existingExecutionContext: js.ExecutionContext | null = null;
readonly openScope = new LongStandingScope();
constructor(parent: SdkObject, url: string) {
super(parent, 'worker');
@ -732,6 +737,7 @@ export class Worker extends SdkObject {
if (this._existingExecutionContext)
this._existingExecutionContext.contextDestroyed('Worker was closed');
this.emit(Worker.Events.Close, this);
this.openScope.close('Worker closed');
}
async evaluateExpression(expression: string, isFunction: boolean | undefined, arg: any): Promise<any> {

View File

@ -82,6 +82,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
private _tracesTmpDir: string | undefined;
private _allResources = new Set<string>();
private _contextCreatedEvent: trace.ContextCreatedTraceEvent;
private _pendingHarEntries = new Set<har.Entry>();
constructor(context: BrowserContext | APIRequestContext, tracesDir: string | undefined) {
super(context, 'tracing');
@ -230,6 +231,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
if (this._state.recording)
throw new Error(`Must stop trace file before stopping tracing`);
this._harTracer.stop();
this.flushHarEntries();
await this._fs.syncAndGetError();
this._state = undefined;
}
@ -272,6 +274,8 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
if (this._state.options.snapshots)
await this._snapshotter?.stop();
this.flushHarEntries();
// Network file survives across chunks, make a snapshot before returning the resulting entries.
// We should pick a name starting with "traceName" and ending with .network.
// Something like <traceName>someSuffixHere.network.
@ -387,14 +391,28 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps
}
onEntryStarted(entry: har.Entry) {
this._pendingHarEntries.add(entry);
}
onEntryFinished(entry: har.Entry) {
this._pendingHarEntries.delete(entry);
const event: trace.ResourceSnapshotTraceEvent = { type: 'resource-snapshot', snapshot: entry };
const visited = visitTraceEvent(event, this._state!.networkSha1s);
this._fs.appendFile(this._state!.networkFile, JSON.stringify(visited) + '\n', true /* flush */);
}
flushHarEntries() {
const harLines: string[] = [];
for (const entry of this._pendingHarEntries) {
const event: trace.ResourceSnapshotTraceEvent = { type: 'resource-snapshot', snapshot: entry };
const visited = visitTraceEvent(event, this._state!.networkSha1s);
harLines.push(JSON.stringify(visited));
}
this._pendingHarEntries.clear();
if (harLines.length)
this._fs.appendFile(this._state!.networkFile, harLines.join('\n') + '\n', true /* flush */);
}
onContentBlob(sha1: string, buffer: Buffer) {
this._appendResource(sha1, buffer);
}