@mmutils/logger 0.0.0-stage → 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 +21 -0
- package/README.md +901 -2
- package/dist/cjs/index.cjs +72 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/levels.cjs +82 -0
- package/dist/cjs/levels.cjs.map +1 -0
- package/dist/cjs/logger.cjs +576 -0
- package/dist/cjs/logger.cjs.map +1 -0
- package/dist/cjs/outputs.cjs +24 -0
- package/dist/cjs/outputs.cjs.map +1 -0
- package/dist/cjs/plugins/columns.cjs +782 -0
- package/dist/cjs/plugins/columns.cjs.map +1 -0
- package/dist/cjs/plugins/graph.cjs +578 -0
- package/dist/cjs/plugins/graph.cjs.map +1 -0
- package/dist/cjs/plugins/json.cjs +644 -0
- package/dist/cjs/plugins/json.cjs.map +1 -0
- package/dist/cjs/plugins/message.cjs +108 -0
- package/dist/cjs/plugins/message.cjs.map +1 -0
- package/dist/cjs/plugins/shared.cjs +194 -0
- package/dist/cjs/plugins/shared.cjs.map +1 -0
- package/dist/cjs/time.cjs +234 -0
- package/dist/cjs/time.cjs.map +1 -0
- package/dist/cjs/utils/text.cjs +646 -0
- package/dist/cjs/utils/text.cjs.map +1 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/levels.js +72 -0
- package/dist/esm/levels.js.map +1 -0
- package/dist/esm/logger.js +572 -0
- package/dist/esm/logger.js.map +1 -0
- package/dist/esm/outputs.js +21 -0
- package/dist/esm/outputs.js.map +1 -0
- package/dist/esm/plugins/columns.js +778 -0
- package/dist/esm/plugins/columns.js.map +1 -0
- package/dist/esm/plugins/graph.js +572 -0
- package/dist/esm/plugins/graph.js.map +1 -0
- package/dist/esm/plugins/json.js +641 -0
- package/dist/esm/plugins/json.js.map +1 -0
- package/dist/esm/plugins/message.js +105 -0
- package/dist/esm/plugins/message.js.map +1 -0
- package/dist/esm/plugins/shared.js +187 -0
- package/dist/esm/plugins/shared.js.map +1 -0
- package/dist/esm/time.js +231 -0
- package/dist/esm/time.js.map +1 -0
- package/dist/esm/utils/text.js +621 -0
- package/dist/esm/utils/text.js.map +1 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/levels.d.ts +50 -0
- package/dist/types/logger.d.ts +245 -0
- package/dist/types/outputs.d.ts +12 -0
- package/dist/types/plugins/columns.d.ts +151 -0
- package/dist/types/plugins/graph.d.ts +243 -0
- package/dist/types/plugins/json.d.ts +169 -0
- package/dist/types/plugins/message.d.ts +181 -0
- package/dist/types/plugins/shared.d.ts +74 -0
- package/dist/types/time.d.ts +48 -0
- package/dist/types/types.d.ts +176 -0
- package/dist/types/utils/text.d.ts +231 -0
- package/package.json +85 -4
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
import { assertLogLevel, LogLevels, LOG_TYPE_VALUES, unknownLogTypeError, LOG_TYPES } from './levels.js';
|
|
2
|
+
import { consoleOutput } from './outputs.js';
|
|
3
|
+
import { describeThrown } from './utils/text.js';
|
|
4
|
+
import { compileTimestamp, DEFAULT_TIMESTAMP_FORMAT } from './time.js';
|
|
5
|
+
|
|
6
|
+
const createClock = (clock) => {
|
|
7
|
+
if (clock === undefined || clock === 'wall')
|
|
8
|
+
return {
|
|
9
|
+
read: (now) => {
|
|
10
|
+
now.time = Date.now();
|
|
11
|
+
},
|
|
12
|
+
start: [Date.now(), 0],
|
|
13
|
+
};
|
|
14
|
+
if (clock === 'precise') {
|
|
15
|
+
// process.hrtime(anchor) gives the exact [seconds, nanoseconds] since
|
|
16
|
+
// the anchor: ~90 ns, faster than hrtime.bigint() (~110-125 ns)
|
|
17
|
+
const anchorTime = Date.now();
|
|
18
|
+
const anchor = process.hrtime();
|
|
19
|
+
return {
|
|
20
|
+
read: (now) => {
|
|
21
|
+
const [seconds, nanoseconds] = process.hrtime(anchor);
|
|
22
|
+
now.time = anchorTime + seconds * 1000 + Math.floor(nanoseconds / 1e6);
|
|
23
|
+
now.timeNs = nanoseconds % 1e6;
|
|
24
|
+
},
|
|
25
|
+
start: [anchorTime, 0],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (typeof clock === 'function') {
|
|
29
|
+
const read = clock;
|
|
30
|
+
return {
|
|
31
|
+
read: (now) => {
|
|
32
|
+
// the time of the log in whole milliseconds; finer clocks: 'precise'
|
|
33
|
+
now.time = Math.floor(read());
|
|
34
|
+
},
|
|
35
|
+
start: [Math.floor(read()), 0],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
throw new TypeError(`Logger: clock must be 'wall', 'precise' or a function, got ${typeName(clock)}.`);
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Creates the timestamp formatter once, from a pattern, options or a
|
|
42
|
+
* formatter function.
|
|
43
|
+
*/
|
|
44
|
+
const createTimestampFormatter = (options, start) => {
|
|
45
|
+
if (options === false)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (options === undefined)
|
|
48
|
+
return compileTimestamp(DEFAULT_TIMESTAMP_FORMAT, { start });
|
|
49
|
+
if (typeof options === 'string')
|
|
50
|
+
return compileTimestamp(options, { start });
|
|
51
|
+
if (typeof options === 'function')
|
|
52
|
+
return options;
|
|
53
|
+
if (typeof options === 'object' && options !== null) {
|
|
54
|
+
const { format = DEFAULT_TIMESTAMP_FORMAT, utc = false } = options;
|
|
55
|
+
if (typeof format !== 'string')
|
|
56
|
+
throw new TypeError(`Logger: timestamp.format must be a pattern string, got ${typeName(format)}.`);
|
|
57
|
+
return compileTimestamp(format, { utc, start });
|
|
58
|
+
}
|
|
59
|
+
throw new TypeError(`Logger: timestamp must be a pattern, options, a function or false, got ${typeName(options)}.`);
|
|
60
|
+
};
|
|
61
|
+
const typeName = (value) => value === null ? 'null'
|
|
62
|
+
: Array.isArray(value) ? 'array'
|
|
63
|
+
: typeof value;
|
|
64
|
+
/**
|
|
65
|
+
* Throws a `TypeError` naming `what` if the value is not a function. Shapes
|
|
66
|
+
* are checked when plugins and pipeline steps are added, so mistakes surface
|
|
67
|
+
* there and not on the first log.
|
|
68
|
+
*/
|
|
69
|
+
const assertFunction = (value, what) => {
|
|
70
|
+
if (typeof value !== 'function')
|
|
71
|
+
throw new TypeError(`${what} is not a function, got ${typeName(value)}.`);
|
|
72
|
+
};
|
|
73
|
+
const assertTemplateMap = (map, what) => {
|
|
74
|
+
if (typeof map !== 'object' || map === null)
|
|
75
|
+
throw new TypeError(`${what} is not an object, got ${typeName(map)}.`);
|
|
76
|
+
for (const key of Object.keys(map))
|
|
77
|
+
assertFunction(map[key], `${what} template "${key}"`);
|
|
78
|
+
};
|
|
79
|
+
const assertPosition = (position, what) => {
|
|
80
|
+
if (position !== undefined && !Number.isInteger(position))
|
|
81
|
+
throw new TypeError(`${what} position is not an integer, got ${typeof position === 'number' ? String(position) : typeName(position)}.`);
|
|
82
|
+
};
|
|
83
|
+
const describeKey = (key) => typeof key === 'symbol' ? String(key) : `"${String(key)}"`;
|
|
84
|
+
/**
|
|
85
|
+
* Reads the methods a plugin adds, before anything is registered: own
|
|
86
|
+
* enumerable string and symbol keys (what `Object.assign` copies), each read
|
|
87
|
+
* once, so throwing getters fail here.
|
|
88
|
+
*
|
|
89
|
+
* @throws TypeError if `methods` is not a plain object: class instances would
|
|
90
|
+
* lose their prototype methods.
|
|
91
|
+
* @throws Error if a method would override an existing logger property.
|
|
92
|
+
*/
|
|
93
|
+
const readMethods = (methods, logger, what) => {
|
|
94
|
+
if (methods === undefined)
|
|
95
|
+
return [];
|
|
96
|
+
if (typeof methods !== 'object' || methods === null)
|
|
97
|
+
throw new TypeError(`${what} methods must return an object, got ${typeName(methods)}.`);
|
|
98
|
+
const proto = Object.getPrototypeOf(methods);
|
|
99
|
+
// the prototype of a plain object, of any realm, is a root object
|
|
100
|
+
if (proto !== null && Object.getPrototypeOf(proto) !== null) {
|
|
101
|
+
const { name } = proto
|
|
102
|
+
.constructor ?? { name: undefined };
|
|
103
|
+
throw new TypeError(`${what} methods must return a plain object, got ${typeof name === 'string' && name ? name : 'an instance'}. Prototype methods of class instances would not be added.`);
|
|
104
|
+
}
|
|
105
|
+
const entries = [];
|
|
106
|
+
for (const key of Reflect.ownKeys(methods)) {
|
|
107
|
+
if (!Object.prototype.propertyIsEnumerable.call(methods, key))
|
|
108
|
+
continue;
|
|
109
|
+
if (key in logger)
|
|
110
|
+
throw new Error(`${what} method ${describeKey(key)} overrides an existing logger property.`);
|
|
111
|
+
entries.push([key, methods[key]]);
|
|
112
|
+
}
|
|
113
|
+
return entries;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Own style group of a sheet, ignoring inherited properties.
|
|
117
|
+
*/
|
|
118
|
+
const ownGroup = (sheet, group) => Object.hasOwn(sheet, group) ? sheet[group] : undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Sheets converted once and shared between loggers: converting a
|
|
121
|
+
* `style-escape-codes` chain takes about 65 ns, and the bundled plugins
|
|
122
|
+
* share their default sheet. Sheets are read when they are added.
|
|
123
|
+
*/
|
|
124
|
+
const compiledSheets = new WeakMap();
|
|
125
|
+
/**
|
|
126
|
+
* Converts the own groups of a sheet to strings.
|
|
127
|
+
*
|
|
128
|
+
* @param what Prefix of error messages, e.g. `Plugin "theme"`.
|
|
129
|
+
* @throws TypeError if a style can't be converted to a string.
|
|
130
|
+
*/
|
|
131
|
+
const compileSheet = (sheet, what) => {
|
|
132
|
+
const cached = compiledSheets.get(sheet);
|
|
133
|
+
if (cached !== undefined)
|
|
134
|
+
return cached;
|
|
135
|
+
// no prototype, like the baked styles: lookups never reach Object.prototype
|
|
136
|
+
const compiled = Object.create(null);
|
|
137
|
+
for (const groupName of ['*', ...LOG_TYPES]) {
|
|
138
|
+
// own groups only: inherited ones may come from prototype pollution
|
|
139
|
+
const group = ownGroup(sheet, groupName);
|
|
140
|
+
if (group === undefined)
|
|
141
|
+
continue;
|
|
142
|
+
compiled[groupName] = Object.entries(group).map(([name, style]) => {
|
|
143
|
+
try {
|
|
144
|
+
return [name, String(style)];
|
|
145
|
+
}
|
|
146
|
+
catch (thrown) {
|
|
147
|
+
throw new TypeError(`${what} style "${groupName}.${name}" can't be converted to an escape code string: ${describeThrown(thrown)}`, { cause: thrown });
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
compiledSheets.set(sheet, compiled);
|
|
152
|
+
return compiled;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Style available to every log type without registering it.
|
|
156
|
+
*/
|
|
157
|
+
const BUILT_IN_STYLES = { '*': { reset: '\x1b[0m' } };
|
|
158
|
+
/**
|
|
159
|
+
* Passes each entry property through the template map of the entry's kind.
|
|
160
|
+
* Properties without a template function stay unchanged. Part of every
|
|
161
|
+
* logger's default transformers.
|
|
162
|
+
*/
|
|
163
|
+
const templateTransformer = (entry, ctx) => {
|
|
164
|
+
const map = ctx.templateMap;
|
|
165
|
+
if (map === undefined)
|
|
166
|
+
return entry;
|
|
167
|
+
for (const key in entry) {
|
|
168
|
+
const template = map[key];
|
|
169
|
+
if (template !== undefined)
|
|
170
|
+
entry[key] = template(entry[key], ctx, key);
|
|
171
|
+
}
|
|
172
|
+
return entry;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Logger implementation without plugin method typing. Use `Logger` instead,
|
|
176
|
+
* which types the methods of plugins passed to the constructor.
|
|
177
|
+
*
|
|
178
|
+
* Every `log` call creates an entry with `id`, `timestamp`, `type`, `kind` and
|
|
179
|
+
* `data`; runs it through `transformers` (which by default contains
|
|
180
|
+
* `templateTransformer`) and hands the result to the output registered for the
|
|
181
|
+
* entry's kind, or the default output.
|
|
182
|
+
*/
|
|
183
|
+
class BaseLogger {
|
|
184
|
+
/** Pipeline steps, executed in order for every log. */
|
|
185
|
+
transformers = [templateTransformer];
|
|
186
|
+
/** Template maps keyed by log kind. */
|
|
187
|
+
templateMaps = Object.create(null);
|
|
188
|
+
/** Kind of logs created without an explicit kind. */
|
|
189
|
+
defaultKind;
|
|
190
|
+
currentLevel;
|
|
191
|
+
/** Numeric value of `level`, compared on every log. */
|
|
192
|
+
threshold;
|
|
193
|
+
nextId = 1;
|
|
194
|
+
useStyles;
|
|
195
|
+
clock;
|
|
196
|
+
/** Default clock, read inline: no call through the reader. */
|
|
197
|
+
wallClock;
|
|
198
|
+
formatTimestamp;
|
|
199
|
+
/** Time of the current log, written by the clock: no allocation per log. */
|
|
200
|
+
now = {
|
|
201
|
+
time: 0,
|
|
202
|
+
timeNs: undefined,
|
|
203
|
+
};
|
|
204
|
+
defaultOutput;
|
|
205
|
+
outputs = Object.create(null);
|
|
206
|
+
styleSheets = [BUILT_IN_STYLES];
|
|
207
|
+
bakedStyles;
|
|
208
|
+
pluginNames = new Set();
|
|
209
|
+
constructor(options = {}) {
|
|
210
|
+
this.level = options.level ?? 'info';
|
|
211
|
+
this.defaultKind = options.defaultKind ?? 'default';
|
|
212
|
+
this.useStyles = options.useStyles ?? true;
|
|
213
|
+
this.clock = createClock(options.clock);
|
|
214
|
+
this.wallClock = options.clock === undefined || options.clock === 'wall';
|
|
215
|
+
this.defaultOutput = options.output ?? consoleOutput;
|
|
216
|
+
this.formatTimestamp = createTimestampFormatter(options.timestamp, this.clock.start);
|
|
217
|
+
this.bakedStyles = this.bake(this.styleSheets, 'Logger:');
|
|
218
|
+
if (options.plugins !== undefined)
|
|
219
|
+
for (const plugin of options.plugins)
|
|
220
|
+
this.register(plugin);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Registers a plugin: its styles, template maps, transformers, outputs,
|
|
224
|
+
* default kind and methods.
|
|
225
|
+
*
|
|
226
|
+
* @returns The same logger, typed with the plugin's methods. Methods the
|
|
227
|
+
* plugin re-declares replace the logger's signatures and docs.
|
|
228
|
+
* @throws Error if a plugin with the same name is already used or a plugin
|
|
229
|
+
* method would override an existing logger property.
|
|
230
|
+
*/
|
|
231
|
+
use(plugin) {
|
|
232
|
+
this.register(plugin);
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Checks if a plugin with a given name is used.
|
|
237
|
+
*/
|
|
238
|
+
hasPlugin(name) {
|
|
239
|
+
return this.pluginNames.has(name);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Registers a plugin atomically: everything is validated and prepared
|
|
243
|
+
* first, so a plugin that throws leaves the logger unchanged and can be
|
|
244
|
+
* fixed and used again.
|
|
245
|
+
*/
|
|
246
|
+
register(plugin) {
|
|
247
|
+
if (typeof plugin === 'function')
|
|
248
|
+
throw new TypeError(`Plugin "${plugin.name}" is a factory function. Call it: use(${plugin.name}()).`);
|
|
249
|
+
if (typeof plugin !== 'object' || plugin === null)
|
|
250
|
+
throw new TypeError(`Plugin is not an object, got ${typeName(plugin)}.`);
|
|
251
|
+
if (typeof plugin.name !== 'string')
|
|
252
|
+
throw new TypeError(`Plugin name is not a string, got ${typeName(plugin.name)}.`);
|
|
253
|
+
const what = `Plugin "${plugin.name}"`;
|
|
254
|
+
if (this.pluginNames.has(plugin.name))
|
|
255
|
+
throw new Error(`${what} is already used.`);
|
|
256
|
+
// 1. validate and prepare: nothing on the logger changes, anything throws
|
|
257
|
+
const { styles, templateMaps, transformers, outputs, defaultKind } = plugin;
|
|
258
|
+
const baked = styles === undefined ? undefined : (this.bake([...this.styleSheets, styles], what));
|
|
259
|
+
const templateMapEntries = templateMaps === undefined ? [] : Object.entries(templateMaps);
|
|
260
|
+
for (const [kind, map] of templateMapEntries)
|
|
261
|
+
assertTemplateMap(map, `${what} template map "${kind}"`);
|
|
262
|
+
const transformerList = transformers === undefined ? [] : [...transformers];
|
|
263
|
+
transformerList.forEach(({ transformer, position }, index) => {
|
|
264
|
+
assertFunction(transformer, `${what} transformer ${String(index)}`);
|
|
265
|
+
assertPosition(position, `${what} transformer ${String(index)}`);
|
|
266
|
+
});
|
|
267
|
+
const outputEntries = outputs === undefined ? [] : Object.entries(outputs);
|
|
268
|
+
for (const [kind, output] of outputEntries)
|
|
269
|
+
assertFunction(output, `${what} output "${kind}"`);
|
|
270
|
+
if (defaultKind !== undefined && typeof defaultKind !== 'string')
|
|
271
|
+
throw new TypeError(`${what} default kind is not a string, got ${typeName(defaultKind)}.`);
|
|
272
|
+
if (plugin.methods !== undefined)
|
|
273
|
+
assertFunction(plugin.methods, `${what} methods`);
|
|
274
|
+
const methods = readMethods(plugin.methods?.(this), this, what);
|
|
275
|
+
// 2. apply: assignments only, nothing throws
|
|
276
|
+
this.pluginNames.add(plugin.name);
|
|
277
|
+
if (styles !== undefined && baked !== undefined) {
|
|
278
|
+
this.styleSheets.push(styles);
|
|
279
|
+
this.bakedStyles = baked;
|
|
280
|
+
}
|
|
281
|
+
for (const [kind, map] of templateMapEntries)
|
|
282
|
+
this.mergeTemplateMap(kind, map);
|
|
283
|
+
for (const { transformer, position } of transformerList)
|
|
284
|
+
this.transformers.splice(position ?? this.transformers.length, 0, transformer);
|
|
285
|
+
for (const [kind, output] of outputEntries)
|
|
286
|
+
this.outputs[kind] = output;
|
|
287
|
+
if (defaultKind !== undefined)
|
|
288
|
+
this.defaultKind = defaultKind;
|
|
289
|
+
for (const [key, value] of methods)
|
|
290
|
+
this[key] = value;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Inserts transformer at a given position. Default: end of the pipeline.
|
|
294
|
+
*/
|
|
295
|
+
addTransformer(transformer, position = this.transformers.length) {
|
|
296
|
+
assertFunction(transformer, 'addTransformer: transformer');
|
|
297
|
+
assertPosition(position, 'addTransformer: transformer');
|
|
298
|
+
this.transformers.splice(position, 0, transformer);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Removes a transformer.
|
|
302
|
+
*
|
|
303
|
+
* @returns `true` if the transformer was found and removed.
|
|
304
|
+
*/
|
|
305
|
+
removeTransformer(transformer) {
|
|
306
|
+
const index = this.transformers.indexOf(transformer);
|
|
307
|
+
if (index === -1)
|
|
308
|
+
return false;
|
|
309
|
+
this.transformers.splice(index, 1);
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Replaces a transformer in place.
|
|
314
|
+
*
|
|
315
|
+
* @returns `true` if the old transformer was found and replaced.
|
|
316
|
+
*/
|
|
317
|
+
replaceTransformer(oldTransformer, transformer) {
|
|
318
|
+
assertFunction(transformer, 'replaceTransformer: transformer');
|
|
319
|
+
const index = this.transformers.indexOf(oldTransformer);
|
|
320
|
+
if (index === -1)
|
|
321
|
+
return false;
|
|
322
|
+
this.transformers[index] = transformer;
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Adds template functions for a given kind. Existing functions for the same
|
|
327
|
+
* property are replaced.
|
|
328
|
+
*
|
|
329
|
+
* Maps are stored without a prototype, so entry keys like `toString` or
|
|
330
|
+
* `hasOwnProperty`, or keys added to `Object.prototype` by other code, are
|
|
331
|
+
* never mistaken for template functions.
|
|
332
|
+
*/
|
|
333
|
+
addTemplateMap(kind, map) {
|
|
334
|
+
assertTemplateMap(map, `addTemplateMap: template map "${kind}"`);
|
|
335
|
+
this.mergeTemplateMap(kind, map);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Sets output for a given kind.
|
|
339
|
+
*/
|
|
340
|
+
setOutput(kind, output) {
|
|
341
|
+
assertFunction(output, `setOutput: output "${kind}"`);
|
|
342
|
+
this.outputs[kind] = output;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Output used for a given kind: the one set for it, or the default output.
|
|
346
|
+
* For plugins that wrap an output for a while and put it back later.
|
|
347
|
+
*/
|
|
348
|
+
getOutput(kind) {
|
|
349
|
+
return this.outputs[kind] ?? this.defaultOutput;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Adds styles and rebakes the escape code strings of all log types. Later
|
|
353
|
+
* style sheets override earlier ones.
|
|
354
|
+
*
|
|
355
|
+
* @throws TypeError if a style can't be converted to a string. The sheet is
|
|
356
|
+
* not added then, so the logger keeps working.
|
|
357
|
+
*/
|
|
358
|
+
addStyles(styleSheet) {
|
|
359
|
+
const baked = this.bake([...this.styleSheets, styleSheet], 'addStyles:');
|
|
360
|
+
this.styleSheets.push(styleSheet);
|
|
361
|
+
this.bakedStyles = baked;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Returns the baked styles of a given log type.
|
|
365
|
+
*/
|
|
366
|
+
getStyles(type) {
|
|
367
|
+
return this.bakedStyles[type];
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Minimum level to output. Checked when set, because levels often come
|
|
371
|
+
* from configuration or environment variables as plain strings: a typo
|
|
372
|
+
* like `'warn'` would otherwise silently turn off all logs.
|
|
373
|
+
*
|
|
374
|
+
* @throws RangeError if the level is unknown.
|
|
375
|
+
*/
|
|
376
|
+
get level() {
|
|
377
|
+
return this.currentLevel;
|
|
378
|
+
}
|
|
379
|
+
set level(level) {
|
|
380
|
+
assertLogLevel(level);
|
|
381
|
+
this.currentLevel = level;
|
|
382
|
+
this.threshold = LogLevels[level];
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Creates a log entry, transforms it and passes it to the output. Does
|
|
386
|
+
* nothing if the type does not pass the current level.
|
|
387
|
+
*
|
|
388
|
+
* @throws TypeError if the type is unknown, e.g. `'silent'` (a level, not a
|
|
389
|
+
* type) from untyped callers.
|
|
390
|
+
*
|
|
391
|
+
* @param type Log type.
|
|
392
|
+
* @param data Logged data.
|
|
393
|
+
* @param kind Log kind that selects template map and output.
|
|
394
|
+
* Default: `defaultKind`.
|
|
395
|
+
*/
|
|
396
|
+
log(type, data, kind = this.defaultKind) {
|
|
397
|
+
// also guards untyped callers: 'silent' or misspelled types throw, even
|
|
398
|
+
// when filtered, so a typo surfaces the first time the line runs
|
|
399
|
+
const value = LOG_TYPE_VALUES[type];
|
|
400
|
+
if (typeof value !== 'number')
|
|
401
|
+
throw unknownLogTypeError(type);
|
|
402
|
+
if (value > this.threshold)
|
|
403
|
+
return;
|
|
404
|
+
// read once: the formatted timestamp and outputs that need machine time
|
|
405
|
+
// (e.g. JSON) share it; not read at all without timestamps
|
|
406
|
+
let time;
|
|
407
|
+
let timeNs;
|
|
408
|
+
if (this.formatTimestamp !== undefined)
|
|
409
|
+
if (this.wallClock)
|
|
410
|
+
time = Date.now();
|
|
411
|
+
else {
|
|
412
|
+
const { now } = this;
|
|
413
|
+
this.clock.read(now);
|
|
414
|
+
time = now.time;
|
|
415
|
+
timeNs = now.timeNs;
|
|
416
|
+
}
|
|
417
|
+
const ctx = {
|
|
418
|
+
type,
|
|
419
|
+
kind,
|
|
420
|
+
time,
|
|
421
|
+
timeNs,
|
|
422
|
+
styles: this.bakedStyles[type],
|
|
423
|
+
templateMap: this.templateMaps[kind],
|
|
424
|
+
};
|
|
425
|
+
let entry = this.createEntry(type, data, kind, time, timeNs);
|
|
426
|
+
for (const transformer of this.transformers)
|
|
427
|
+
entry = transformer(entry, ctx);
|
|
428
|
+
(this.outputs[kind] ?? this.defaultOutput)(entry, ctx);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Logs a fatal error that leads to an immediate halt of all operations.
|
|
432
|
+
*
|
|
433
|
+
* Without plugins the output is the log entry object:
|
|
434
|
+
* `{ id, timestamp, type: 'fatal', kind, data }`.
|
|
435
|
+
*
|
|
436
|
+
* @param data Any value, stored as the entry's `data`.
|
|
437
|
+
* @param kind Log kind that selects the template map and output.
|
|
438
|
+
* Default: `defaultKind`.
|
|
439
|
+
*/
|
|
440
|
+
fatal(data, kind) {
|
|
441
|
+
this.log('fatal', data, kind);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Logs an error that might lead to a halt of the current operation.
|
|
445
|
+
*
|
|
446
|
+
* Without plugins the output is the log entry object:
|
|
447
|
+
* `{ id, timestamp, type: 'error', kind, data }`.
|
|
448
|
+
*
|
|
449
|
+
* @param data Any value, stored as the entry's `data`.
|
|
450
|
+
* @param kind Log kind that selects the template map and output.
|
|
451
|
+
* Default: `defaultKind`.
|
|
452
|
+
*/
|
|
453
|
+
error(data, kind) {
|
|
454
|
+
this.log('error', data, kind);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Logs a warning about something that might produce an unexpected result
|
|
458
|
+
* later in the execution.
|
|
459
|
+
*
|
|
460
|
+
* Without plugins the output is the log entry object:
|
|
461
|
+
* `{ id, timestamp, type: 'warning', kind, data }`.
|
|
462
|
+
*
|
|
463
|
+
* @param data Any value, stored as the entry's `data`.
|
|
464
|
+
* @param kind Log kind that selects the template map and output.
|
|
465
|
+
* Default: `defaultKind`.
|
|
466
|
+
*/
|
|
467
|
+
warning(data, kind) {
|
|
468
|
+
this.log('warning', data, kind);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Logs an important milestone of the execution flow, relevant in production.
|
|
472
|
+
*
|
|
473
|
+
* Without plugins the output is the log entry object:
|
|
474
|
+
* `{ id, timestamp, type: 'info', kind, data }`.
|
|
475
|
+
*
|
|
476
|
+
* @param data Any value, stored as the entry's `data`.
|
|
477
|
+
* @param kind Log kind that selects the template map and output.
|
|
478
|
+
* Default: `defaultKind`.
|
|
479
|
+
*/
|
|
480
|
+
info(data, kind) {
|
|
481
|
+
this.log('info', data, kind);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Logs information that helps to debug a problem.
|
|
485
|
+
*
|
|
486
|
+
* Without plugins the output is the log entry object:
|
|
487
|
+
* `{ id, timestamp, type: 'debug', kind, data }`.
|
|
488
|
+
*
|
|
489
|
+
* @param data Any value, stored as the entry's `data`.
|
|
490
|
+
* @param kind Log kind that selects the template map and output.
|
|
491
|
+
* Default: `defaultKind`.
|
|
492
|
+
*/
|
|
493
|
+
debug(data, kind) {
|
|
494
|
+
this.log('debug', data, kind);
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Logs an execution checkpoint, to narrow down the execution path.
|
|
498
|
+
*
|
|
499
|
+
* Without plugins the output is the log entry object:
|
|
500
|
+
* `{ id, timestamp, type: 'trace', kind, data }`.
|
|
501
|
+
*
|
|
502
|
+
* @param data Any value, stored as the entry's `data`.
|
|
503
|
+
* @param kind Log kind that selects the template map and output.
|
|
504
|
+
* Default: `defaultKind`.
|
|
505
|
+
*/
|
|
506
|
+
trace(data, kind) {
|
|
507
|
+
this.log('trace', data, kind);
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Logs information of importance during a close examination of the
|
|
511
|
+
* execution flow.
|
|
512
|
+
*
|
|
513
|
+
* Without plugins the output is the log entry object:
|
|
514
|
+
* `{ id, timestamp, type: 'verbose', kind, data }`.
|
|
515
|
+
*
|
|
516
|
+
* @param data Any value, stored as the entry's `data`.
|
|
517
|
+
* @param kind Log kind that selects the template map and output.
|
|
518
|
+
* Default: `defaultKind`.
|
|
519
|
+
*/
|
|
520
|
+
verbose(data, kind) {
|
|
521
|
+
this.log('verbose', data, kind);
|
|
522
|
+
}
|
|
523
|
+
createEntry(type, data, kind, time, timeNs) {
|
|
524
|
+
const id = this.nextId++;
|
|
525
|
+
if (this.formatTimestamp === undefined)
|
|
526
|
+
return { id, type, kind, data };
|
|
527
|
+
// set whenever timestamps are on
|
|
528
|
+
const timestamp = this.formatTimestamp(time, timeNs ?? 0);
|
|
529
|
+
return { id, timestamp, type, kind, data };
|
|
530
|
+
}
|
|
531
|
+
mergeTemplateMap(kind, map) {
|
|
532
|
+
this.templateMaps[kind] = Object.assign(Object.create(null), this.templateMaps[kind], map);
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Bakes style sheets to escape code strings per log type, without changing
|
|
536
|
+
* the logger. Styles are converted even when `useStyles` is off, so invalid
|
|
537
|
+
* ones always fail when added.
|
|
538
|
+
*
|
|
539
|
+
* @param what Prefix of error messages, e.g. `Plugin "theme"`.
|
|
540
|
+
* @throws TypeError if a style can't be converted to a string.
|
|
541
|
+
*/
|
|
542
|
+
bake(sheets, what) {
|
|
543
|
+
const compiled = sheets.map((sheet) => compileSheet(sheet, what));
|
|
544
|
+
const baked = {};
|
|
545
|
+
for (const type of LOG_TYPES) {
|
|
546
|
+
const styles = Object.create(null);
|
|
547
|
+
for (const sheet of compiled)
|
|
548
|
+
for (const groupName of ['*', type]) {
|
|
549
|
+
const group = sheet[groupName];
|
|
550
|
+
if (group !== undefined)
|
|
551
|
+
for (const [name, text] of group)
|
|
552
|
+
styles[name] = this.useStyles ? text : '';
|
|
553
|
+
}
|
|
554
|
+
baked[type] = Object.freeze(styles);
|
|
555
|
+
}
|
|
556
|
+
return baked;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Logger extensible by plugins. Plugins can be passed to the constructor or
|
|
561
|
+
* chained with `use`; both type the added methods:
|
|
562
|
+
*
|
|
563
|
+
* ```ts
|
|
564
|
+
* const logger = new Logger({ plugins: [messagePlugin(), graphPlugin()] });
|
|
565
|
+
* const same = new Logger().use(messagePlugin()).use(graphPlugin());
|
|
566
|
+
* logger.infoGraph([1, 2, 3]);
|
|
567
|
+
* ```
|
|
568
|
+
*/
|
|
569
|
+
const Logger = BaseLogger;
|
|
570
|
+
|
|
571
|
+
export { BaseLogger, Logger, templateTransformer };
|
|
572
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sources":["../../src/logger.ts"],"sourcesContent":["import {\n assertLogLevel,\n LOG_TYPE_VALUES,\n LOG_TYPES,\n LogLevels,\n unknownLogTypeError,\n} from './levels.js';\nimport { consoleOutput } from './outputs.js';\nimport { describeThrown } from './utils/text.js';\nimport type {\n BakedStyles,\n LogContext,\n LogEntry,\n LoggerOptions,\n LoggerPlugin,\n LogLevel,\n Override,\n PluginMethods,\n LogType,\n Output,\n StyleSheet,\n TemplateFn,\n TemplateMap,\n Clock,\n Transformer,\n} from './types.js';\nimport {\n compileTimestamp,\n DEFAULT_TIMESTAMP_FORMAT,\n type TimestampFormatter,\n} from './time.js';\n\n/**\n * Reads the time of a log: epoch milliseconds and, with the `'precise'`\n * clock, nanoseconds within the millisecond. Writes into `now`, so a log\n * allocates nothing for its time.\n */\ninterface ClockReader {\n read(now: { time: number; timeNs: number | undefined }): void;\n /** Time when the logger was created, the start of elapsed time. */\n readonly start: readonly [time: number, timeNs: number];\n}\n\nconst createClock = (clock: Clock | undefined): ClockReader => {\n if (clock === undefined || clock === 'wall')\n return {\n read: (now) => {\n now.time = Date.now();\n },\n start: [Date.now(), 0],\n };\n if (clock === 'precise') {\n // process.hrtime(anchor) gives the exact [seconds, nanoseconds] since\n // the anchor: ~90 ns, faster than hrtime.bigint() (~110-125 ns)\n const anchorTime = Date.now();\n const anchor = process.hrtime();\n return {\n read: (now) => {\n const [seconds, nanoseconds] = process.hrtime(anchor);\n now.time = anchorTime + seconds * 1000 + Math.floor(nanoseconds / 1e6);\n now.timeNs = nanoseconds % 1e6;\n },\n start: [anchorTime, 0],\n };\n }\n if (typeof clock === 'function') {\n const read = clock;\n return {\n read: (now) => {\n // the time of the log in whole milliseconds; finer clocks: 'precise'\n now.time = Math.floor(read());\n },\n start: [Math.floor(read()), 0],\n };\n }\n throw new TypeError(\n `Logger: clock must be 'wall', 'precise' or a function, got ${typeName(clock)}.`\n );\n};\n\n/**\n * Creates the timestamp formatter once, from a pattern, options or a\n * formatter function.\n */\nconst createTimestampFormatter = (\n options: LoggerOptions['timestamp'],\n start: readonly [number, number]\n): TimestampFormatter | undefined => {\n if (options === false) return undefined;\n if (options === undefined)\n return compileTimestamp(DEFAULT_TIMESTAMP_FORMAT, { start });\n if (typeof options === 'string') return compileTimestamp(options, { start });\n if (typeof options === 'function') return options;\n if (typeof options === 'object' && (options as unknown) !== null) {\n const { format = DEFAULT_TIMESTAMP_FORMAT, utc = false } = options;\n if (typeof format !== 'string')\n throw new TypeError(\n `Logger: timestamp.format must be a pattern string, got ${typeName(format)}.`\n );\n return compileTimestamp(format, { utc, start });\n }\n throw new TypeError(\n `Logger: timestamp must be a pattern, options, a function or false, got ${typeName(options)}.`\n );\n};\n\nconst typeName = (value: unknown): string =>\n value === null ? 'null'\n : Array.isArray(value) ? 'array'\n : typeof value;\n\n/**\n * Throws a `TypeError` naming `what` if the value is not a function. Shapes\n * are checked when plugins and pipeline steps are added, so mistakes surface\n * there and not on the first log.\n */\nconst assertFunction = (value: unknown, what: string): void => {\n if (typeof value !== 'function')\n throw new TypeError(`${what} is not a function, got ${typeName(value)}.`);\n};\n\nconst assertTemplateMap = (map: unknown, what: string): void => {\n if (typeof map !== 'object' || map === null)\n throw new TypeError(`${what} is not an object, got ${typeName(map)}.`);\n for (const key of Object.keys(map))\n assertFunction(\n (map as Record<string, unknown>)[key],\n `${what} template \"${key}\"`\n );\n};\n\nconst assertPosition = (position: unknown, what: string): void => {\n if (position !== undefined && !Number.isInteger(position))\n throw new TypeError(\n `${what} position is not an integer, got ${typeof position === 'number' ? String(position) : typeName(position)}.`\n );\n};\n\nconst describeKey = (key: PropertyKey): string =>\n typeof key === 'symbol' ? String(key) : `\"${String(key)}\"`;\n\n/**\n * Reads the methods a plugin adds, before anything is registered: own\n * enumerable string and symbol keys (what `Object.assign` copies), each read\n * once, so throwing getters fail here.\n *\n * @throws TypeError if `methods` is not a plain object: class instances would\n * lose their prototype methods.\n * @throws Error if a method would override an existing logger property.\n */\nconst readMethods = (\n methods: unknown,\n logger: object,\n what: string\n): [key: PropertyKey, value: unknown][] => {\n if (methods === undefined) return [];\n if (typeof methods !== 'object' || methods === null)\n throw new TypeError(\n `${what} methods must return an object, got ${typeName(methods)}.`\n );\n const proto: unknown = Object.getPrototypeOf(methods);\n // the prototype of a plain object, of any realm, is a root object\n if (proto !== null && Object.getPrototypeOf(proto) !== null) {\n const { name } = (proto as { constructor?: { name?: unknown } })\n .constructor ?? { name: undefined };\n throw new TypeError(\n `${what} methods must return a plain object, got ${typeof name === 'string' && name ? name : 'an instance'}. Prototype methods of class instances would not be added.`\n );\n }\n const entries: [PropertyKey, unknown][] = [];\n for (const key of Reflect.ownKeys(methods)) {\n if (!Object.prototype.propertyIsEnumerable.call(methods, key)) continue;\n if (key in logger)\n throw new Error(\n `${what} method ${describeKey(key)} overrides an existing logger property.`\n );\n entries.push([key, (methods as Record<PropertyKey, unknown>)[key]]);\n }\n return entries;\n};\n\n/**\n * Own style group of a sheet, ignoring inherited properties.\n */\nconst ownGroup = (\n sheet: StyleSheet,\n group: LogType | '*'\n): StyleSheet[LogType | '*'] =>\n Object.hasOwn(sheet, group) ? sheet[group] : undefined;\n\n/**\n * A style sheet with its styles converted to strings, per group.\n */\ntype CompiledSheet = Partial<\n Record<LogType | '*', readonly (readonly [name: string, text: string])[]>\n>;\n\n/**\n * Sheets converted once and shared between loggers: converting a\n * `style-escape-codes` chain takes about 65 ns, and the bundled plugins\n * share their default sheet. Sheets are read when they are added.\n */\nconst compiledSheets = new WeakMap<StyleSheet, CompiledSheet>();\n\n/**\n * Converts the own groups of a sheet to strings.\n *\n * @param what Prefix of error messages, e.g. `Plugin \"theme\"`.\n * @throws TypeError if a style can't be converted to a string.\n */\nconst compileSheet = (sheet: StyleSheet, what: string): CompiledSheet => {\n const cached = compiledSheets.get(sheet);\n if (cached !== undefined) return cached;\n // no prototype, like the baked styles: lookups never reach Object.prototype\n const compiled = Object.create(null) as CompiledSheet;\n for (const groupName of ['*', ...LOG_TYPES] as const) {\n // own groups only: inherited ones may come from prototype pollution\n const group = ownGroup(sheet, groupName);\n if (group === undefined) continue;\n compiled[groupName] = Object.entries(group).map(([name, style]) => {\n try {\n return [name, String(style)] as const;\n } catch (thrown) {\n throw new TypeError(\n `${what} style \"${groupName}.${name}\" can't be converted to an escape code string: ${describeThrown(thrown)}`,\n { cause: thrown }\n );\n }\n });\n }\n compiledSheets.set(sheet, compiled);\n return compiled;\n};\n\n/**\n * Style available to every log type without registering it.\n */\nconst BUILT_IN_STYLES: StyleSheet = { '*': { reset: '\\x1b[0m' } };\n\n/**\n * Passes each entry property through the template map of the entry's kind.\n * Properties without a template function stay unchanged. Part of every\n * logger's default transformers.\n */\nexport const templateTransformer: Transformer = (entry, ctx) => {\n const map = ctx.templateMap;\n if (map === undefined) return entry;\n for (const key in entry) {\n const template = map[key];\n if (template !== undefined) entry[key] = template(entry[key], ctx, key);\n }\n return entry;\n};\n\n/**\n * Logger implementation without plugin method typing. Use `Logger` instead,\n * which types the methods of plugins passed to the constructor.\n *\n * Every `log` call creates an entry with `id`, `timestamp`, `type`, `kind` and\n * `data`; runs it through `transformers` (which by default contains\n * `templateTransformer`) and hands the result to the output registered for the\n * entry's kind, or the default output.\n */\nexport class BaseLogger {\n /** Pipeline steps, executed in order for every log. */\n readonly transformers: Transformer[] = [templateTransformer];\n /** Template maps keyed by log kind. */\n readonly templateMaps: Record<string, TemplateMap> = Object.create(\n null\n ) as Record<string, TemplateMap>;\n\n /** Kind of logs created without an explicit kind. */\n defaultKind: string;\n\n private currentLevel!: LogLevel;\n /** Numeric value of `level`, compared on every log. */\n private threshold!: number;\n private nextId = 1;\n private readonly useStyles: boolean;\n private readonly clock: ClockReader;\n /** Default clock, read inline: no call through the reader. */\n private readonly wallClock: boolean;\n private readonly formatTimestamp: TimestampFormatter | undefined;\n /** Time of the current log, written by the clock: no allocation per log. */\n private readonly now: { time: number; timeNs: number | undefined } = {\n time: 0,\n timeNs: undefined,\n };\n private readonly defaultOutput: Output;\n private readonly outputs: Record<string, Output> = Object.create(\n null\n ) as Record<string, Output>;\n private readonly styleSheets: StyleSheet[] = [BUILT_IN_STYLES];\n private bakedStyles!: Record<LogType, BakedStyles>;\n private readonly pluginNames = new Set<string>();\n\n constructor(options: LoggerOptions = {}) {\n this.level = options.level ?? 'info';\n this.defaultKind = options.defaultKind ?? 'default';\n this.useStyles = options.useStyles ?? true;\n this.clock = createClock(options.clock);\n this.wallClock = options.clock === undefined || options.clock === 'wall';\n this.defaultOutput = options.output ?? consoleOutput;\n this.formatTimestamp = createTimestampFormatter(\n options.timestamp,\n this.clock.start\n );\n this.bakedStyles = this.bake(this.styleSheets, 'Logger:');\n if (options.plugins !== undefined)\n for (const plugin of options.plugins) this.register(plugin);\n }\n\n /**\n * Registers a plugin: its styles, template maps, transformers, outputs,\n * default kind and methods.\n *\n * @returns The same logger, typed with the plugin's methods. Methods the\n * plugin re-declares replace the logger's signatures and docs.\n * @throws Error if a plugin with the same name is already used or a plugin\n * method would override an existing logger property.\n */\n use<T extends object, M extends object>(\n this: T,\n plugin: LoggerPlugin<M>\n ): Override<T, M> {\n (this as unknown as BaseLogger).register(plugin);\n return this as unknown as Override<T, M>;\n }\n\n /**\n * Checks if a plugin with a given name is used.\n */\n hasPlugin(name: string): boolean {\n return this.pluginNames.has(name);\n }\n\n /**\n * Registers a plugin atomically: everything is validated and prepared\n * first, so a plugin that throws leaves the logger unchanged and can be\n * fixed and used again.\n */\n private register(plugin: LoggerPlugin): void {\n if (typeof plugin === 'function')\n throw new TypeError(\n `Plugin \"${(plugin as { name: string }).name}\" is a factory function. Call it: use(${(plugin as { name: string }).name}()).`\n );\n if (typeof plugin !== 'object' || (plugin as unknown) === null)\n throw new TypeError(`Plugin is not an object, got ${typeName(plugin)}.`);\n if (typeof plugin.name !== 'string')\n throw new TypeError(\n `Plugin name is not a string, got ${typeName(plugin.name)}.`\n );\n const what = `Plugin \"${plugin.name}\"`;\n if (this.pluginNames.has(plugin.name))\n throw new Error(`${what} is already used.`);\n\n // 1. validate and prepare: nothing on the logger changes, anything throws\n const { styles, templateMaps, transformers, outputs, defaultKind } = plugin;\n const baked =\n styles === undefined ? undefined : (\n this.bake([...this.styleSheets, styles], what)\n );\n const templateMapEntries =\n templateMaps === undefined ? [] : Object.entries(templateMaps);\n for (const [kind, map] of templateMapEntries)\n assertTemplateMap(map, `${what} template map \"${kind}\"`);\n const transformerList = transformers === undefined ? [] : [...transformers];\n transformerList.forEach(({ transformer, position }, index) => {\n assertFunction(transformer, `${what} transformer ${String(index)}`);\n assertPosition(position, `${what} transformer ${String(index)}`);\n });\n const outputEntries = outputs === undefined ? [] : Object.entries(outputs);\n for (const [kind, output] of outputEntries)\n assertFunction(output, `${what} output \"${kind}\"`);\n if (defaultKind !== undefined && typeof defaultKind !== 'string')\n throw new TypeError(\n `${what} default kind is not a string, got ${typeName(defaultKind)}.`\n );\n if (plugin.methods !== undefined)\n assertFunction(plugin.methods, `${what} methods`);\n const methods = readMethods(plugin.methods?.(this), this, what);\n\n // 2. apply: assignments only, nothing throws\n this.pluginNames.add(plugin.name);\n if (styles !== undefined && baked !== undefined) {\n this.styleSheets.push(styles);\n this.bakedStyles = baked;\n }\n for (const [kind, map] of templateMapEntries)\n this.mergeTemplateMap(kind, map);\n for (const { transformer, position } of transformerList)\n this.transformers.splice(\n position ?? this.transformers.length,\n 0,\n transformer\n );\n for (const [kind, output] of outputEntries) this.outputs[kind] = output;\n if (defaultKind !== undefined) this.defaultKind = defaultKind;\n for (const [key, value] of methods)\n (this as unknown as Record<PropertyKey, unknown>)[key] = value;\n }\n\n /**\n * Inserts transformer at a given position. Default: end of the pipeline.\n */\n addTransformer(\n transformer: Transformer,\n position: number = this.transformers.length\n ): void {\n assertFunction(transformer, 'addTransformer: transformer');\n assertPosition(position, 'addTransformer: transformer');\n this.transformers.splice(position, 0, transformer);\n }\n\n /**\n * Removes a transformer.\n *\n * @returns `true` if the transformer was found and removed.\n */\n removeTransformer(transformer: Transformer): boolean {\n const index = this.transformers.indexOf(transformer);\n if (index === -1) return false;\n this.transformers.splice(index, 1);\n return true;\n }\n\n /**\n * Replaces a transformer in place.\n *\n * @returns `true` if the old transformer was found and replaced.\n */\n replaceTransformer(oldTransformer: Transformer, transformer: Transformer) {\n assertFunction(transformer, 'replaceTransformer: transformer');\n const index = this.transformers.indexOf(oldTransformer);\n if (index === -1) return false;\n this.transformers[index] = transformer;\n return true;\n }\n\n /**\n * Adds template functions for a given kind. Existing functions for the same\n * property are replaced.\n *\n * Maps are stored without a prototype, so entry keys like `toString` or\n * `hasOwnProperty`, or keys added to `Object.prototype` by other code, are\n * never mistaken for template functions.\n */\n addTemplateMap(kind: string, map: TemplateMap): void {\n assertTemplateMap(map, `addTemplateMap: template map \"${kind}\"`);\n this.mergeTemplateMap(kind, map);\n }\n\n /**\n * Sets output for a given kind.\n */\n setOutput(kind: string, output: Output): void {\n assertFunction(output, `setOutput: output \"${kind}\"`);\n this.outputs[kind] = output;\n }\n\n /**\n * Output used for a given kind: the one set for it, or the default output.\n * For plugins that wrap an output for a while and put it back later.\n */\n getOutput(kind: string): Output {\n return this.outputs[kind] ?? this.defaultOutput;\n }\n\n /**\n * Adds styles and rebakes the escape code strings of all log types. Later\n * style sheets override earlier ones.\n *\n * @throws TypeError if a style can't be converted to a string. The sheet is\n * not added then, so the logger keeps working.\n */\n addStyles(styleSheet: StyleSheet): void {\n const baked = this.bake([...this.styleSheets, styleSheet], 'addStyles:');\n this.styleSheets.push(styleSheet);\n this.bakedStyles = baked;\n }\n\n /**\n * Returns the baked styles of a given log type.\n */\n getStyles(type: LogType): BakedStyles {\n return this.bakedStyles[type];\n }\n\n /**\n * Minimum level to output. Checked when set, because levels often come\n * from configuration or environment variables as plain strings: a typo\n * like `'warn'` would otherwise silently turn off all logs.\n *\n * @throws RangeError if the level is unknown.\n */\n get level(): LogLevel {\n return this.currentLevel;\n }\n\n set level(level: LogLevel) {\n assertLogLevel(level);\n this.currentLevel = level;\n this.threshold = LogLevels[level];\n }\n\n /**\n * Creates a log entry, transforms it and passes it to the output. Does\n * nothing if the type does not pass the current level.\n *\n * @throws TypeError if the type is unknown, e.g. `'silent'` (a level, not a\n * type) from untyped callers.\n *\n * @param type Log type.\n * @param data Logged data.\n * @param kind Log kind that selects template map and output.\n * Default: `defaultKind`.\n */\n log(type: LogType, data: unknown, kind = this.defaultKind): void {\n // also guards untyped callers: 'silent' or misspelled types throw, even\n // when filtered, so a typo surfaces the first time the line runs\n const value = LOG_TYPE_VALUES[type];\n if (typeof value !== 'number') throw unknownLogTypeError(type);\n if (value > this.threshold) return;\n\n // read once: the formatted timestamp and outputs that need machine time\n // (e.g. JSON) share it; not read at all without timestamps\n let time: number | undefined;\n let timeNs: number | undefined;\n if (this.formatTimestamp !== undefined)\n if (this.wallClock) time = Date.now();\n else {\n const { now } = this;\n this.clock.read(now);\n time = now.time;\n timeNs = now.timeNs;\n }\n const ctx: LogContext = {\n type,\n kind,\n time,\n timeNs,\n styles: this.bakedStyles[type],\n templateMap: this.templateMaps[kind],\n };\n\n let entry = this.createEntry(type, data, kind, time, timeNs);\n for (const transformer of this.transformers)\n entry = transformer(entry, ctx);\n\n (this.outputs[kind] ?? this.defaultOutput)(entry, ctx);\n }\n\n /**\n * Logs a fatal error that leads to an immediate halt of all operations.\n *\n * Without plugins the output is the log entry object:\n * `{ id, timestamp, type: 'fatal', kind, data }`.\n *\n * @param data Any value, stored as the entry's `data`.\n * @param kind Log kind that selects the template map and output.\n * Default: `defaultKind`.\n */\n fatal(data: unknown, kind?: string): void {\n this.log('fatal', data, kind);\n }\n\n /**\n * Logs an error that might lead to a halt of the current operation.\n *\n * Without plugins the output is the log entry object:\n * `{ id, timestamp, type: 'error', kind, data }`.\n *\n * @param data Any value, stored as the entry's `data`.\n * @param kind Log kind that selects the template map and output.\n * Default: `defaultKind`.\n */\n error(data: unknown, kind?: string): void {\n this.log('error', data, kind);\n }\n\n /**\n * Logs a warning about something that might produce an unexpected result\n * later in the execution.\n *\n * Without plugins the output is the log entry object:\n * `{ id, timestamp, type: 'warning', kind, data }`.\n *\n * @param data Any value, stored as the entry's `data`.\n * @param kind Log kind that selects the template map and output.\n * Default: `defaultKind`.\n */\n warning(data: unknown, kind?: string): void {\n this.log('warning', data, kind);\n }\n\n /**\n * Logs an important milestone of the execution flow, relevant in production.\n *\n * Without plugins the output is the log entry object:\n * `{ id, timestamp, type: 'info', kind, data }`.\n *\n * @param data Any value, stored as the entry's `data`.\n * @param kind Log kind that selects the template map and output.\n * Default: `defaultKind`.\n */\n info(data: unknown, kind?: string): void {\n this.log('info', data, kind);\n }\n\n /**\n * Logs information that helps to debug a problem.\n *\n * Without plugins the output is the log entry object:\n * `{ id, timestamp, type: 'debug', kind, data }`.\n *\n * @param data Any value, stored as the entry's `data`.\n * @param kind Log kind that selects the template map and output.\n * Default: `defaultKind`.\n */\n debug(data: unknown, kind?: string): void {\n this.log('debug', data, kind);\n }\n\n /**\n * Logs an execution checkpoint, to narrow down the execution path.\n *\n * Without plugins the output is the log entry object:\n * `{ id, timestamp, type: 'trace', kind, data }`.\n *\n * @param data Any value, stored as the entry's `data`.\n * @param kind Log kind that selects the template map and output.\n * Default: `defaultKind`.\n */\n trace(data: unknown, kind?: string): void {\n this.log('trace', data, kind);\n }\n\n /**\n * Logs information of importance during a close examination of the\n * execution flow.\n *\n * Without plugins the output is the log entry object:\n * `{ id, timestamp, type: 'verbose', kind, data }`.\n *\n * @param data Any value, stored as the entry's `data`.\n * @param kind Log kind that selects the template map and output.\n * Default: `defaultKind`.\n */\n verbose(data: unknown, kind?: string): void {\n this.log('verbose', data, kind);\n }\n\n private createEntry(\n type: LogType,\n data: unknown,\n kind: string,\n time: number | undefined,\n timeNs: number | undefined\n ): LogEntry {\n const id = this.nextId++;\n if (this.formatTimestamp === undefined) return { id, type, kind, data };\n // set whenever timestamps are on\n const timestamp = this.formatTimestamp(time as number, timeNs ?? 0);\n return { id, timestamp, type, kind, data };\n }\n\n private mergeTemplateMap(kind: string, map: TemplateMap): void {\n this.templateMaps[kind] = Object.assign(\n Object.create(null) as Record<string, TemplateFn>,\n this.templateMaps[kind],\n map\n );\n }\n\n /**\n * Bakes style sheets to escape code strings per log type, without changing\n * the logger. Styles are converted even when `useStyles` is off, so invalid\n * ones always fail when added.\n *\n * @param what Prefix of error messages, e.g. `Plugin \"theme\"`.\n * @throws TypeError if a style can't be converted to a string.\n */\n private bake(\n sheets: readonly StyleSheet[],\n what: string\n ): Record<LogType, BakedStyles> {\n const compiled = sheets.map((sheet) => compileSheet(sheet, what));\n const baked = {} as Record<LogType, BakedStyles>;\n for (const type of LOG_TYPES) {\n const styles: Record<string, string> = Object.create(null) as Record<\n string,\n string\n >;\n for (const sheet of compiled)\n for (const groupName of ['*', type] as const) {\n const group = sheet[groupName];\n if (group !== undefined)\n for (const [name, text] of group)\n styles[name] = this.useStyles ? text : '';\n }\n baked[type] = Object.freeze(styles);\n }\n return baked;\n }\n}\n\n/**\n * Logger with the methods of its plugins. Plugin methods with the same name as\n * logger methods replace their signatures and docs.\n *\n * @template M Methods added or re-declared by plugins.\n */\nexport type Logger<M = unknown> = Override<BaseLogger, M>;\n\nexport interface LoggerConstructor {\n /**\n * Creates a logger. Plugins passed in `options.plugins` are used in order\n * and their methods are added to the logger's type.\n */\n new <const P extends readonly LoggerPlugin[] = []>(\n options?: LoggerOptions<P>\n ): Logger<PluginMethods<P>>;\n readonly prototype: BaseLogger;\n}\n\n/**\n * Logger extensible by plugins. Plugins can be passed to the constructor or\n * chained with `use`; both type the added methods:\n *\n * ```ts\n * const logger = new Logger({ plugins: [messagePlugin(), graphPlugin()] });\n * const same = new Logger().use(messagePlugin()).use(graphPlugin());\n * logger.infoGraph([1, 2, 3]);\n * ```\n */\nexport const Logger = BaseLogger as LoggerConstructor;\n"],"names":[],"mappings":"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"}
|