Skip to content

Commit 5b7af12

Browse files
authoredJan 13, 2023
feat: support show app.timing in timline string (#260)
```bash egg start timeline: ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ [289ms] - #0 Process Start ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ [510ms] - #1 Application Start ▇ [2ms] - #2 Load Plugin ▇ [1ms] - #3 Load Config ▇ [0ms] - #4 Require(0) ~/eggjs/egg-core/test/fixtures/egg/config/config.default.js ▇ [0ms] - #5 Require(1) ~/eggjs/egg-core/test/fixtures/egg/config/config.unittest.js ▇ [0ms] - #6 Load extend/application.js ▇ [0ms] - #7 Require(2) ~/eggjs/egg-core/test/fixtures/egg/app/extend/application.js ▇ [1ms] - #8 Load extend/context.js ▇ [0ms] - #9 Load extend/request.js ▇ [0ms] - #10 Load extend/response.js ▇ [1ms] - #11 Load app.js ▇ [0ms] - #12 Require(3) ~/eggjs/egg-core/test/fixtures/egg/node_modules/session/app.js ▇ [0ms] - #13 Require(4) app.js ▇▇▇▇▇▇ [101ms] - #14 readyCallback in a ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ [501ms] - #15 readyCallback in b ▇ [4ms] - #16 Load Middleware ▇ [4ms] - #17 Load "middlewares" to Application ▇ [2ms] - #18 Load Service ▇ [2ms] - #19 Load "service" to Context ▇ [0ms] - #20 Load Controller ▇ [0ms] - #21 Load "controller" to Application ▇ [0ms] - #22 Load Router ```
1 parent 9a4553d commit 5b7af12

File tree

4 files changed

+50
-4
lines changed

4 files changed

+50
-4
lines changed
 

‎lib/utils/timing.js

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
'use strict';
22

3+
const { EOL } = require('os');
34
const assert = require('assert');
5+
46
const MAP = Symbol('Timing#map');
57
const LIST = Symbol('Timing#list');
68

79
class Timing {
8-
910
constructor() {
1011
this._enable = true;
12+
this._start = null;
1113
this[MAP] = new Map();
1214
this[LIST] = [];
1315

@@ -16,7 +18,7 @@ class Timing {
1618

1719
init() {
1820
// process start time
19-
this.start('Process Start', Date.now() - Math.floor((process.uptime() * 1000)));
21+
this.start('Process Start', Date.now() - Math.floor(process.uptime() * 1000));
2022
this.end('Process Start');
2123

2224
if (typeof process.scriptStartTime === 'number') {
@@ -32,6 +34,9 @@ class Timing {
3234
if (this[MAP].has(name)) this.end(name);
3335

3436
start = start || Date.now();
37+
if (this._start === null) {
38+
this._start = start;
39+
}
3540
const item = {
3641
name,
3742
start,
@@ -71,6 +76,29 @@ class Timing {
7176
toJSON() {
7277
return this[LIST];
7378
}
79+
80+
itemToString(timelineEnd, item, times) {
81+
const isEnd = typeof item.duration === 'number';
82+
const duration = isEnd ? item.duration : timelineEnd - item.start;
83+
const offset = item.start - this._start;
84+
const status = `${duration}ms${isEnd ? '' : ' NOT_END'}`;
85+
const timespan = Math.floor((offset * times).toFixed(6));
86+
let timeline = Math.floor((duration * times).toFixed(6));
87+
timeline = timeline > 0 ? timeline : 1; // make sure there is at least one unit
88+
const message = `#${item.index} ${item.name}`;
89+
return ' '.repeat(timespan) + '▇'.repeat(timeline) + ` [${status}] - ${message}`;
90+
}
91+
92+
toString(prefix = 'egg start timeline:', width = 50) {
93+
const timelineEnd = Date.now();
94+
const timelineDuration = timelineEnd - this._start;
95+
let times = 1;
96+
if (timelineDuration > width) {
97+
times = width / timelineDuration;
98+
}
99+
// follow https://github.com/node-modules/time-profile/blob/master/lib/profiler.js#L88
100+
return prefix + EOL + this[LIST].map(item => this.itemToString(timelineEnd, item, times)).join(EOL);
101+
}
74102
}
75103

76104
module.exports = Timing;

‎package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"lint": "eslint .",
1414
"test": "npm run lint -- --fix && npm run test-local",
1515
"test-local": "egg-bin test -p",
16+
"test-single": "egg-bin test",
1617
"cov": "egg-bin cov -p",
1718
"ci": "npm run lint && npm run cov",
1819
"contributor": "git-contributor"
@@ -58,7 +59,7 @@
5859
"co": "^4.6.0",
5960
"debug": "^4.1.1",
6061
"depd": "^2.0.0",
61-
"egg-logger": "^2.4.1",
62+
"egg-logger": "^3.1.0",
6263
"egg-path-matching": "^1.0.1",
6364
"extend2": "^1.0.0",
6465
"get-ready": "^2.0.1",

‎test/egg.test.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,15 @@ describe('test/egg.test.js', () => {
149149
assert(message === '[egg:core:ready_timeout] %s seconds later %s was still unable to finish.');
150150
assert(b === 10);
151151
assert(a === 'a');
152+
console.log(app.timing.toString());
152153
done();
153154
});
154155
app.ready(() => {
155156
throw new Error('should not be called');
156157
});
157158
});
158159

159-
it('should log info when plugin is not ready', done => {
160+
it('should log info when plugin is ready', done => {
160161
app = utils.createApp('ready');
161162
app.loader.loadAll();
162163
let message = '';
@@ -166,6 +167,7 @@ describe('test/egg.test.js', () => {
166167
app.ready(() => {
167168
assert(/\[egg:core:ready_stat] end ready task a, remain \["b"]/.test(message));
168169
assert(/\[egg:core:ready_stat] end ready task b, remain \[]/.test(message));
170+
console.log(app.timing.toString());
169171
done();
170172
});
171173
});
@@ -206,6 +208,9 @@ describe('test/egg.test.js', () => {
206208
assert(app.beforeStartFunction === false);
207209
await app.ready();
208210
assert(app.beforeStartFunction === true);
211+
const timeline = app.timing.toString();
212+
console.log(timeline);
213+
assert.match(timeline, /#14 Before Start in app.js:3:7/);
209214
});
210215

211216
it('should beforeStart excute timeout without EGG_READY_TIMEOUT_ENV too short', function(done) {
@@ -215,6 +220,10 @@ describe('test/egg.test.js', () => {
215220
app.once('ready_timeout', id => {
216221
const file = path.normalize('test/fixtures/beforestart-with-timeout-env/app.js');
217222
assert(id.includes(file));
223+
const timeline = app.timing.toString();
224+
console.log(timeline);
225+
assert.match(timeline, / \[\d+ms NOT_END] - #1 Application Start/);
226+
assert.match(timeline, / \[\d+ms NOT_END] - #14 Before Start in app.js:3:7/);
218227
done();
219228
});
220229
});
@@ -224,6 +233,7 @@ describe('test/egg.test.js', () => {
224233
app.loader.loadAll();
225234
app.once('error', err => {
226235
assert(err.message === 'not ready');
236+
console.log(app.timing.toString());
227237
done();
228238
});
229239
});
@@ -236,6 +246,7 @@ describe('test/egg.test.js', () => {
236246
throw new Error('should not run');
237247
} catch (err) {
238248
assert(err.message === 'not ready');
249+
console.log(app.timing.toString());
239250
}
240251
});
241252

@@ -760,6 +771,9 @@ describe('test/egg.test.js', () => {
760771
'didReady',
761772
'beforeClose',
762773
]);
774+
console.log(app.timing.toString());
775+
assert.match(app.timing.toString(), /egg start timeline:/);
776+
assert.match(app.timing.toString(), /#1 Application Start/);
763777
});
764778
});
765779

‎test/utils/timing.test.js

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ describe('test/utils/timing.test.js', () => {
2121
assert(json[2].name === 'b');
2222
assert(json[2].end - json[2].start === json[2].duration);
2323
assert(json[2].pid === process.pid);
24+
25+
timing.start('c');
26+
console.log(timing.toString());
2427
});
2528

2629
it('should set item when start', () => {

0 commit comments

Comments
 (0)