@mmutils/logger 0.1.0 → 0.1.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.
Files changed (2) hide show
  1. package/README.md +159 -22
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -78,6 +78,8 @@ Requires Node.js 20 or newer.
78
78
 
79
79
  ## Quick start
80
80
 
81
+ <!-- code:quick-start -->
82
+
81
83
  ```ts
82
84
  import { Logger, messagePlugin, graphPlugin } from '@mmutils/logger';
83
85
 
@@ -92,8 +94,12 @@ logger.error(new Error('Connection lost'));
92
94
  logger.infoGraph([1, 3, 8, 21, 8, 3], { title: 'CPU', unit: '%' });
93
95
  ```
94
96
 
95
- This prints the sample at the top. Plugins can also be chained, with the
96
- same typing:
97
+ <!-- /code -->
98
+
99
+ This prints the sample at the top
100
+ ([`examples/quick-start.js`](examples/quick-start.js)); every feature has
101
+ its own example, see [Examples](#examples). Plugins can also be chained,
102
+ with the same typing:
97
103
 
98
104
  ```ts
99
105
  const logger = new Logger().use(messagePlugin()).use(graphPlugin());
@@ -291,6 +297,36 @@ logger.infoGraph(values, {
291
297
  });
292
298
  ```
293
299
 
300
+ For example, from [`examples/graphs.js`](examples/graphs.js), with the
301
+ datasets of [`examples/data.js`](examples/data.js):
302
+
303
+ <!-- code:graph -->
304
+
305
+ ```ts
306
+ logger.infoGraph(latency, {
307
+ title: 'Latency',
308
+ unit: 'ms',
309
+ precision: 0,
310
+ aggregate: 'max', // the slowest request of each bar
311
+ axis: { start: 0, end: 1032.4, unit: 'ms', capTo: 1 }, // a time axis
312
+ });
313
+ logger.warningGraph(queue, {
314
+ title: 'Queue',
315
+ rows: 2,
316
+ axis: { start: 'Mon', end: 'Fri' },
317
+ });
318
+ logger.infoGraph(temperatures, {
319
+ title: 'Temperature',
320
+ unit: '°C',
321
+ precision: 1,
322
+ rows: 4,
323
+ baseline: 20, // warmer days grow up, colder days down
324
+ axis: { start: 'Mar 2', end: 'Mar 15' },
325
+ });
326
+ ```
327
+
328
+ <!-- /code -->
329
+
294
330
  ![A latency graph with max aggregation and a time axis, a queue graph with day labels, and a temperature graph split at 20 °C](assets/graph.svg)
295
331
 
296
332
  <details>
@@ -300,14 +336,14 @@ logger.infoGraph(values, {
300
336
 
301
337
  ```text
302
338
  2026/03/16 15:35:00 [i] info
303
- Latency 89.17 ms
304
- │ █ │
305
- │ ▁▁ ▁▁█ │
306
- │▆█████▇▅▄▃▂▃▄▅▆█████▇▆▄▃▂▂▃▅▆▇│
339
+ Latency 370 ms
340
+ │ ▇ ▇ ▃ ▆ █ ▃ │
341
+ │▃▄█▅▅▄█▃▂ █ ▁▂█▄▅▅█▄▃▂▁█ │
342
+ │████████████▇█████████████▇▇▇█│
307
343
  0ms 1s 32ms
308
- average: 20.72 ms 0.00 ms
309
- min: 8.00 ms
310
- max: 89.17 ms
344
+ average: 154 ms 0 ms
345
+ min: 105 ms
346
+ max: 370 ms
311
347
  2026/03/16 15:35:00 /!\ warning
312
348
  Queue 9.00
313
349
  │ ▁▁▃▃▄▆▆██▆▆▄▃▃▁▁ │
@@ -317,16 +353,16 @@ average: 4.76 0.00
317
353
  min: 1.00
318
354
  max: 9.00
319
355
  2026/03/16 15:35:00 [i] info
320
- Temperature 25.1 °C
321
- │ ▁▂▁▁ │
322
- │ ▄▅▇██████▆▆▂▂ │
323
- │ ▀▀█████████████│
324
- │ ▔▀▀█████▀▀▔▔│
356
+ Temperature 25.8 °C
357
+ │ ▂▃▆▇██▆▄▁ │
358
+ │▄▄█████████▄▃ ▁▁▁▁│
359
+ │ ▀▀████████▀▔▔ │
360
+ │ ▔▔▀▀▀▀▔ │
325
361
  Mar 2 Mar 15
326
- average: 18.4 °C 11.5 °C
362
+ average: 20.4 °C 15.4 °C
327
363
  baseline: 20.0 °C
328
- min: 11.5 °C
329
- max: 25.1 °C
364
+ min: 15.4 °C
365
+ max: 25.8 °C
330
366
  ```
331
367
 
332
368
  <!-- /output -->
@@ -388,6 +424,38 @@ from -10 to 10:
388
424
  | `'max'` | only down, from 10 |
389
425
  | `20` (any value) | only down, from 20: the range holds it |
390
426
 
427
+ The first three on a wave from -8 to 8
428
+ ([`examples/graph-baseline.js`](examples/graph-baseline.js) has a realistic
429
+ case for each):
430
+
431
+ ![The same wave with baseline 0 (split), 'min' (bars up) and 'max' (bars down), side by side](assets/baseline.svg)
432
+
433
+ <details>
434
+ <summary><sub>The output above as plain text</sub></summary>
435
+
436
+ <!-- output:baseline -->
437
+
438
+ ```text
439
+ info | info | info
440
+ baseline: 0 8 | baseline: 'min' 8 | baseline: 'max' 8
441
+ │ ▄▆██▆▄ │ | │ ▄▆██▆▄ │ | │███▀▔ ▔▀█████████████│
442
+ │ ▄████████▄ │ | │ ▄████████▄ │ | │█▀ ▀███████████│
443
+ │ ▀████████▀│ | │████████████▄ ▄│ | │ ▀████████▀│
444
+ │ ▀▀██▀▀ │ | │██████████████▄▂ ▂▄██│ | │ ▀▀██▀▀ │
445
+ average: 0 -8 | average: 0 -8 | average: 0 -8
446
+ baseline: 0 | min: -8 | min: -8
447
+ min: -8 | max: 8 | max: 8
448
+ max: 8 | |
449
+ ```
450
+
451
+ <!-- /output -->
452
+
453
+ <sub><i>Bars and frames may not line up in this text if your font lacks the block characters; the image shows the real alignment.</i></sub>
454
+
455
+ </details>
456
+
457
+ ---
458
+
391
459
  ```ts
392
460
  logger.infoGraph(temperatures, {
393
461
  title: 'Temperature',
@@ -469,6 +537,8 @@ ignored)` if the plugin has none. A `max` below a numeric baseline is
469
537
  `columnsPlugin()` lays out messages and graphs side by side. Each log is a
470
538
  cell of a grid; `column()` picks the column the next logs go to:
471
539
 
540
+ <!-- code:columns -->
541
+
472
542
  ```ts
473
543
  const logger = new Logger({ timestamp: 'HH:mm:ss' }) // short, for narrow columns
474
544
  .use(messagePlugin())
@@ -488,6 +558,8 @@ for (const column of [0, 1]) {
488
558
  logger.endColumns();
489
559
  ```
490
560
 
561
+ <!-- /code -->
562
+
491
563
  ![Two columns side by side: wrapped messages and graphs, call for call](assets/columns.svg)
492
564
 
493
565
  <details>
@@ -608,20 +680,31 @@ collectors, and becomes the default kind. Use it **instead of**
608
680
  one output style (e.g. JSON in production, `messagePlugin` in development).
609
681
  If both set the default kind, the last one used wins:
610
682
 
683
+ <!-- code:json -->
684
+
611
685
  ```ts
612
686
  import { Logger, jsonPlugin } from '@mmutils/logger';
613
687
 
614
688
  const logger = new Logger({ plugins: [jsonPlugin()] });
689
+ const err = Object.assign(new Error('connect ECONNREFUSED 127.0.0.1:5432'), {
690
+ code: 'ECONNREFUSED',
691
+ });
615
692
 
616
693
  logger.info({ msg: 'Server started', port: 8080 });
617
694
  logger.error({ msg: 'Query failed', err });
618
695
  ```
619
696
 
620
- ```
697
+ <!-- /code -->
698
+
699
+ <!-- output:json -->
700
+
701
+ ```text
621
702
  {"id":1,"time":"2026-03-16T15:35:00.000Z","type":"info","data":{"msg":"Server started","port":8080}}
622
- {"id":2,"time":"2026-03-16T15:35:00.004Z","type":"error","data":{"msg":"Query failed","err":{"name":"Error","message":"connect ECONNREFUSED 127.0.0.1:5432","stack":"Error: connect ECONNREFUSED 127.0.0.1:5432\n at …","code":"ECONNREFUSED"}}}
703
+ {"id":2,"time":"2026-03-16T15:35:00.000Z","type":"error","data":{"msg":"Query failed","err":{"name":"Error","message":"connect ECONNREFUSED 127.0.0.1:5432","stack":"Error: connect ECONNREFUSED 127.0.0.1:5432\n at main (file:///app/server.js:12:16)","code":"ECONNREFUSED"}}}
623
704
  ```
624
705
 
706
+ <!-- /output -->
707
+
625
708
  ```ts
626
709
  jsonPlugin({
627
710
  kind: 'json', // kind written by the plugin
@@ -761,7 +844,32 @@ plugins use:
761
844
  The level colors are the terminal's 16 basic colors, so they follow its
762
845
  theme: red for `fatal` (its badge is white on red), bright red for `error`,
763
846
  yellow for `warning`, blue for `info`, magenta for `debug`, cyan for
764
- `trace`, gray for `verbose`.
847
+ `trace`, gray for `verbose`
848
+ ([`examples/levels.js`](examples/levels.js),
849
+ [`examples/styles.js`](examples/styles.js)):
850
+
851
+ ![One message per log type, from fatal to verbose, each with its symbol, badge and color](assets/levels.svg)
852
+
853
+ <details>
854
+ <summary><sub>The output above as plain text</sub></summary>
855
+
856
+ <!-- output:levels -->
857
+
858
+ ```text
859
+ 2026/03/16 15:35:00 [X] fatal Out of memory: the process exits now
860
+ 2026/03/16 15:35:00 [!] error Payment failed: card declined for order 1042
861
+ 2026/03/16 15:35:00 /!\ warning Disk 91% full on /var, cleanup starts at 95%
862
+ 2026/03/16 15:35:00 [i] info Server listening on http://localhost:8080
863
+ 2026/03/16 15:35:00 (?) debug Cache miss for user:42, loading from the database
864
+ 2026/03/16 15:35:00 /\/ trace GET /api/orders → 200 in 34 ms
865
+ 2026/03/16 15:35:00 ... verbose Pool: 3 of 10 connections in use
866
+ ```
867
+
868
+ <!-- /output -->
869
+
870
+ </details>
871
+
872
+ ---
765
873
 
766
874
  ### Symbols
767
875
 
@@ -879,14 +987,43 @@ Re-declaring an existing logger method in `M` replaces its signature and docs
879
987
  in autocomplete. That's how `messagePlugin` changes `info(data: unknown)` to
880
988
  `info(message: string)`.
881
989
 
990
+ ## Examples
991
+
992
+ Each file in [`examples/`](examples) shows one topic, with comments on what
993
+ to look for in its output. Build first, then run one, or all of them with
994
+ `npm run demo`:
995
+
996
+ ```sh
997
+ npm run build
998
+ node examples/graphs.js
999
+ ```
1000
+
1001
+ | File | Shows |
1002
+ | ------------------------------------------------- | ------------------------------------------------------------ |
1003
+ | [`quick-start.js`](examples/quick-start.js) | The quick start above |
1004
+ | [`levels.js`](examples/levels.js) | The seven log types, filtering with `level` |
1005
+ | [`messages.js`](examples/messages.js) | Text, objects, arrays, errors, values JSON can't represent |
1006
+ | [`timestamps.js`](examples/timestamps.js) | Patterns, UTC, the precise clock, elapsed time, a fixed time |
1007
+ | [`graphs.js`](examples/graphs.js) | Size, `aggregate`, axis labels, statistics |
1008
+ | [`graph-baseline.js`](examples/graph-baseline.js) | `baseline`, `min` and `max` on realistic data |
1009
+ | [`columns.js`](examples/columns.js) | Call for call, wrap modes, graph widths, `row(n)` |
1010
+ | [`live.js`](examples/live.js) | A status board redrawn in place (run it in a terminal) |
1011
+ | [`json.js`](examples/json.js) | JSON lines, time formats, limits, an audit kind |
1012
+ | [`safety.js`](examples/safety.js) | Sanitizing, output limits, data that can't be read |
1013
+ | [`styles.js`](examples/styles.js) | Level colors, symbols, overrides, `useStyles: false` |
1014
+ | [`custom-plugin.js`](examples/custom-plugin.js) | A new kind with a method, a transformer |
1015
+
1016
+ The images in this README are drawn from the same files
1017
+ (`npm run images`), so they show what the examples print.
1018
+
882
1019
  ## Development
883
1020
 
884
1021
  ```sh
885
1022
  npm install
886
1023
  npm run check # format, lint, typecheck, tests
887
1024
  npm run build # dist/esm, dist/cjs, dist/types
888
- npm run demo # feature tour (after build)
889
- npm run images # README images in assets/ and their text, from real output (after build)
1025
+ npm run demo # every example, one after the other (after build)
1026
+ npm run images # README images, their text and code, from examples/ (after build)
890
1027
  ```
891
1028
 
892
1029
  ## AI use
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmutils/logger",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Plugin-extensible TypeScript logger: a transformer pipeline, baked ANSI styles, styled messages, terminal bar graphs, side-by-side columns and JSON lines.",
5
5
  "keywords": [
6
6
  "logger",