metalog 3.1.5 → 3.1.8

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/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  ## [Unreleased][unreleased]
4
4
 
5
+ ## [3.1.8][] - 2022-03-30
6
+
7
+ - Add support for json-only logs
8
+
9
+ ## [3.1.7][] - 2022-03-17
10
+
11
+ - Fix unlink empty files
12
+ - Improve error handling
13
+ - Update dependencies and package maintenance
14
+
15
+ ## [3.1.6][] - 2021-12-08
16
+
17
+ - Fix typings
18
+ - Remove useless code from tests
19
+ - Fix unlink file bug
20
+
5
21
  ## [3.1.5][] - 2021-10-11
6
22
 
7
23
  - Update dependencies and npm audit fix
@@ -52,7 +68,10 @@
52
68
 
53
69
  First generation of Metarhia Logger
54
70
 
55
- [unreleased]: https://github.com/metarhia/metalog/compare/v3.1.5...HEAD
71
+ [unreleased]: https://github.com/metarhia/metalog/compare/v3.1.8...HEAD
72
+ [3.1.8]: https://github.com/metarhia/metalog/compare/v3.1.7...v3.1.8
73
+ [3.1.7]: https://github.com/metarhia/metalog/compare/v3.1.6...v3.1.7
74
+ [3.1.6]: https://github.com/metarhia/metalog/compare/v3.1.5...v3.1.6
56
75
  [3.1.5]: https://github.com/metarhia/metalog/compare/v3.1.4...v3.1.5
57
76
  [3.1.4]: https://github.com/metarhia/metalog/compare/v3.1.3...v3.1.4
58
77
  [3.1.3]: https://github.com/metarhia/metalog/compare/v3.1.2...v3.1.3
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2021 Metarhia
3
+ Copyright (c) 2017-2022 Metarhia
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Meta Logger for Metarhia
2
2
 
