@matter/general 0.13.0-alpha.0-20250322-f085fa576 → 0.13.0-alpha.0-20250324-d7b7d9731

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/cjs/log/Console.d.ts +21 -0
  2. package/dist/cjs/log/Console.d.ts.map +1 -0
  3. package/dist/cjs/log/Console.js +58 -0
  4. package/dist/cjs/log/Console.js.map +6 -0
  5. package/dist/cjs/log/Diagnostic.d.ts +6 -0
  6. package/dist/cjs/log/Diagnostic.d.ts.map +1 -1
  7. package/dist/cjs/log/Diagnostic.js +16 -0
  8. package/dist/cjs/log/Diagnostic.js.map +1 -1
  9. package/dist/cjs/log/LogDestination.d.ts +67 -0
  10. package/dist/cjs/log/LogDestination.d.ts.map +1 -0
  11. package/dist/cjs/log/LogDestination.js +65 -0
  12. package/dist/cjs/log/LogDestination.js.map +6 -0
  13. package/dist/cjs/log/LogFormat.d.ts +18 -12
  14. package/dist/cjs/log/LogFormat.d.ts.map +1 -1
  15. package/dist/cjs/log/LogFormat.js +17 -24
  16. package/dist/cjs/log/LogFormat.js.map +1 -1
  17. package/dist/cjs/log/LogLevel.d.ts +19 -9
  18. package/dist/cjs/log/LogLevel.d.ts.map +1 -1
  19. package/dist/cjs/log/LogLevel.js +40 -25
  20. package/dist/cjs/log/LogLevel.js.map +1 -1
  21. package/dist/cjs/log/Logger.d.ts +157 -106
  22. package/dist/cjs/log/Logger.d.ts.map +1 -1
  23. package/dist/cjs/log/Logger.js +298 -256
  24. package/dist/cjs/log/Logger.js.map +2 -2
  25. package/dist/cjs/log/index.d.ts +1 -0
  26. package/dist/cjs/log/index.d.ts.map +1 -1
  27. package/dist/cjs/log/index.js +1 -0
  28. package/dist/cjs/log/index.js.map +1 -1
  29. package/dist/cjs/transaction/Transaction.d.ts +19 -19
  30. package/dist/esm/log/Console.d.ts +21 -0
  31. package/dist/esm/log/Console.d.ts.map +1 -0
  32. package/dist/esm/log/Console.js +38 -0
  33. package/dist/esm/log/Console.js.map +6 -0
  34. package/dist/esm/log/Diagnostic.d.ts +6 -0
  35. package/dist/esm/log/Diagnostic.d.ts.map +1 -1
  36. package/dist/esm/log/Diagnostic.js +16 -0
  37. package/dist/esm/log/Diagnostic.js.map +1 -1
  38. package/dist/esm/log/LogDestination.d.ts +67 -0
  39. package/dist/esm/log/LogDestination.d.ts.map +1 -0
  40. package/dist/esm/log/LogDestination.js +45 -0
  41. package/dist/esm/log/LogDestination.js.map +6 -0
  42. package/dist/esm/log/LogFormat.d.ts +18 -12
  43. package/dist/esm/log/LogFormat.d.ts.map +1 -1
  44. package/dist/esm/log/LogFormat.js +17 -24
  45. package/dist/esm/log/LogFormat.js.map +1 -1
  46. package/dist/esm/log/LogLevel.d.ts +19 -9
  47. package/dist/esm/log/LogLevel.d.ts.map +1 -1
  48. package/dist/esm/log/LogLevel.js +40 -25
  49. package/dist/esm/log/LogLevel.js.map +1 -1
  50. package/dist/esm/log/Logger.d.ts +157 -106
  51. package/dist/esm/log/Logger.d.ts.map +1 -1
  52. package/dist/esm/log/Logger.js +298 -256
  53. package/dist/esm/log/Logger.js.map +2 -2
  54. package/dist/esm/log/index.d.ts +1 -0
  55. package/dist/esm/log/index.d.ts.map +1 -1
  56. package/dist/esm/log/index.js +1 -0
  57. package/dist/esm/log/index.js.map +1 -1
  58. package/dist/esm/transaction/Transaction.d.ts +19 -19
  59. package/package.json +2 -2
  60. package/src/log/Console.ts +52 -0
  61. package/src/log/Diagnostic.ts +21 -0
  62. package/src/log/LogDestination.ts +113 -0
  63. package/src/log/LogFormat.ts +39 -36
  64. package/src/log/LogLevel.ts +55 -25
  65. package/src/log/Logger.ts +379 -314
  66. package/src/log/index.ts +1 -0
