axe 9.0.0 → 10.0.1
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/README.md +724 -179
- package/dist/axe.js +1153 -7063
- package/dist/axe.min.js +1 -1
- package/lib/index.js +261 -166
- package/package.json +21 -16
package/lib/index.js
CHANGED
|
@@ -2,219 +2,252 @@
|
|
|
2
2
|
|
|
3
3
|
// eslint-disable-next-line import/no-unassigned-import
|
|
4
4
|
require('console-polyfill');
|
|
5
|
-
|
|
6
|
-
const cuid = require('cuid');
|
|
7
|
-
|
|
5
|
+
const combine = require('maybe-combine-errors');
|
|
8
6
|
const format = require('@ladjs/format-util');
|
|
9
|
-
|
|
10
7
|
const formatSpecifiers = require('format-specifiers');
|
|
11
|
-
|
|
8
|
+
const get = require('@strikeentco/get');
|
|
12
9
|
const isError = require('iserror');
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
10
|
+
const mergeOptions = require('merge-options');
|
|
11
|
+
const pMapSeries = require('p-map-series');
|
|
16
12
|
const parseAppInfo = require('parse-app-info');
|
|
17
|
-
|
|
18
13
|
const parseErr = require('parse-err');
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const superagent = require('superagent');
|
|
23
|
-
|
|
14
|
+
const pickDeep = require('pick-deep');
|
|
15
|
+
const set = require('@strikeentco/set');
|
|
16
|
+
const unset = require('unset-value');
|
|
24
17
|
const {
|
|
25
18
|
boolean
|
|
26
19
|
} = require('boolean');
|
|
27
|
-
|
|
28
20
|
const pkg = require('../package.json');
|
|
29
|
-
|
|
30
21
|
const omittedLoggerKeys = new Set(['config', 'log']);
|
|
31
22
|
const levels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
|
|
32
23
|
const aliases = {
|
|
33
24
|
warning: 'warn',
|
|
34
25
|
err: 'error'
|
|
35
26
|
};
|
|
36
|
-
const
|
|
37
|
-
const levelError = "`level` invalid, must be: ".concat(levels.join(', ')); // <https://stackoverflow.com/a/43233163>
|
|
27
|
+
const levelError = `\`level\` invalid, must be: ${levels.join(', ')}`;
|
|
38
28
|
|
|
29
|
+
// <https://github.com/sindresorhus/is-plain-obj/blob/main/index.js>
|
|
30
|
+
function isPlainObject(value) {
|
|
31
|
+
if (typeof value !== 'object' || value === null) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const prototype = Object.getPrototypeOf(value);
|
|
35
|
+
return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// <https://github.com/GeenenTijd/dotify/blob/master/dotify.js>
|
|
39
|
+
function dotifyToArray(obj) {
|
|
40
|
+
const res = [];
|
|
41
|
+
function recurse(obj, current) {
|
|
42
|
+
for (const key of Object.keys(obj)) {
|
|
43
|
+
const value = obj[key];
|
|
44
|
+
const newKey = current ? current + '.' + key : key; // joined key with dot
|
|
45
|
+
// if (value && typeof value === 'object' && !(value instanceof Date) && !ObjectID.isValid(value)) {
|
|
46
|
+
if (isPlainObject(value)) {
|
|
47
|
+
recurse(value, newKey); // it's a nested object, so do it again
|
|
48
|
+
} else {
|
|
49
|
+
res.push(newKey);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
recurse(obj);
|
|
54
|
+
return res;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// <https://stackoverflow.com/a/43233163>
|
|
39
58
|
function isEmpty(value) {
|
|
40
59
|
return value === undefined || value === null || typeof value === 'object' && Object.keys(value).length === 0 || typeof value === 'string' && value.trim().length === 0;
|
|
41
60
|
}
|
|
42
|
-
|
|
43
61
|
function isNull(value) {
|
|
44
62
|
return value === null;
|
|
45
63
|
}
|
|
46
|
-
|
|
47
64
|
function isUndefined(value) {
|
|
48
65
|
return typeof value === 'undefined';
|
|
49
66
|
}
|
|
50
|
-
|
|
51
67
|
function isObject(value) {
|
|
52
68
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
53
69
|
}
|
|
54
|
-
|
|
55
70
|
function isString(value) {
|
|
56
71
|
return typeof value === 'string';
|
|
57
72
|
}
|
|
58
|
-
|
|
59
73
|
function isFunction(value) {
|
|
60
74
|
return typeof value === 'function';
|
|
61
75
|
}
|
|
62
|
-
|
|
63
|
-
function isBoolean(value) {
|
|
64
|
-
return typeof value === 'boolean';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
76
|
class Axe {
|
|
68
77
|
constructor() {
|
|
69
78
|
var _this = this;
|
|
70
|
-
|
|
71
79
|
let config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
const remappedFields = {};
|
|
81
|
+
if (process.env.AXE_REMAPPED_META_FIELDS) {
|
|
82
|
+
const arr = process.env.AXE_REMAPPED_META_FIELDS.split(',').map(v => v.split(':'));
|
|
83
|
+
for (const [prop, value] of arr) {
|
|
84
|
+
remappedFields[prop] = value;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.config = mergeOptions({
|
|
88
|
+
showStack: process.env.AXE_SHOW_STACK ? boolean(process.env.AXE_SHOW_STACK) : true,
|
|
89
|
+
meta: Object.assign({
|
|
90
|
+
show: process.env.AXE_SHOW_META ? boolean(process.env.AXE_SHOW_META) : true,
|
|
91
|
+
remappedFields,
|
|
92
|
+
omittedFields: process.env.AXE_OMIT_META_FIELDS ? process.env.AXE_OMIT_META_FIELDS.split(',').map(s => s.trim()) : ['level', 'err', 'app', 'args'],
|
|
93
|
+
pickedFields: process.env.AXE_PICK_META_FIELDS ? process.env.AXE_PICK_META_FIELDS.split(',').map(s => s.trim()) : [],
|
|
94
|
+
cleanupRemapping: true
|
|
95
|
+
}, typeof config.meta === 'object' ? config.meta : {}),
|
|
96
|
+
version: pkg.version,
|
|
84
97
|
silent: false,
|
|
85
98
|
logger: console,
|
|
86
99
|
name: false,
|
|
87
100
|
level: 'info',
|
|
88
101
|
levels: ['info', 'warn', 'error', 'fatal'],
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (this.config.showMeta) {
|
|
96
|
-
this.config.meta.show = this.config.showMeta;
|
|
97
|
-
delete this.config.showMeta;
|
|
98
|
-
}
|
|
99
|
-
|
|
102
|
+
appInfo: process.env.AXE_APP_INFO ? boolean(process.env.AXE_APP_INFO) : true,
|
|
103
|
+
hooks: Object.assign({
|
|
104
|
+
pre: [],
|
|
105
|
+
post: []
|
|
106
|
+
}, typeof config.hooks === 'object' ? config.hooks : {})
|
|
107
|
+
}, config);
|
|
100
108
|
this.appInfo = this.config.appInfo ? isFunction(parseAppInfo) ? parseAppInfo() : false : false;
|
|
101
|
-
this.log = this.log.bind(this);
|
|
109
|
+
this.log = this.log.bind(this);
|
|
102
110
|
|
|
111
|
+
// Inherit methods from parent logger
|
|
103
112
|
const methods = Object.keys(this.config.logger).filter(key => !omittedLoggerKeys.has(key));
|
|
104
|
-
|
|
105
113
|
for (const element of methods) {
|
|
106
114
|
this[element] = this.config.logger[element];
|
|
107
|
-
}
|
|
108
|
-
|
|
115
|
+
}
|
|
109
116
|
|
|
117
|
+
// Bind helper functions for each log level
|
|
110
118
|
for (const element of levels) {
|
|
119
|
+
// Ensure function exists in logger passed
|
|
120
|
+
if (typeof this.config.logger[element] !== 'function') {
|
|
121
|
+
if (element === 'fatal') {
|
|
122
|
+
this.config.logger.fatal = this.config.logger.error || this.config.logger.info || this.config.logger.log;
|
|
123
|
+
} else {
|
|
124
|
+
this.config.logger[element] = this.config.logger.info || this.config.logger.log;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Bind log handler which normalizes args and populates meta
|
|
111
129
|
this[element] = function () {
|
|
112
130
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
113
131
|
args[_key] = arguments[_key];
|
|
114
132
|
}
|
|
115
|
-
|
|
116
133
|
return _this.log(element, ...Array.prototype.slice.call(args));
|
|
117
134
|
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
135
|
+
}
|
|
121
136
|
this.setLevel = this.setLevel.bind(this);
|
|
122
137
|
this.getNormalizedLevel = this.getNormalizedLevel.bind(this);
|
|
123
138
|
this.setName = this.setName.bind(this);
|
|
124
|
-
this.setCallback = this.setCallback.bind(this); // Set the logger name
|
|
125
139
|
|
|
126
|
-
|
|
140
|
+
// Set the logger name
|
|
141
|
+
if (this.config.name) this.setName(this.config.name);
|
|
127
142
|
|
|
128
|
-
|
|
143
|
+
// Set the logger level
|
|
144
|
+
this.setLevel(this.config.level);
|
|
129
145
|
|
|
146
|
+
// Aliases
|
|
130
147
|
this.err = this.error;
|
|
131
148
|
this.warning = this.warn;
|
|
132
|
-
}
|
|
133
149
|
|
|
134
|
-
|
|
135
|
-
this.
|
|
150
|
+
// Pre and Post Hooks
|
|
151
|
+
this.pre = function (level, fn) {
|
|
152
|
+
this.config.hooks.pre.push(function (_level) {
|
|
153
|
+
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
|
|
154
|
+
args[_key2 - 1] = arguments[_key2];
|
|
155
|
+
}
|
|
156
|
+
if (level !== _level) return [...args];
|
|
157
|
+
return fn(...args);
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
this.post = function (level, fn) {
|
|
161
|
+
this.config.hooks.post.push(function (_level) {
|
|
162
|
+
for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
|
|
163
|
+
args[_key3 - 1] = arguments[_key3];
|
|
164
|
+
}
|
|
165
|
+
if (level !== _level) return [...args];
|
|
166
|
+
return fn(...args);
|
|
167
|
+
});
|
|
168
|
+
};
|
|
136
169
|
}
|
|
137
|
-
|
|
138
170
|
setLevel(level) {
|
|
139
|
-
if (!isString(level) ||
|
|
140
|
-
|
|
141
|
-
if (isString(this.config.logger.logLevel)) this.config.logger.logLevel = level;else this.config.logger.level = level;
|
|
171
|
+
if (!isString(level) || levels.indexOf(level) === -1) throw new Error(levelError);
|
|
172
|
+
// Support signale logger and other loggers that use `logLevel`
|
|
173
|
+
if (isString(this.config.logger.logLevel)) this.config.logger.logLevel = level;else this.config.logger.level = level;
|
|
174
|
+
// Adjusts `this.config.levels` array
|
|
142
175
|
// so that it has all proceeding (inclusive)
|
|
143
|
-
|
|
144
176
|
this.config.levels = levels.slice(levels.indexOf(level));
|
|
145
177
|
}
|
|
146
|
-
|
|
147
178
|
getNormalizedLevel(level) {
|
|
148
179
|
if (!isString(level)) return 'info';
|
|
149
180
|
if (isString(aliases[level])) return aliases[level];
|
|
150
|
-
if (
|
|
181
|
+
if (levels.indexOf(level) === -1) return 'info';
|
|
151
182
|
return level;
|
|
152
183
|
}
|
|
153
|
-
|
|
154
184
|
setName(name) {
|
|
155
|
-
if (!isString(name)) throw new Error('`name` must be a String');
|
|
156
|
-
|
|
185
|
+
if (!isString(name)) throw new Error('`name` must be a String');
|
|
186
|
+
// Support signale logger and other loggers that use `scope`
|
|
157
187
|
if (isString(this.config.logger.scope)) this.config.logger.scope = name;else this.config.logger.name = name;
|
|
158
|
-
}
|
|
159
|
-
|
|
188
|
+
}
|
|
160
189
|
|
|
190
|
+
// eslint-disable-next-line complexity
|
|
161
191
|
log(level, message, meta) {
|
|
162
192
|
const originalArgs = [];
|
|
193
|
+
const errors = [];
|
|
163
194
|
if (!isUndefined(level)) originalArgs.push(level);
|
|
164
195
|
if (!isUndefined(message)) originalArgs.push(message);
|
|
165
196
|
if (!isUndefined(meta)) originalArgs.push(meta);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
args[_key2 - 3] = arguments[_key2];
|
|
197
|
+
for (var _len4 = arguments.length, args = new Array(_len4 > 3 ? _len4 - 3 : 0), _key4 = 3; _key4 < _len4; _key4++) {
|
|
198
|
+
args[_key4 - 3] = arguments[_key4];
|
|
169
199
|
}
|
|
170
|
-
|
|
171
200
|
for (const arg of Array.prototype.slice.call(args)) {
|
|
172
201
|
originalArgs.push(arg);
|
|
173
202
|
}
|
|
174
|
-
|
|
175
203
|
const {
|
|
176
204
|
config
|
|
177
205
|
} = this;
|
|
178
206
|
let modifier = 0;
|
|
179
|
-
|
|
180
207
|
if (isString(level) && isString(aliases[level])) {
|
|
181
208
|
level = aliases[level];
|
|
182
209
|
} else if (isError(level)) {
|
|
183
210
|
meta = message;
|
|
184
211
|
message = level;
|
|
185
212
|
level = 'error';
|
|
186
|
-
} else if (!isString(level) ||
|
|
213
|
+
} else if (!isString(level) || levels.indexOf(level) === -1) {
|
|
187
214
|
meta = message;
|
|
188
215
|
message = level;
|
|
189
216
|
level = this.getNormalizedLevel(level);
|
|
190
217
|
modifier = -1;
|
|
191
|
-
}
|
|
218
|
+
}
|
|
192
219
|
|
|
220
|
+
// Return early if it is not a valid logging level
|
|
221
|
+
if (config.levels.indexOf(level) === -1) return;
|
|
193
222
|
|
|
223
|
+
// Bunyan support (meta, message, ...args)
|
|
194
224
|
let isBunyan = false;
|
|
195
|
-
|
|
196
225
|
if ((isObject(message) || Array.isArray(message)) && isString(meta)) {
|
|
197
226
|
isBunyan = true;
|
|
198
227
|
const _meta = meta;
|
|
199
228
|
meta = message;
|
|
200
229
|
message = isString(_meta) && originalArgs.length >= 3 + modifier ? format(...originalArgs.slice(2 + modifier)) : _meta;
|
|
201
|
-
}
|
|
230
|
+
}
|
|
202
231
|
|
|
232
|
+
// If message was undefined then set it to level
|
|
233
|
+
if (isUndefined(message)) message = level;
|
|
203
234
|
|
|
204
|
-
|
|
235
|
+
// If only `message` was passed then if it was an Object
|
|
205
236
|
// preserve it as an Object by setting it as meta
|
|
206
|
-
|
|
207
237
|
if (originalArgs.slice(1 + modifier).length === 1 && !isString(message) && !isError(message)) {
|
|
208
238
|
meta = {
|
|
209
239
|
message
|
|
210
240
|
};
|
|
211
241
|
message = level;
|
|
212
242
|
} else if (!isBunyan && originalArgs.length >= 4 + modifier) {
|
|
213
|
-
|
|
214
|
-
// then infer to use util.format on everything
|
|
215
|
-
message = format(...originalArgs.slice(1 + modifier));
|
|
243
|
+
message = undefined;
|
|
216
244
|
meta = {};
|
|
217
|
-
|
|
245
|
+
const messages = [];
|
|
246
|
+
for (const arg of originalArgs) {
|
|
247
|
+
if (isError(arg)) errors.push(arg);else if (isString(arg)) messages.push(arg);
|
|
248
|
+
}
|
|
249
|
+
if (errors.length === 0 && messages.length > 0) message = format(...messages);else if (errors.length > 0 && level === 'log') level = 'error';
|
|
250
|
+
} else if (!isBunyan && originalArgs.length === 3 + modifier && isString(message) && formatSpecifiers.some(t => message.indexOf(t) !== -1)) {
|
|
218
251
|
// Otherwise if there are three args and if the `message` contains
|
|
219
252
|
// a placeholder token (e.g. '%s' or '%d' - see above `formatSpecifiers` variable)
|
|
220
253
|
// then we can infer that the `meta` arg passed is used for formatting
|
|
@@ -222,9 +255,8 @@ class Axe {
|
|
|
222
255
|
meta = {};
|
|
223
256
|
} else if (!isError(message)) {
|
|
224
257
|
if (isError(meta)) {
|
|
225
|
-
meta
|
|
226
|
-
|
|
227
|
-
}; // } else if (!isPlainObject(meta) && !isUndefined(meta) && !isNull(meta)) {
|
|
258
|
+
errors.push(meta);
|
|
259
|
+
meta = {};
|
|
228
260
|
} else if (!isObject(meta) && !isUndefined(meta) && !isNull(meta)) {
|
|
229
261
|
// If the `meta` variable passed was not an Object then convert it
|
|
230
262
|
message = format(message, meta);
|
|
@@ -235,65 +267,49 @@ class Axe {
|
|
|
235
267
|
// (as opposed to using something like fast-json-stringify)
|
|
236
268
|
message = format(message);
|
|
237
269
|
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
|
|
270
|
+
} else if (isError(meta)) {
|
|
271
|
+
errors.push(meta);
|
|
272
|
+
// handle additional args
|
|
273
|
+
for (const arg of originalArgs.slice(2 + modifier)) {
|
|
274
|
+
// should skip this better with slice and modifier adjustment
|
|
275
|
+
if (meta === arg) continue;
|
|
276
|
+
if (isError(arg)) errors.push(arg);
|
|
277
|
+
}
|
|
278
|
+
meta = {};
|
|
279
|
+
}
|
|
241
280
|
if (!isUndefined(meta) && !isObject(meta)) meta = {
|
|
242
|
-
meta
|
|
281
|
+
original_meta: meta
|
|
243
282
|
};else if (!isObject(meta)) meta = {};
|
|
244
|
-
const hadErrorInMeta = isObject(meta.err);
|
|
245
|
-
let error;
|
|
246
|
-
|
|
247
283
|
if (isError(message)) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
message
|
|
252
|
-
} = message);
|
|
253
|
-
} else if (isError(meta.err)) {
|
|
254
|
-
error = meta.err;
|
|
255
|
-
} // Omit `callback` from `meta` if it was passed
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const callback = isFunction(config.callback) && (!isBoolean(meta.callback) || meta.callback);
|
|
259
|
-
meta = omit(meta, ['callback']); // Set default level on meta
|
|
260
|
-
|
|
261
|
-
meta.level = level; // Add `app` object to metadata
|
|
262
|
-
|
|
263
|
-
if (this.appInfo) meta.app = this.appInfo; // Set the body used for returning with and sending logs
|
|
264
|
-
// (and also remove circular references)
|
|
265
|
-
|
|
266
|
-
const body = safeStringify({
|
|
267
|
-
message,
|
|
268
|
-
meta
|
|
269
|
-
}); // Send to Cabin or other logging service here the `message` and `meta`
|
|
270
|
-
|
|
271
|
-
if (config.capture && config.levels.includes(level) && (!isError(error) || !error._captureFailed)) {
|
|
272
|
-
// If the user didn't specify a key
|
|
273
|
-
// and they are using the default endpoint
|
|
274
|
-
// then we should throw an error to them
|
|
275
|
-
if (config.endpoint === endpoint && !config.key) throw new Error("Cabin API key required (e.g. `{ key: 'YOUR-CABIN-API-KEY' })`)\n<https://cabinjs.com>"); // Capture the log over HTTP
|
|
276
|
-
|
|
277
|
-
const request = superagent.post(config.endpoint).set('X-Request-Id', cuid()).timeout(config.timeout);
|
|
278
|
-
if (!process.browser) request.set('User-Agent', "axe/".concat(pkg.version)); // Basic auth (e.g. Cabin API key)
|
|
279
|
-
|
|
280
|
-
if (config.key) request.auth(config.key); // Set headers if any
|
|
284
|
+
errors.unshift(message);
|
|
285
|
+
message = undefined;
|
|
286
|
+
}
|
|
281
287
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
288
|
+
//
|
|
289
|
+
// rewrite `meta.err` to `meta.original_err` for consistency
|
|
290
|
+
// (in case someone has an object with `.err` property on it with an error)
|
|
291
|
+
//
|
|
292
|
+
if (isObject(meta.err)) {
|
|
293
|
+
if (isError(meta.err)) errors.push(meta.err);
|
|
294
|
+
meta.original_err = isError(meta.err) ? parseErr(meta.err) : meta.err;
|
|
295
|
+
}
|
|
296
|
+
let err;
|
|
297
|
+
if (errors.length > 0) {
|
|
298
|
+
err = combine(errors);
|
|
299
|
+
meta.err = parseErr(err);
|
|
300
|
+
if (!isString(message)) message = err.message;
|
|
301
|
+
}
|
|
290
302
|
|
|
303
|
+
// Set `args` prop with original arguments passed
|
|
304
|
+
meta.args = originalArgs;
|
|
291
305
|
|
|
292
|
-
|
|
306
|
+
// Set default level on meta
|
|
307
|
+
meta.level = level;
|
|
293
308
|
|
|
294
|
-
|
|
309
|
+
// Add `app` object to metadata
|
|
310
|
+
if (this.appInfo) meta.app = this.appInfo;
|
|
295
311
|
|
|
296
|
-
|
|
312
|
+
//
|
|
297
313
|
// determine log method to use
|
|
298
314
|
//
|
|
299
315
|
// if we didn't pass a level as a method
|
|
@@ -302,30 +318,109 @@ class Axe {
|
|
|
302
318
|
//
|
|
303
319
|
// and fatal should use error (e.g. in browser)
|
|
304
320
|
//
|
|
321
|
+
const method = modifier === -1 ? 'log' : level;
|
|
305
322
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
//
|
|
323
|
+
//
|
|
324
|
+
// NOTE: using lodash _.omit and _.pick would have been _very slow_
|
|
325
|
+
//
|
|
326
|
+
// const omittedAndPickedFields = {
|
|
327
|
+
// ..._.omit(meta, this.config.meta.omittedFields),
|
|
328
|
+
// ..._.pick(meta, this.config.meta.pickedFields)
|
|
329
|
+
// };
|
|
330
|
+
//
|
|
331
|
+
// also we don't want to mutate anything in `meta`
|
|
332
|
+
// and ideally we only want to pick exactly what we need
|
|
333
|
+
// (and not have two operations, one for omit, and one for pick)
|
|
334
|
+
//
|
|
309
335
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
336
|
+
if (!isEmpty(this.config.meta.remappedFields)) {
|
|
337
|
+
for (const key of Object.keys(this.config.meta.remappedFields)) {
|
|
338
|
+
set(meta, this.config.meta.remappedFields[key], get(meta, key));
|
|
339
|
+
unset(meta, key);
|
|
340
|
+
// cleanup empty objects after remapping
|
|
341
|
+
if (this.config.meta.cleanupRemapping) {
|
|
342
|
+
const index = key.lastIndexOf('.');
|
|
343
|
+
if (index === -1) continue;
|
|
344
|
+
const parentKey = key.slice(0, index);
|
|
345
|
+
if (isEmpty(get(meta, parentKey))) unset(meta, parentKey);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (!isEmpty(this.config.meta.omittedFields) || !isEmpty(this.config.meta.pickedFields)) {
|
|
350
|
+
const dotified = dotifyToArray(meta);
|
|
351
|
+
// dotified = [
|
|
352
|
+
// 'err.name',
|
|
353
|
+
// 'err.message',
|
|
354
|
+
// 'err.stack',
|
|
355
|
+
// 'level',
|
|
356
|
+
// 'app.name',
|
|
357
|
+
// 'app.version',
|
|
358
|
+
// 'app.node',
|
|
359
|
+
// 'app.hash',
|
|
360
|
+
// // ...
|
|
361
|
+
// ]
|
|
362
|
+
|
|
363
|
+
if (!isEmpty(this.config.meta.omittedFields)) {
|
|
364
|
+
for (const prop of this.config.meta.omittedFields) {
|
|
365
|
+
// <https://stackoverflow.com/a/9882349>
|
|
366
|
+
let i = dotified.length;
|
|
367
|
+
while (i--) {
|
|
368
|
+
if (dotified[i] === prop || dotified[i].indexOf(`${prop}.`) === 0) dotified.splice(i, 1);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (!isEmpty(this.config.meta.pickedFields)) {
|
|
373
|
+
for (const prop of this.config.meta.pickedFields) {
|
|
374
|
+
// response.headers.boop
|
|
375
|
+
// response.headers.beep
|
|
376
|
+
// response.body
|
|
377
|
+
// response.text
|
|
378
|
+
// response
|
|
379
|
+
//
|
|
380
|
+
// so we need to split by the first period and omit any keys from dotified starting with it
|
|
381
|
+
const index = prop.indexOf('.');
|
|
382
|
+
const key = prop.slice(0, index + 1);
|
|
383
|
+
if (index !== -1) {
|
|
384
|
+
let i = dotified.length;
|
|
385
|
+
while (i--) {
|
|
386
|
+
if (dotified[i].indexOf(key) === 0) dotified.splice(i, 1);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// finally add it if it did not already exist
|
|
391
|
+
if (dotified.indexOf(prop) === -1) dotified.push(prop);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
313
394
|
|
|
314
|
-
|
|
315
|
-
|
|
395
|
+
// now we call pick-deep using the final array
|
|
396
|
+
meta = pickDeep(meta, dotified);
|
|
397
|
+
}
|
|
316
398
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
} else {
|
|
322
|
-
this.config.logger[method](message, omitted);
|
|
323
|
-
} // Return the parsed body in case we need it
|
|
399
|
+
// pre-hooks
|
|
400
|
+
for (const hook of this.config.hooks.pre) {
|
|
401
|
+
[err, message, meta] = hook(method, err, message, meta);
|
|
402
|
+
}
|
|
324
403
|
|
|
404
|
+
// only invoke logger methods if it was not silent
|
|
405
|
+
if (!config.silent) {
|
|
406
|
+
// Show stack trace if necessary (along with any metadata)
|
|
407
|
+
if (isError(err) && config.showStack) {
|
|
408
|
+
if (!config.meta.show || isEmpty(meta)) {
|
|
409
|
+
this.config.logger[method](err);
|
|
410
|
+
} else {
|
|
411
|
+
this.config.logger[method](err, meta);
|
|
412
|
+
}
|
|
413
|
+
} else if (!config.meta.show || isEmpty(meta)) {
|
|
414
|
+
this.config.logger[method](message);
|
|
415
|
+
} else {
|
|
416
|
+
this.config.logger[method](message, meta);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
325
419
|
|
|
326
|
-
|
|
420
|
+
// post-hooks
|
|
421
|
+
pMapSeries(this.config.hooks.post, hook => hook(method, err, message, meta)).then().catch(err => {
|
|
422
|
+
this.config.logger.error(err);
|
|
423
|
+
});
|
|
327
424
|
}
|
|
328
|
-
|
|
329
425
|
}
|
|
330
|
-
|
|
331
426
|
module.exports = Axe;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "axe",
|
|
3
|
-
"description": "
|
|
4
|
-
"version": "
|
|
3
|
+
"description": "Axe is a logger-agnostic wrapper that normalizes logs regardless of argument style. Great for large development teams, old and new projects, and works with Pino, Bunyan, Winston, console, and more. It is lightweight, performant, highly-configurable, and automatically adds OS, CPU, and Git information to your logs. It supports hooks (useful for masking sensitive data) and dot-notation remapping, omitting, and picking of log metadata properties. Made for Forward Email, Lad, and Cabin.",
|
|
4
|
+
"version": "10.0.1",
|
|
5
5
|
"author": "Nick Baugh <niftylettuce@gmail.com> (http://niftylettuce.com)",
|
|
6
6
|
"browser": {
|
|
7
7
|
"parse-app-info": false
|
|
@@ -11,20 +11,25 @@
|
|
|
11
11
|
},
|
|
12
12
|
"contributors": [
|
|
13
13
|
"Nick Baugh <niftylettuce@gmail.com> (http://niftylettuce.com)",
|
|
14
|
-
"Alexis Tyler <xo@wvvw.me> (https://wvvw.me/)"
|
|
14
|
+
"Alexis Tyler <xo@wvvw.me> (https://wvvw.me/)",
|
|
15
|
+
"shadowgate15 (https://github.com/shadowgate15)",
|
|
16
|
+
"Spencer Snyder <sasnyde2@gmail.com> (https://spencersnyder.io)"
|
|
15
17
|
],
|
|
16
18
|
"dependencies": {
|
|
17
19
|
"@ladjs/format-util": "^1.0.4",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
20
|
+
"@strikeentco/get": "1.0.1",
|
|
21
|
+
"@strikeentco/set": "1.0.2",
|
|
22
|
+
"boolean": "3.2.0",
|
|
23
|
+
"console-polyfill": "0.3.0",
|
|
22
24
|
"format-specifiers": "^1.0.0",
|
|
23
|
-
"iserror": "
|
|
24
|
-
"
|
|
25
|
+
"iserror": "0.0.2",
|
|
26
|
+
"maybe-combine-errors": "1.0.0",
|
|
27
|
+
"merge-options": "3.0.4",
|
|
28
|
+
"p-map-series": "2",
|
|
25
29
|
"parse-app-info": "^4.0.3",
|
|
26
30
|
"parse-err": "^0.0.12",
|
|
27
|
-
"
|
|
31
|
+
"pick-deep": "1.0.0",
|
|
32
|
+
"unset-value": "2.0.1"
|
|
28
33
|
},
|
|
29
34
|
"devDependencies": {
|
|
30
35
|
"@babel/cli": "^7.17.10",
|
|
@@ -55,7 +60,7 @@
|
|
|
55
60
|
"rimraf": "^3.0.2",
|
|
56
61
|
"signale": "^1.4.0",
|
|
57
62
|
"sinon": "^14.0.0",
|
|
58
|
-
"tinyify": "
|
|
63
|
+
"tinyify": "3.0.0",
|
|
59
64
|
"xo": "^0.50.0"
|
|
60
65
|
},
|
|
61
66
|
"engines": {
|
|
@@ -111,16 +116,16 @@
|
|
|
111
116
|
},
|
|
112
117
|
"scripts": {
|
|
113
118
|
"ava": "cross-env NODE_ENV=test ava",
|
|
114
|
-
"browserify": "browserify src/index.js -o dist/axe.js -s Axe -g [ babelify --configFile ./.dist.babelrc ]",
|
|
119
|
+
"browserify": "browserify src/index.js -o dist/axe.js -s Axe -g [ babelify --configFile ./.dist.babelrc.json ]",
|
|
115
120
|
"build": "npm run build:clean && npm run build:lib && npm run build:dist",
|
|
116
121
|
"build:clean": "rimraf lib dist",
|
|
117
122
|
"build:dist": "npm run browserify && npm run minify",
|
|
118
|
-
"build:lib": "babel --config-file ./.lib.babelrc src --out-dir lib",
|
|
123
|
+
"build:lib": "babel --config-file ./.lib.babelrc.json src --out-dir lib",
|
|
119
124
|
"lint": "xo --fix && remark . -qfo && fixpack",
|
|
120
125
|
"lint-build": "npm run lint-lib && npm run lint-dist",
|
|
121
|
-
"lint-dist": "eslint --no-inline-config -c .dist.eslintrc dist",
|
|
122
|
-
"lint-lib": "eslint --no-inline-config -c .lib.eslintrc lib",
|
|
123
|
-
"minify": "cross-env NODE_ENV=production browserify src/index.js -o dist/axe.min.js -s Axe -g [ babelify --configFile ./.dist.babelrc ] -p tinyify",
|
|
126
|
+
"lint-dist": "eslint --no-inline-config -c .dist.eslintrc.json dist",
|
|
127
|
+
"lint-lib": "eslint --no-inline-config -c .lib.eslintrc.json lib",
|
|
128
|
+
"minify": "cross-env NODE_ENV=production browserify src/index.js -o dist/axe.min.js -s Axe -g [ babelify --configFile ./.dist.babelrc.json ] -p tinyify",
|
|
124
129
|
"nyc": "cross-env NODE_ENV=test nyc ava",
|
|
125
130
|
"prepare": "husky install",
|
|
126
131
|
"pretest": "npm run lint",
|