@emdzej/bimmerz-logger 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +131 -0
- package/README.md +235 -0
- package/dist/categories.d.ts +21 -0
- package/dist/categories.d.ts.map +1 -0
- package/dist/categories.js +36 -0
- package/dist/categories.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/levels.d.ts +21 -0
- package/dist/levels.d.ts.map +1 -0
- package/dist/levels.js +30 -0
- package/dist/levels.js.map +1 -0
- package/dist/logger.d.ts +49 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +136 -0
- package/dist/logger.js.map +1 -0
- package/dist/logger.test.d.ts +2 -0
- package/dist/logger.test.d.ts.map +1 -0
- package/dist/logger.test.js +199 -0
- package/dist/logger.test.js.map +1 -0
- package/dist/sinks/buffer.d.ts +23 -0
- package/dist/sinks/buffer.d.ts.map +1 -0
- package/dist/sinks/buffer.js +44 -0
- package/dist/sinks/buffer.js.map +1 -0
- package/dist/sinks/console.d.ts +34 -0
- package/dist/sinks/console.d.ts.map +1 -0
- package/dist/sinks/console.js +106 -0
- package/dist/sinks/console.js.map +1 -0
- package/dist/sinks/multi.d.ts +13 -0
- package/dist/sinks/multi.d.ts.map +1 -0
- package/dist/sinks/multi.js +26 -0
- package/dist/sinks/multi.js.map +1 -0
- package/dist/sinks/null.d.ts +10 -0
- package/dist/sinks/null.d.ts.map +1 -0
- package/dist/sinks/null.js +15 -0
- package/dist/sinks/null.js.map +1 -0
- package/dist/sinks/pino.d.ts +37 -0
- package/dist/sinks/pino.d.ts.map +1 -0
- package/dist/sinks/pino.js +39 -0
- package/dist/sinks/pino.js.map +1 -0
- package/dist/types.d.ts +121 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# PolyForm Noncommercial License 1.0.0
|
|
2
|
+
|
|
3
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
4
|
+
|
|
5
|
+
## Acceptance
|
|
6
|
+
|
|
7
|
+
In order to get any license under these terms, you must agree
|
|
8
|
+
to them as both strict obligations and conditions to all
|
|
9
|
+
your licenses.
|
|
10
|
+
|
|
11
|
+
## Copyright License
|
|
12
|
+
|
|
13
|
+
The licensor grants you a copyright license for the
|
|
14
|
+
software to do everything you might do with the software
|
|
15
|
+
that would otherwise infringe the licensor's copyright
|
|
16
|
+
in it for any permitted purpose. However, you may
|
|
17
|
+
only distribute the software according to [Distribution
|
|
18
|
+
License](#distribution-license) and make changes or new works
|
|
19
|
+
based on the software according to [Changes and New Works
|
|
20
|
+
License](#changes-and-new-works-license).
|
|
21
|
+
|
|
22
|
+
## Distribution License
|
|
23
|
+
|
|
24
|
+
The licensor grants you an additional copyright license
|
|
25
|
+
to distribute copies of the software. Your license
|
|
26
|
+
to distribute covers distributing the software with
|
|
27
|
+
changes and new works permitted by [Changes and New Works
|
|
28
|
+
License](#changes-and-new-works-license).
|
|
29
|
+
|
|
30
|
+
## Notices
|
|
31
|
+
|
|
32
|
+
You must ensure that anyone who gets a copy of any part of
|
|
33
|
+
the software from you also gets a copy of these terms or the
|
|
34
|
+
URL for them above, as well as copies of any plain-text lines
|
|
35
|
+
beginning with `Required Notice:` that the licensor provided
|
|
36
|
+
with the software. For example:
|
|
37
|
+
|
|
38
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
39
|
+
|
|
40
|
+
## Changes and New Works License
|
|
41
|
+
|
|
42
|
+
The licensor grants you an additional copyright license to
|
|
43
|
+
make changes and new works based on the software for any
|
|
44
|
+
permitted purpose.
|
|
45
|
+
|
|
46
|
+
## Patent License
|
|
47
|
+
|
|
48
|
+
The licensor grants you a patent license for the software that
|
|
49
|
+
covers patent claims the licensor can license, or becomes able
|
|
50
|
+
to license, that you would infringe by using the software.
|
|
51
|
+
|
|
52
|
+
## Noncommercial Purposes
|
|
53
|
+
|
|
54
|
+
Any noncommercial purpose is a permitted purpose.
|
|
55
|
+
|
|
56
|
+
## Personal Uses
|
|
57
|
+
|
|
58
|
+
Personal use for research, experiment, and testing for
|
|
59
|
+
the benefit of public knowledge, personal study, private
|
|
60
|
+
entertainment, hobby projects, amateur pursuits, or religious
|
|
61
|
+
observance, without any anticipated commercial application,
|
|
62
|
+
is use for a permitted purpose.
|
|
63
|
+
|
|
64
|
+
## Noncommercial Organizations
|
|
65
|
+
|
|
66
|
+
Use by any charitable organization, educational institution,
|
|
67
|
+
public research organization, public safety or health
|
|
68
|
+
organization, environmental protection organization,
|
|
69
|
+
or government institution is use for a permitted purpose
|
|
70
|
+
regardless of the source of funding or obligations resulting
|
|
71
|
+
from the funding.
|
|
72
|
+
|
|
73
|
+
## Fair Use
|
|
74
|
+
|
|
75
|
+
You may have "fair use" rights for the software under the
|
|
76
|
+
law. These terms do not limit them.
|
|
77
|
+
|
|
78
|
+
## No Other Rights
|
|
79
|
+
|
|
80
|
+
These terms do not allow you to sublicense or transfer any of
|
|
81
|
+
your licenses to anyone else, or prevent the licensor from
|
|
82
|
+
granting licenses to anyone else. These terms do not imply
|
|
83
|
+
any other licenses.
|
|
84
|
+
|
|
85
|
+
## Patent Defense
|
|
86
|
+
|
|
87
|
+
If you make any written claim that the software infringes or
|
|
88
|
+
contributes to infringement of any patent, your patent license
|
|
89
|
+
for the software granted under these terms ends immediately. If
|
|
90
|
+
your company makes such a claim, your patent license ends
|
|
91
|
+
immediately for work on behalf of your company.
|
|
92
|
+
|
|
93
|
+
## Violations
|
|
94
|
+
|
|
95
|
+
The first time you are notified in writing that you have
|
|
96
|
+
violated any of these terms, or done anything with the software
|
|
97
|
+
not covered by your licenses, your licenses can nonetheless
|
|
98
|
+
continue if you come into full compliance with these terms,
|
|
99
|
+
and take practical steps to correct past violations, within
|
|
100
|
+
32 days of receiving notice. Otherwise, all your licenses
|
|
101
|
+
end immediately.
|
|
102
|
+
|
|
103
|
+
## No Liability
|
|
104
|
+
|
|
105
|
+
***As far as the law allows, the software comes as is, without
|
|
106
|
+
any warranty or condition, and the licensor will not be liable
|
|
107
|
+
to you for any damages arising out of these terms or the use
|
|
108
|
+
or nature of the software, under any kind of legal claim.***
|
|
109
|
+
|
|
110
|
+
## Definitions
|
|
111
|
+
|
|
112
|
+
The **licensor** is the individual or entity offering these
|
|
113
|
+
terms, and the **software** is the software the licensor makes
|
|
114
|
+
available under these terms.
|
|
115
|
+
|
|
116
|
+
**You** refers to the individual or entity agreeing to these
|
|
117
|
+
terms.
|
|
118
|
+
|
|
119
|
+
**Your company** is any legal entity, sole proprietorship,
|
|
120
|
+
or other kind of organization that you work for, plus all
|
|
121
|
+
organizations that have control over, are under the control of,
|
|
122
|
+
or are under common control with that organization. **Control**
|
|
123
|
+
means ownership of substantially all the assets of an entity,
|
|
124
|
+
or the power to direct its management and policies by vote,
|
|
125
|
+
contract, or otherwise. Control can be direct or indirect.
|
|
126
|
+
|
|
127
|
+
**Your licenses** are all the licenses granted to you for the
|
|
128
|
+
software under these terms.
|
|
129
|
+
|
|
130
|
+
**Use** means anything you do with the software requiring one
|
|
131
|
+
of your licenses.
|
package/README.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# @emdzej/bimmerz-logger
|
|
2
|
+
|
|
3
|
+
Shared structured logger for the bimmerz family of tools
|
|
4
|
+
([`ediabasx`](https://github.com/emdzej/ediabasx),
|
|
5
|
+
[`inpax`](https://github.com/emdzej/inpax),
|
|
6
|
+
[`ncsx`](https://github.com/emdzej/ncsx), and the apps that build on
|
|
7
|
+
them).
|
|
8
|
+
|
|
9
|
+
**Pino-shape API**, hierarchical categories, runtime-mutable central
|
|
10
|
+
config, pluggable sinks. No environment variables. Works in both
|
|
11
|
+
Node and the browser; tree-shake-friendly so web bundles don't ship
|
|
12
|
+
pino.
|
|
13
|
+
|
|
14
|
+
## TL;DR
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { configureLogger, getLogger } from '@emdzej/bimmerz-logger';
|
|
18
|
+
|
|
19
|
+
// App start — configure once, anywhere.
|
|
20
|
+
configureLogger({
|
|
21
|
+
level: 'info',
|
|
22
|
+
categories: {
|
|
23
|
+
EDIABASX: 'debug',
|
|
24
|
+
'EDIABASX.parser': 'trace',
|
|
25
|
+
INPAX: 'info',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Anywhere in the codebase — log with or without a category.
|
|
30
|
+
const log = getLogger('EDIABASX.parser');
|
|
31
|
+
log.debug({ jobId: 'C_S_LESEN' }, 'parsing request packet');
|
|
32
|
+
log.info('parser ready');
|
|
33
|
+
|
|
34
|
+
// Want to flip on debug for one subsystem at runtime?
|
|
35
|
+
configureLogger({ categories: { ...prev, INPAX: 'debug' } });
|
|
36
|
+
// — every previously-handed-out INPAX logger sees the new level immediately.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Design
|
|
40
|
+
|
|
41
|
+
The interface is the same shape as pino — `log.debug(bindings, msg)`,
|
|
42
|
+
levels `trace` through `fatal`, `log.child(bindings)`. We don't
|
|
43
|
+
re-export pino's types because we don't want our public API locked
|
|
44
|
+
to one implementation. The default sink is a small console wrapper
|
|
45
|
+
(works in browser + Node); apps that want pino's pretty-print, JSON,
|
|
46
|
+
or file destinations opt in via `@emdzej/bimmerz-logger/sinks/pino`.
|
|
47
|
+
|
|
48
|
+
Logger handles are **proxies**, not snapshots — they consult the live
|
|
49
|
+
config on every call. So once an app calls `configureLogger(…)`, every
|
|
50
|
+
logger handle anyone ever cached picks up the new settings on its next
|
|
51
|
+
emit. No need to "refetch" loggers from callers.
|
|
52
|
+
|
|
53
|
+
Categories are **hierarchical** by dot. A rule for `EDIABASX` applies
|
|
54
|
+
to `EDIABASX.parser` and `EDIABASX.parser.lexer` unless a more
|
|
55
|
+
specific rule wins. Most specific match always wins:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
configureLogger({
|
|
59
|
+
level: 'warn',
|
|
60
|
+
categories: {
|
|
61
|
+
EDIABASX: 'debug', // covers EDIABASX, EDIABASX.runner, …
|
|
62
|
+
'EDIABASX.parser': 'trace', // overrides for parser sub-tree
|
|
63
|
+
INPAX: 'info',
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
getLogger('EDIABASX.parser.lexer').trace('hit'); // matches EDIABASX.parser → 'trace' → emitted
|
|
68
|
+
getLogger('EDIABASX.runner').debug('hit'); // matches EDIABASX → 'debug' → emitted
|
|
69
|
+
getLogger('INPAX.dispatcher').debug('miss'); // matches INPAX → 'info' → dropped
|
|
70
|
+
getLogger().debug('miss'); // root → 'warn' fallback → dropped
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## API
|
|
74
|
+
|
|
75
|
+
### `configureLogger(partial: Partial<LoggerConfig>)`
|
|
76
|
+
|
|
77
|
+
Replace or merge into the active configuration. Shallow merge —
|
|
78
|
+
`categories` and `sink` are replaced wholesale when present in the
|
|
79
|
+
partial.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
configureLogger({ level: 'debug' }); // bump default level
|
|
83
|
+
configureLogger({ categories: { EDIABASX: 'trace' } }); // change category rules
|
|
84
|
+
configureLogger({ categories: {} }); // clear all category rules
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Apply early in your app's entry point. You can re-apply at any time
|
|
88
|
+
— the change is immediate for every existing logger handle.
|
|
89
|
+
|
|
90
|
+
### `getLogger(category?: string): Logger`
|
|
91
|
+
|
|
92
|
+
Returns a logger handle. With no argument, the root logger
|
|
93
|
+
(category = `null`). With a dot-separated string, a category-scoped
|
|
94
|
+
logger.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const root = getLogger();
|
|
98
|
+
const parser = getLogger('EDIABASX.parser');
|
|
99
|
+
const job = parser.child({ jobId: 'C_S_LESEN' });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `Logger`
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
interface Logger {
|
|
106
|
+
readonly level: LogLevel; // currently-effective threshold (live)
|
|
107
|
+
|
|
108
|
+
trace(msg: string): void;
|
|
109
|
+
trace(bindings: object, msg: string): void;
|
|
110
|
+
debug(msg: string): void;
|
|
111
|
+
debug(bindings: object, msg: string): void;
|
|
112
|
+
info(msg: string): void;
|
|
113
|
+
info(bindings: object, msg: string): void;
|
|
114
|
+
warn(...): void;
|
|
115
|
+
error(...): void;
|
|
116
|
+
fatal(...): void;
|
|
117
|
+
|
|
118
|
+
child(bindings: object): Logger;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Two call forms — string-only `log.info("done")`, or bindings-first
|
|
123
|
+
`log.info({ jobId, count }, "done")`. Bindings are merged with any
|
|
124
|
+
permanent `child()` bindings; call bindings win on key conflicts.
|
|
125
|
+
|
|
126
|
+
`log.level` is a read-only getter that returns the live effective
|
|
127
|
+
level for this logger's category. Cheap to call — use it as an
|
|
128
|
+
escape hatch for hot paths where formatting the message is expensive:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
if (log.level === 'trace') {
|
|
132
|
+
log.trace({ details: expensiveDump() }, 'sg op');
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Sinks
|
|
137
|
+
|
|
138
|
+
Bundled sinks (importable from the main entry):
|
|
139
|
+
|
|
140
|
+
| Function | Use |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `consoleSink({ colors?, relativeTime? })` | Default. Routes through `console.{debug,info,warn,error}`. ANSI colour when TTY. |
|
|
143
|
+
| `bufferSink({ capacity? })` | In-memory ring of last N records. `.snapshot()` returns them — drives "Download log" UIs. |
|
|
144
|
+
| `multiSink(a, b, …)` | Fan one record out to every wrapped sink. Failures in one sink don't poison the others. |
|
|
145
|
+
| `nullSink()` | Drops everything. Tests, or to disable logging without changing level. |
|
|
146
|
+
|
|
147
|
+
Optional pino sink — import from the subpath so it's not in the
|
|
148
|
+
default tree-shake graph:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { pinoSink } from '@emdzej/bimmerz-logger/sinks/pino';
|
|
152
|
+
|
|
153
|
+
configureLogger({
|
|
154
|
+
level: 'info',
|
|
155
|
+
sink: pinoSink({ pretty: true }), // pino-pretty when TTY
|
|
156
|
+
// or: pinoSink({ destination: '/var/log/app.log' })
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Sink contract
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
interface Sink {
|
|
164
|
+
write(record: LogRecord): void;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface LogRecord {
|
|
168
|
+
level: LogLevel;
|
|
169
|
+
category: string | null;
|
|
170
|
+
bindings: Record<string, unknown>;
|
|
171
|
+
msg: string;
|
|
172
|
+
time: number; // Date.now()
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Roll your own sink for special destinations:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const httpSink: Sink = {
|
|
180
|
+
write(rec) {
|
|
181
|
+
if (rec.level === 'error' || rec.level === 'fatal') {
|
|
182
|
+
navigator.sendBeacon('/log', JSON.stringify(rec));
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
configureLogger({
|
|
188
|
+
sink: multiSink(consoleSink(), httpSink),
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## What we don't do
|
|
193
|
+
|
|
194
|
+
- **No environment-variable reads.** Apps are responsible for
|
|
195
|
+
mapping their CLI flags / wizard config / settings panel onto
|
|
196
|
+
`configureLogger(…)`. Keeps the library portable and
|
|
197
|
+
predictable.
|
|
198
|
+
- **No printf-style formatting.** Use template literals or
|
|
199
|
+
bindings:
|
|
200
|
+
```ts
|
|
201
|
+
log.debug({ a, b }, 'compared'); // ✅ bindings
|
|
202
|
+
log.debug(`compared ${a} vs ${b}`); // ✅ template literal
|
|
203
|
+
log.debug({}, 'compared %s vs %s', a, b); // ❌ not supported
|
|
204
|
+
```
|
|
205
|
+
- **No async sinks.** All sinks are sync. If you need network or
|
|
206
|
+
storage shipping, wrap a sync sink that enqueues to your own
|
|
207
|
+
async pipeline.
|
|
208
|
+
|
|
209
|
+
## Migration from `@emdzej/ediabasx-logger` / `@emdzej/inpax-logger`
|
|
210
|
+
|
|
211
|
+
Those packages will be retired once the codebases here are migrated.
|
|
212
|
+
The shapes are similar — `configureLogger({...})` plus
|
|
213
|
+
`getLogger("module")` — so most call sites need only an import path
|
|
214
|
+
change:
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
// old
|
|
218
|
+
import { getLogger, configureLogger } from '@emdzej/ediabasx-logger';
|
|
219
|
+
// new
|
|
220
|
+
import { getLogger, configureLogger } from '@emdzej/bimmerz-logger';
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Behavioural differences worth knowing:
|
|
224
|
+
|
|
225
|
+
- `configureLogger` now takes effect on **existing** logger handles.
|
|
226
|
+
ediabasx-logger only affected new ones.
|
|
227
|
+
- pino types are no longer in the public surface. `Logger` is our own
|
|
228
|
+
interface (same shape). If you typed something as `pino.Logger`,
|
|
229
|
+
swap to `Logger` from this package.
|
|
230
|
+
- `pretty` / `destination` options moved off the package-level config
|
|
231
|
+
and into the pino sink. Get them by switching the sink:
|
|
232
|
+
```ts
|
|
233
|
+
import { pinoSink } from '@emdzej/bimmerz-logger/sinks/pino';
|
|
234
|
+
configureLogger({ sink: pinoSink({ pretty: true }) });
|
|
235
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hierarchical category resolution.
|
|
3
|
+
*
|
|
4
|
+
* Categories are dot-separated paths (`EDIABASX.parser.lexer`).
|
|
5
|
+
* `resolveLevel("EDIABASX.parser.lexer", rules, fallback)` walks up
|
|
6
|
+
* the path looking for a matching rule — `EDIABASX.parser.lexer`
|
|
7
|
+
* first, then `EDIABASX.parser`, then `EDIABASX`, then the
|
|
8
|
+
* fallback. First match wins.
|
|
9
|
+
*
|
|
10
|
+
* This is what makes "set INPAX to info, EDIABASX to debug, but
|
|
11
|
+
* EDIABASX.parser to trace" work without having to enumerate every
|
|
12
|
+
* subsystem in the rules.
|
|
13
|
+
*/
|
|
14
|
+
import type { LogLevel } from './types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the effective level for `category` given a rule map
|
|
17
|
+
* and a fallback. The root category — `null` or `''` — always
|
|
18
|
+
* gets the fallback (no rule can match an unnamed category).
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveLevel(category: string | null, rules: Readonly<Record<string, LogLevel>> | undefined, fallback: LogLevel): LogLevel;
|
|
21
|
+
//# sourceMappingURL=categories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../src/categories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,GAAG,SAAS,EACrD,QAAQ,EAAE,QAAQ,GACjB,QAAQ,CAYV"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hierarchical category resolution.
|
|
3
|
+
*
|
|
4
|
+
* Categories are dot-separated paths (`EDIABASX.parser.lexer`).
|
|
5
|
+
* `resolveLevel("EDIABASX.parser.lexer", rules, fallback)` walks up
|
|
6
|
+
* the path looking for a matching rule — `EDIABASX.parser.lexer`
|
|
7
|
+
* first, then `EDIABASX.parser`, then `EDIABASX`, then the
|
|
8
|
+
* fallback. First match wins.
|
|
9
|
+
*
|
|
10
|
+
* This is what makes "set INPAX to info, EDIABASX to debug, but
|
|
11
|
+
* EDIABASX.parser to trace" work without having to enumerate every
|
|
12
|
+
* subsystem in the rules.
|
|
13
|
+
*/
|
|
14
|
+
import { LEVEL_VALUES } from './levels.js';
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the effective level for `category` given a rule map
|
|
17
|
+
* and a fallback. The root category — `null` or `''` — always
|
|
18
|
+
* gets the fallback (no rule can match an unnamed category).
|
|
19
|
+
*/
|
|
20
|
+
export function resolveLevel(category, rules, fallback) {
|
|
21
|
+
if (!rules || !category)
|
|
22
|
+
return fallback;
|
|
23
|
+
// Walk up dot segments: foo.bar.baz → foo.bar → foo → (fallback)
|
|
24
|
+
let path = category;
|
|
25
|
+
while (path.length > 0) {
|
|
26
|
+
const hit = rules[path];
|
|
27
|
+
if (hit !== undefined && hit in LEVEL_VALUES)
|
|
28
|
+
return hit;
|
|
29
|
+
const dot = path.lastIndexOf('.');
|
|
30
|
+
if (dot < 0)
|
|
31
|
+
break;
|
|
32
|
+
path = path.slice(0, dot);
|
|
33
|
+
}
|
|
34
|
+
return fallback;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=categories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.js","sourceRoot":"","sources":["../src/categories.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,QAAuB,EACvB,KAAqD,EACrD,QAAkB;IAElB,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACzC,iEAAiE;IACjE,IAAI,IAAI,GAAG,QAAQ,CAAC;IACpB,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,IAAI,YAAY;YAAE,OAAO,GAAG,CAAC;QACzD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,GAAG,GAAG,CAAC;YAAE,MAAM;QACnB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@emdzej/bimmerz-logger` — shared structured logger for the bimmerz
|
|
3
|
+
* family. See `README.md` for the design rationale and migration
|
|
4
|
+
* notes; the in-source doc on each export carries the API details.
|
|
5
|
+
*
|
|
6
|
+
* Pino-shape `Logger` interface, hierarchical category resolution,
|
|
7
|
+
* runtime-mutable central config, pluggable sink. Tree-shake-friendly
|
|
8
|
+
* — the default entry doesn't pull pino in, so web bundles stay light.
|
|
9
|
+
* Apps that want pino's JSON/pretty/file transports import the sink
|
|
10
|
+
* from `@emdzej/bimmerz-logger/sinks/pino`.
|
|
11
|
+
*/
|
|
12
|
+
export { configureLogger, getLogger, getLoggerConfig } from './logger.js';
|
|
13
|
+
export { resolveLevel } from './categories.js';
|
|
14
|
+
export { LEVEL_VALUES, levelPasses } from './levels.js';
|
|
15
|
+
export { bufferSink, type BufferSink, type BufferSinkOptions } from './sinks/buffer.js';
|
|
16
|
+
export { consoleSink, type ConsoleSinkOptions } from './sinks/console.js';
|
|
17
|
+
export { multiSink } from './sinks/multi.js';
|
|
18
|
+
export { nullSink } from './sinks/null.js';
|
|
19
|
+
export type { LogBindings, LogLevel, LogRecord, Logger, LoggerConfig, Sink, } from './types.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,YAAY,EACV,WAAW,EACX,QAAQ,EACR,SAAS,EACT,MAAM,EACN,YAAY,EACZ,IAAI,GACL,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@emdzej/bimmerz-logger` — shared structured logger for the bimmerz
|
|
3
|
+
* family. See `README.md` for the design rationale and migration
|
|
4
|
+
* notes; the in-source doc on each export carries the API details.
|
|
5
|
+
*
|
|
6
|
+
* Pino-shape `Logger` interface, hierarchical category resolution,
|
|
7
|
+
* runtime-mutable central config, pluggable sink. Tree-shake-friendly
|
|
8
|
+
* — the default entry doesn't pull pino in, so web bundles stay light.
|
|
9
|
+
* Apps that want pino's JSON/pretty/file transports import the sink
|
|
10
|
+
* from `@emdzej/bimmerz-logger/sinks/pino`.
|
|
11
|
+
*/
|
|
12
|
+
import { setDefaultSink } from './logger.js';
|
|
13
|
+
import { consoleSink } from './sinks/console.js';
|
|
14
|
+
// Install the default sink at module load. Apps can override via
|
|
15
|
+
// `configureLogger({ sink: … })` any time; this just ensures
|
|
16
|
+
// imports that never call `configureLogger` still emit somewhere.
|
|
17
|
+
setDefaultSink(consoleSink());
|
|
18
|
+
export { configureLogger, getLogger, getLoggerConfig } from './logger.js';
|
|
19
|
+
export { resolveLevel } from './categories.js';
|
|
20
|
+
export { LEVEL_VALUES, levelPasses } from './levels.js';
|
|
21
|
+
export { bufferSink } from './sinks/buffer.js';
|
|
22
|
+
export { consoleSink } from './sinks/console.js';
|
|
23
|
+
export { multiSink } from './sinks/multi.js';
|
|
24
|
+
export { nullSink } from './sinks/null.js';
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,iEAAiE;AACjE,6DAA6D;AAC7D,kEAAkE;AAClE,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;AAE9B,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,UAAU,EAA2C,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,WAAW,EAA2B,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/levels.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Level ordering + threshold helpers. Numeric values mirror pino's
|
|
3
|
+
* so a wrapping pino sink (or anyone comparing against pino's
|
|
4
|
+
* `logger.levels.values`) gets the same numbers back.
|
|
5
|
+
*/
|
|
6
|
+
import type { LogLevel } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Numeric weight of each level. Higher = more severe. `silent` is
|
|
9
|
+
* `Infinity` so no record ever beats the threshold when the
|
|
10
|
+
* effective level is `silent`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const LEVEL_VALUES: Record<LogLevel, number>;
|
|
13
|
+
/**
|
|
14
|
+
* `true` when a record at `record` severity passes a `threshold`
|
|
15
|
+
* filter — i.e. the line should be emitted.
|
|
16
|
+
*
|
|
17
|
+
* Example: `levelPasses('debug', 'info')` → `false` (debug is below
|
|
18
|
+
* info). `levelPasses('error', 'info')` → `true`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function levelPasses(record: LogLevel, threshold: LogLevel): boolean;
|
|
21
|
+
//# sourceMappingURL=levels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"levels.d.ts","sourceRoot":"","sources":["../src/levels.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAQjD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAE1E"}
|
package/dist/levels.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Level ordering + threshold helpers. Numeric values mirror pino's
|
|
3
|
+
* so a wrapping pino sink (or anyone comparing against pino's
|
|
4
|
+
* `logger.levels.values`) gets the same numbers back.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Numeric weight of each level. Higher = more severe. `silent` is
|
|
8
|
+
* `Infinity` so no record ever beats the threshold when the
|
|
9
|
+
* effective level is `silent`.
|
|
10
|
+
*/
|
|
11
|
+
export const LEVEL_VALUES = {
|
|
12
|
+
trace: 10,
|
|
13
|
+
debug: 20,
|
|
14
|
+
info: 30,
|
|
15
|
+
warn: 40,
|
|
16
|
+
error: 50,
|
|
17
|
+
fatal: 60,
|
|
18
|
+
silent: Number.POSITIVE_INFINITY,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* `true` when a record at `record` severity passes a `threshold`
|
|
22
|
+
* filter — i.e. the line should be emitted.
|
|
23
|
+
*
|
|
24
|
+
* Example: `levelPasses('debug', 'info')` → `false` (debug is below
|
|
25
|
+
* info). `levelPasses('error', 'info')` → `true`.
|
|
26
|
+
*/
|
|
27
|
+
export function levelPasses(record, threshold) {
|
|
28
|
+
return LEVEL_VALUES[record] >= LEVEL_VALUES[threshold];
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=levels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"levels.js","sourceRoot":"","sources":["../src/levels.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAA6B;IACpD,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,MAAM,CAAC,iBAAiB;CACjC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAgB,EAAE,SAAmB;IAC/D,OAAO,YAAY,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,SAAS,CAAC,CAAC;AACzD,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger implementation + central config.
|
|
3
|
+
*
|
|
4
|
+
* Logger handles are thin proxies that consult the live module-
|
|
5
|
+
* scoped config on every call. That's what makes
|
|
6
|
+
* `configureLogger({ categories: { EDIABASX: 'debug' } })` flip
|
|
7
|
+
* existing handles' behaviour instantly — no need to refetch
|
|
8
|
+
* loggers from callers.
|
|
9
|
+
*
|
|
10
|
+
* Performance: level resolution is a Map lookup + at most ~3 dot-
|
|
11
|
+
* segment slices for typical category paths. Both happen *before*
|
|
12
|
+
* any binding merge or sink dispatch, so a `log.debug({…}, 'msg')`
|
|
13
|
+
* call that's below threshold spends about as much time as a
|
|
14
|
+
* branch + Map.get. Same shape as pino's "no-op below level"
|
|
15
|
+
* pattern.
|
|
16
|
+
*/
|
|
17
|
+
import type { Logger, LoggerConfig, Sink } from './types.js';
|
|
18
|
+
/** @internal — called from index.ts after sink modules load. */
|
|
19
|
+
export declare function setDefaultSink(sink: Sink): void;
|
|
20
|
+
/**
|
|
21
|
+
* Replace or merge into the active configuration. The merge is
|
|
22
|
+
* shallow — `categories` and `sink` are replaced wholesale when
|
|
23
|
+
* present in the partial. Pass `categories: {}` to clear all
|
|
24
|
+
* per-category overrides.
|
|
25
|
+
*
|
|
26
|
+
* Effective immediately for every logger handle, including ones
|
|
27
|
+
* already returned by `getLogger()`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function configureLogger(config: Partial<LoggerConfig>): void;
|
|
30
|
+
/**
|
|
31
|
+
* Snapshot of the active configuration. Returned object is a copy
|
|
32
|
+
* — mutating it doesn't affect the live config (use
|
|
33
|
+
* `configureLogger()` for that).
|
|
34
|
+
*/
|
|
35
|
+
export declare function getLoggerConfig(): Readonly<LoggerConfig>;
|
|
36
|
+
/**
|
|
37
|
+
* Get a logger handle. Call with no arguments for the root logger
|
|
38
|
+
* (category = `null`); pass a dot-separated string to scope under
|
|
39
|
+
* a category. Re-calling with the same category does NOT return
|
|
40
|
+
* the same instance — handles are cheap, and shared identity would
|
|
41
|
+
* make `child()` bindings spill across callers.
|
|
42
|
+
*
|
|
43
|
+
* Examples:
|
|
44
|
+
* const log = getLogger();
|
|
45
|
+
* const parser = getLogger("EDIABASX.parser");
|
|
46
|
+
* const job = parser.child({ jobId: "C_S_LESEN" });
|
|
47
|
+
*/
|
|
48
|
+
export declare function getLogger(category?: string): Logger;
|
|
49
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAIV,MAAM,EACN,YAAY,EACZ,IAAI,EACL,MAAM,YAAY,CAAC;AASpB,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAE/C;AAOD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAInE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,QAAQ,CAAC,YAAY,CAAC,CAMxD;AAiED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|