forked from GoogleChrome/lighthouse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
trace.js
133 lines (107 loc) · 4.17 KB
/
trace.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview
* This gatherer collects all network and page devtools protocol traffic during the timespan/navigation.
* This protocol log can be used to recreate the network records using lib/network-recorder.js.
*/
import BaseGatherer from '../base-gatherer.js';
import {TraceProcessor} from '../../lib/tracehouse/trace-processor.js';
class Trace extends BaseGatherer {
/** @type {LH.Trace} */
_trace = {traceEvents: []};
static getDefaultTraceCategories() {
return [
// Exclude default categories. We'll be selective to minimize trace size
'-*',
// Used instead of 'toplevel' in Chrome 71+
'disabled-by-default-lighthouse',
// Used for Cumulative Layout Shift metric
'loading',
// All compile/execute events are captured by parent events in devtools.timeline..
// But the v8 category provides some nice context for only <0.5% of the trace size
'v8',
// Same situation here. This category is there for RunMicrotasks only, but with other teams
// accidentally excluding microtasks, we don't want to assume a parent event will always exist
'v8.execute',
// For extracting UserTiming marks/measures
'blink.user_timing',
// Not mandatory but not used much
'blink.console',
// Most of the events we need are from these two categories
'devtools.timeline',
'disabled-by-default-devtools.timeline',
// Up to 450 (https://goo.gl/rBfhn4) JPGs added to the trace
'disabled-by-default-devtools.screenshot',
// This doesn't add its own events, but adds a `stackTrace` property to devtools.timeline events
'disabled-by-default-devtools.timeline.stack',
// Additional categories used by devtools. Not used by Lighthouse, but included to facilitate
// loading traces from Lighthouse into the Performance panel.
'disabled-by-default-devtools.timeline.frame',
'latencyInfo',
// For CLS root causes.
'disabled-by-default-devtools.timeline.invalidationTracking',
// Not used by Lighthouse (yet) but included for users that want JS samples when looking at
// a trace collected by Lighthouse (e.g. "View Trace" workflow in DevTools)
'disabled-by-default-v8.cpu_profiler',
];
}
/**
* @param {LH.Gatherer.ProtocolSession} session
* @return {Promise<LH.Trace>}
*/
static async endTraceAndCollectEvents(session) {
/** @type {Array<LH.TraceEvent>} */
const traceEvents = [];
/**
* Listener for when dataCollected events fire for each trace chunk
* @param {LH.Crdp.Tracing.DataCollectedEvent} data
*/
const dataListener = function(data) {
traceEvents.push(...data.value);
};
session.on('Tracing.dataCollected', dataListener);
return new Promise((resolve, reject) => {
session.once('Tracing.tracingComplete', _ => {
session.off('Tracing.dataCollected', dataListener);
resolve({traceEvents});
});
session.sendCommand('Tracing.end').catch(reject);
});
}
static symbol = Symbol('Trace');
/** @type {LH.Gatherer.GathererMeta} */
meta = {
symbol: Trace.symbol,
supportedModes: ['timespan', 'navigation'],
};
/**
* @param {LH.Gatherer.Context} passContext
*/
async startSensitiveInstrumentation({driver, gatherMode, settings}) {
const traceCategories = Trace.getDefaultTraceCategories()
.concat(settings.additionalTraceCategories || []);
await driver.defaultSession.sendCommand('Page.enable');
await driver.defaultSession.sendCommand('Tracing.start', {
categories: traceCategories.join(','),
options: 'sampling-frequency=10000', // 1000 is default and too slow.
});
if (gatherMode === 'timespan') {
await driver.defaultSession.sendCommand('Tracing.recordClockSyncMarker',
{syncId: TraceProcessor.TIMESPAN_MARKER_ID});
}
}
/**
* @param {LH.Gatherer.Context} passContext
*/
async stopSensitiveInstrumentation({driver}) {
this._trace = await Trace.endTraceAndCollectEvents(driver.defaultSession);
}
getArtifact() {
return this._trace;
}
}
export default Trace;