Skip to content

Commit b207f89

Browse files
killaguatian25
andauthored
feat: timing support Process Start/Script Start (#222)
* feat: timing support Process Start/Script Start * doc: add timing doc Co-authored-by: TZ | 天猪 <atian25@qq.com>
1 parent 0746ff1 commit b207f89

7 files changed

Lines changed: 156 additions & 56 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ test/fixtures/egg/node_modules/egg-core
1010
.nyc_output
1111
package-lock.json
1212
run
13+
test/fixtures/*/timing.json

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,39 @@ call | `Boolean` | determine whether invoke when exports is funct
235235
inject | `Object` | an object that be the argument when invoke the function
236236
filter | `Function` | a function that filter the exports which can be loaded
237237

238+
## Timing
239+
240+
EggCore record boot progress with `Timing`, include:
241+
- Process start time
242+
- Script start time(node don't implement an interface like `process.uptime` to record the script start running time, framework can implement a prestart file used with node `--require` options to set `process.scriptTime`)
243+
- Application start time
244+
- Load duration
245+
- `require` duration
246+
247+
### start
248+
249+
Start record a item. If the item exits, end the old one and start a new one.
250+
251+
- {String} name - record item name
252+
- {Number} [start] - record item start time, default is Date.now()
253+
254+
### end
255+
256+
End a item.
257+
258+
- {String} name - end item name
259+
260+
### toJSON
261+
262+
Generate all record items to json
263+
264+
- {String} name - record item name
265+
- {Number} start - item start time
266+
- {Number} end - item end time
267+
- {Number} duration - item duration
268+
- {Number} pid - pid
269+
- {Number} index - item index
270+
238271
## Questions & Suggestions
239272

240273
Please open an issue [here](https://github.com/eggjs/egg/issues).

lib/utils/timing.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,26 @@ class Timing {
1111
this._enable = true;
1212
this[MAP] = new Map();
1313
this[LIST] = [];
14+
15+
this.init();
16+
}
17+
18+
init() {
19+
// process start time
20+
this.start('Process Start', Date.now() - Math.floor((process.uptime() * 1000)));
21+
22+
if (typeof process.scriptStartTime === 'number') {
23+
// js script start execute time
24+
this.start('Script Start', process.scriptStartTime);
25+
}
1426
}
1527

16-
start(name) {
28+
start(name, start) {
1729
if (!name || !this._enable) return;
1830

1931
if (this[MAP].has(name)) this.end(name);
2032

21-
const start = Date.now();
33+
start = start || Date.now();
2234
const item = {
2335
name,
2436
start,

test/egg.test.js

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const coffee = require('coffee');
1212
const utils = require('./utils');
1313
const EggCore = require('..').EggCore;
1414
const awaitEvent = require('await-event');
15+
const fs = require('mz/fs');
1516

1617
describe('test/egg.test.js', () => {
1718
afterEach(mm.restore);
@@ -479,47 +480,47 @@ describe('test/egg.test.js', () => {
479480
yield app.ready();
480481

481482
const json = app.timing.toJSON();
482-
assert(json.length === 24);
483+
assert(json.length === 25);
483484

484-
assert(json[0].name === 'Application Start');
485-
assert(json[0].end - json[0].start === json[0].duration);
486-
assert(json[0].pid === process.pid);
485+
assert(json[1].name === 'Application Start');
486+
assert(json[1].end - json[1].start === json[1].duration);
487+
assert(json[1].pid === process.pid);
487488

488489
// loadPlugin
489-
assert(json[1].name === 'Load Plugin');
490+
assert(json[2].name === 'Load Plugin');
490491

491492
// loadConfig
492-
assert(json[2].name === 'Load Config');
493-
assert(json[3].name === 'Require(0) config/config.default.js');
494-
assert(json[5].name === 'Require(2) config/config.default.js');
493+
assert(json[3].name === 'Load Config');
494+
assert(json[4].name === 'Require(0) config/config.default.js');
495+
assert(json[6].name === 'Require(2) config/config.default.js');
495496

496497
// loadExtend
497-
assert(json[7].name === 'Load extend/application.js');
498-
assert(json[9].name === 'Require(5) app/extend/application.js');
498+
assert(json[8].name === 'Load extend/application.js');
499+
assert(json[10].name === 'Require(5) app/extend/application.js');
499500

500501
// loadCustomApp
501-
assert(json[10].name === 'Load app.js');
502-
assert(json[11].name === 'Require(6) app.js');
503-
assert(json[12].name === 'Before Start in app.js:6:9');
504-
assert(json[13].name === 'Load "proxy" to Context');
505-
assert(json[14].name === 'Load Controller');
506-
assert(json[15].name === 'Load "controller" to Application');
502+
assert(json[11].name === 'Load app.js');
503+
assert(json[12].name === 'Require(6) app.js');
504+
assert(json[13].name === 'Before Start in app.js:6:9');
505+
assert(json[14].name === 'Load "proxy" to Context');
506+
assert(json[15].name === 'Load Controller');
507+
assert(json[16].name === 'Load "controller" to Application');
507508

508509
// loadService
509-
assert(json[16].name === 'Load Service');
510-
assert(json[17].name === 'Load "service" to Context');
510+
assert(json[17].name === 'Load Service');
511+
assert(json[18].name === 'Load "service" to Context');
511512

512513
// loadMiddleware
513-
assert(json[18].name === 'Load Middleware');
514-
assert(json[19].name === 'Load "middlewares" to Application');
514+
assert(json[19].name === 'Load Middleware');
515+
assert(json[20].name === 'Load "middlewares" to Application');
515516

516517
// loadController
517-
assert(json[20].name === 'Load Controller');
518-
assert(json[21].name === 'Load "controller" to Application');
518+
assert(json[21].name === 'Load Controller');
519+
assert(json[22].name === 'Load "controller" to Application');
519520

520521
// loadRouter
521-
assert(json[22].name === 'Load Router');
522-
assert(json[23].name === 'Require(7) app/router.js');
522+
assert(json[23].name === 'Load Router');
523+
assert(json[24].name === 'Require(7) app/router.js');
523524
});
524525
});
525526

@@ -533,31 +534,46 @@ describe('test/egg.test.js', () => {
533534
yield app.ready();
534535

535536
const json = app.timing.toJSON();
536-
assert(json.length === 13);
537+
assert(json.length === 14);
537538

538-
assert(json[0].name === 'Application Start');
539-
assert(json[0].end - json[0].start === json[0].duration);
540-
assert(json[0].pid === process.pid);
539+
assert(json[1].name === 'Application Start');
540+
assert(json[1].end - json[1].start === json[1].duration);
541+
assert(json[1].pid === process.pid);
541542

542543
// loadPlugin
543-
assert(json[1].name === 'Load Plugin');
544+
assert(json[2].name === 'Load Plugin');
544545

545546
// loadConfig
546-
assert(json[2].name === 'Load Config');
547-
assert(json[3].name === 'Require(0) config/config.default.js');
548-
assert(json[5].name === 'Require(2) config/config.default.js');
547+
assert(json[3].name === 'Load Config');
548+
assert(json[4].name === 'Require(0) config/config.default.js');
549+
assert(json[6].name === 'Require(2) config/config.default.js');
549550

550551
// loadExtend
551-
assert(json[7].name === 'Load extend/application.js');
552-
assert(json[9].name === 'Require(5) app/extend/application.js');
552+
assert(json[8].name === 'Load extend/application.js');
553+
assert(json[10].name === 'Require(5) app/extend/application.js');
553554

554555
// loadCustomAgent
555-
assert(json[10].name === 'Load agent.js');
556-
assert(json[11].name === 'Require(6) agent.js');
557-
assert(json[12].name === 'Before Start in agent.js:5:11');
556+
assert(json[11].name === 'Load agent.js');
557+
assert(json[12].name === 'Require(6) agent.js');
558+
assert(json[13].name === 'Before Start in agent.js:5:11');
558559
});
559560
});
560561

562+
describe('script timing', () => {
563+
it('should work', async () => {
564+
const fixtureApp = utils.getFilepath('timing');
565+
await coffee.fork(path.join(fixtureApp, 'index.js'))
566+
.beforeScript(path.join(fixtureApp, 'preload'))
567+
.debug()
568+
.expect('code', 0)
569+
.end();
570+
const timingJSON = await fs.readFile(path.join(fixtureApp, 'timing.json'), 'utf8');
571+
const timing = JSON.parse(timingJSON);
572+
const scriptStart = timing.find(item => item.name === 'Script Start');
573+
assert(scriptStart);
574+
assert(scriptStart.start);
575+
});
576+
});
561577
});
562578

563579
describe('boot', () => {

test/fixtures/timing/index.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
6+
const EggApplication = require('../egg').Application;
7+
const utils = require('../../utils');
8+
9+
class Application extends EggApplication {
10+
get [Symbol.for('egg#eggPath')]() {
11+
return __dirname;
12+
}
13+
toJSON() {
14+
return {
15+
name: this.name,
16+
plugins: this.plugins,
17+
config: this.config,
18+
};
19+
}
20+
}
21+
22+
const app = utils.createApp('application', { Application });
23+
app.loader.loadAll();
24+
app.ready(err => {
25+
fs.writeFileSync(path.join(__dirname, 'timing.json'), JSON.stringify(app.timing.toJSON()));
26+
process.exit(err ? 1 : 0);
27+
});

test/fixtures/timing/preload.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
'use strict';
2+
3+
process.scriptStartTime = Date.now();

test/utils/timing.test.js

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,48 +13,48 @@ describe('test/utils/timing.test.js', () => {
1313
timing.end('b');
1414

1515
const json = timing.toJSON();
16-
assert(json.length === 2);
16+
assert(json.length === 3);
1717

18-
assert(json[0].name === 'a');
19-
assert(json[0].end - json[0].start === json[0].duration);
20-
assert(json[0].pid === process.pid);
21-
assert(json[1].name === 'b');
18+
assert(json[1].name === 'a');
2219
assert(json[1].end - json[1].start === json[1].duration);
2320
assert(json[1].pid === process.pid);
21+
assert(json[2].name === 'b');
22+
assert(json[2].end - json[2].start === json[2].duration);
23+
assert(json[2].pid === process.pid);
2424
});
2525

2626
it('should set item when start', () => {
2727
const timing = new Timing();
2828
timing.start('a');
2929

3030
const json = timing.toJSON();
31-
assert(json[0].name === 'a');
32-
assert(json[0].start);
33-
assert(json[0].end === undefined);
34-
assert(json[0].duration === undefined);
31+
assert(json[1].name === 'a');
32+
assert(json[1].start);
33+
assert(json[1].end === undefined);
34+
assert(json[1].duration === undefined);
3535
});
3636

3737
it('should ignore start when name is empty', () => {
3838
const timing = new Timing();
3939
timing.start();
4040

4141
const json = timing.toJSON();
42-
assert(json.length === 0);
42+
assert(json.length === 1);
4343
});
4444

4545
it('should throw when name exists', () => {
4646
const timing = new Timing();
4747
timing.start('a');
48-
assert(timing.toJSON().length === 1);
48+
assert(timing.toJSON().length === 2);
4949

5050
timing.start('a');
51-
assert(timing.toJSON().length === 2);
51+
assert(timing.toJSON().length === 3);
5252
});
5353

5454
it('should ignore end when name dont exist', () => {
5555
const timing = new Timing();
5656
timing.end();
57-
assert(timing.toJSON().length === 0);
57+
assert(timing.toJSON().length === 1);
5858
});
5959

6060
it('should enable/disable', () => {
@@ -74,9 +74,9 @@ describe('test/utils/timing.test.js', () => {
7474

7575
const json = timing.toJSON();
7676

77-
assert(json[0].name === 'a');
78-
assert(json[1].name === 'c');
79-
assert(json.length === 2);
77+
assert(json[1].name === 'a');
78+
assert(json[2].name === 'c');
79+
assert(json.length === 3);
8080
});
8181

8282
it('should clear', () => {
@@ -85,7 +85,7 @@ describe('test/utils/timing.test.js', () => {
8585
timing.end('a');
8686

8787
const json = timing.toJSON();
88-
assert(json[0].name === 'a');
88+
assert(json[1].name === 'a');
8989

9090
timing.clear();
9191

@@ -105,4 +105,12 @@ describe('test/utils/timing.test.js', () => {
105105
timing.end('a');
106106
}, /should run timing.start\('a'\) first/);
107107
});
108+
109+
it('should init process start time', () => {
110+
const timing = new Timing();
111+
112+
const processStart = timing.toJSON().find(item => item.name === 'Process Start');
113+
assert(processStart);
114+
assert(processStart.start);
115+
});
108116
});

0 commit comments

Comments
 (0)