package/src/log/Logger.ts CHANGED
@@ -10,97 +10,264 @@ import { ImplementationError, NotImplementedError } from "../MatterError.js";
10
10
  import { Time } from "../time/Time.js";
11
11
  import { Bytes } from "../util/Bytes.js";
12
12
  import { Diagnostic } from "./Diagnostic.js";
13
+ import { LogDestination, LogDestinations } from "./LogDestination.js";
13
14
  import { LogFormat } from "./LogFormat.js";
14
15
  import { LogLevel } from "./LogLevel.js";
15
16
 
16
17
  /**
17
- * Log messages to the console. This is the default logging mechanism.
18
- */
19
- export function consoleLogger(level: LogLevel, formattedLog: string, _facility?: string) {
20
- const console = (<any>consoleLogger).console;
21
- switch (level) {
22
- case LogLevel.DEBUG:
23
- console.debug(formattedLog);
24
- break;
25
- case LogLevel.INFO:
26
- console.info(formattedLog);
27
- break;
28
- case LogLevel.NOTICE:
29
- console.info(formattedLog);
30
- break;
31
- case LogLevel.WARN:
32
- console.warn(formattedLog);
33
- break;
34
- case LogLevel.ERROR:
35
- console.error(formattedLog);
36
- break;
37
- case LogLevel.FATAL:
38
- console.error(formattedLog);
39
- break;
40
- }
41
- }
42
-
43
- const globalConsole = console;
44
- export namespace consoleLogger {
45
- /**
46
- * The target for consoleLogger.
47
- */
48
- // eslint-disable-next-line prefer-const
49
- export let console = globalConsole;
50
- }
51
-
52
- /**
53
- * Create a log formatter for a given format.
54
- */
55
- function logFormatterFor(formatName: string): LoggerDefinition["logFormatter"] {
56
- const format = LogFormat(formatName);
57
-
58
- return (now, level, facility, prefix, ...values) =>
59
- format(Diagnostic.message({ now, level, facility, prefix, values }));
60
- }
61
-
62
- /**
63
- * Definition of one registered Logger.
64
- */
65
- type LoggerDefinition = {
66
- logIdentifier: string;
67
- logFormatter: (now: Date, level: LogLevel, facility: string, prefix: string, ...values: any[]) => string;
68
- log: (level: LogLevel, formattedLog: string, facility?: string) => void;
69
- defaultLogLevel: LogLevel;
70
- logLevels: { [facility: string]: LogLevel };
71
- context?: Diagnostic.Context;
72
- };
73
-
74
- /**
75
- * Logger that can be used to emit traces.
76
- *
77
- * The class supports adding multiple loggers for different targets. A default logger (identifier "default") is added on
78
- * startup which logs to "console".
18
+ * matter.js logging API
79
19
  *
80
20
  * Usage:
81
21
  *
82
- * const facility = Logger.get("loggerName");
83
- * facility.debug("My debug message", "my extra value to log");
22
+ * const logger = Logger.get("loggerName");
23
+ * logger.debug("My debug message", "my extra value to log");
84
24
  *
85
- * The configuration of the default logger can be adjusted by using the static properties of the Logger class:
25
+ * matter.js writes logs to each {@link LogDestination} in {@link Logger.destinations}. By default a single destination
26
+ * named "default" writes to the JS console.
86
27
  *
87
- * - Logger.defaultLogLevel sets the default log level for all the facility
88
- * - Logger.logLevels = { loggerName: Level.DEBUG } can set the level for the specific loggers
89
- * - Logger.format = Format.ANSI enables colorization via ANSI escape sequences in default formatter
28
+ * You may adjust log verbosity and format by modifying the properties on destinations. For example:
90
29
  *
91
- * For additional loggers, use Logger.addLogger() to add a new logger with a specific identifier. Afterwards the
92
- * configuration of these can be adjusted using static methods with the identifier as first parameter:
93
- *
94
- * - Logger.setFormatForLogger("loggerName", Format.ANSI)
95
- * - Logger.setLogLevelsForLogger("loggerName", { loggerName: Level.DEBUG })
96
- * - Logger.setDefaultLoglevelForLogger("loggerName", Level.DEBUG)
30
+ * `Logger.format = LogFormat.PLAIN` sets all destinations to write plaintext
31
+ * `Logger.destinations.default.format = LogFormat.format.ansi` sets one destination to write ANSI
32
+ * `Logger.level = LogLevel.NOTICE` sets "notice" as the minimum level for all destinations
33
+ * `Logger.destinations.default.level = LogLevel.NOTICE` sets "notice" as level for one destination
97
34
  */
