Skip to content

Commit cf7dbd8

Browse files
refactor(@embark/core): refactor logger to provide correct origins
Also make a few more revisions: Revise the "write logs" testing strategy such that it's not necessary for the logger functions to take an optional callback. Drop unused `tmp` package from `packages/core/logger` since it's not used in the tests. Strip colors before writing to the log file, use a two-space delimiter between sections of each logged line in the log file, and collapse whitespace in the message section of each line. These changes make the log file more amenable to being processed with cli tools such as awk, cut, etc. It's also possible in a text editor to replace `' '` with `\t` and the load the file in a spreadsheet, with each line-section in its own column. Rearrange the sections of each logged line so that it's easier to read, and only include the origin if the loglevel is debug or trace.
1 parent 337133a commit cf7dbd8

File tree

4 files changed

+153
-99
lines changed

4 files changed

+153
-99
lines changed

packages/core/logger/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
"@babel/runtime-corejs3": "7.8.3",
5050
"colors": "1.4.0",
5151
"core-js": "3.6.4",
52-
"date-and-time": "0.12.0"
52+
"date-and-time": "0.12.0",
53+
"fs-extra": "8.1.0"
5354
},
5455
"devDependencies": {
5556
"@babel/core": "7.7.7",
@@ -59,8 +60,7 @@
5960
"eslint": "6.8.0",
6061
"jest": "24.9.0",
6162
"npm-run-all": "4.1.5",
62-
"rimraf": "3.0.0",
63-
"tmp": "0.1.0"
63+
"rimraf": "3.0.0"
6464
},
6565
"engines": {
6666
"node": ">=10.17.0",

packages/core/logger/src/index.js

Lines changed: 110 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
const async = require('async');
22
require('colors');
3-
const fs = require('fs');
3+
const fs = require('fs-extra');
44
const date = require('date-and-time');
55
const { escapeHtml } = require('./utils');
66
const util = require('util');
77

88
const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss:SSS';
9+
const DELIM = ' ';
910

1011
export const LogLevels = {
1112
error: 'error',
@@ -21,28 +22,45 @@ export class Logger {
2122
this.logLevel = options.logLevel || 'info';
2223
this._logFunction = options.logFunction || console.log;
2324
this.fs = options.fs || fs;
24-
this.logFunction = function(...args) {
25-
const color = args[args.length - 1];
26-
args.splice(args.length - 1, 1);
27-
this._logFunction(...args.filter(arg => arg ?? false).map(arg => {
28-
if (color) {
29-
return typeof arg === 'object' ? util.inspect(arg, 2)[color] : arg[color];
30-
}
31-
return typeof arg === 'object' ? util.inspect(arg, 2) : arg;
32-
}));
25+
26+
this.logFunction = function(args, color) {
27+
args = Array.isArray(args) ? args : [args];
28+
this._logFunction(...(args.filter(arg => arg ?? false).map(arg => {
29+
if (typeof arg === 'object') arg = util.inspect(arg, 2);
30+
return color ? arg[color] : arg;
31+
})));
3332
};
33+
3434
this.logFile = options.logFile;
35+
if (this.logFile) {
36+
this.fs.ensureFileSync(this.logFile);
37+
}
3538

36-
this.writeToFile = async.cargo((tasks, callback) => {
39+
const isDebugOrTrace = ['debug', 'trace'].includes(this.logLevel);
40+
this.isDebugOrTrace = isDebugOrTrace;
41+
42+
const noop = () => {};
43+
this.writeToFile = async.cargo((tasks, callback = noop) => {
3744
if (!this.logFile) {
3845
return callback();
3946
}
4047
let logs = '';
41-
let origin = "[" + ((new Error().stack).split("at ")[3]).trim() + "]";
4248
tasks.forEach(task => {
43-
logs += `[${date.format(new Date(), DATE_FORMAT)}] ${task.prefix} ${task.args}\n`;
49+
let message = [].concat(task.args).join(' ').trim();
50+
if (!message) return;
51+
const dts = `[${date.format(new Date(), DATE_FORMAT)}]`;
52+
message = message.replace(/\s+/g, ' ');
53+
let origin = '';
54+
if (isDebugOrTrace) origin = `${DELIM}${task.origin.match(/^at\s+.*(\(.*\))/)[1] || '(unknown)'}`;
55+
const prefix = task.prefix;
56+
logs += `${dts}${DELIM}${prefix}${DELIM}${message}${origin}\n`;
4457
});
45-
this.fs.appendFile(this.logFile, `\n${origin} ${logs}`, err => {
58+
59+
if (!logs) {
60+
callback();
61+
}
62+
63+
this.fs.appendFile(this.logFile, logs.stripColors, err => {
4664
if (err) {
4765
this.logFunction(`There was an error writing to the log file: ${err}`, 'red');
4866
return callback(err);
@@ -71,116 +89,135 @@ export class Logger {
7189
return;
7290
}
7391

74-
let callback = () => {};
75-
if (typeof args[args.length - 1] === 'function') {
76-
callback = args[args.length - 1];
77-
args.splice(args.length - 1, 1);
78-
}
79-
8092
this.events.emit("log", "error", args);
81-
this.logFunction(...args, 'red');
82-
this.writeToFile.push({ prefix: "[error]: ", args }, callback);
93+
this.logFunction(args, 'red');
94+
95+
let origin;
96+
if (this.isDebugOrTrace) {
97+
try {
98+
const stack = new Error().stack;
99+
origin = stack.split('\n')[2].trim();
100+
// eslint-disable-next-line no-empty
101+
} catch (e) {}
102+
}
103+
this.writeToFile.push({ args, origin, prefix: "[error]" });
83104
}
84105

85106
warn(...args) {
86107
if (!args.length || !(this.shouldLog('warn'))) {
87108
return;
88109
}
89110

90-
let callback = () => {};
91-
if (typeof args[args.length - 1] === 'function') {
92-
callback = args[args.length - 1];
93-
args.splice(args.length - 1, 1);
94-
}
95-
96111
this.events.emit("log", "warn", args);
97-
this.logFunction(...args, 'yellow');
98-
this.writeToFile.push({ prefix: "[warning]: ", args }, callback);
112+
this.logFunction(args, 'yellow');
113+
114+
let origin;
115+
if (this.isDebugOrTrace) {
116+
try {
117+
const stack = new Error().stack;
118+
origin = stack.split('\n')[2].trim();
119+
// eslint-disable-next-line no-empty
120+
} catch (e) {}
121+
}
122+
this.writeToFile.push({ args, origin, prefix: "[warn]" });
99123
}
100124

101125
info(...args) {
102126
if (!args.length || !(this.shouldLog('info'))) {
103127
return;
104128
}
105129

106-
let callback = () => {};
107-
if (typeof args[args.length - 1] === 'function') {
108-
callback = args[args.length - 1];
109-
args.splice(args.length - 1, 1);
110-
}
111-
112130
this.events.emit("log", "info", args);
113-
this.logFunction(...args, 'green');
114-
this.writeToFile.push({ prefix: "[info]: ", args }, callback);
131+
this.logFunction(args, 'green');
132+
133+
let origin;
134+
if (this.isDebugOrTrace) {
135+
try {
136+
const stack = new Error().stack;
137+
origin = stack.split('\n')[2].trim();
138+
// eslint-disable-next-line no-empty
139+
} catch (e) {}
140+
}
141+
this.writeToFile.push({ args, origin, prefix: "[info]" });
115142
}
116143

117144
consoleOnly(...args) {
118145
if (!args.length || !(this.shouldLog('info'))) {
119146
return;
120147
}
121148

122-
let callback = () => {};
123-
if (typeof args[args.length - 1] === 'function') {
124-
callback = args[args.length - 1];
125-
args.splice(args.length - 1, 1);
126-
}
149+
this.logFunction(args, 'green');
127150

128-
this.logFunction(...args, 'green');
129-
this.writeToFile.push({prefix: "[consoleOnly]: ", args }, callback);
151+
let origin;
152+
if (this.isDebugOrTrace) {
153+
try {
154+
const stack = new Error().stack;
155+
origin = stack.split('\n')[2].trim();
156+
// eslint-disable-next-line no-empty
157+
} catch (e) {}
158+
}
159+
this.writeToFile.push({ args, origin, prefix: "[consoleOnly]" });
130160
}
131161

132162
debug(...args) {
133163
if (!args.length || !(this.shouldLog('debug'))) {
134164
return;
135165
}
136166

137-
let callback = () => {};
138-
if (typeof args[args.length - 1] === 'function') {
139-
callback = args[args.length - 1];
140-
args.splice(args.length - 1, 1);
141-
}
142-
143167
this.events.emit("log", "debug", args);
144-
this.logFunction(...args, null);
145-
this.writeToFile.push({ prefix: "[debug]: ", args }, callback);
168+
this.logFunction(args, null);
169+
170+
let origin;
171+
if (this.isDebugOrTrace) {
172+
try {
173+
const stack = new Error().stack;
174+
origin = stack.split('\n')[2].trim();
175+
// eslint-disable-next-line no-empty
176+
} catch (e) {}
177+
}
178+
this.writeToFile.push({ args, origin, prefix: "[debug]" });
146179
}
147180

148181
trace(...args) {
149182
if (!args.length || !(this.shouldLog('trace'))) {
150183
return;
151184
}
152185

153-
let callback = () => {};
154-
if (typeof args[args.length - 1] === 'function') {
155-
callback = args[args.length - 1];
156-
args.splice(args.length - 1, 1);
157-
}
158-
159186
this.events.emit("log", "trace", args);
160-
this.logFunction(...args, null);
161-
this.writeToFile.push({ prefix: "[trace]: ", args }, callback);
187+
this.logFunction(args, null);
188+
189+
let origin;
190+
if (this.isDebugOrTrace) {
191+
try {
192+
const stack = new Error().stack;
193+
origin = stack.split('\n')[2].trim();
194+
// eslint-disable-next-line no-empty
195+
} catch (e) {}
196+
}
197+
this.writeToFile.push({ args, origin, prefix: "[trace]" });
162198
}
163199

164-
dir(...args) {
165-
const txt = args[0];
166-
if (!txt || !(this.shouldLog('info'))) {
200+
dir(obj) {
201+
if (!obj || !(this.shouldLog('info'))) {
167202
return;
168203
}
169204

170-
let callback = () => {};
171-
if (typeof args[args.length - 1] === 'function') {
172-
callback = args[args.length - 1];
173-
args.splice(args.length - 1, 1);
174-
}
205+
this.events.emit("log", "dir", obj);
206+
this.logFunction(obj, null);
175207

176-
this.events.emit("log", "dir", txt);
177-
this.logFunction(txt, null);
178-
this.writeToFile({ prefix: "[dir]: ", args }, callback);
208+
let origin;
209+
if (this.isDebugOrTrace) {
210+
try {
211+
const stack = new Error().stack;
212+
origin = stack.split('\n')[2].trim();
213+
// eslint-disable-next-line no-empty
214+
} catch (e) {}
215+
}
216+
this.writeToFile({ args: obj, origin, prefix: "[dir]" });
179217
}
180218

181219
shouldLog(level) {
182220
const logLevels = Object.keys(LogLevels);
183221
return (logLevels.indexOf(level) <= logLevels.indexOf(this.logLevel));
184222
}
185223
}
186-

0 commit comments

Comments
 (0)