3
3
  [![ci status](https://github.com/metarhia/metalog/workflows/Testing%20CI/badge.svg)](https://github.com/metarhia/metalog/actions?query=workflow%3A%22Testing+CI%22+branch%3Amaster)
4
- [![codacy](https://api.codacy.com/project/badge/Grade/7aaad5ed17c74634855fa6202a03a56e)](https://www.codacy.com/app/metarhia/metalog)
5
4
  [![snyk](https://snyk.io/test/github/metarhia/impress/badge.svg)](https://snyk.io/test/github/metarhia/impress)
6
5
  [![npm version](https://img.shields.io/npm/v/metalog.svg?style=flat)](https://www.npmjs.com/package/metalog)
7
6
  [![npm downloads/month](https://img.shields.io/npm/dm/metalog.svg)](https://www.npmjs.com/package/metalog)
@@ -22,6 +21,7 @@ const logger = await metalog.openLog({
22
21
  writeBuffer: 64 * 1024, // buffer size (default 64kb)
23
22
  keepDays: 5, // delete after N days, 0 - disable
24
23
  home: process.cwd(), // remove substring from paths
24
+ json: false, // print logs in JSON format, by default false
25
25
  });
26
26
 
27
27
  const { console } = logger;
@@ -31,6 +31,6 @@ await logger.close();
31
31
 
32
32
  ## License & Contributors
33
33
 
34
- Copyright (c) 2017-2021 [Metarhia contributors](https://github.com/metarhia/metalog/graphs/contributors).
34
+ Copyright (c) 2017-2022 [Metarhia contributors](https://github.com/metarhia/metalog/graphs/contributors).
35
35
  Metalog is [MIT licensed](./LICENSE).\
36
36
  Metalog is a part of [Metarhia](https://github.com/metarhia) technology stack.
package/metalog.d.ts CHANGED
@@ -3,13 +3,14 @@ import EventEmitter = require('events');
3
3
  interface LoggerOptions {
4
4
  path: string;
5
5
  home: string;
6
- workerId: number;
7
- createStream: () => NodeJS.WritableStream;
6
+ workerId?: number;
7
+ createStream?: () => NodeJS.WritableStream;
8
8
  writeInterval: number;
9
9
  writeBuffer: number;
10
10
  keepDays: number;
11
- toFile: Array<string>;
12
- toStdout: Array<string>;
11
+ json?: boolean;
12
+ toFile?: Array<string>;
13
+ toStdout?: Array<string>;
13
14
  }
14
15
 
15
16
  export class Logger extends EventEmitter {
@@ -27,9 +28,9 @@ export class Logger extends EventEmitter {
27
28
  lock: boolean;
28
29
  buffer: Array<Buffer>;
29
30
  file: string;
30
- toFile: Array<string>;
31
+ toFile: Record<string, boolean>;
31
32
  fsEnabled: boolean;
32
- toStdout: Array<string>;
33
+ toStdout: Record<string, boolean>;
33
34
  console: Console;
34
35
  constructor(args: LoggerOptions);
35
36
  createLogDir(): Promise<void>;
package/metalog.js CHANGED
@@ -77,10 +77,13 @@ const getNextReopen = () => {
77
77
  return nextDate - curTime + DAY_MILLISECONDS;
78
78
  };
79
79
 
80
+ const isError = (val) =>
81
+ Object.prototype.toString.call(val) === '[object Error]';
82
+
80
83
  class Console {
81
84
  constructor(write) {
82
85
  this._write = write;
83
- this._groupIndent = '';
86
+ this._groupIndent = 0;
84
87
  this._counts = new Map();
85
88
  this._times = new Map();
86
89
  }
@@ -89,7 +92,7 @@ class Console {
89
92
  try {
90
93
  console.assert(assertion, ...args);
91
94
  } catch (err) {
92
- this._write('error', `${this._groupIndent}${err.stack}`);
95
+ this._write('error', this._groupIndent, err.stack);
93
96
  }
94
97
  }
95
98
 
@@ -102,7 +105,7 @@ class Console {
102
105
  let cnt = this._counts.get(label) || 0;
103
106
  cnt++;
104
107
  this._counts.set(label, cnt);
105
- this._write('debug', `${this._groupIndent}${label}: ${cnt}`);
108
+ this._write('debug', this._groupIndent, `${label}: ${cnt}`);
106
109
  }
107
110
 
108
111
  countReset(label = 'default') {
@@ -110,23 +113,38 @@ class Console {
110
113
  }
111
114
 
112
115
  debug(...args) {
113
- const msg = util.format(...args);
114
- this._write('debug', `${this._groupIndent}${msg}`);
116
+ this._write('debug', this._groupIndent, ...args);
115
117
  }
116
118
 
117
119
  dir(...args) {
118
- const msg = util.inspect(...args);
119
- this._write('debug', `${this._groupIndent}${msg}`);
120
+ this._write('debug', this._groupIndent, ...args);
120
121
  }
121
122
 
122
- error(...args) {
123
+ trace(...args) {
123
124
  const msg = util.format(...args);
124
- this._write('error', `${this._groupIndent}${msg}`);
125
+ const err = new Error(msg);
126
+ this._write('debug', this._groupIndent, `Trace${err.stack}`);
127
+ }
128
+
129
+ info(...args) {
130
+ this._write('info', this._groupIndent, ...args);
131
+ }
132
+
133
+ log(...args) {
134
+ this._write('log', this._groupIndent, ...args);
135
+ }
136
+
137
+ warn(...args) {
138
+ this._write('warn', this._groupIndent, ...args);
139
+ }
140
+
141
+ error(...args) {
142
+ this._write('error', this._groupIndent, ...args);
125
143
  }
126
144
 
127
145
  group(...args) {
128
146
  if (args.length !== 0) this.log(...args);
129
- this._groupIndent = ' '.repeat(this._groupIndent.length + INDENT);
147
+ this._groupIndent += INDENT;
130
148
  }
131
149
 
132
150
  groupCollapsed(...args) {
@@ -135,21 +153,11 @@ class Console {
135
153
 
136
154
  groupEnd() {
137
155
  if (this._groupIndent.length === 0) return;
138
- this._groupIndent = ' '.repeat(this._groupIndent.length - INDENT);
139
- }
140
-
141
- info(...args) {
142
- const msg = util.format(...args);
143
- this._write('info', `${this._groupIndent}${msg}`);
144
- }
145
-
146
- log(...args) {
147
- const msg = util.format(...args);
148
- this._write('log', `${this._groupIndent}${msg}`);
156
+ this._groupIndent -= INDENT;
149
157
  }
150
158
 
151
159
  table(tabularData) {
152
- this._write('log', JSON.stringify(tabularData));
160
+ this._write('log', 0, JSON.stringify(tabularData));
153
161
  }
154
162
 
155
163
  time(label = 'default') {
@@ -160,31 +168,18 @@ class Console {
160
168
  const startTime = this._times.get(label);
161
169
  const totalTime = process.hrtime(startTime);
162
170
  const totalTimeMs = totalTime[0] * 1e3 + totalTime[1] / 1e6;
163
- const msg = `${this._groupIndent}${label}: ${totalTimeMs}ms`;
164
- this.timeLog(label, msg);
171
+ this.timeLog(label, `${label}: ${totalTimeMs}ms`);
165
172
  this._times.delete(label);
166
173
  }
167
174
 
168
175
  timeLog(label, ...args) {
169
176
  const startTime = this._times.get(label);
170
177
  if (startTime === undefined) {
171
- const msg = `${this._groupIndent}Warning: No such label '${label}'`;
172
- this._write('warn', msg);
178
+ const msg = `Warning: No such label '${label}'`;
179
+ this._write('warn', this._groupIndent, msg);
173
180
  return;
174
181
  }
175
- const msg = util.format(...args);
176
- this._write('debug', msg);
177
- }
178
-
179
- trace(...args) {
180
- const msg = util.format(...args);
181
- const err = new Error(msg);
182
- this._write('debug', `${this._groupIndent}Trace${err.stack}`);
183
- }
184
-
185
- warn(...args) {
186
- const msg = util.format(...args);
187
- this._write('warn', `${this._groupIndent}${msg}`);
182
+ this._write('debug', this._groupIndent, ...args);
188
183
  }
189
184
  }
190
185
 
@@ -192,7 +187,7 @@ class Logger extends events.EventEmitter {
192
187
  constructor(args) {
193
188
  super();
194
189
  const { workerId = 0, createStream = fs.createWriteStream } = args;
195
- const { writeInterval, writeBuffer, keepDays, home } = args;
190
+ const { writeInterval, writeBuffer, keepDays, home, json } = args;
196
191
  const { toFile, toStdout } = args;
197
192
  this.active = false;
198
193
  this.path = args.path;
@@ -202,6 +197,7 @@ class Logger extends events.EventEmitter {
202
197
  this.writeBuffer = writeBuffer || DEFAULT_BUFFER_SIZE;
203
198
  this.keepDays = keepDays || DEFAULT_KEEP_DAYS;
204
199
  this.home = home;
200
+ this.json = Boolean(json);
205
201
  this.stream = null;
206
202
  this.reopenTimer = null;
207
203
  this.flushTimer = null;
@@ -211,7 +207,7 @@ class Logger extends events.EventEmitter {
211
207
  this.toFile = logTypes(toFile);
212
208
  this.fsEnabled = Object.keys(this.toFile).length !== 0;
213
209
  this.toStdout = logTypes(toStdout);
214
- this.console = new Console((type, message) => this.write(type, message));
210
+ this.console = new Console((...args) => this.write(...args));
215
211
  return this.open();
216
212
  }
217
213
 
@@ -224,7 +220,8 @@ class Logger extends events.EventEmitter {
224
220
  resolve();
225
221
  return;
226
222
  }
227
- this.emit(new Error(`Can not create directory: ${this.path}\n`));
223
+ const error = new Error(`Can not create directory: ${this.path}\n`);
224
+ this.emit('error', error);
228
225
  reject();
229
226
  });
230
227
  });
@@ -246,7 +243,10 @@ class Logger extends events.EventEmitter {
246
243
  this.once('close', () => {
247
244
  this.open();
248
245
  });
249
- this.close();
246
+ this.close().catch((err) => {
247
+ process.stdout.write(`${err.stack}\n`);
248
+ this.emit('error', err);
249
+ });
250
250
  }, nextReopen);
251
251
  if (this.keepDays) await this.rotate();
252
252
  const options = { flags: 'a', bufferSize: this.writeBuffer };
@@ -278,8 +278,6 @@ class Logger extends events.EventEmitter {
278
278
  return new Promise((resolve, reject) => {
279
279
  this.flush((err) => {
280
280
  if (err) {
281
- process.stdout.write(`${err.stack}\n`);
282
- this.emit('error', err);
283
281
  reject(err);
284
282
  return;
285
283
  }
@@ -291,11 +289,11 @@ class Logger extends events.EventEmitter {
291
289
  this.reopenTimer = null;
292
290
  const fileName = this.file;
293
291
  this.emit('close');
294
- resolve();
295
292
  fs.stat(fileName, (err, stats) => {
296
293
  if (!err && stats.size === 0) {
297
- fsp.unlink(this.file);
294
+ fsp.unlink(fileName).catch(() => {});
298
295
  }
296
+ resolve();
299
297
  });
300
298
  });
301
299
  });
@@ -321,25 +319,63 @@ class Logger extends events.EventEmitter {
321
319
  }
322
320
  }
323
321
 
324
- write(type, s) {
325
- const date = new Date();
326
- const dateTime = date.toISOString();
322
+ format(type, indent, ...args) {
327
323
  const normalize = type === 'error' || type === 'debug';
328
- const message = normalize ? this.normalizeStack(s) : s;
324
+ const s = `${' '.repeat(indent)}${util.format(...args)}`;
325
+ return normalize ? this.normalizeStack(s) : s;
326
+ }
327
+
328
+ formatPretty(type, indent, ...args) {
329
+ const dateTime = new Date().toISOString();
330
+ const message = this.format(type, indent, ...args);
331
+ const normalColor = TEXT_COLOR[type];
332
+ const markColor = TYPE_COLOR[type];
333
+ const time = normalColor(dateTime.substring(TIME_START, TIME_END));
334
+ const id = normalColor(this.workerId);
335
+ const mark = markColor(' ' + type.padEnd(TYPE_LENGTH));
336
+ const msg = normalColor(message);
337
+ return `${time} ${id} ${mark} ${msg}`;
338
+ }
339
+
340
+ formatFile(type, indent, ...args) {
341
+ const dateTime = new Date().toISOString();
342
+ const message = this.format(type, indent, ...args);
343
+ const msg = metautil.replace(message, '\n', LINE_SEPARATOR);
344
+ return `${dateTime} [${type}] ${msg}`;
345
+ }
346
+
347
+ formatJson(type, indent, ...args) {
348
+ const log = {
349
+ timestamp: new Date().toISOString(),
350
+ workerId: this.workerId,
351
+ level: type,
352
+ message: null,
353
+ };
354
+ if (isError(args[0])) {
355
+ log.err = this.expandError(args[0]);
356
+ args = args.slice(1);
357
+ } else if (typeof args[0] === 'object') {
358
+ Object.assign(log, args[0]);
359
+ if (isError(log.err)) log.err = this.expandError(log.err);
360
+ if (isError(log.error)) log.error = this.expandError(log.error);
361
+ args = args.slice(1);
362
+ }
363
+ log.message = util.format(...args);
364
+ return JSON.stringify(log);
365
+ }
366
+
367
+ write(type, indent, ...args) {
329
368
  if (this.toStdout[type]) {
330
- const normalColor = TEXT_COLOR[type];
331
- const markColor = TYPE_COLOR[type];
332
- const time = normalColor(dateTime.substring(TIME_START, TIME_END));
333
- const id = normalColor(this.workerId);
334
- const mark = markColor(' ' + type.padEnd(TYPE_LENGTH));
335
- const msg = normalColor(message);
336
- const line = `${time} ${id} ${mark} ${msg}\n`;
337
- process.stdout.write(line);
369
+ const line = this.json
370
+ ? this.formatJson(type, indent, ...args)
371
+ : this.formatPretty(type, indent, ...args);
372
+ process.stdout.write(line + '\n');
338
373
  }
339
374
  if (this.toFile[type]) {
340
- const msg = metautil.replace(message, '\n', LINE_SEPARATOR);
341
- const line = `${dateTime} [${type}] ${msg}\n`;
342
- const buffer = Buffer.from(line);
375
+ const line = this.json
376
+ ? this.formatJson(type, indent, ...args)
377
+ : this.formatFile(type, indent, ...args);
378
+ const buffer = Buffer.from(line + '\n');
343
379
  this.buffer.push(buffer);
344
380
  }
345
381
  }
@@ -375,6 +411,14 @@ class Logger extends events.EventEmitter {
375
411
  if (this.home) res = metautil.replace(res, this.home, '');
376
412
  return res;
377
413
  }
414
+
415
+ expandError(err) {
416
+ return {
417
+ message: err.message,
418
+ stack: this.normalizeStack(err.stack),
419
+ ...err,
420
+ };
421
+ }
378
422
  }
379
423
 
380
424
  const openLog = async (args) => new Logger(args);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metalog",
3
- "version": "3.1.5",
3
+ "version": "3.1.8",
4
4
  "author": "Timur Shemsedinov <timur.shemsedinov@gmail.com>",
5
5
  "description": "Logger for Metarhia",
6
6
  "license": "MIT",
@@ -49,21 +49,21 @@
49
49
  "fmt": "prettier --write \"**/*.js\" \"**/*.json\" \"**/*.md\" \"**/.*rc\" \"**/*.ts\""
50
50
  },
51
51
  "engines": {
52
- "node": "^12.10 || 14 || 16"
52
+ "node": "^12.10 || 14 || 16 || 17"
53
53
  },
54
54
  "dependencies": {
55
55
  "concolor": "^1.0.2",
56
- "metautil": "^3.5.16"
56
+ "metautil": "^3.5.19"
57
57
  },
58
58
  "devDependencies": {
59
- "@types/node": "^16.10.3",
60
- "eslint": "^7.32.0",
59
+ "@types/node": "^17.0.21",
60
+ "eslint": "^8.11.0",
61
61
  "eslint-config-metarhia": "^7.0.0",
62
- "eslint-config-prettier": "^8.3.0",
63
- "eslint-plugin-import": "^2.24.2",
62
+ "eslint-config-prettier": "^8.5.0",
63
+ "eslint-plugin-import": "^2.25.4",
64
64
  "eslint-plugin-prettier": "^4.0.0",
65
- "metatests": "^0.7.2",
66
- "prettier": "^2.4.1",
67
- "typescript": "^4.4.3"
65
+ "metatests": "^0.8.2",
66
+ "prettier": "^2.6.0",
67
+ "typescript": "^4.6.2"
68
68
  }
69
69
  }