@fend/firo 0.0.3 → 0.0.5
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 +115 -29
- package/dist/index.cjs +70 -53
- package/dist/index.d.cts +51 -5
- package/dist/index.d.ts +51 -5
- package/dist/index.js +73 -51
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# firo 🌲
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@fend/firo)
|
|
4
|
+
[](https://jsr.io/@fend/firo)
|
|
5
|
+
[](https://jsr.io/@fend/firo/score)
|
|
6
|
+
[](https://github.com/fend25/firo/blob/main/README.md)
|
|
7
|
+
[](https://github.com/fend25/firo/actions/workflows/publish.yml)
|
|
8
|
+
[](https://github.com/fend25/firo)
|
|
9
|
+
|
|
3
10
|
**Spruce up your logs!**
|
|
4
11
|
|
|
5
12
|
The logger for Node.js, Bun and Deno you've been looking for.
|
|
@@ -47,9 +54,9 @@ deno add jsr:@fend/firo
|
|
|
47
54
|
## Quick start
|
|
48
55
|
|
|
49
56
|
```ts
|
|
50
|
-
import {
|
|
57
|
+
import { createFiro } from '@fend/firo'
|
|
51
58
|
|
|
52
|
-
const log =
|
|
59
|
+
const log = createFiro()
|
|
53
60
|
|
|
54
61
|
// log() is shorthand for log.info()
|
|
55
62
|
log('Server started')
|
|
@@ -72,7 +79,7 @@ Dev output:
|
|
|
72
79
|
Colored, human-readable. Errors go to `stderr`, everything else to `stdout`.
|
|
73
80
|
|
|
74
81
|
```ts
|
|
75
|
-
const log =
|
|
82
|
+
const log = createFiro({ mode: 'dev' })
|
|
76
83
|
```
|
|
77
84
|
|
|
78
85
|
### Prod
|
|
@@ -80,7 +87,7 @@ const log = createLogger({ mode: 'dev' })
|
|
|
80
87
|
Structured NDJSON. Everything goes to `stdout` — let your infrastructure route it.
|
|
81
88
|
|
|
82
89
|
```ts
|
|
83
|
-
const log =
|
|
90
|
+
const log = createFiro({ mode: 'prod' })
|
|
84
91
|
|
|
85
92
|
log.info('Request handled', { status: 200 })
|
|
86
93
|
// {"timestamp":"2024-01-15T14:32:01.204Z","level":"info","message":"Request handled","data":{"status":200}}
|
|
@@ -94,9 +101,9 @@ The best way to use **firo** in web frameworks is to store a child logger in `As
|
|
|
94
101
|
|
|
95
102
|
```ts
|
|
96
103
|
import { AsyncLocalStorage } from 'node:util'
|
|
97
|
-
import {
|
|
104
|
+
import { createFiro } from '@fend/firo'
|
|
98
105
|
|
|
99
|
-
const logger =
|
|
106
|
+
const logger = createFiro()
|
|
100
107
|
const storage = new AsyncLocalStorage()
|
|
101
108
|
|
|
102
109
|
// Middleware example
|
|
@@ -133,13 +140,13 @@ Debug lines are dimmed in dev mode to reduce visual noise.
|
|
|
133
140
|
|
|
134
141
|
```ts
|
|
135
142
|
// Suppress debug in dev, keep everything in prod
|
|
136
|
-
const log =
|
|
143
|
+
const log = createFiro({
|
|
137
144
|
minLevelInDev: 'info',
|
|
138
145
|
minLevelInProd: 'warn',
|
|
139
146
|
})
|
|
140
147
|
|
|
141
148
|
// Or a single threshold for both modes
|
|
142
|
-
const log =
|
|
149
|
+
const log = createFiro({ minLevel: 'warn' })
|
|
143
150
|
```
|
|
144
151
|
|
|
145
152
|
## Context
|
|
@@ -147,7 +154,7 @@ const log = createLogger({ minLevel: 'warn' })
|
|
|
147
154
|
Attach persistent key/value pairs to a logger instance. They appear in every log line.
|
|
148
155
|
|
|
149
156
|
```ts
|
|
150
|
-
const log =
|
|
157
|
+
const log = createFiro()
|
|
151
158
|
|
|
152
159
|
log.addContext('service', 'auth')
|
|
153
160
|
log.addContext('env', 'production')
|
|
@@ -164,7 +171,7 @@ log.info('Started')
|
|
|
164
171
|
log.addContext({ key: 'userId', value: 'u-789', omitKey: true })
|
|
165
172
|
// renders as [u-789] instead of [userId:u-789]
|
|
166
173
|
|
|
167
|
-
// Pin a specific color (0–
|
|
174
|
+
// Pin a specific color by palette index (0–29)
|
|
168
175
|
log.addContext({ key: 'region', value: 'west', colorIndex: 3 })
|
|
169
176
|
|
|
170
177
|
// Use any ANSI color — 256-color, truecolor, anything
|
|
@@ -189,7 +196,7 @@ const ctx = log.getContext() // ContextItem[]
|
|
|
189
196
|
Create a scoped logger that inherits the parent's context at the moment of creation. Parent and child are fully isolated — mutations on one do not affect the other.
|
|
190
197
|
|
|
191
198
|
```ts
|
|
192
|
-
const log =
|
|
199
|
+
const log = createFiro()
|
|
193
200
|
log.addContext('service', 'api')
|
|
194
201
|
|
|
195
202
|
const reqLog = log.child({ requestId: 'req-123', method: 'POST' })
|
|
@@ -260,7 +267,22 @@ const myTransport: TransportFn = (level, context, msg, data, opts) => {
|
|
|
260
267
|
// opts: LogOptions | undefined
|
|
261
268
|
}
|
|
262
269
|
|
|
263
|
-
const log =
|
|
270
|
+
const log = createFiro({ transport: myTransport })
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### FiroUtils
|
|
274
|
+
|
|
275
|
+
`FiroUtils` exposes helper functions useful for building custom transports:
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { FiroUtils } from '@fend/firo'
|
|
279
|
+
|
|
280
|
+
FiroUtils.wrapToError(value) // coerce unknown → Error
|
|
281
|
+
FiroUtils.serializeError(err) // Error → plain object { message, stack, name }
|
|
282
|
+
FiroUtils.safeStringify(obj) // JSON.stringify with bigint support + fallback
|
|
283
|
+
FiroUtils.jsonReplacer // replacer for JSON.stringify (handles bigint)
|
|
284
|
+
FiroUtils.colorize(text, idx) // wrap text in ANSI color by palette index
|
|
285
|
+
FiroUtils.colorizeLevel(level, t) // wrap text in level color (red/yellow/dim)
|
|
264
286
|
```
|
|
265
287
|
|
|
266
288
|
## Dev transport options
|
|
@@ -268,9 +290,9 @@ const log = createLogger({ transport: myTransport })
|
|
|
268
290
|
Fine-tune the dev transport's timestamp format. For example, to remove seconds and milliseconds:
|
|
269
291
|
|
|
270
292
|
```ts
|
|
271
|
-
import {
|
|
293
|
+
import { createFiro } from '@fend/firo'
|
|
272
294
|
|
|
273
|
-
const log =
|
|
295
|
+
const log = createFiro({
|
|
274
296
|
devTransportConfig: {
|
|
275
297
|
timeOptions: {
|
|
276
298
|
hour: '2-digit',
|
|
@@ -282,6 +304,45 @@ const log = createLogger({
|
|
|
282
304
|
})
|
|
283
305
|
```
|
|
284
306
|
|
|
307
|
+
## Prod transport options
|
|
308
|
+
|
|
309
|
+
Configure the prod (JSON) transport's timestamp format:
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
// Epoch ms (faster, same as pino)
|
|
313
|
+
const log = createFiro({
|
|
314
|
+
mode: 'prod',
|
|
315
|
+
prodTransportConfig: { timestamp: 'epoch' }
|
|
316
|
+
})
|
|
317
|
+
// {"timestamp":1711100000000,"level":"info","message":"hello"}
|
|
318
|
+
|
|
319
|
+
// ISO 8601 (default, human-readable)
|
|
320
|
+
const log = createFiro({ mode: 'prod' })
|
|
321
|
+
// {"timestamp":"2024-01-15T14:32:01.204Z","level":"info","message":"hello"}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Custom destination
|
|
325
|
+
|
|
326
|
+
By default, prod transport writes to `process.stdout`. You can redirect output to any object with a `.write(string)` method:
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
import { createFiro } from '@fend/firo'
|
|
330
|
+
import { createWriteStream } from 'node:fs'
|
|
331
|
+
|
|
332
|
+
// Write to a file
|
|
333
|
+
const log = createFiro({
|
|
334
|
+
mode: 'prod',
|
|
335
|
+
prodTransportConfig: { dest: createWriteStream('/var/log/app.log') }
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
// Use SonicBoom for async buffered writes (same as pino)
|
|
339
|
+
import SonicBoom from 'sonic-boom'
|
|
340
|
+
const log = createFiro({
|
|
341
|
+
mode: 'prod',
|
|
342
|
+
prodTransportConfig: { dest: new SonicBoom({ fd: 1 }) }
|
|
343
|
+
})
|
|
344
|
+
```
|
|
345
|
+
|
|
285
346
|
## Color palette
|
|
286
347
|
|
|
287
348
|
Most loggers give you monochrome walls of text. firo gives you **30 handpicked colors** that make context badges instantly scannable — you stop reading and start seeing.
|
|
@@ -290,14 +351,14 @@ Most loggers give you monochrome walls of text. firo gives you **30 handpicked c
|
|
|
290
351
|
|
|
291
352
|
### How it works
|
|
292
353
|
|
|
293
|
-
By default, firo auto-assigns colors from
|
|
354
|
+
By default, firo auto-assigns colors from all 30 palette colors using a hash of the context key. Similar keys like `user-1` and `user-2` land on different colors automatically.
|
|
294
355
|
|
|
295
|
-
|
|
356
|
+
You can also pin a specific color using `FIRO_COLORS` — a named palette with full IDE autocomplete:
|
|
296
357
|
|
|
297
358
|
```ts
|
|
298
|
-
import {
|
|
359
|
+
import { createFiro, FIRO_COLORS } from '@fend/firo'
|
|
299
360
|
|
|
300
|
-
const log =
|
|
361
|
+
const log = createFiro()
|
|
301
362
|
|
|
302
363
|
log.addContext('region', { value: 'west', color: FIRO_COLORS.coral })
|
|
303
364
|
log.addContext('service', { value: 'auth', color: FIRO_COLORS.skyBlue })
|
|
@@ -315,18 +376,12 @@ log.addContext('trace', { value: 'abc', color: '38;5;214' }) // 256-colo
|
|
|
315
376
|
log.addContext('span', { value: 'xyz', color: '38;2;255;105;180' }) // truecolor pink
|
|
316
377
|
```
|
|
317
378
|
|
|
318
|
-
###
|
|
379
|
+
### Restrict to safe colors
|
|
319
380
|
|
|
320
|
-
|
|
381
|
+
If your terminal doesn't support 256 colors, you can restrict auto-hash to 10 basic terminal-safe colors:
|
|
321
382
|
|
|
322
383
|
```ts
|
|
323
|
-
const log =
|
|
324
|
-
|
|
325
|
-
// Now every context key auto-gets one of 30 distinct colors
|
|
326
|
-
log.addContext('service', 'api')
|
|
327
|
-
log.addContext('region', 'west')
|
|
328
|
-
log.addContext('pod', 'web-3')
|
|
329
|
-
// Each badge is a different, beautiful color — no configuration needed
|
|
384
|
+
const log = createFiro({ useAllColors: false })
|
|
330
385
|
```
|
|
331
386
|
|
|
332
387
|
## Why not pino?
|
|
@@ -347,6 +402,35 @@ The problem with pino is development. Its default output is raw JSON — one gia
|
|
|
347
402
|
|
|
348
403
|
In prod it emits clean NDJSON, same as pino. Your log aggregator won't know the difference.
|
|
349
404
|
|
|
405
|
+
## Performance
|
|
406
|
+
|
|
407
|
+
Prod mode (NDJSON) with `timestamp: 'epoch'`, Apple M1, Node.js 25. Average time per 100K log lines (lower is better):
|
|
408
|
+
|
|
409
|
+
| Scenario | ops/sec | ms |
|
|
410
|
+
| ---------------------- | ------- | ------ |
|
|
411
|
+
| simple string | 782,488 | 127.8 |
|
|
412
|
+
| string + small obj | 656,512 | 152.3 |
|
|
413
|
+
| string + bigger obj | 513,087 | 194.9 |
|
|
414
|
+
| with 3 context items | 570,441 | 175.3 |
|
|
415
|
+
| child logger (2 ctx) | 568,977 | 175.8 |
|
|
416
|
+
| error with Error obj | 470,758 | 212.4 |
|
|
417
|
+
|
|
418
|
+
For comparison, here's [pino's own benchmark](https://github.com/pinojs/pino/blob/main/docs/benchmarks.md) (100K `"hello world"` logs):
|
|
419
|
+
|
|
420
|
+
| Logger | ms |
|
|
421
|
+
| ---------------- | ------ |
|
|
422
|
+
| pino | 114.8 |
|
|
423
|
+
| **firo** | **127.8** |
|
|
424
|
+
| bole | 172.7 |
|
|
425
|
+
| pino (NodeStream)| 159.2 |
|
|
426
|
+
| debug | 220.5 |
|
|
427
|
+
| winston | 270.2 |
|
|
428
|
+
| bunyan | 377.4 |
|
|
429
|
+
|
|
430
|
+
Pino is faster thanks to [SonicBoom](https://github.com/pinojs/sonic-boom) — an optimized async writer with buffering and [fast-json-stringify](https://github.com/fastify/fast-json-stringify) for schema-compiled serialization. firo uses plain `JSON.stringify` + `process.stdout.write` and lands within 8% of pino — a difference of ~130 nanoseconds per log line.
|
|
431
|
+
|
|
432
|
+
Run it yourself: `pnpm bench`
|
|
433
|
+
|
|
350
434
|
## API reference
|
|
351
435
|
|
|
352
436
|
### Logger methods
|
|
@@ -362,8 +446,9 @@ In prod it emits clean NDJSON, same as pino. Your log aggregator won't know the
|
|
|
362
446
|
| `addContext(item)` | Add a context entry (object form) |
|
|
363
447
|
| `removeFromContext(key)` | Remove a context entry by key |
|
|
364
448
|
| `getContext()` | Return the current context array |
|
|
449
|
+
| `hasInContext(key)` | Check if a context key exists |
|
|
365
450
|
|
|
366
|
-
### `
|
|
451
|
+
### `createFiro(config?)`
|
|
367
452
|
|
|
368
453
|
| Option | Type | Default | Description |
|
|
369
454
|
|---|---|---|---|
|
|
@@ -373,7 +458,8 @@ In prod it emits clean NDJSON, same as pino. Your log aggregator won't know the
|
|
|
373
458
|
| `minLevelInProd` | `LogLevel` | — | Overrides `minLevel` in prod mode |
|
|
374
459
|
| `transport` | `TransportFn` | — | Custom transport, overrides `mode` |
|
|
375
460
|
| `devTransportConfig` | `DevTransportConfig` | — | Options for the built-in dev transport |
|
|
376
|
-
| `
|
|
461
|
+
| `prodTransportConfig` | `ProdTransportConfig` | — | Options for the built-in JSON prod transport |
|
|
462
|
+
| `useAllColors` | `boolean` | `true` | Use all 30 palette colors for auto-hash (set `false` for 10 safe colors) |
|
|
377
463
|
|
|
378
464
|
## License
|
|
379
465
|
|
package/dist/index.cjs
CHANGED
|
@@ -31,13 +31,27 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
FIRO_COLORS: () => FIRO_COLORS,
|
|
34
|
+
FiroUtils: () => utils_exports,
|
|
34
35
|
createDevTransport: () => createDevTransport,
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
createFiro: () => createFiro,
|
|
37
|
+
createProdTransport: () => createProdTransport
|
|
37
38
|
});
|
|
38
39
|
module.exports = __toCommonJS(index_exports);
|
|
39
40
|
|
|
40
41
|
// src/utils.ts
|
|
42
|
+
var utils_exports = {};
|
|
43
|
+
__export(utils_exports, {
|
|
44
|
+
FIRO_COLORS: () => FIRO_COLORS,
|
|
45
|
+
LOG_LEVELS: () => LOG_LEVELS,
|
|
46
|
+
colorize: () => colorize,
|
|
47
|
+
colorizeLevel: () => colorizeLevel,
|
|
48
|
+
getColorIndex: () => getColorIndex,
|
|
49
|
+
jsonReplacer: () => jsonReplacer,
|
|
50
|
+
safeStringify: () => safeStringify,
|
|
51
|
+
serializeError: () => serializeError,
|
|
52
|
+
wrapToError: () => wrapToError
|
|
53
|
+
});
|
|
54
|
+
var import_node_util = require("util");
|
|
41
55
|
var LOG_LEVELS = {
|
|
42
56
|
debug: 20,
|
|
43
57
|
info: 30,
|
|
@@ -82,9 +96,9 @@ var COLORS_LIST = Object.values(FIRO_COLORS);
|
|
|
82
96
|
var SAFE_COLORS_COUNT = 10;
|
|
83
97
|
var getColorIndex = (str, useAllColors = false) => {
|
|
84
98
|
let hash = 0;
|
|
85
|
-
str.
|
|
86
|
-
hash =
|
|
87
|
-
}
|
|
99
|
+
for (let i = 0, len = str.length; i < len; i++) {
|
|
100
|
+
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
101
|
+
}
|
|
88
102
|
const range = useAllColors ? COLORS_LIST.length : SAFE_COLORS_COUNT;
|
|
89
103
|
return Math.abs(hash % range);
|
|
90
104
|
};
|
|
@@ -92,6 +106,29 @@ var colorize = (text, colorIndex, color) => {
|
|
|
92
106
|
const code = color ?? (COLORS_LIST[colorIndex] || COLORS_LIST[colorIndex % SAFE_COLORS_COUNT]);
|
|
93
107
|
return `\x1B[${code}m${text}\x1B[0m`;
|
|
94
108
|
};
|
|
109
|
+
var jsonReplacer = (_key, value) => typeof value === "bigint" ? value.toString() : value;
|
|
110
|
+
var safeStringify = (obj) => {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.stringify(obj, jsonReplacer);
|
|
113
|
+
} catch {
|
|
114
|
+
return (0, import_node_util.inspect)(obj);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var wrapToError = (obj) => {
|
|
118
|
+
if (obj instanceof Error) return obj;
|
|
119
|
+
return new Error(
|
|
120
|
+
typeof obj === "object" && obj !== null ? safeStringify(obj) : String(obj)
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
var serializeError = (_err) => {
|
|
124
|
+
const err = wrapToError(_err);
|
|
125
|
+
return {
|
|
126
|
+
message: err.message,
|
|
127
|
+
stack: err.stack,
|
|
128
|
+
name: err.name,
|
|
129
|
+
...err
|
|
130
|
+
};
|
|
131
|
+
};
|
|
95
132
|
var colorizeLevel = (level, text) => {
|
|
96
133
|
if (level === "info") return text;
|
|
97
134
|
switch (level) {
|
|
@@ -109,8 +146,8 @@ var colorizeLevel = (level, text) => {
|
|
|
109
146
|
}
|
|
110
147
|
};
|
|
111
148
|
|
|
112
|
-
// src/
|
|
113
|
-
var
|
|
149
|
+
// src/transport_dev.ts
|
|
150
|
+
var import_node_util2 = require("util");
|
|
114
151
|
var import_node_process = __toESM(require("process"), 1);
|
|
115
152
|
var createDevTransport = (config = {}) => {
|
|
116
153
|
const locale = config.locale ?? void 0;
|
|
@@ -138,9 +175,9 @@ var createDevTransport = (config = {}) => {
|
|
|
138
175
|
let dataStr = "";
|
|
139
176
|
if (data !== void 0) {
|
|
140
177
|
const inspectOptions = opts?.pretty ? { compact: false, colors: true, depth: null } : { compact: true, breakLength: Infinity, colors: true, depth: null };
|
|
141
|
-
dataStr = (0,
|
|
178
|
+
dataStr = (0, import_node_util2.inspect)(data, inspectOptions);
|
|
142
179
|
}
|
|
143
|
-
const msgStr = typeof msg === "object" && msg !== null ? (0,
|
|
180
|
+
const msgStr = typeof msg === "object" && msg !== null ? (0, import_node_util2.inspect)(msg, { colors: true, compact: true, breakLength: Infinity }) : String(msg);
|
|
144
181
|
const parts = [
|
|
145
182
|
`[${timestamp}]`,
|
|
146
183
|
// Normal (not dimmed)
|
|
@@ -154,35 +191,17 @@ var createDevTransport = (config = {}) => {
|
|
|
154
191
|
};
|
|
155
192
|
return transport;
|
|
156
193
|
};
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
var wrapToError = (obj) => {
|
|
165
|
-
if (obj instanceof Error) return obj;
|
|
166
|
-
return new Error(
|
|
167
|
-
typeof obj === "object" && obj !== null ? safeStringify(obj) : String(obj)
|
|
168
|
-
);
|
|
169
|
-
};
|
|
170
|
-
var serializeError = (_err) => {
|
|
171
|
-
const err = wrapToError(_err);
|
|
172
|
-
return {
|
|
173
|
-
message: err.message,
|
|
174
|
-
stack: err.stack,
|
|
175
|
-
name: err.name,
|
|
176
|
-
...err
|
|
177
|
-
};
|
|
178
|
-
};
|
|
179
|
-
var buildRecord = (level, context, msg, data) => {
|
|
194
|
+
|
|
195
|
+
// src/transport_prod.ts
|
|
196
|
+
var import_node_util3 = require("util");
|
|
197
|
+
var import_node_process2 = __toESM(require("process"), 1);
|
|
198
|
+
var buildRecord = (level, context, msg, getTimestamp, data) => {
|
|
180
199
|
const contextObj = context.reduce((acc, item) => {
|
|
181
200
|
acc[item.key] = item.value;
|
|
182
201
|
return acc;
|
|
183
202
|
}, {});
|
|
184
203
|
const logRecord = {
|
|
185
|
-
timestamp: (
|
|
204
|
+
timestamp: getTimestamp(),
|
|
186
205
|
level,
|
|
187
206
|
...contextObj
|
|
188
207
|
};
|
|
@@ -206,16 +225,18 @@ var buildRecord = (level, context, msg, data) => {
|
|
|
206
225
|
}
|
|
207
226
|
return logRecord;
|
|
208
227
|
};
|
|
209
|
-
var
|
|
228
|
+
var createProdTransport = (config = {}) => {
|
|
229
|
+
const getTimestamp = config.timestamp === "epoch" ? () => Date.now() : () => (/* @__PURE__ */ new Date()).toISOString();
|
|
230
|
+
const dest = config.dest ?? import_node_process2.default.stdout;
|
|
210
231
|
return (level, context, msg, data) => {
|
|
211
|
-
const record = buildRecord(level, context, msg, data);
|
|
232
|
+
const record = buildRecord(level, context, msg, getTimestamp, data);
|
|
212
233
|
let line;
|
|
213
234
|
try {
|
|
214
|
-
line = JSON.stringify(record) + "\n";
|
|
235
|
+
line = JSON.stringify(record, jsonReplacer) + "\n";
|
|
215
236
|
} catch {
|
|
216
|
-
if (record.data) record.data = (0,
|
|
237
|
+
if (record.data) record.data = (0, import_node_util3.inspect)(record.data);
|
|
217
238
|
try {
|
|
218
|
-
line = JSON.stringify(record) + "\n";
|
|
239
|
+
line = JSON.stringify(record, jsonReplacer) + "\n";
|
|
219
240
|
} catch {
|
|
220
241
|
line = JSON.stringify({
|
|
221
242
|
timestamp: record.timestamp,
|
|
@@ -225,28 +246,25 @@ var createJsonTransport = () => {
|
|
|
225
246
|
}) + "\n";
|
|
226
247
|
}
|
|
227
248
|
}
|
|
228
|
-
|
|
249
|
+
dest.write(line);
|
|
229
250
|
};
|
|
230
251
|
};
|
|
231
252
|
|
|
232
253
|
// src/index.ts
|
|
233
|
-
var
|
|
234
|
-
|
|
254
|
+
var createFiro = (config = {}, parentContext = []) => {
|
|
255
|
+
const useAllColors = config.useAllColors ?? true;
|
|
256
|
+
const fill = (item) => ({
|
|
235
257
|
...item,
|
|
236
258
|
colorIndex: typeof item.colorIndex === "number" ? item.colorIndex : getColorIndex(item.key, useAllColors),
|
|
237
259
|
color: item.color,
|
|
238
260
|
omitKey: item.omitKey ?? false
|
|
239
|
-
};
|
|
240
|
-
};
|
|
241
|
-
var createLoggerInternal = (config, parentContext) => {
|
|
242
|
-
const useAllColors = config.useAllColors ?? false;
|
|
243
|
-
const fill = (item) => fillContextItem(item, useAllColors);
|
|
261
|
+
});
|
|
244
262
|
const appendContextWithInvokeContext = (context2, invokeContext) => {
|
|
245
263
|
if (!invokeContext || invokeContext.length === 0) return context2;
|
|
246
264
|
return [...context2, ...invokeContext.map(fill)];
|
|
247
265
|
};
|
|
248
266
|
const context = [...parentContext.map(fill)];
|
|
249
|
-
const transport = config.transport ?? (config.mode === "prod" ?
|
|
267
|
+
const transport = config.transport ?? (config.mode === "prod" ? createProdTransport(config.prodTransportConfig) : createDevTransport(config.devTransportConfig));
|
|
250
268
|
const minLevelName = config.mode === "prod" ? config.minLevelInProd ?? config.minLevel : config.minLevelInDev ?? config.minLevel;
|
|
251
269
|
const minLevel = LOG_LEVELS[minLevelName ?? "debug"];
|
|
252
270
|
const getContext = () => context;
|
|
@@ -277,7 +295,7 @@ var createLoggerInternal = (config, parentContext) => {
|
|
|
277
295
|
}
|
|
278
296
|
return { key, value, colorIndex: getColorIndex(key, useAllColors) };
|
|
279
297
|
});
|
|
280
|
-
return
|
|
298
|
+
return createFiro({ transport, minLevel: minLevelName, useAllColors }, [...context, ...newItems]);
|
|
281
299
|
};
|
|
282
300
|
const debug = (msg, data, opts) => {
|
|
283
301
|
if (minLevel > LOG_LEVELS.debug) return;
|
|
@@ -306,16 +324,15 @@ var createLoggerInternal = (config, parentContext) => {
|
|
|
306
324
|
child,
|
|
307
325
|
addContext,
|
|
308
326
|
getContext,
|
|
327
|
+
hasInContext,
|
|
309
328
|
removeFromContext: removeKeyFromContext
|
|
310
329
|
});
|
|
311
330
|
};
|
|
312
|
-
var createLogger = (config = {}) => {
|
|
313
|
-
return createLoggerInternal(config, []);
|
|
314
|
-
};
|
|
315
331
|
// Annotate the CommonJS export names for ESM import in node:
|
|
316
332
|
0 && (module.exports = {
|
|
317
333
|
FIRO_COLORS,
|
|
334
|
+
FiroUtils,
|
|
318
335
|
createDevTransport,
|
|
319
|
-
|
|
320
|
-
|
|
336
|
+
createFiro,
|
|
337
|
+
createProdTransport
|
|
321
338
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/** Available log severity levels. */
|
|
2
2
|
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
3
|
+
declare const LOG_LEVELS: {
|
|
4
|
+
readonly debug: 20;
|
|
5
|
+
readonly info: 30;
|
|
6
|
+
readonly warn: 40;
|
|
7
|
+
readonly error: 50;
|
|
8
|
+
};
|
|
3
9
|
/** Primitive types allowed as context values. */
|
|
4
10
|
type ContextValue = string | number | boolean | null | undefined;
|
|
5
11
|
/** Options to customize how a context item is rendered. */
|
|
@@ -68,6 +74,34 @@ declare const FIRO_COLORS: {
|
|
|
68
74
|
readonly tangerine: "38;5;208";
|
|
69
75
|
readonly periwinkle: "38;5;147";
|
|
70
76
|
};
|
|
77
|
+
declare const getColorIndex: (str: string, useAllColors?: boolean) => number;
|
|
78
|
+
declare const colorize: (text: string, colorIndex: number, color?: string) => string;
|
|
79
|
+
declare const jsonReplacer: (_key: string, value: unknown) => unknown;
|
|
80
|
+
declare const safeStringify: (obj: unknown) => string;
|
|
81
|
+
declare const wrapToError: (obj: unknown) => Error;
|
|
82
|
+
declare const serializeError: (_err: unknown) => any;
|
|
83
|
+
declare const colorizeLevel: (level: LogLevel, text: string) => string;
|
|
84
|
+
|
|
85
|
+
type utils_ContextExtension = ContextExtension;
|
|
86
|
+
type utils_ContextItem = ContextItem;
|
|
87
|
+
type utils_ContextItemWithOptions = ContextItemWithOptions;
|
|
88
|
+
type utils_ContextOptions = ContextOptions;
|
|
89
|
+
type utils_ContextValue = ContextValue;
|
|
90
|
+
declare const utils_FIRO_COLORS: typeof FIRO_COLORS;
|
|
91
|
+
declare const utils_LOG_LEVELS: typeof LOG_LEVELS;
|
|
92
|
+
type utils_LogLevel = LogLevel;
|
|
93
|
+
type utils_LogOptions = LogOptions;
|
|
94
|
+
type utils_TransportFn = TransportFn;
|
|
95
|
+
declare const utils_colorize: typeof colorize;
|
|
96
|
+
declare const utils_colorizeLevel: typeof colorizeLevel;
|
|
97
|
+
declare const utils_getColorIndex: typeof getColorIndex;
|
|
98
|
+
declare const utils_jsonReplacer: typeof jsonReplacer;
|
|
99
|
+
declare const utils_safeStringify: typeof safeStringify;
|
|
100
|
+
declare const utils_serializeError: typeof serializeError;
|
|
101
|
+
declare const utils_wrapToError: typeof wrapToError;
|
|
102
|
+
declare namespace utils {
|
|
103
|
+
export { type utils_ContextExtension as ContextExtension, type utils_ContextItem as ContextItem, type utils_ContextItemWithOptions as ContextItemWithOptions, type utils_ContextOptions as ContextOptions, type utils_ContextValue as ContextValue, utils_FIRO_COLORS as FIRO_COLORS, utils_LOG_LEVELS as LOG_LEVELS, type utils_LogLevel as LogLevel, type utils_LogOptions as LogOptions, type utils_TransportFn as TransportFn, utils_colorize as colorize, utils_colorizeLevel as colorizeLevel, utils_getColorIndex as getColorIndex, utils_jsonReplacer as jsonReplacer, utils_safeStringify as safeStringify, utils_serializeError as serializeError, utils_wrapToError as wrapToError };
|
|
104
|
+
}
|
|
71
105
|
|
|
72
106
|
/**
|
|
73
107
|
* Configuration options for the development transport.
|
|
@@ -86,13 +120,23 @@ type DevTransportConfig = {
|
|
|
86
120
|
* @returns A `TransportFn` that writes to the console.
|
|
87
121
|
*/
|
|
88
122
|
declare const createDevTransport: (config?: DevTransportConfig) => TransportFn;
|
|
123
|
+
|
|
124
|
+
type TimestampFormat = 'iso' | 'epoch';
|
|
125
|
+
type ProdTransportConfig = {
|
|
126
|
+
/** Timestamp format: 'iso' (default) for ISO 8601 string, 'epoch' for ms since Unix epoch. */
|
|
127
|
+
timestamp?: TimestampFormat;
|
|
128
|
+
/** Output destination. Any object with a `.write(string)` method. Defaults to `process.stdout`. */
|
|
129
|
+
dest?: {
|
|
130
|
+
write(s: string): unknown;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
89
133
|
/**
|
|
90
134
|
* Creates a built-in transport optimized for production.
|
|
91
135
|
* Emits strictly structured NDJSON (Newline Delimited JSON) to stdout.
|
|
92
136
|
*
|
|
93
137
|
* @returns A `TransportFn` that writes JSON to standard output.
|
|
94
138
|
*/
|
|
95
|
-
declare const
|
|
139
|
+
declare const createProdTransport: (config?: ProdTransportConfig) => TransportFn;
|
|
96
140
|
|
|
97
141
|
/**
|
|
98
142
|
* Configuration options for creating a logger instance.
|
|
@@ -110,11 +154,13 @@ type LoggerConfig = {
|
|
|
110
154
|
transport?: TransportFn;
|
|
111
155
|
/** Options for fine-tuning the built-in development transport (e.g. timestamp format). */
|
|
112
156
|
devTransportConfig?: DevTransportConfig;
|
|
113
|
-
/**
|
|
157
|
+
/** Options for the built-in prod transport (e.g. timestamp format). */
|
|
158
|
+
prodTransportConfig?: ProdTransportConfig;
|
|
159
|
+
/** Use the full extended color palette (30 colors including 256-color) for auto-assigned context badges. Defaults to true. Set to false to restrict to 10 terminal-safe colors. */
|
|
114
160
|
useAllColors?: boolean;
|
|
115
161
|
};
|
|
116
162
|
/**
|
|
117
|
-
* The logger instance returned by `
|
|
163
|
+
* The logger instance returned by `createFiro`.
|
|
118
164
|
* It is a callable object: calling `log(msg)` is shorthand for `log.info(msg)`.
|
|
119
165
|
*/
|
|
120
166
|
interface Firo {
|
|
@@ -153,6 +199,6 @@ interface Firo {
|
|
|
153
199
|
* @param config Optional configuration for log levels, mode, and transports.
|
|
154
200
|
* @returns A fully configured `Firo` instance.
|
|
155
201
|
*/
|
|
156
|
-
declare const
|
|
202
|
+
declare const createFiro: (config?: LoggerConfig, parentContext?: ContextItem[]) => Firo;
|
|
157
203
|
|
|
158
|
-
export { type ContextExtension, type ContextItem, type ContextItemWithOptions, type ContextOptions, type ContextValue, type DevTransportConfig, FIRO_COLORS, type Firo, type LogLevel, type LogOptions, type LoggerConfig, type TransportFn, createDevTransport,
|
|
204
|
+
export { type ContextExtension, type ContextItem, type ContextItemWithOptions, type ContextOptions, type ContextValue, type DevTransportConfig, FIRO_COLORS, type Firo, utils as FiroUtils, type LogLevel, type LogOptions, type LoggerConfig, type ProdTransportConfig, type TimestampFormat, type TransportFn, createDevTransport, createFiro, createProdTransport };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/** Available log severity levels. */
|
|
2
2
|
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
3
|
+
declare const LOG_LEVELS: {
|
|
4
|
+
readonly debug: 20;
|
|
5
|
+
readonly info: 30;
|
|
6
|
+
readonly warn: 40;
|
|
7
|
+
readonly error: 50;
|
|
8
|
+
};
|
|
3
9
|
/** Primitive types allowed as context values. */
|
|
4
10
|
type ContextValue = string | number | boolean | null | undefined;
|
|
5
11
|
/** Options to customize how a context item is rendered. */
|
|
@@ -68,6 +74,34 @@ declare const FIRO_COLORS: {
|
|
|
68
74
|
readonly tangerine: "38;5;208";
|
|
69
75
|
readonly periwinkle: "38;5;147";
|
|
70
76
|
};
|
|
77
|
+
declare const getColorIndex: (str: string, useAllColors?: boolean) => number;
|
|
78
|
+
declare const colorize: (text: string, colorIndex: number, color?: string) => string;
|
|
79
|
+
declare const jsonReplacer: (_key: string, value: unknown) => unknown;
|
|
80
|
+
declare const safeStringify: (obj: unknown) => string;
|
|
81
|
+
declare const wrapToError: (obj: unknown) => Error;
|
|
82
|
+
declare const serializeError: (_err: unknown) => any;
|
|
83
|
+
declare const colorizeLevel: (level: LogLevel, text: string) => string;
|
|
84
|
+
|
|
85
|
+
type utils_ContextExtension = ContextExtension;
|
|
86
|
+
type utils_ContextItem = ContextItem;
|
|
87
|
+
type utils_ContextItemWithOptions = ContextItemWithOptions;
|
|
88
|
+
type utils_ContextOptions = ContextOptions;
|
|
89
|
+
type utils_ContextValue = ContextValue;
|
|
90
|
+
declare const utils_FIRO_COLORS: typeof FIRO_COLORS;
|
|
91
|
+
declare const utils_LOG_LEVELS: typeof LOG_LEVELS;
|
|
92
|
+
type utils_LogLevel = LogLevel;
|
|
93
|
+
type utils_LogOptions = LogOptions;
|
|
94
|
+
type utils_TransportFn = TransportFn;
|
|
95
|
+
declare const utils_colorize: typeof colorize;
|
|
96
|
+
declare const utils_colorizeLevel: typeof colorizeLevel;
|
|
97
|
+
declare const utils_getColorIndex: typeof getColorIndex;
|
|
98
|
+
declare const utils_jsonReplacer: typeof jsonReplacer;
|
|
99
|
+
declare const utils_safeStringify: typeof safeStringify;
|
|
100
|
+
declare const utils_serializeError: typeof serializeError;
|
|
101
|
+
declare const utils_wrapToError: typeof wrapToError;
|
|
102
|
+
declare namespace utils {
|
|
103
|
+
export { type utils_ContextExtension as ContextExtension, type utils_ContextItem as ContextItem, type utils_ContextItemWithOptions as ContextItemWithOptions, type utils_ContextOptions as ContextOptions, type utils_ContextValue as ContextValue, utils_FIRO_COLORS as FIRO_COLORS, utils_LOG_LEVELS as LOG_LEVELS, type utils_LogLevel as LogLevel, type utils_LogOptions as LogOptions, type utils_TransportFn as TransportFn, utils_colorize as colorize, utils_colorizeLevel as colorizeLevel, utils_getColorIndex as getColorIndex, utils_jsonReplacer as jsonReplacer, utils_safeStringify as safeStringify, utils_serializeError as serializeError, utils_wrapToError as wrapToError };
|
|
104
|
+
}
|
|
71
105
|
|
|
72
106
|
/**
|
|
73
107
|
* Configuration options for the development transport.
|
|
@@ -86,13 +120,23 @@ type DevTransportConfig = {
|
|
|
86
120
|
* @returns A `TransportFn` that writes to the console.
|
|
87
121
|
*/
|
|
88
122
|
declare const createDevTransport: (config?: DevTransportConfig) => TransportFn;
|
|
123
|
+
|
|
124
|
+
type TimestampFormat = 'iso' | 'epoch';
|
|
125
|
+
type ProdTransportConfig = {
|
|
126
|
+
/** Timestamp format: 'iso' (default) for ISO 8601 string, 'epoch' for ms since Unix epoch. */
|
|
127
|
+
timestamp?: TimestampFormat;
|
|
128
|
+
/** Output destination. Any object with a `.write(string)` method. Defaults to `process.stdout`. */
|
|
129
|
+
dest?: {
|
|
130
|
+
write(s: string): unknown;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
89
133
|
/**
|
|
90
134
|
* Creates a built-in transport optimized for production.
|
|
91
135
|
* Emits strictly structured NDJSON (Newline Delimited JSON) to stdout.
|
|
92
136
|
*
|
|
93
137
|
* @returns A `TransportFn` that writes JSON to standard output.
|
|
94
138
|
*/
|
|
95
|
-
declare const
|
|
139
|
+
declare const createProdTransport: (config?: ProdTransportConfig) => TransportFn;
|
|
96
140
|
|
|
97
141
|
/**
|
|
98
142
|
* Configuration options for creating a logger instance.
|
|
@@ -110,11 +154,13 @@ type LoggerConfig = {
|
|
|
110
154
|
transport?: TransportFn;
|
|
111
155
|
/** Options for fine-tuning the built-in development transport (e.g. timestamp format). */
|
|
112
156
|
devTransportConfig?: DevTransportConfig;
|
|
113
|
-
/**
|
|
157
|
+
/** Options for the built-in prod transport (e.g. timestamp format). */
|
|
158
|
+
prodTransportConfig?: ProdTransportConfig;
|
|
159
|
+
/** Use the full extended color palette (30 colors including 256-color) for auto-assigned context badges. Defaults to true. Set to false to restrict to 10 terminal-safe colors. */
|
|
114
160
|
useAllColors?: boolean;
|
|
115
161
|
};
|
|
116
162
|
/**
|
|
117
|
-
* The logger instance returned by `
|
|
163
|
+
* The logger instance returned by `createFiro`.
|
|
118
164
|
* It is a callable object: calling `log(msg)` is shorthand for `log.info(msg)`.
|
|
119
165
|
*/
|
|
120
166
|
interface Firo {
|
|
@@ -153,6 +199,6 @@ interface Firo {
|
|
|
153
199
|
* @param config Optional configuration for log levels, mode, and transports.
|
|
154
200
|
* @returns A fully configured `Firo` instance.
|
|
155
201
|
*/
|
|
156
|
-
declare const
|
|
202
|
+
declare const createFiro: (config?: LoggerConfig, parentContext?: ContextItem[]) => Firo;
|
|
157
203
|
|
|
158
|
-
export { type ContextExtension, type ContextItem, type ContextItemWithOptions, type ContextOptions, type ContextValue, type DevTransportConfig, FIRO_COLORS, type Firo, type LogLevel, type LogOptions, type LoggerConfig, type TransportFn, createDevTransport,
|
|
204
|
+
export { type ContextExtension, type ContextItem, type ContextItemWithOptions, type ContextOptions, type ContextValue, type DevTransportConfig, FIRO_COLORS, type Firo, utils as FiroUtils, type LogLevel, type LogOptions, type LoggerConfig, type ProdTransportConfig, type TimestampFormat, type TransportFn, createDevTransport, createFiro, createProdTransport };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
1
7
|
// src/utils.ts
|
|
8
|
+
var utils_exports = {};
|
|
9
|
+
__export(utils_exports, {
|
|
10
|
+
FIRO_COLORS: () => FIRO_COLORS,
|
|
11
|
+
LOG_LEVELS: () => LOG_LEVELS,
|
|
12
|
+
colorize: () => colorize,
|
|
13
|
+
colorizeLevel: () => colorizeLevel,
|
|
14
|
+
getColorIndex: () => getColorIndex,
|
|
15
|
+
jsonReplacer: () => jsonReplacer,
|
|
16
|
+
safeStringify: () => safeStringify,
|
|
17
|
+
serializeError: () => serializeError,
|
|
18
|
+
wrapToError: () => wrapToError
|
|
19
|
+
});
|
|
20
|
+
import { inspect } from "util";
|
|
2
21
|
var LOG_LEVELS = {
|
|
3
22
|
debug: 20,
|
|
4
23
|
info: 30,
|
|
@@ -43,9 +62,9 @@ var COLORS_LIST = Object.values(FIRO_COLORS);
|
|
|
43
62
|
var SAFE_COLORS_COUNT = 10;
|
|
44
63
|
var getColorIndex = (str, useAllColors = false) => {
|
|
45
64
|
let hash = 0;
|
|
46
|
-
str.
|
|
47
|
-
hash =
|
|
48
|
-
}
|
|
65
|
+
for (let i = 0, len = str.length; i < len; i++) {
|
|
66
|
+
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
67
|
+
}
|
|
49
68
|
const range = useAllColors ? COLORS_LIST.length : SAFE_COLORS_COUNT;
|
|
50
69
|
return Math.abs(hash % range);
|
|
51
70
|
};
|
|
@@ -53,6 +72,29 @@ var colorize = (text, colorIndex, color) => {
|
|
|
53
72
|
const code = color ?? (COLORS_LIST[colorIndex] || COLORS_LIST[colorIndex % SAFE_COLORS_COUNT]);
|
|
54
73
|
return `\x1B[${code}m${text}\x1B[0m`;
|
|
55
74
|
};
|
|
75
|
+
var jsonReplacer = (_key, value) => typeof value === "bigint" ? value.toString() : value;
|
|
76
|
+
var safeStringify = (obj) => {
|
|
77
|
+
try {
|
|
78
|
+
return JSON.stringify(obj, jsonReplacer);
|
|
79
|
+
} catch {
|
|
80
|
+
return inspect(obj);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var wrapToError = (obj) => {
|
|
84
|
+
if (obj instanceof Error) return obj;
|
|
85
|
+
return new Error(
|
|
86
|
+
typeof obj === "object" && obj !== null ? safeStringify(obj) : String(obj)
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
var serializeError = (_err) => {
|
|
90
|
+
const err = wrapToError(_err);
|
|
91
|
+
return {
|
|
92
|
+
message: err.message,
|
|
93
|
+
stack: err.stack,
|
|
94
|
+
name: err.name,
|
|
95
|
+
...err
|
|
96
|
+
};
|
|
97
|
+
};
|
|
56
98
|
var colorizeLevel = (level, text) => {
|
|
57
99
|
if (level === "info") return text;
|
|
58
100
|
switch (level) {
|
|
@@ -70,8 +112,8 @@ var colorizeLevel = (level, text) => {
|
|
|
70
112
|
}
|
|
71
113
|
};
|
|
72
114
|
|
|
73
|
-
// src/
|
|
74
|
-
import { inspect } from "util";
|
|
115
|
+
// src/transport_dev.ts
|
|
116
|
+
import { inspect as inspect2 } from "util";
|
|
75
117
|
import process from "process";
|
|
76
118
|
var createDevTransport = (config = {}) => {
|
|
77
119
|
const locale = config.locale ?? void 0;
|
|
@@ -99,9 +141,9 @@ var createDevTransport = (config = {}) => {
|
|
|
99
141
|
let dataStr = "";
|
|
100
142
|
if (data !== void 0) {
|
|
101
143
|
const inspectOptions = opts?.pretty ? { compact: false, colors: true, depth: null } : { compact: true, breakLength: Infinity, colors: true, depth: null };
|
|
102
|
-
dataStr =
|
|
144
|
+
dataStr = inspect2(data, inspectOptions);
|
|
103
145
|
}
|
|
104
|
-
const msgStr = typeof msg === "object" && msg !== null ?
|
|
146
|
+
const msgStr = typeof msg === "object" && msg !== null ? inspect2(msg, { colors: true, compact: true, breakLength: Infinity }) : String(msg);
|
|
105
147
|
const parts = [
|
|
106
148
|
`[${timestamp}]`,
|
|
107
149
|
// Normal (not dimmed)
|
|
@@ -115,35 +157,17 @@ var createDevTransport = (config = {}) => {
|
|
|
115
157
|
};
|
|
116
158
|
return transport;
|
|
117
159
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
var wrapToError = (obj) => {
|
|
126
|
-
if (obj instanceof Error) return obj;
|
|
127
|
-
return new Error(
|
|
128
|
-
typeof obj === "object" && obj !== null ? safeStringify(obj) : String(obj)
|
|
129
|
-
);
|
|
130
|
-
};
|
|
131
|
-
var serializeError = (_err) => {
|
|
132
|
-
const err = wrapToError(_err);
|
|
133
|
-
return {
|
|
134
|
-
message: err.message,
|
|
135
|
-
stack: err.stack,
|
|
136
|
-
name: err.name,
|
|
137
|
-
...err
|
|
138
|
-
};
|
|
139
|
-
};
|
|
140
|
-
var buildRecord = (level, context, msg, data) => {
|
|
160
|
+
|
|
161
|
+
// src/transport_prod.ts
|
|
162
|
+
import { inspect as inspect3 } from "util";
|
|
163
|
+
import process2 from "process";
|
|
164
|
+
var buildRecord = (level, context, msg, getTimestamp, data) => {
|
|
141
165
|
const contextObj = context.reduce((acc, item) => {
|
|
142
166
|
acc[item.key] = item.value;
|
|
143
167
|
return acc;
|
|
144
168
|
}, {});
|
|
145
169
|
const logRecord = {
|
|
146
|
-
timestamp: (
|
|
170
|
+
timestamp: getTimestamp(),
|
|
147
171
|
level,
|
|
148
172
|
...contextObj
|
|
149
173
|
};
|
|
@@ -167,16 +191,18 @@ var buildRecord = (level, context, msg, data) => {
|
|
|
167
191
|
}
|
|
168
192
|
return logRecord;
|
|
169
193
|
};
|
|
170
|
-
var
|
|
194
|
+
var createProdTransport = (config = {}) => {
|
|
195
|
+
const getTimestamp = config.timestamp === "epoch" ? () => Date.now() : () => (/* @__PURE__ */ new Date()).toISOString();
|
|
196
|
+
const dest = config.dest ?? process2.stdout;
|
|
171
197
|
return (level, context, msg, data) => {
|
|
172
|
-
const record = buildRecord(level, context, msg, data);
|
|
198
|
+
const record = buildRecord(level, context, msg, getTimestamp, data);
|
|
173
199
|
let line;
|
|
174
200
|
try {
|
|
175
|
-
line = JSON.stringify(record) + "\n";
|
|
201
|
+
line = JSON.stringify(record, jsonReplacer) + "\n";
|
|
176
202
|
} catch {
|
|
177
|
-
if (record.data) record.data =
|
|
203
|
+
if (record.data) record.data = inspect3(record.data);
|
|
178
204
|
try {
|
|
179
|
-
line = JSON.stringify(record) + "\n";
|
|
205
|
+
line = JSON.stringify(record, jsonReplacer) + "\n";
|
|
180
206
|
} catch {
|
|
181
207
|
line = JSON.stringify({
|
|
182
208
|
timestamp: record.timestamp,
|
|
@@ -186,28 +212,25 @@ var createJsonTransport = () => {
|
|
|
186
212
|
}) + "\n";
|
|
187
213
|
}
|
|
188
214
|
}
|
|
189
|
-
|
|
215
|
+
dest.write(line);
|
|
190
216
|
};
|
|
191
217
|
};
|
|
192
218
|
|
|
193
219
|
// src/index.ts
|
|
194
|
-
var
|
|
195
|
-
|
|
220
|
+
var createFiro = (config = {}, parentContext = []) => {
|
|
221
|
+
const useAllColors = config.useAllColors ?? true;
|
|
222
|
+
const fill = (item) => ({
|
|
196
223
|
...item,
|
|
197
224
|
colorIndex: typeof item.colorIndex === "number" ? item.colorIndex : getColorIndex(item.key, useAllColors),
|
|
198
225
|
color: item.color,
|
|
199
226
|
omitKey: item.omitKey ?? false
|
|
200
|
-
};
|
|
201
|
-
};
|
|
202
|
-
var createLoggerInternal = (config, parentContext) => {
|
|
203
|
-
const useAllColors = config.useAllColors ?? false;
|
|
204
|
-
const fill = (item) => fillContextItem(item, useAllColors);
|
|
227
|
+
});
|
|
205
228
|
const appendContextWithInvokeContext = (context2, invokeContext) => {
|
|
206
229
|
if (!invokeContext || invokeContext.length === 0) return context2;
|
|
207
230
|
return [...context2, ...invokeContext.map(fill)];
|
|
208
231
|
};
|
|
209
232
|
const context = [...parentContext.map(fill)];
|
|
210
|
-
const transport = config.transport ?? (config.mode === "prod" ?
|
|
233
|
+
const transport = config.transport ?? (config.mode === "prod" ? createProdTransport(config.prodTransportConfig) : createDevTransport(config.devTransportConfig));
|
|
211
234
|
const minLevelName = config.mode === "prod" ? config.minLevelInProd ?? config.minLevel : config.minLevelInDev ?? config.minLevel;
|
|
212
235
|
const minLevel = LOG_LEVELS[minLevelName ?? "debug"];
|
|
213
236
|
const getContext = () => context;
|
|
@@ -238,7 +261,7 @@ var createLoggerInternal = (config, parentContext) => {
|
|
|
238
261
|
}
|
|
239
262
|
return { key, value, colorIndex: getColorIndex(key, useAllColors) };
|
|
240
263
|
});
|
|
241
|
-
return
|
|
264
|
+
return createFiro({ transport, minLevel: minLevelName, useAllColors }, [...context, ...newItems]);
|
|
242
265
|
};
|
|
243
266
|
const debug = (msg, data, opts) => {
|
|
244
267
|
if (minLevel > LOG_LEVELS.debug) return;
|
|
@@ -267,15 +290,14 @@ var createLoggerInternal = (config, parentContext) => {
|
|
|
267
290
|
child,
|
|
268
291
|
addContext,
|
|
269
292
|
getContext,
|
|
293
|
+
hasInContext,
|
|
270
294
|
removeFromContext: removeKeyFromContext
|
|
271
295
|
});
|
|
272
296
|
};
|
|
273
|
-
var createLogger = (config = {}) => {
|
|
274
|
-
return createLoggerInternal(config, []);
|
|
275
|
-
};
|
|
276
297
|
export {
|
|
277
298
|
FIRO_COLORS,
|
|
299
|
+
utils_exports as FiroUtils,
|
|
278
300
|
createDevTransport,
|
|
279
|
-
|
|
280
|
-
|
|
301
|
+
createFiro,
|
|
302
|
+
createProdTransport
|
|
281
303
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fend/firo",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Elegant logger for Node.js, Bun and Deno with brilliant DX.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"firo",
|
|
@@ -37,13 +37,6 @@
|
|
|
37
37
|
"files": [
|
|
38
38
|
"dist"
|
|
39
39
|
],
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "tsup",
|
|
42
|
-
"test": "node --import tsx --test test/*.test.ts",
|
|
43
|
-
"check": "tsc --noEmit && node --import tsx --test test/*.test.ts",
|
|
44
|
-
"typecheck": "tsc --noEmit",
|
|
45
|
-
"demo": "tsx demo.ts"
|
|
46
|
-
},
|
|
47
40
|
"engines": {
|
|
48
41
|
"node": ">=16"
|
|
49
42
|
},
|
|
@@ -52,5 +45,13 @@
|
|
|
52
45
|
"tsup": "^8.5.1",
|
|
53
46
|
"tsx": "^4.0.0",
|
|
54
47
|
"typescript": "^5.9.3"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"test": "node --import tsx --test test/*.test.ts",
|
|
52
|
+
"check": "tsc --noEmit && node --import tsx --test test/*.test.ts",
|
|
53
|
+
"typecheck": "tsc --noEmit",
|
|
54
|
+
"demo": "tsx demo.ts",
|
|
55
|
+
"bench": "tsx benchmark/prod.ts > /dev/null"
|
|
55
56
|
}
|
|
56
|
-
}
|
|
57
|
+
}
|