@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/dist/logger.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
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 { resolveLevel } from './categories.js';
|
|
18
|
+
import { levelPasses } from './levels.js';
|
|
19
|
+
/**
|
|
20
|
+
* Default sink — lazily installed on the active config when no
|
|
21
|
+
* `sink` is explicitly supplied. Set via `setDefaultSink()` from
|
|
22
|
+
* the sink-side init so we don't have a circular dep.
|
|
23
|
+
*/
|
|
24
|
+
let DEFAULT_SINK = null;
|
|
25
|
+
/** @internal — called from index.ts after sink modules load. */
|
|
26
|
+
export function setDefaultSink(sink) {
|
|
27
|
+
DEFAULT_SINK = sink;
|
|
28
|
+
}
|
|
29
|
+
/** Module-scoped live config. Initialized to a sensible "info, console" default. */
|
|
30
|
+
const active = {
|
|
31
|
+
level: 'info',
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Replace or merge into the active configuration. The merge is
|
|
35
|
+
* shallow — `categories` and `sink` are replaced wholesale when
|
|
36
|
+
* present in the partial. Pass `categories: {}` to clear all
|
|
37
|
+
* per-category overrides.
|
|
38
|
+
*
|
|
39
|
+
* Effective immediately for every logger handle, including ones
|
|
40
|
+
* already returned by `getLogger()`.
|
|
41
|
+
*/
|
|
42
|
+
export function configureLogger(config) {
|
|
43
|
+
if (config.level !== undefined)
|
|
44
|
+
active.level = config.level;
|
|
45
|
+
if (config.categories !== undefined)
|
|
46
|
+
active.categories = config.categories;
|
|
47
|
+
if (config.sink !== undefined)
|
|
48
|
+
active.sink = config.sink;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Snapshot of the active configuration. Returned object is a copy
|
|
52
|
+
* — mutating it doesn't affect the live config (use
|
|
53
|
+
* `configureLogger()` for that).
|
|
54
|
+
*/
|
|
55
|
+
export function getLoggerConfig() {
|
|
56
|
+
return {
|
|
57
|
+
level: active.level,
|
|
58
|
+
categories: active.categories ? { ...active.categories } : undefined,
|
|
59
|
+
sink: active.sink,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
class LoggerImpl {
|
|
63
|
+
category;
|
|
64
|
+
bindings;
|
|
65
|
+
constructor(category, bindings = {}) {
|
|
66
|
+
this.category = category;
|
|
67
|
+
this.bindings = bindings;
|
|
68
|
+
}
|
|
69
|
+
get level() {
|
|
70
|
+
return resolveLevel(this.category, active.categories, active.level);
|
|
71
|
+
}
|
|
72
|
+
trace(a, b) {
|
|
73
|
+
this.emit('trace', a, b);
|
|
74
|
+
}
|
|
75
|
+
debug(a, b) {
|
|
76
|
+
this.emit('debug', a, b);
|
|
77
|
+
}
|
|
78
|
+
info(a, b) {
|
|
79
|
+
this.emit('info', a, b);
|
|
80
|
+
}
|
|
81
|
+
warn(a, b) {
|
|
82
|
+
this.emit('warn', a, b);
|
|
83
|
+
}
|
|
84
|
+
error(a, b) {
|
|
85
|
+
this.emit('error', a, b);
|
|
86
|
+
}
|
|
87
|
+
fatal(a, b) {
|
|
88
|
+
this.emit('fatal', a, b);
|
|
89
|
+
}
|
|
90
|
+
child(bindings) {
|
|
91
|
+
return new LoggerImpl(this.category, { ...this.bindings, ...bindings });
|
|
92
|
+
}
|
|
93
|
+
emit(level, a, b) {
|
|
94
|
+
const threshold = resolveLevel(this.category, active.categories, active.level);
|
|
95
|
+
if (!levelPasses(level, threshold))
|
|
96
|
+
return;
|
|
97
|
+
let msg;
|
|
98
|
+
let callBindings;
|
|
99
|
+
if (typeof a === 'string') {
|
|
100
|
+
msg = a;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
callBindings = a;
|
|
104
|
+
msg = b ?? '';
|
|
105
|
+
}
|
|
106
|
+
const mergedBindings = callBindings === undefined
|
|
107
|
+
? this.bindings
|
|
108
|
+
: { ...this.bindings, ...callBindings };
|
|
109
|
+
const record = {
|
|
110
|
+
level,
|
|
111
|
+
category: this.category,
|
|
112
|
+
bindings: mergedBindings,
|
|
113
|
+
msg,
|
|
114
|
+
time: Date.now(),
|
|
115
|
+
};
|
|
116
|
+
const sink = active.sink ?? DEFAULT_SINK;
|
|
117
|
+
if (sink)
|
|
118
|
+
sink.write(record);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get a logger handle. Call with no arguments for the root logger
|
|
123
|
+
* (category = `null`); pass a dot-separated string to scope under
|
|
124
|
+
* a category. Re-calling with the same category does NOT return
|
|
125
|
+
* the same instance — handles are cheap, and shared identity would
|
|
126
|
+
* make `child()` bindings spill across callers.
|
|
127
|
+
*
|
|
128
|
+
* Examples:
|
|
129
|
+
* const log = getLogger();
|
|
130
|
+
* const parser = getLogger("EDIABASX.parser");
|
|
131
|
+
* const job = parser.child({ jobId: "C_S_LESEN" });
|
|
132
|
+
*/
|
|
133
|
+
export function getLogger(category) {
|
|
134
|
+
return new LoggerImpl(category ?? null);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.test.d.ts","sourceRoot":"","sources":["../src/logger.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { configureLogger, getLogger, getLoggerConfig } from './logger.js';
|
|
3
|
+
import { resolveLevel } from './categories.js';
|
|
4
|
+
import { levelPasses } from './levels.js';
|
|
5
|
+
import { bufferSink } from './sinks/buffer.js';
|
|
6
|
+
import { multiSink } from './sinks/multi.js';
|
|
7
|
+
import { nullSink } from './sinks/null.js';
|
|
8
|
+
/** Reset to a known state after each test so tests don't leak config. */
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
configureLogger({ level: 'info', categories: {}, sink: nullSink() });
|
|
11
|
+
});
|
|
12
|
+
describe('levelPasses', () => {
|
|
13
|
+
it('matches pino ordering', () => {
|
|
14
|
+
expect(levelPasses('debug', 'info')).toBe(false);
|
|
15
|
+
expect(levelPasses('info', 'info')).toBe(true);
|
|
16
|
+
expect(levelPasses('error', 'info')).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it('silent blocks everything', () => {
|
|
19
|
+
expect(levelPasses('fatal', 'silent')).toBe(false);
|
|
20
|
+
expect(levelPasses('trace', 'silent')).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('resolveLevel hierarchy', () => {
|
|
24
|
+
const rules = { EDIABASX: 'debug', 'EDIABASX.parser': 'trace', INPAX: 'info' };
|
|
25
|
+
it('returns fallback for null category', () => {
|
|
26
|
+
expect(resolveLevel(null, rules, 'warn')).toBe('warn');
|
|
27
|
+
});
|
|
28
|
+
it('uses exact match when present', () => {
|
|
29
|
+
expect(resolveLevel('EDIABASX', rules, 'warn')).toBe('debug');
|
|
30
|
+
});
|
|
31
|
+
it('walks up dot segments', () => {
|
|
32
|
+
expect(resolveLevel('EDIABASX.parser.lexer', rules, 'warn')).toBe('trace');
|
|
33
|
+
expect(resolveLevel('EDIABASX.runner', rules, 'warn')).toBe('debug');
|
|
34
|
+
});
|
|
35
|
+
it('falls back when no segment matches', () => {
|
|
36
|
+
expect(resolveLevel('OTHER.subsystem', rules, 'warn')).toBe('warn');
|
|
37
|
+
});
|
|
38
|
+
it('ignores rules with bad level values', () => {
|
|
39
|
+
expect(resolveLevel('FOO', { FOO: 'bogus' }, 'warn')).toBe('warn');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('Logger basic dispatch', () => {
|
|
43
|
+
it('emits records at or above the threshold', () => {
|
|
44
|
+
const buf = bufferSink();
|
|
45
|
+
configureLogger({ level: 'info', sink: buf });
|
|
46
|
+
const log = getLogger();
|
|
47
|
+
log.debug('skipped');
|
|
48
|
+
log.info('kept');
|
|
49
|
+
log.warn('kept too');
|
|
50
|
+
const recs = buf.snapshot();
|
|
51
|
+
expect(recs.map((r) => r.msg)).toEqual(['kept', 'kept too']);
|
|
52
|
+
expect(recs[0]?.level).toBe('info');
|
|
53
|
+
});
|
|
54
|
+
it('attaches bindings when called with (obj, msg)', () => {
|
|
55
|
+
const buf = bufferSink();
|
|
56
|
+
configureLogger({ level: 'trace', sink: buf });
|
|
57
|
+
getLogger('A').info({ id: 7, tag: 'x' }, 'with bindings');
|
|
58
|
+
expect(buf.snapshot()[0]).toMatchObject({
|
|
59
|
+
level: 'info',
|
|
60
|
+
category: 'A',
|
|
61
|
+
bindings: { id: 7, tag: 'x' },
|
|
62
|
+
msg: 'with bindings',
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
it('emits empty bindings when called with (msg) only', () => {
|
|
66
|
+
const buf = bufferSink();
|
|
67
|
+
configureLogger({ level: 'trace', sink: buf });
|
|
68
|
+
getLogger().info('bare');
|
|
69
|
+
expect(buf.snapshot()[0]?.bindings).toEqual({});
|
|
70
|
+
});
|
|
71
|
+
it('attaches a `time` epoch ms', () => {
|
|
72
|
+
const buf = bufferSink();
|
|
73
|
+
configureLogger({ level: 'trace', sink: buf });
|
|
74
|
+
const before = Date.now();
|
|
75
|
+
getLogger().info('t');
|
|
76
|
+
const after = Date.now();
|
|
77
|
+
const rec = buf.snapshot()[0];
|
|
78
|
+
expect(rec.time).toBeGreaterThanOrEqual(before);
|
|
79
|
+
expect(rec.time).toBeLessThanOrEqual(after);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('Logger category resolution', () => {
|
|
83
|
+
it('applies per-category levels', () => {
|
|
84
|
+
const buf = bufferSink();
|
|
85
|
+
configureLogger({
|
|
86
|
+
level: 'warn',
|
|
87
|
+
categories: { EDIABASX: 'debug' },
|
|
88
|
+
sink: buf,
|
|
89
|
+
});
|
|
90
|
+
getLogger('EDIABASX').debug('kept');
|
|
91
|
+
getLogger('INPAX').debug('dropped');
|
|
92
|
+
getLogger().debug('dropped too');
|
|
93
|
+
expect(buf.snapshot().map((r) => r.msg)).toEqual(['kept']);
|
|
94
|
+
});
|
|
95
|
+
it('hierarchical override beats parent', () => {
|
|
96
|
+
const buf = bufferSink();
|
|
97
|
+
configureLogger({
|
|
98
|
+
level: 'warn',
|
|
99
|
+
categories: { EDIABASX: 'debug', 'EDIABASX.parser': 'trace' },
|
|
100
|
+
sink: buf,
|
|
101
|
+
});
|
|
102
|
+
getLogger('EDIABASX.parser').trace('kept');
|
|
103
|
+
getLogger('EDIABASX.runner').trace('dropped');
|
|
104
|
+
expect(buf.snapshot().map((r) => r.msg)).toEqual(['kept']);
|
|
105
|
+
});
|
|
106
|
+
it('logger.level reflects the live effective threshold', () => {
|
|
107
|
+
configureLogger({ level: 'warn', categories: { FOO: 'trace' } });
|
|
108
|
+
expect(getLogger('FOO').level).toBe('trace');
|
|
109
|
+
expect(getLogger('BAR').level).toBe('warn');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe('runtime reconfigure', () => {
|
|
113
|
+
it('affects existing logger handles', () => {
|
|
114
|
+
const buf = bufferSink();
|
|
115
|
+
configureLogger({ level: 'info', sink: buf });
|
|
116
|
+
const log = getLogger('X');
|
|
117
|
+
log.debug('dropped #1');
|
|
118
|
+
configureLogger({ level: 'debug' });
|
|
119
|
+
log.debug('kept after reconfigure');
|
|
120
|
+
expect(buf.snapshot().map((r) => r.msg)).toEqual(['kept after reconfigure']);
|
|
121
|
+
});
|
|
122
|
+
it('partial reconfigure merges with existing config', () => {
|
|
123
|
+
configureLogger({ level: 'error', categories: { A: 'debug' } });
|
|
124
|
+
configureLogger({ level: 'info' }); // categories should remain
|
|
125
|
+
const cfg = getLoggerConfig();
|
|
126
|
+
expect(cfg.level).toBe('info');
|
|
127
|
+
expect(cfg.categories).toEqual({ A: 'debug' });
|
|
128
|
+
});
|
|
129
|
+
it('explicit empty categories clears overrides', () => {
|
|
130
|
+
configureLogger({ level: 'warn', categories: { A: 'debug' } });
|
|
131
|
+
configureLogger({ categories: {} });
|
|
132
|
+
expect(getLoggerConfig().categories).toEqual({});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('child loggers', () => {
|
|
136
|
+
it('carry permanent bindings on every call', () => {
|
|
137
|
+
const buf = bufferSink();
|
|
138
|
+
configureLogger({ level: 'trace', sink: buf });
|
|
139
|
+
const log = getLogger('X').child({ tenant: 'acme' });
|
|
140
|
+
log.info('one');
|
|
141
|
+
log.info({ extra: 1 }, 'two');
|
|
142
|
+
expect(buf.snapshot().map((r) => r.bindings)).toEqual([
|
|
143
|
+
{ tenant: 'acme' },
|
|
144
|
+
{ tenant: 'acme', extra: 1 },
|
|
145
|
+
]);
|
|
146
|
+
});
|
|
147
|
+
it('call-binding overrides child binding on key conflict', () => {
|
|
148
|
+
const buf = bufferSink();
|
|
149
|
+
configureLogger({ level: 'trace', sink: buf });
|
|
150
|
+
const log = getLogger().child({ tenant: 'acme' });
|
|
151
|
+
log.info({ tenant: 'override' }, 'x');
|
|
152
|
+
expect(buf.snapshot()[0]?.bindings).toEqual({ tenant: 'override' });
|
|
153
|
+
});
|
|
154
|
+
it('child inherits category + level resolution', () => {
|
|
155
|
+
configureLogger({ level: 'warn', categories: { Y: 'trace' } });
|
|
156
|
+
const log = getLogger('Y').child({ a: 1 });
|
|
157
|
+
expect(log.level).toBe('trace');
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe('bufferSink', () => {
|
|
161
|
+
it('keeps records up to capacity', () => {
|
|
162
|
+
const buf = bufferSink({ capacity: 3 });
|
|
163
|
+
configureLogger({ level: 'trace', sink: buf });
|
|
164
|
+
for (let i = 0; i < 5; i++)
|
|
165
|
+
getLogger().info(`m${i}`);
|
|
166
|
+
expect(buf.snapshot().map((r) => r.msg)).toEqual(['m2', 'm3', 'm4']);
|
|
167
|
+
expect(buf.size()).toBe(3);
|
|
168
|
+
});
|
|
169
|
+
it('clear() empties the buffer', () => {
|
|
170
|
+
const buf = bufferSink();
|
|
171
|
+
configureLogger({ level: 'trace', sink: buf });
|
|
172
|
+
getLogger().info('a');
|
|
173
|
+
buf.clear();
|
|
174
|
+
expect(buf.size()).toBe(0);
|
|
175
|
+
expect(buf.snapshot()).toEqual([]);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
describe('multiSink', () => {
|
|
179
|
+
it('fans out to every wrapped sink', () => {
|
|
180
|
+
const a = bufferSink();
|
|
181
|
+
const b = bufferSink();
|
|
182
|
+
configureLogger({ level: 'trace', sink: multiSink(a, b) });
|
|
183
|
+
getLogger().info('hi');
|
|
184
|
+
expect(a.snapshot().map((r) => r.msg)).toEqual(['hi']);
|
|
185
|
+
expect(b.snapshot().map((r) => r.msg)).toEqual(['hi']);
|
|
186
|
+
});
|
|
187
|
+
it('isolates failing sinks from healthy ones', () => {
|
|
188
|
+
const angry = {
|
|
189
|
+
write() {
|
|
190
|
+
throw new Error('boom');
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
const calm = bufferSink();
|
|
194
|
+
configureLogger({ level: 'trace', sink: multiSink(angry, calm) });
|
|
195
|
+
expect(() => getLogger().info('hi')).not.toThrow();
|
|
196
|
+
expect(calm.snapshot().map((r) => r.msg)).toEqual(['hi']);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
//# sourceMappingURL=logger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.test.js","sourceRoot":"","sources":["../src/logger.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory ring-buffer sink. Holds the last `capacity` records and
|
|
3
|
+
* lets UI code snapshot them on demand — drives "Download log"
|
|
4
|
+
* buttons in web apps without having to also intercept the console.
|
|
5
|
+
*
|
|
6
|
+
* Capacity defaults to 5000 (~1MB if records average 200 bytes).
|
|
7
|
+
* Older records are dropped silently as new ones arrive.
|
|
8
|
+
*/
|
|
9
|
+
import type { LogRecord, Sink } from '../types.js';
|
|
10
|
+
export interface BufferSink extends Sink {
|
|
11
|
+
/** Records currently held, oldest → newest. */
|
|
12
|
+
snapshot(): LogRecord[];
|
|
13
|
+
/** Drop every held record. */
|
|
14
|
+
clear(): void;
|
|
15
|
+
/** Number of records currently held (≤ capacity). */
|
|
16
|
+
size(): number;
|
|
17
|
+
}
|
|
18
|
+
export interface BufferSinkOptions {
|
|
19
|
+
/** Max records held; older ones drop. Default 5000. */
|
|
20
|
+
capacity?: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function bufferSink(opts?: BufferSinkOptions): BufferSink;
|
|
23
|
+
//# sourceMappingURL=buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../src/sinks/buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,UAAW,SAAQ,IAAI;IACtC,+CAA+C;IAC/C,QAAQ,IAAI,SAAS,EAAE,CAAC;IACxB,8BAA8B;IAC9B,KAAK,IAAI,IAAI,CAAC;IACd,qDAAqD;IACrD,IAAI,IAAI,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,UAAU,CAgCnE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory ring-buffer sink. Holds the last `capacity` records and
|
|
3
|
+
* lets UI code snapshot them on demand — drives "Download log"
|
|
4
|
+
* buttons in web apps without having to also intercept the console.
|
|
5
|
+
*
|
|
6
|
+
* Capacity defaults to 5000 (~1MB if records average 200 bytes).
|
|
7
|
+
* Older records are dropped silently as new ones arrive.
|
|
8
|
+
*/
|
|
9
|
+
export function bufferSink(opts = {}) {
|
|
10
|
+
const capacity = Math.max(1, opts.capacity ?? 5000);
|
|
11
|
+
// Plain array is fine — pop+shift would be O(N); we use an
|
|
12
|
+
// index-based ring so push is O(1) and snapshot is O(N) only on
|
|
13
|
+
// demand.
|
|
14
|
+
const ring = new Array(capacity);
|
|
15
|
+
let head = 0; // next write position
|
|
16
|
+
let count = 0;
|
|
17
|
+
return {
|
|
18
|
+
write(record) {
|
|
19
|
+
ring[head] = record;
|
|
20
|
+
head = (head + 1) % capacity;
|
|
21
|
+
if (count < capacity)
|
|
22
|
+
count++;
|
|
23
|
+
},
|
|
24
|
+
snapshot() {
|
|
25
|
+
const out = [];
|
|
26
|
+
const start = count < capacity ? 0 : head;
|
|
27
|
+
for (let i = 0; i < count; i++) {
|
|
28
|
+
const r = ring[(start + i) % capacity];
|
|
29
|
+
if (r)
|
|
30
|
+
out.push(r);
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
},
|
|
34
|
+
clear() {
|
|
35
|
+
ring.fill(undefined);
|
|
36
|
+
head = 0;
|
|
37
|
+
count = 0;
|
|
38
|
+
},
|
|
39
|
+
size() {
|
|
40
|
+
return count;
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer.js","sourceRoot":"","sources":["../../src/sinks/buffer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkBH,MAAM,UAAU,UAAU,CAAC,OAA0B,EAAE;IACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;IACpD,2DAA2D;IAC3D,gEAAgE;IAChE,UAAU;IACV,MAAM,IAAI,GAA8B,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC5D,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,sBAAsB;IACpC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO;QACL,KAAK,CAAC,MAAiB;YACrB,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;YACpB,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;YAC7B,IAAI,KAAK,GAAG,QAAQ;gBAAE,KAAK,EAAE,CAAC;QAChC,CAAC;QACD,QAAQ;YACN,MAAM,GAAG,GAAgB,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;gBACvC,IAAI,CAAC;oBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACrB,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QACD,KAAK;YACH,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACrB,IAAI,GAAG,CAAC,CAAC;YACT,KAAK,GAAG,CAAC,CAAC;QACZ,CAAC;QACD,IAAI;YACF,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default sink — works in Node and the browser, no dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Routes through `console.{trace|debug|info|warn|error}` per level
|
|
5
|
+
* so browser devtools' level-filter sidebar works correctly. In
|
|
6
|
+
* Node, console.* writes to stderr (warn/error) or stdout (rest)
|
|
7
|
+
* — same as bare `console.log`. For Node CLIs that want
|
|
8
|
+
* pino-pretty / file destinations, switch to
|
|
9
|
+
* `@emdzej/bimmerz-logger/sinks/pino`.
|
|
10
|
+
*
|
|
11
|
+
* Line format:
|
|
12
|
+
* 2026-05-23T19:14:32.123Z DEBUG [EDIABASX.parser] msg {jobId:"C_S_LESEN"}
|
|
13
|
+
*
|
|
14
|
+
* Bindings render as compact JSON. ANSI colours are added when the
|
|
15
|
+
* environment looks like a TTY (best-effort: `process.stdout.isTTY`
|
|
16
|
+
* in Node, never in the browser).
|
|
17
|
+
*/
|
|
18
|
+
import type { Sink } from '../types.js';
|
|
19
|
+
export interface ConsoleSinkOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Force colour on/off. Defaults to "on if Node TTY, off otherwise".
|
|
22
|
+
* Browser devtools renders ANSI literally, so we leave it off there
|
|
23
|
+
* unless explicitly requested.
|
|
24
|
+
*/
|
|
25
|
+
colors?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Render `time` as a relative `+12ms` offset from the sink's
|
|
28
|
+
* creation moment instead of an absolute ISO timestamp. Handy for
|
|
29
|
+
* spotting time gaps between adjacent calls.
|
|
30
|
+
*/
|
|
31
|
+
relativeTime?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare function consoleSink(opts?: ConsoleSinkOptions): Sink;
|
|
34
|
+
//# sourceMappingURL=console.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/sinks/console.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAuB,IAAI,EAAE,MAAM,aAAa,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAkDD,wBAAgB,WAAW,CAAC,IAAI,GAAE,kBAAuB,GAAG,IAAI,CAmB/D"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default sink — works in Node and the browser, no dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Routes through `console.{trace|debug|info|warn|error}` per level
|
|
5
|
+
* so browser devtools' level-filter sidebar works correctly. In
|
|
6
|
+
* Node, console.* writes to stderr (warn/error) or stdout (rest)
|
|
7
|
+
* — same as bare `console.log`. For Node CLIs that want
|
|
8
|
+
* pino-pretty / file destinations, switch to
|
|
9
|
+
* `@emdzej/bimmerz-logger/sinks/pino`.
|
|
10
|
+
*
|
|
11
|
+
* Line format:
|
|
12
|
+
* 2026-05-23T19:14:32.123Z DEBUG [EDIABASX.parser] msg {jobId:"C_S_LESEN"}
|
|
13
|
+
*
|
|
14
|
+
* Bindings render as compact JSON. ANSI colours are added when the
|
|
15
|
+
* environment looks like a TTY (best-effort: `process.stdout.isTTY`
|
|
16
|
+
* in Node, never in the browser).
|
|
17
|
+
*/
|
|
18
|
+
const ANSI = {
|
|
19
|
+
reset: '\x1b[0m',
|
|
20
|
+
gray: '\x1b[90m',
|
|
21
|
+
cyan: '\x1b[36m',
|
|
22
|
+
green: '\x1b[32m',
|
|
23
|
+
yellow: '\x1b[33m',
|
|
24
|
+
red: '\x1b[31m',
|
|
25
|
+
bgRed: '\x1b[41m',
|
|
26
|
+
};
|
|
27
|
+
const LEVEL_COLOR = {
|
|
28
|
+
trace: ANSI.gray,
|
|
29
|
+
debug: ANSI.cyan,
|
|
30
|
+
info: ANSI.green,
|
|
31
|
+
warn: ANSI.yellow,
|
|
32
|
+
error: ANSI.red,
|
|
33
|
+
fatal: ANSI.bgRed,
|
|
34
|
+
silent: '',
|
|
35
|
+
};
|
|
36
|
+
const LEVEL_TAG = {
|
|
37
|
+
trace: 'TRACE',
|
|
38
|
+
debug: 'DEBUG',
|
|
39
|
+
info: 'INFO ',
|
|
40
|
+
warn: 'WARN ',
|
|
41
|
+
error: 'ERROR',
|
|
42
|
+
fatal: 'FATAL',
|
|
43
|
+
silent: '',
|
|
44
|
+
};
|
|
45
|
+
const LEVEL_METHOD = {
|
|
46
|
+
trace: 'debug',
|
|
47
|
+
debug: 'debug',
|
|
48
|
+
info: 'info',
|
|
49
|
+
warn: 'warn',
|
|
50
|
+
error: 'error',
|
|
51
|
+
fatal: 'error',
|
|
52
|
+
silent: 'log',
|
|
53
|
+
};
|
|
54
|
+
function detectTty() {
|
|
55
|
+
// Node: process.stdout.isTTY → typically true under terminals.
|
|
56
|
+
// Avoid `process` in a way that bundlers can't tree-shake out
|
|
57
|
+
// gracefully — `globalThis` access is cheap.
|
|
58
|
+
const g = globalThis;
|
|
59
|
+
return !!g.process?.stdout?.isTTY;
|
|
60
|
+
}
|
|
61
|
+
export function consoleSink(opts = {}) {
|
|
62
|
+
const colors = opts.colors ?? detectTty();
|
|
63
|
+
const t0 = opts.relativeTime ? Date.now() : 0;
|
|
64
|
+
return {
|
|
65
|
+
write(record) {
|
|
66
|
+
const tag = LEVEL_TAG[record.level];
|
|
67
|
+
const tagColored = colors ? `${LEVEL_COLOR[record.level]}${tag}${ANSI.reset}` : tag;
|
|
68
|
+
const time = opts.relativeTime
|
|
69
|
+
? `+${(record.time - t0).toString().padStart(4)}ms`
|
|
70
|
+
: new Date(record.time).toISOString();
|
|
71
|
+
const cat = record.category ? ` [${record.category}]` : '';
|
|
72
|
+
const bindings = Object.keys(record.bindings).length > 0
|
|
73
|
+
? ` ${safeStringify(record.bindings)}`
|
|
74
|
+
: '';
|
|
75
|
+
const line = `${time} ${tagColored}${cat} ${record.msg}${bindings}`;
|
|
76
|
+
const method = LEVEL_METHOD[record.level];
|
|
77
|
+
console[method](line);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* JSON.stringify with circular-ref guard and Error → {name, message,
|
|
83
|
+
* stack} expansion. Bindings often carry Error instances or shared
|
|
84
|
+
* state objects; we don't want a circular ref or a "[object Object]"
|
|
85
|
+
* to drop information.
|
|
86
|
+
*/
|
|
87
|
+
function safeStringify(value) {
|
|
88
|
+
const seen = new WeakSet();
|
|
89
|
+
try {
|
|
90
|
+
return JSON.stringify(value, (_, v) => {
|
|
91
|
+
if (v instanceof Error) {
|
|
92
|
+
return { name: v.name, message: v.message, stack: v.stack };
|
|
93
|
+
}
|
|
94
|
+
if (typeof v === 'object' && v !== null) {
|
|
95
|
+
if (seen.has(v))
|
|
96
|
+
return '[Circular]';
|
|
97
|
+
seen.add(v);
|
|
98
|
+
}
|
|
99
|
+
return v;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return '[unserializable]';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=console.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"console.js","sourceRoot":"","sources":["../../src/sinks/console.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan out one record to every wrapped sink. Common pairing:
|
|
3
|
+
* `multiSink(consoleSink(), bufferSink({ capacity: 10_000 }))` —
|
|
4
|
+
* see lines in devtools while also accumulating them for an
|
|
5
|
+
* end-user "Download log" button.
|
|
6
|
+
*
|
|
7
|
+
* Failures in one sink don't stop later sinks — each `write` is
|
|
8
|
+
* wrapped in try/catch and errors are swallowed (logging
|
|
9
|
+
* recursively from a logging error would loop).
|
|
10
|
+
*/
|
|
11
|
+
import type { Sink } from '../types.js';
|
|
12
|
+
export declare function multiSink(...sinks: Sink[]): Sink;
|
|
13
|
+
//# sourceMappingURL=multi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi.d.ts","sourceRoot":"","sources":["../../src/sinks/multi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAa,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnD,wBAAgB,SAAS,CAAC,GAAG,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAahD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan out one record to every wrapped sink. Common pairing:
|
|
3
|
+
* `multiSink(consoleSink(), bufferSink({ capacity: 10_000 }))` —
|
|
4
|
+
* see lines in devtools while also accumulating them for an
|
|
5
|
+
* end-user "Download log" button.
|
|
6
|
+
*
|
|
7
|
+
* Failures in one sink don't stop later sinks — each `write` is
|
|
8
|
+
* wrapped in try/catch and errors are swallowed (logging
|
|
9
|
+
* recursively from a logging error would loop).
|
|
10
|
+
*/
|
|
11
|
+
export function multiSink(...sinks) {
|
|
12
|
+
return {
|
|
13
|
+
write(record) {
|
|
14
|
+
for (const s of sinks) {
|
|
15
|
+
try {
|
|
16
|
+
s.write(record);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Intentional: don't let one bad sink kill the others, and
|
|
20
|
+
// don't log the failure (that would re-enter `write`).
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=multi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi.js","sourceRoot":"","sources":["../../src/sinks/multi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,UAAU,SAAS,CAAC,GAAG,KAAa;IACxC,OAAO;QACL,KAAK,CAAC,MAAiB;YACrB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACtB,IAAI,CAAC;oBACH,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAClB,CAAC;gBAAC,MAAM,CAAC;oBACP,2DAA2D;oBAC3D,uDAAuD;gBACzD,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Null sink — drops every record. Use in tests so logging code
|
|
3
|
+
* doesn't pollute the test runner output, or in production code
|
|
4
|
+
* paths where you want to disable logging entirely without going
|
|
5
|
+
* through `silent` level (e.g. a "verbose" CLI flag that controls
|
|
6
|
+
* level but a separate "quiet" flag that controls the sink).
|
|
7
|
+
*/
|
|
8
|
+
import type { Sink } from '../types.js';
|
|
9
|
+
export declare function nullSink(): Sink;
|
|
10
|
+
//# sourceMappingURL=null.d.ts.map
|