@percy/logger 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/logger.js +55 -56
- package/dist/utils.js +8 -6
- package/package.json +2 -2
package/dist/logger.js
CHANGED
|
@@ -6,48 +6,52 @@ const LOG_LEVELS = {
|
|
|
6
6
|
info: 1,
|
|
7
7
|
warn: 2,
|
|
8
8
|
error: 3
|
|
9
|
-
};
|
|
10
|
-
// messages to stdout and stderr depending on the log level and debug string.
|
|
9
|
+
};
|
|
11
10
|
|
|
11
|
+
// A PercyLogger instance retains logs in-memory for quick lookups while also writing log
|
|
12
|
+
// messages to stdout and stderr depending on the log level and debug string.
|
|
12
13
|
export class PercyLogger {
|
|
13
14
|
// default log level
|
|
14
|
-
level = 'info';
|
|
15
|
+
level = 'info';
|
|
15
16
|
|
|
17
|
+
// namespace regular expressions used to determine which debug logs to write
|
|
16
18
|
namespaces = {
|
|
17
19
|
include: [/^.*?$/],
|
|
18
20
|
exclude: []
|
|
19
|
-
};
|
|
21
|
+
};
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
// in-memory store for logs and meta info
|
|
24
|
+
messages = new Set();
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
// track deprecations to limit noisy logging
|
|
27
|
+
deprecations = new Set();
|
|
24
28
|
|
|
29
|
+
// static vars can be overriden for testing
|
|
25
30
|
static stdout = process.stdout;
|
|
26
|
-
static stderr = process.stderr;
|
|
31
|
+
static stderr = process.stderr;
|
|
27
32
|
|
|
33
|
+
// Handles setting env var values and returns a singleton
|
|
28
34
|
constructor() {
|
|
29
35
|
let {
|
|
30
36
|
instance = this
|
|
31
37
|
} = this.constructor;
|
|
32
|
-
|
|
33
38
|
if (process.env.PERCY_DEBUG) {
|
|
34
39
|
instance.debug(process.env.PERCY_DEBUG);
|
|
35
40
|
} else if (process.env.PERCY_LOGLEVEL) {
|
|
36
41
|
instance.loglevel(process.env.PERCY_LOGLEVEL);
|
|
37
42
|
}
|
|
38
|
-
|
|
39
43
|
this.constructor.instance = instance;
|
|
40
44
|
return instance;
|
|
41
|
-
}
|
|
42
|
-
|
|
45
|
+
}
|
|
43
46
|
|
|
47
|
+
// Change log level at any time or return the current log level
|
|
44
48
|
loglevel(level) {
|
|
45
49
|
if (level) this.level = level;
|
|
46
50
|
return this.level;
|
|
47
|
-
}
|
|
48
|
-
// comma separated debug string
|
|
49
|
-
|
|
51
|
+
}
|
|
50
52
|
|
|
53
|
+
// Change namespaces by generating an array of namespace regular expressions from a
|
|
54
|
+
// comma separated debug string
|
|
51
55
|
debug(namespaces) {
|
|
52
56
|
if (this.namespaces.string === namespaces) return;
|
|
53
57
|
this.namespaces.string = namespaces;
|
|
@@ -56,22 +60,20 @@ export class PercyLogger {
|
|
|
56
60
|
this.loglevel('debug');
|
|
57
61
|
this.namespaces = namespaces.reduce((namespaces, ns) => {
|
|
58
62
|
ns = ns.replace(/:?\*/g, m => m[0] === ':' ? ':?.*?' : '.*?');
|
|
59
|
-
|
|
60
63
|
if (ns[0] === '-') {
|
|
61
64
|
namespaces.exclude.push(new RegExp('^' + ns.substr(1) + '$'));
|
|
62
65
|
} else {
|
|
63
66
|
namespaces.include.push(new RegExp('^' + ns + '$'));
|
|
64
67
|
}
|
|
65
|
-
|
|
66
68
|
return namespaces;
|
|
67
69
|
}, {
|
|
68
70
|
string: namespaces,
|
|
69
71
|
include: [],
|
|
70
72
|
exclude: []
|
|
71
73
|
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
+
}
|
|
74
75
|
|
|
76
|
+
// Creates a new log group and returns level specific functions for logging
|
|
75
77
|
group(name) {
|
|
76
78
|
return Object.keys(LOG_LEVELS).reduce((group, level) => Object.assign(group, {
|
|
77
79
|
[level]: this.log.bind(this, name, level)
|
|
@@ -84,44 +86,43 @@ export class PercyLogger {
|
|
|
84
86
|
stdout: this.constructor.stdout,
|
|
85
87
|
stderr: this.constructor.stderr
|
|
86
88
|
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
+
}
|
|
89
90
|
|
|
91
|
+
// Query for a set of logs by filtering the in-memory store
|
|
90
92
|
query(filter) {
|
|
91
93
|
return Array.from(this.messages).filter(filter);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
+
}
|
|
94
95
|
|
|
96
|
+
// Formats messages before they are logged to stdio
|
|
95
97
|
format(debug, level, message, elapsed) {
|
|
96
98
|
let color = (n, m) => this.isTTY ? colors[n](m) : m;
|
|
97
|
-
|
|
98
99
|
let begin,
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
end,
|
|
101
|
+
suffix = '';
|
|
101
102
|
let label = 'percy';
|
|
102
|
-
|
|
103
103
|
if (arguments.length === 1) {
|
|
104
104
|
// format(message)
|
|
105
105
|
[debug, message] = [null, debug];
|
|
106
106
|
} else if (arguments.length === 2) {
|
|
107
107
|
// format(debug, message)
|
|
108
108
|
[level, message] = [null, level];
|
|
109
|
-
}
|
|
110
|
-
|
|
109
|
+
}
|
|
111
110
|
|
|
112
|
-
|
|
111
|
+
// do not format leading or trailing newlines
|
|
112
|
+
[, begin, message, end] = message.match(LINE_PAD_REGEXP);
|
|
113
113
|
|
|
114
|
+
// include debug information
|
|
114
115
|
if (this.level === 'debug') {
|
|
115
|
-
if (debug) label += `:${debug}`;
|
|
116
|
+
if (debug) label += `:${debug}`;
|
|
116
117
|
|
|
118
|
+
// include elapsed time since last log
|
|
117
119
|
if (elapsed != null) {
|
|
118
120
|
suffix = ' ' + color('grey', `(${elapsed}ms)`);
|
|
119
121
|
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
+
}
|
|
122
123
|
|
|
124
|
+
// add colors
|
|
123
125
|
label = color('magenta', label);
|
|
124
|
-
|
|
125
126
|
if (level === 'error') {
|
|
126
127
|
// red errors
|
|
127
128
|
message = color('red', message);
|
|
@@ -132,54 +133,52 @@ export class PercyLogger {
|
|
|
132
133
|
// blue info and debug URLs
|
|
133
134
|
message = message.replace(URL_REGEXP, color('blue', '$&'));
|
|
134
135
|
}
|
|
135
|
-
|
|
136
136
|
return `${begin}[${label}] ${message}${suffix}${end}`;
|
|
137
|
-
}
|
|
138
|
-
|
|
137
|
+
}
|
|
139
138
|
|
|
139
|
+
// True if stdout is a TTY interface
|
|
140
140
|
get isTTY() {
|
|
141
141
|
return !!this.constructor.stdout.isTTY;
|
|
142
|
-
}
|
|
143
|
-
|
|
142
|
+
}
|
|
144
143
|
|
|
144
|
+
// Replaces the current line with a log message
|
|
145
145
|
progress(debug, message, persist) {
|
|
146
146
|
if (!this.shouldLog(debug, 'info')) return;
|
|
147
147
|
let {
|
|
148
148
|
stdout
|
|
149
149
|
} = this.constructor;
|
|
150
|
-
|
|
151
150
|
if (this.isTTY || !this._progress) {
|
|
152
151
|
message && (message = this.format(debug, message));
|
|
153
152
|
if (this.isTTY) stdout.cursorTo(0);else message && (message = message + '\n');
|
|
154
153
|
if (message) stdout.write(message);
|
|
155
154
|
if (this.isTTY) stdout.clearLine(1);
|
|
156
155
|
}
|
|
157
|
-
|
|
158
156
|
this._progress = !!message && {
|
|
159
157
|
message,
|
|
160
158
|
persist
|
|
161
159
|
};
|
|
162
|
-
}
|
|
163
|
-
|
|
160
|
+
}
|
|
164
161
|
|
|
162
|
+
// Returns true or false if the level and debug group can write messages to stdio
|
|
165
163
|
shouldLog(debug, level) {
|
|
166
164
|
return LOG_LEVELS[level] != null && LOG_LEVELS[level] >= LOG_LEVELS[this.level] && !this.namespaces.exclude.some(ns => ns.test(debug)) && this.namespaces.include.some(ns => ns.test(debug));
|
|
167
|
-
}
|
|
168
|
-
|
|
165
|
+
}
|
|
169
166
|
|
|
167
|
+
// Ensures that deprecation messages are not logged more than once
|
|
170
168
|
deprecated(debug, message, meta) {
|
|
171
169
|
if (this.deprecations.has(message)) return;
|
|
172
170
|
this.deprecations.add(message);
|
|
173
171
|
this.log(debug, 'warn', `Warning: ${message}`, meta);
|
|
174
|
-
}
|
|
175
|
-
// information to store with the message and other info
|
|
176
|
-
|
|
172
|
+
}
|
|
177
173
|
|
|
174
|
+
// Generic log method accepts a debug group, log level, log message, and optional meta
|
|
175
|
+
// information to store with the message and other info
|
|
178
176
|
log(debug, level, message, meta = {}) {
|
|
179
177
|
// message might be an error-like object
|
|
180
178
|
let err = typeof message !== 'string' && (level === 'debug' || level === 'error');
|
|
181
|
-
err && (err = message.message ? Error.prototype.toString.call(message) : message.toString());
|
|
179
|
+
err && (err = message.message ? Error.prototype.toString.call(message) : message.toString());
|
|
182
180
|
|
|
181
|
+
// save log entries
|
|
183
182
|
let timestamp = Date.now();
|
|
184
183
|
message = err ? message.stack || err : message.toString();
|
|
185
184
|
let entry = {
|
|
@@ -190,19 +189,21 @@ export class PercyLogger {
|
|
|
190
189
|
timestamp,
|
|
191
190
|
error: !!err
|
|
192
191
|
};
|
|
193
|
-
this.messages.add(entry);
|
|
192
|
+
this.messages.add(entry);
|
|
194
193
|
|
|
194
|
+
// maybe write the message to stdio
|
|
195
195
|
if (this.shouldLog(debug, level)) {
|
|
196
196
|
// unless the loglevel is debug, write shorter error messages
|
|
197
197
|
if (err && this.level !== 'debug') message = err;
|
|
198
|
-
this.write({
|
|
198
|
+
this.write({
|
|
199
|
+
...entry,
|
|
199
200
|
message
|
|
200
201
|
});
|
|
201
202
|
this.lastlog = timestamp;
|
|
202
203
|
}
|
|
203
|
-
}
|
|
204
|
-
|
|
204
|
+
}
|
|
205
205
|
|
|
206
|
+
// Writes a log entry to stdio based on the loglevel
|
|
206
207
|
write({
|
|
207
208
|
debug,
|
|
208
209
|
level,
|
|
@@ -211,23 +212,21 @@ export class PercyLogger {
|
|
|
211
212
|
error
|
|
212
213
|
}) {
|
|
213
214
|
var _this$_progress;
|
|
214
|
-
|
|
215
215
|
let elapsed = timestamp - (this.lastlog || timestamp);
|
|
216
216
|
let msg = this.format(debug, error ? 'error' : level, message, elapsed);
|
|
217
217
|
let progress = this.isTTY && this._progress;
|
|
218
218
|
let {
|
|
219
219
|
stdout,
|
|
220
220
|
stderr
|
|
221
|
-
} = this.constructor;
|
|
221
|
+
} = this.constructor;
|
|
222
222
|
|
|
223
|
+
// clear any logged progress
|
|
223
224
|
if (progress) {
|
|
224
225
|
stdout.cursorTo(0);
|
|
225
226
|
stdout.clearLine(0);
|
|
226
227
|
}
|
|
227
|
-
|
|
228
228
|
(level === 'info' ? stdout : stderr).write(msg + '\n');
|
|
229
229
|
if (!((_this$_progress = this._progress) !== null && _this$_progress !== void 0 && _this$_progress.persist)) delete this._progress;else if (progress) stdout.write(progress.message);
|
|
230
230
|
}
|
|
231
|
-
|
|
232
231
|
}
|
|
233
232
|
export default PercyLogger;
|
package/dist/utils.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
const {
|
|
2
2
|
assign,
|
|
3
3
|
entries
|
|
4
|
-
} = Object;
|
|
4
|
+
} = Object;
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// matches ansi escape sequences
|
|
7
|
+
export const ANSI_REG = new RegExp('[\\u001B\\u009B][[\\]()#;?]*((?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)' + '|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', 'g');
|
|
7
8
|
|
|
9
|
+
// color names by ansi escape code
|
|
8
10
|
export const ANSI_COLORS = {
|
|
9
11
|
'91m': 'red',
|
|
10
12
|
'32m': 'green',
|
|
@@ -12,15 +14,15 @@ export const ANSI_COLORS = {
|
|
|
12
14
|
'34m': 'blue',
|
|
13
15
|
'95m': 'magenta',
|
|
14
16
|
'90m': 'grey'
|
|
15
|
-
};
|
|
17
|
+
};
|
|
16
18
|
|
|
19
|
+
// colorize each line of a string using an ansi escape sequence
|
|
17
20
|
const LINE_REG = /^.*$/gm;
|
|
18
|
-
|
|
19
21
|
function colorize(code, str) {
|
|
20
22
|
return str.replace(LINE_REG, line => `\u001b[${code}${line}\u001b[39m`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
+
}
|
|
23
24
|
|
|
25
|
+
// map ansi colors to bound colorize functions
|
|
24
26
|
export const colors = entries(ANSI_COLORS).reduce((colors, [code, name]) => {
|
|
25
27
|
return assign(colors, {
|
|
26
28
|
[name]: colorize.bind(null, code)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/logger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,5 +31,5 @@
|
|
|
31
31
|
"test": "node ../../scripts/test",
|
|
32
32
|
"test:coverage": "yarn test --coverage"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "fd72688e449d6dd3eafd346fc07879cb3bb01a4e"
|
|
35
35
|
}
|