98
35
  export class Logger {
99
- static logger: Array<LoggerDefinition>;
36
+ /**
37
+ * Log destinations.
38
+ *
39
+ * By default there is a single destination named "default". You can create new destinations using
40
+ * {@link LogDestination}. Add or remove destinations by modifying this object.
41
+ *
42
+ * Throws an error if you access a destination that doesn't exist.
43
+ */
44
+ static destinations = LogDestinations();
45
+
46
+ /**
47
+ * The number of indents to print with messages.
48
+ */
100
49
  static nestingLevel: number;
50
+
101
51
  readonly #name: string;
102
52
 
103
- /** Add additional logger to the list of loggers including the default configuration. */
53
+ /**
54
+ * Create a new logger for a facility.
55
+ *
56
+ * @param name the name of the facility
57
+ * @returns a new facility
58
+ */
59
+ static get(name: string) {
60
+ return new Logger(name);
61
+ }
62
+
63
+ /**
64
+ * Get the default log level.
65
+ */
66
+ static get level() {
67
+ return LogDestination.defaults.level;
68
+ }
69
+
70
+ /**
71
+ * Set log level as name or number for all destinations.
72
+ */
73
+ static set level(level: LogLevel | string) {
74
+ level = LogLevel(level);
75
+
76
+ LogDestination.defaults.level = level;
77
+
78
+ for (const name in this.destinations) {
79
+ this.destinations[name].level = level;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Get the default facility levels.
85
+ */
86
+ static get facilityLevels() {
87
+ return LogDestination.defaults.facilityLevels;
88
+ }
89
+
90
+ /**
91
+ * Set log level as name or number for facilities in all destinations.
92
+ *
93
+ * Existing levels that are not named in {@link levels} will remain unchanged.
94
+ */
95
+ static set facilityLevels(levels: Record<string, LogLevel | string>) {
96
+ for (const name in levels) {
97
+ levels[name] = LogLevel(levels[name]);
98
+ }
99
+
100
+ Object.assign(LogDestination.defaults.facilityLevels, levels);
101
+
102
+ for (const name in this.destinations) {
103
+ Object.assign(this.destinations[name].facilityLevels, levels);
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Get the default format name.
109
+ */
110
+ static get format(): string {
111
+ return LogDestination.defaults.format.name;
112
+ }
113
+
114
+ /**
115
+ * Set the format for all destinations.
116
+ */
117
+ static set format(format: string | LogFormat.Formatter) {
118
+ format = LogFormat(format);
119
+
120
+ LogDestination.defaults.format = format;
121
+
122
+ for (const name in this.destinations) {
123
+ this.destinations[name].format = format;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Mask a string with a given character. If unmaskedLength is provided then these number of characters will be
129
+ * shown unmasked.
130
+ *
131
+ * @param str String to mask
132
+ * @param maskChar character to mask with
133
+ * @param unmaskedLength number of characters to show unmasked in the beginning
134
+ */
135
+ static maskString(str: string, maskChar = "*", unmaskedLength?: number) {
136
+ return str.substring(0, unmaskedLength ?? 0) + str.substring(unmaskedLength ?? 0).replace(/./g, maskChar);
137
+ }
138
+
139
+ /**
140
+ * Perform operations in a nested logging context. Messages will be
141
+ * indented while the context executes.
142
+ */
143
+ static nest<T>(context: () => T): T {
144
+ this.nestingLevel++;
145
+ try {
146
+ return context();
147
+ } finally {
148
+ this.nestingLevel--;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Async version of nest().
154
+ */
155
+ static async nestAsync(context: () => Promise<any>) {
156
+ this.nestingLevel++;
157
+ try {
158
+ return await context();
159
+ } finally {
160
+ this.nestingLevel--;
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Unhandled error reporter.
166
+ *
167
+ * Some environments do not report full error details such as {@link Error#cause} and {@link AggregateError#errors}.
168
+ *
169
+ * To ensure these details are always recorded somewhere, unhandled errors may be reported here.
170
+ *
171
+ * To disable this behavior replace this function.
172
+ */
173
+ static reportUnhandledError(error: Error) {
174
+ try {
175
+ Logger.get("Logger").fatal("Unhandled error detected:", error);
176
+ } catch (e) {
177
+ // We do not want to cause yet another error so if logging fails for any reason it goes unreported
178
+ }
179
+ }
180
+
181
+ constructor(name: string) {
182
+ this.#name = name;
183
+ }
184
+
185
+ debug(...values: unknown[]) {
186
+ this.#log(LogLevel.DEBUG, values);
187
+ }
188
+
189
+ info(...values: unknown[]) {
190
+ this.#log(LogLevel.INFO, values);
191
+ }
192
+
193
+ notice(...values: unknown[]) {
194
+ this.#log(LogLevel.NOTICE, values);
195
+ }
196
+
197
+ warn(...values: unknown[]) {
198
+ this.#log(LogLevel.WARN, values);
199
+ }
200
+
201
+ error(...values: unknown[]) {
202
+ this.#log(LogLevel.ERROR, values);
203
+ }
204
+
205
+ fatal(...values: unknown[]) {
206
+ this.#log(LogLevel.FATAL, values);
207
+ }
208
+
209
+ log(level: LogLevel, ...values: unknown[]) {
210
+ this.#log(level, values);
211
+ }
212
+
213
+ #log(level: LogLevel, values: unknown[]) {
214
+ for (const name in Logger.destinations) {
215
+ const dest = Logger.destinations[name];
216
+
217
+ if (level < (dest.facilityLevels?.[this.#name] ?? dest.level)) {
218
+ return;
219
+ }
220
+
221
+ if (!dest.context) {
222
+ dest.context = Diagnostic.Context();
223
+ }
224
+
225
+ dest.context.run(() =>
226
+ dest.add(
227
+ Diagnostic.message({
228
+ now: Time.now(),
229
+ facility: this.#name,
230
+ level,
231
+ prefix: nestingPrefix(),
232
+ values,
233
+ }),
234
+ ),
235
+ );
236
+ }
237
+ }
238
+
239
+ //
240
+ // DEPRECATED API SURFACE FOLLOWS
241
+ //
242
+
243
+ /**
244
+ * Stringify a value (BigInt aware) as JSON.
245
+ *
246
+ * @param data the value to stringify
247
+ * @returns the stringified value
248
+ *
249
+ * @deprecated use {@link Diagnostic.json}
250
+ */
251
+ static toJSON(data: any) {
252
+ return JSON.stringify(data, (_, value) => {
253
+ if (typeof value === "bigint") {
254
+ return value.toString();
255
+ }
256
+ if (value instanceof Uint8Array) {
257
+ return Bytes.toHex(value);
258
+ }
259
+ if (value === undefined) {
260
+ return "undefined";
261
+ }
262
+ return value;
263
+ });
264
+ }
265
+
266
+ /**
267
+ * Add additional logger to the list of loggers including the default configuration.
268
+ *
269
+ * @deprecated use {@link destinations}
270
+ */
104
271
  public static addLogger(
105
272
  identifier: string,
106
273
  logger: (level: LogLevel, formattedLog: string) => void,
@@ -110,87 +277,70 @@ export class Logger {
110
277
  logFormat?: string;
111
278
  },
112
279
  ) {
113
- if (Logger.logger.some(logger => logger.logIdentifier === identifier)) {
114
- throw new NotImplementedError(`Logger "${identifier}" already exists`);
280
+ if (identifier in this.destinations) {
281
+ throw new ImplementationError(`Logger "${identifier}" already exists`);
115
282
  }
116
- Logger.logger.push({
117
- logIdentifier: identifier,
118
- logFormatter: logFormatterFor(options?.logFormat ?? LogFormat.PLAIN),
119
- log: logger,
120
- defaultLogLevel: options?.defaultLogLevel ?? LogLevel.DEBUG,
121
- logLevels: options?.logLevels ?? {},
122
- });
283
+ const dest = LogDestination({ name: identifier });
284
+ const legacy = adaptDestinationToLegacy(dest);
285
+ legacy.log = logger;
286
+ if (options?.defaultLogLevel !== undefined) {
287
+ legacy.defaultLogLevel = options.defaultLogLevel;
288
+ }
289
+ if (options?.logLevels !== undefined) {
290
+ legacy.logLevels = options.logLevels;
291
+ }
292
+ if (options?.logFormat !== undefined) {
293
+ legacy.logFormatter = logFormatterFor(options.logFormat);
294
+ }
295
+ this.destinations[identifier] = dest;
123
296
  }
124
297
 
298
+ /**
299
+ * @deprecated use {@link destinations}
300
+ */
125
301
  public static removeLogger(identifier: string) {
126
- const index = Logger.logger.findIndex(logger => logger.logIdentifier === identifier);
127
- if (index === -1) {
302
+ if (!(identifier in this.destinations)) {
128
303
  throw new NotImplementedError(`Logger "${identifier}" does not exist`);
129
304
  }
130
- Logger.logger.splice(index, 1);
305
+ delete this.destinations[identifier];
131
306
  }
132
307
 
133
308
  /**
134
309
  * Check if a logger with the matching identifier exists.
135
310
  * @param identifier The identifier of the logger
311
+ *
312
+ * @deprecated use {@link destinations}
136
313
  */
137
314
  public static hasLoggerForIdentifier(identifier: string) {
138
- return Logger.logger.some(logger => logger.logIdentifier === identifier);
315
+ return identifier in this.destinations;
139
316
  }
140
317
 
141
318
  /**
142
319
  * Get the logger with the matching identifier.
143
320
  * @param identifier The identifier of the logger
321
+ *
322
+ * @deprecated use {@link destinations}
144
323
  */
145
324
  public static getLoggerForIdentifier(identifier: string) {
146
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
147
- if (logger === undefined) {
325
+ const dest = this.destinations[identifier];
326
+ if (dest === undefined) {
148
327
  throw new NotImplementedError(`Unknown logger "${identifier}"`);
149
328
  }
150
- return logger;
329
+ return adaptDestinationToLegacy(dest);
151
330
  }
152
331
 
153
332
  /**
154
- * Set log level using configuration-style level name for the default logger.
333
+ * @deprecated use {@link destinations}
155
334
  */
156
- static set level(level: number | string) {
157
- if (level === undefined) {
158
- level = LogLevel.DEBUG;
159
- }
160
-
161
- let levelNum;
162
- if (typeof level === "string") {
163
- if (level.match(/^\d+$/)) {
164
- levelNum = Number.parseInt(level);
165
- } else {
166
- levelNum = (LogLevel as unknown as Record<string, number | undefined>)[level.toUpperCase()];
167
- if (levelNum === undefined) {
168
- throw new ImplementationError(`Unsupported log level "${level}"`);
169
- }
170
- }
171
- } else {
172
- levelNum = level;
173
- }
174
-
175
- if (LogLevel[levelNum] === undefined) {
176
- throw new ImplementationError(`Unsupported log level "${level}"`);
177
- }
178
-
179
- Logger.defaultLogLevel = levelNum;
180
- }
181
-
182
- /**
183
- * Set logFormatter using configuration-style format name.
184
- *
185
- * @param format the name of the formatter (see Format enum)
186
- */
187
- static set format(format: string) {
188
- Logger.setLogFormatterForLogger("default", logFormatterFor(format));
335
+ public static getLoggerforIdentifier(identifier: string) {
336
+ return this.getLoggerForIdentifier(identifier);
189
337
  }
190
338
 
191
339
  /**
192
340
  * Set facility loglevels for the default logger.
193
341
  * @param levels The levels to set
342
+ *
343
+ * @deprecated use {@link destinations}
194
344
  */
195
345
  public static set logLevels(levels: { [facility: string]: LogLevel }) {
196
346
  Logger.setLogLevelsForLogger("default", levels);
@@ -198,6 +348,8 @@ export class Logger {
198
348
 
199
349
  /**
200
350
  * Get facility loglevels for the default logger.
351
+ *
352
+ * @deprecated use {@link Logger.facilityLevels}
201
353
  */
202
354
  public static get logLevels() {
203
355
  return Logger.getLoggerForIdentifier("default").logLevels;
@@ -207,6 +359,8 @@ export class Logger {
207
359
  * Set default loglevel for the default logger.
208
360
  *
209
361
  * @param level The level to set
362
+ *
363
+ * @deprecated use {@link Logger.level}
210
364
  */
211
365
  public static set defaultLogLevel(level: LogLevel) {
212
366
  Logger.setDefaultLoglevelForLogger("default", level);
@@ -214,6 +368,8 @@ export class Logger {
214
368
 
215
369
  /**
216
370
  * Get default loglevel for the default logger.
371
+ *
372
+ * @deprecated use {@link destinations}
217
373
  */
218
374
  public static get defaultLogLevel() {
219
375
  return Logger.getLoggerForIdentifier("default").defaultLogLevel;
@@ -223,6 +379,8 @@ export class Logger {
223
379
  * Set the log function for the default logger.
224
380
  *
225
381
  * @param log The log function to set
382
+ *
383
+ * @deprecated use {@link destinations}
226
384
  */
227
385
  public static set log(log: (level: LogLevel, formattedLog: string, facility?: string) => void) {
228
386
  Logger.setLogger("default", log);
@@ -230,6 +388,8 @@ export class Logger {
230
388
 
231
389
  /**
232
390
  * Get the log function for the default logger.
391
+ *
392
+ * @deprecated use {@link destinations}
233
393
  */
234
394
  public static get log() {
235
395
  return Logger.getLoggerForIdentifier("default").log;
@@ -239,6 +399,8 @@ export class Logger {
239
399
  * Set the log formatter for the default logger.
240
400
  *
241
401
  * @param logFormatter
402
+ *
403
+ * @deprecated use {@link destinations}
242
404
  */
243
405
  public static set logFormatter(
244
406
  logFormatter: (now: Date, level: LogLevel, facility: string, nestingPrefix: string, values: any[]) => string,
@@ -248,6 +410,8 @@ export class Logger {
248
410
 
249
411
  /**
250
412
  * Get the log formatter for the default logger.
413
+ *
414
+ * @deprecated use {@link destinations}
251
415
  */
252
416
  public static get logFormatter() {
253
417
  return Logger.getLoggerForIdentifier("default").logFormatter;
@@ -258,14 +422,11 @@ export class Logger {
258
422
  *
259
423
  * @param identifier The identifier of the logger
260
424
  * @param format the name of the formatter (see Format enum)
425
+ *
426
+ * @deprecated use {@link destinations}
261
427
  */
262
428
  public static setFormatForLogger(identifier: string, format: string) {
263
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
264
- if (logger) {
265
- logger.logFormatter = logFormatterFor(format);
266
- } else {
267
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
268
- }
429
+ this.getLoggerForIdentifier(identifier).logFormatter = logFormatterFor(format);
269
430
  }
270
431
 
271
432
  /**
@@ -273,14 +434,11 @@ export class Logger {
273
434
  *
274
435
  * @param identifier The identifier of the logger
275
436
  * @param level The level to set
437
+ *
438
+ * @deprecated use {@link destinations}
276
439
  */
277
440
  public static setDefaultLoglevelForLogger(identifier: string, level: LogLevel) {
278
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
279
- if (logger) {
280
- logger.defaultLogLevel = level;
281
- } else {
282
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
283
- }
441
+ this.getLoggerForIdentifier(identifier).defaultLogLevel = level;
284
442
  }
285
443
 
286
444
  /**
@@ -288,14 +446,11 @@ export class Logger {
288
446
  *
289
447
  * @param identifier The identifier of the logger
290
448
  * @param levels The levels to set
449
+ *
450
+ * @deprecated use {@link destinations}
291
451
  */
292
452
  public static setLogLevelsForLogger(identifier: string, levels: { [facility: string]: LogLevel }) {
293
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
294
- if (logger) {
295
- logger.logLevels = levels;
296
- } else {
297
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
298
- }
453
+ this.getLoggerForIdentifier(identifier).logLevels = levels;
299
454
  }
300
455
 
301
456
  /**
@@ -303,17 +458,14 @@ export class Logger {
303
458
  *
304
459
  * @param identifier The identifier of the logger
305
460
  * @param log The log function to set
461
+ *
462
+ * @deprecated use {@link destinations}
306
463
  */
307
464
  public static setLogger(
308
465
  identifier: string,
309
466
  log: (level: LogLevel, formattedLog: string, facility?: string) => void,
310
467
  ) {
311
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
312
- if (logger) {
313
- logger.log = log;
314
- } else {
315
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
316
- }
468
+ this.getLoggerForIdentifier(identifier).log = log;
317
469
  }
318
470
 
319
471
  /**
@@ -321,168 +473,14 @@ export class Logger {
321
473
  *
322
474
  * @param identifier The identifier of the logger
323
475
  * @param logFormatter The log formatter to set
476
+ *
477
+ * @deprecated use {@link destinations}
324
478
  */
325
479
  static setLogFormatterForLogger(
326
480
  identifier: string,
327
481
  logFormatter: (now: Date, level: LogLevel, facility: string, nestingPrefix: string, values: any[]) => string,
328
482
  ) {
329
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
330
- if (logger) {
331
- logger.logFormatter = logFormatter;
332
- } else {
333
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
334
- }
335
- }
336
-
337
- /**
338
- * Create a new facility.
339
- *
340
- * @param name the name of the facility
341
- * @returns a new facility
342
- */
343
- static get(name: string) {
344
- return new Logger(name);
345
- }
346
-
347
- /**
348
- * Stringify a value (BigInt aware) as JSON.
349
- *
350
- * @param data the value to stringify
351
- * @returns the stringified value
352
- */
353
- static toJSON(data: any) {
354
- return JSON.stringify(data, (_, value) => {
355
- if (typeof value === "bigint") {
356
- return value.toString();
357
- }
358
- if (value instanceof Uint8Array) {
359
- return Bytes.toHex(value);
360
- }
361
- if (value === undefined) {
362
- return "undefined";
363
- }
364
- return value;
365
- });
366
- }
367
-
368
- /**
369
- * Mask a string with a given character. If unmaskedLength is provided then these number of characters will be
370
- * shown unmasked.
371
- *
372
- * @param str String to mask
373
- * @param maskChar character to mask with
374
- * @param unmaskedLength number of characters to show unmasked in the beginning
375
- */
376
- static maskString(str: string, maskChar = "*", unmaskedLength?: number) {
377
- return str.substring(0, unmaskedLength ?? 0) + str.substring(unmaskedLength ?? 0).replace(/./g, maskChar);
378
- }
379
-
380
- /**
381
- * Perform operations in a nested logging context. Messages will be
382
- * indented while the context executes.
383
- */
384
- static nest<T>(context: () => T): T {
385
- this.nestingLevel++;
386
- try {
387
- return context();
388
- } finally {
389
- this.nestingLevel--;
390
- }
391
- }
392
-
393
- /**
394
- * Async version of nest().
395
- */
396
- static async nestAsync(context: () => Promise<any>) {
397
- this.nestingLevel++;
398
- try {
399
- return await context();
400
- } finally {
401
- this.nestingLevel--;
402
- }
403
- }
404
-
405
- /**
406
- * Unhandled error reporter.
407
- *
408
- * Some environments do not report full error details such as {@link Error#cause} and {@link AggregateError#errors}.
409
- *
410
- * To ensure these details are always recorded somewhere, unhandled errors may be reported here.
411
- *
412
- * To disable this behavior replace this function.
413
- */
414
- static reportUnhandledError(error: Error) {
415
- try {
416
- Logger.get("Logger").fatal("Unhandled error detected:", error);
417
- } catch (e) {
418
- // We do not want to cause yet another error so if logging fails for any reason it goes unreported
419
- }
420
- }
421
-
422
- /**
423
- * Invoke logic and return any log messages produced.
424
- */
425
- static capture(fn: () => void, fromLogger = "default") {
426
- if (!Logger) {
427
- throw new Error("No logger loaded, cannot capture logs");
428
- }
429
- const logger = Logger.getLoggerForIdentifier(fromLogger);
430
- const actualLogSettings = {
431
- logFormatter: logger.logFormatter,
432
- log: logger.log,
433
- defaultLogLevel: logger.defaultLogLevel,
434
- logLevels: { ...logger.logLevels },
435
- };
436
-
437
- try {
438
- Logger.setFormatForLogger(fromLogger, LogFormat.PLAIN);
439
- const captured = new Array<{ level: LogLevel; message: string }>();
440
- Logger.setLogger(fromLogger, (level, message) =>
441
- captured.push({
442
- level,
443
- message: message.replace(/\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d/, "xxxx-xx-xx xx:xx:xx.xxx"),
444
- }),
445
- );
446
- fn();
447
- return captured;
448
- } finally {
449
- Logger.setLogFormatterForLogger(fromLogger, actualLogSettings.logFormatter);
450
- Logger.setDefaultLoglevelForLogger(fromLogger, actualLogSettings.defaultLogLevel);
451
- Logger.setLogLevelsForLogger(fromLogger, actualLogSettings.logLevels);
452
- Logger.setLogger(fromLogger, actualLogSettings.log);
453
- }
454
- }
455
-
456
- constructor(name: string) {
457
- this.#name = name;
458
- }
459
-
460
- debug = (...values: any[]) => this.#log(LogLevel.DEBUG, values);
461
- info = (...values: any[]) => this.#log(LogLevel.INFO, values);
462
- notice = (...values: any[]) => this.#log(LogLevel.NOTICE, values);
463
- warn = (...values: any[]) => this.#log(LogLevel.WARN, values);
464
- error = (...values: any[]) => this.#log(LogLevel.ERROR, values);
465
- fatal = (...values: any[]) => this.#log(LogLevel.FATAL, values);
466
- log = (level: LogLevel, ...values: any[]) => this.#log(level, values);
467
-
468
- #log(level: LogLevel, values: any[]) {
469
- for (const logger of Logger.logger) {
470
- if (level < (logger.logLevels[this.#name] ?? logger.defaultLogLevel)) {
471
- return;
472
- }
473
-
474
- if (!logger.context) {
475
- logger.context = Diagnostic.Context();
476
- }
477
-
478
- logger.context.run(() =>
479
- logger.log(
480
- level,
481
- logger.logFormatter(Time.now(), level, this.#name, nestingPrefix(), values),
482
- this.#name,
483
- ),
484
- );
485
- }
483
+ this.getLoggerForIdentifier(identifier).logFormatter = logFormatter;
486
484
  }
487
485
  }
488
486
 
@@ -494,13 +492,7 @@ function nestingPrefix() {
494
492
  }
495
493
 
496
494
  Boot.init(() => {
497
- Logger.logger = new Array<LoggerDefinition>({
498
- logIdentifier: "default",
499
- logFormatter: LogFormat.plain,
500
- log: consoleLogger,
501
- defaultLogLevel: LogLevel.DEBUG,
502
- logLevels: {},
503
- });
495
+ Logger.destinations = LogDestinations();
504
496
  Logger.nestingLevel = 0;
505
497
 
506
498
  // Hook for testing frameworks
@@ -510,3 +502,76 @@ Boot.init(() => {
510
502
  });
511
503
 
512
504
  CancelablePromise.logger = Logger.get("CancelablePromise");
505
+
506
+ /**
507
+ * Create a log formatter for a given format.
508
+ *
509
+ * @deprecated
510
+ */
511
+ function logFormatterFor(formatName: string): LoggerDefinition["logFormatter"] {
512
+ const format = LogFormat(formatName);
513
+
514
+ return (now, level, facility, prefix, ...values) =>
515
+ format(Diagnostic.message({ now, level, facility, prefix, values }));
516
+ }
517
+
518
+ /**
519
+ * Definition of one registered Logger.
520
+ *
521
+ * @deprecated
522
+ */
523
+ type LoggerDefinition = {
524
+ logIdentifier: string;
525
+ logFormatter: (now: Date, level: LogLevel, facility: string, prefix: string, values: any[]) => string;
526
+ log: (level: LogLevel, formattedLog: string, facility?: string) => void;
527
+ defaultLogLevel: LogLevel;
528
+ logLevels: { [facility: string]: LogLevel };
529
+ context?: Diagnostic.Context;
530
+ };
531
+
532
+ /**
533
+ * @deprecated
534
+ */
535
+ function adaptDestinationToLegacy(destination: LogDestination): LoggerDefinition {
536
+ return {
537
+ get logIdentifier() {
538
+ return destination.name;
539
+ },
540
+
541
+ get logFormatter() {
542
+ return (now: Date, level: LogLevel, facility: string, prefix: string, values: any[]) =>
543
+ destination.format(Diagnostic.message({ now, level, facility, prefix, values }));
544
+ },
545
+
546
+ set logFormatter(logFormatter: LoggerDefinition["logFormatter"]) {
547
+ destination.format = (message: Diagnostic.Message) =>
548
+ logFormatter(message.now, message.level, message.facility, message.prefix, message.values);
549
+ },
550
+
551
+ get log() {
552
+ return (level: LogLevel, formattedLog: string, facility?: string) =>
553
+ destination.write(formattedLog, Diagnostic.message({ level, facility }));
554
+ },
555
+
556
+ set log(log: LoggerDefinition["log"]) {
557
+ destination.write = (text: string, message: Diagnostic.Message) =>
558
+ log(message.level, text, message.facility);
559
+ },
560
+
561
+ get defaultLogLevel() {
562
+ return destination.level;
563
+ },
564
+
565
+ set defaultLogLevel(level: LogLevel) {
566
+ destination.level = level;
567
+ },
568
+
569
+ get logLevels() {
570
+ return destination.facilityLevels;
571
+ },
572
+
573
+ set logLevels(levels: Record<string, LogLevel>) {
574
+ destination.facilityLevels = levels;
575
+ },
576
+ };
577
+ }