UNPKG

4.81 kBJavaScriptView Raw
1/**
2 * Copyright 2017 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16const {helper, assert} = require('./helper');
17const fs = require('fs');
18
19const openAsync = helper.promisify(fs.open);
20const writeAsync = helper.promisify(fs.write);
21const closeAsync = helper.promisify(fs.close);
22
23class Tracing {
24 /**
25 * @param {!Puppeteer.CDPSession} client
26 */
27 constructor(client) {
28 this._client = client;
29 this._recording = false;
30 this._path = '';
31 }
32
33 /**
34 * @param {!Object} options
35 */
36 /* async */ start(options) {return (fn => {
37 const gen = fn.call(this);
38 return new Promise((resolve, reject) => {
39 function step(key, arg) {
40 let info, value;
41 try {
42 info = gen[key](arg);
43 value = info.value;
44 } catch (error) {
45 reject(error);
46 return;
47 }
48 if (info.done) {
49 resolve(value);
50 } else {
51 return Promise.resolve(value).then(
52 value => {
53 step('next', value);
54 },
55 err => {
56 step('throw', err);
57 });
58 }
59 }
60 return step('next');
61 });
62})(function*(){
63 assert(!this._recording, 'Cannot start recording trace while already recording trace.');
64
65 const defaultCategories = [
66 '-*', 'devtools.timeline', 'v8.execute', 'disabled-by-default-devtools.timeline',
67 'disabled-by-default-devtools.timeline.frame', 'toplevel',
68 'blink.console', 'blink.user_timing', 'latencyInfo', 'disabled-by-default-devtools.timeline.stack',
69 'disabled-by-default-v8.cpu_profiler', 'disabled-by-default-v8.cpu_profiler.hires'
70 ];
71 const categoriesArray = options.categories || defaultCategories;
72
73 if (options.screenshots)
74 categoriesArray.push('disabled-by-default-devtools.screenshot');
75
76 this._path = options.path;
77 this._recording = true;
78 (yield this._client.send('Tracing.start', {
79 transferMode: 'ReturnAsStream',
80 categories: categoriesArray.join(',')
81 }));
82 });}
83
84 /* async */ stop() {return (fn => {
85 const gen = fn.call(this);
86 return new Promise((resolve, reject) => {
87 function step(key, arg) {
88 let info, value;
89 try {
90 info = gen[key](arg);
91 value = info.value;
92 } catch (error) {
93 reject(error);
94 return;
95 }
96 if (info.done) {
97 resolve(value);
98 } else {
99 return Promise.resolve(value).then(
100 value => {
101 step('next', value);
102 },
103 err => {
104 step('throw', err);
105 });
106 }
107 }
108 return step('next');
109 });
110})(function*(){
111 let fulfill;
112 const contentPromise = new Promise(x => fulfill = x);
113 this._client.once('Tracing.tracingComplete', event => {
114 this._readStream(event.stream, this._path).then(fulfill);
115 });
116 (yield this._client.send('Tracing.end'));
117 this._recording = false;
118 return contentPromise;
119 });}
120
121 /**
122 * @param {string} handle
123 * @param {string} path
124 */
125 /* async */ _readStream(handle, path) {return (fn => {
126 const gen = fn.call(this);
127 return new Promise((resolve, reject) => {
128 function step(key, arg) {
129 let info, value;
130 try {
131 info = gen[key](arg);
132 value = info.value;
133 } catch (error) {
134 reject(error);
135 return;
136 }
137 if (info.done) {
138 resolve(value);
139 } else {
140 return Promise.resolve(value).then(
141 value => {
142 step('next', value);
143 },
144 err => {
145 step('throw', err);
146 });
147 }
148 }
149 return step('next');
150 });
151})(function*(){
152 let eof = false;
153 let file;
154 if (path)
155 file = (yield openAsync(path, 'w'));
156 const bufs = [];
157 while (!eof) {
158 const response = (yield this._client.send('IO.read', {handle}));
159 eof = response.eof;
160 bufs.push(Buffer.from(response.data));
161 if (path)
162 (yield writeAsync(file, response.data));
163 }
164 if (path)
165 (yield closeAsync(file));
166 (yield this._client.send('IO.close', {handle}));
167 let resultBuffer = null;
168 try {
169 resultBuffer = Buffer.concat(bufs);
170 } finally {
171 return resultBuffer;
172 }
173 });}
174}
175helper.tracePublicAPI(Tracing);
176
177module.exports = Tracing;