@matter/general 0.13.0-alpha.0-20250318-c1aa38b08 → 0.13.0-alpha.0-20250323-770919c6a

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 (119) hide show
  1. package/dist/cjs/codec/DnsCodec.js +1 -1
  2. package/dist/cjs/codec/DnsCodec.js.map +1 -1
  3. package/dist/cjs/log/Console.d.ts +21 -0
  4. package/dist/cjs/log/Console.d.ts.map +1 -0
  5. package/dist/cjs/log/Console.js +58 -0
  6. package/dist/cjs/log/Console.js.map +6 -0
  7. package/dist/cjs/log/Diagnostic.d.ts +6 -0
  8. package/dist/cjs/log/Diagnostic.d.ts.map +1 -1
  9. package/dist/cjs/log/Diagnostic.js +16 -0
  10. package/dist/cjs/log/Diagnostic.js.map +1 -1
  11. package/dist/cjs/log/LogDestination.d.ts +67 -0
  12. package/dist/cjs/log/LogDestination.d.ts.map +1 -0
  13. package/dist/cjs/log/LogDestination.js +65 -0
  14. package/dist/cjs/log/LogDestination.js.map +6 -0
  15. package/dist/cjs/log/LogFormat.d.ts +18 -12
  16. package/dist/cjs/log/LogFormat.d.ts.map +1 -1
  17. package/dist/cjs/log/LogFormat.js +17 -24
  18. package/dist/cjs/log/LogFormat.js.map +1 -1
  19. package/dist/cjs/log/LogLevel.d.ts +19 -9
  20. package/dist/cjs/log/LogLevel.d.ts.map +1 -1
  21. package/dist/cjs/log/LogLevel.js +40 -25
  22. package/dist/cjs/log/LogLevel.js.map +1 -1
  23. package/dist/cjs/log/Logger.d.ts +165 -109
  24. package/dist/cjs/log/Logger.d.ts.map +1 -1
  25. package/dist/cjs/log/Logger.js +307 -254
  26. package/dist/cjs/log/Logger.js.map +2 -2
  27. package/dist/cjs/log/index.d.ts +1 -0
  28. package/dist/cjs/log/index.d.ts.map +1 -1
  29. package/dist/cjs/log/index.js +1 -0
  30. package/dist/cjs/log/index.js.map +1 -1
  31. package/dist/cjs/time/Time.d.ts +1 -0
  32. package/dist/cjs/time/Time.d.ts.map +1 -1
  33. package/dist/cjs/time/Time.js +3 -0
  34. package/dist/cjs/time/Time.js.map +1 -1
  35. package/dist/cjs/transaction/Participant.d.ts +3 -3
  36. package/dist/cjs/transaction/Participant.d.ts.map +1 -1
  37. package/dist/cjs/transaction/Transaction.d.ts +20 -20
  38. package/dist/cjs/transaction/Tx.js +3 -3
  39. package/dist/cjs/transaction/Tx.js.map +1 -1
  40. package/dist/cjs/util/Construction.js +2 -2
  41. package/dist/cjs/util/Construction.js.map +1 -1
  42. package/dist/cjs/util/DataReadQueue.d.ts +4 -0
  43. package/dist/cjs/util/DataReadQueue.d.ts.map +1 -1
  44. package/dist/cjs/util/DataReadQueue.js +6 -0
  45. package/dist/cjs/util/DataReadQueue.js.map +1 -1
  46. package/dist/cjs/util/FormattedText.js +4 -2
  47. package/dist/cjs/util/FormattedText.js.map +1 -1
  48. package/dist/cjs/util/Observable.d.ts +137 -12
  49. package/dist/cjs/util/Observable.d.ts.map +1 -1
  50. package/dist/cjs/util/Observable.js +297 -35
  51. package/dist/cjs/util/Observable.js.map +2 -2
  52. package/dist/esm/codec/DnsCodec.js +1 -1
  53. package/dist/esm/codec/DnsCodec.js.map +1 -1
  54. package/dist/esm/log/Console.d.ts +21 -0
  55. package/dist/esm/log/Console.d.ts.map +1 -0
  56. package/dist/esm/log/Console.js +38 -0
  57. package/dist/esm/log/Console.js.map +6 -0
  58. package/dist/esm/log/Diagnostic.d.ts +6 -0
  59. package/dist/esm/log/Diagnostic.d.ts.map +1 -1
  60. package/dist/esm/log/Diagnostic.js +16 -0
  61. package/dist/esm/log/Diagnostic.js.map +1 -1
  62. package/dist/esm/log/LogDestination.d.ts +67 -0
  63. package/dist/esm/log/LogDestination.d.ts.map +1 -0
  64. package/dist/esm/log/LogDestination.js +45 -0
  65. package/dist/esm/log/LogDestination.js.map +6 -0
  66. package/dist/esm/log/LogFormat.d.ts +18 -12
  67. package/dist/esm/log/LogFormat.d.ts.map +1 -1
  68. package/dist/esm/log/LogFormat.js +17 -24
  69. package/dist/esm/log/LogFormat.js.map +1 -1
  70. package/dist/esm/log/LogLevel.d.ts +19 -9
  71. package/dist/esm/log/LogLevel.d.ts.map +1 -1
  72. package/dist/esm/log/LogLevel.js +40 -25
  73. package/dist/esm/log/LogLevel.js.map +1 -1
  74. package/dist/esm/log/Logger.d.ts +165 -109
  75. package/dist/esm/log/Logger.d.ts.map +1 -1
  76. package/dist/esm/log/Logger.js +307 -254
  77. package/dist/esm/log/Logger.js.map +2 -2
  78. package/dist/esm/log/index.d.ts +1 -0
  79. package/dist/esm/log/index.d.ts.map +1 -1
  80. package/dist/esm/log/index.js +1 -0
  81. package/dist/esm/log/index.js.map +1 -1
  82. package/dist/esm/time/Time.d.ts +1 -0
  83. package/dist/esm/time/Time.d.ts.map +1 -1
  84. package/dist/esm/time/Time.js +3 -0
  85. package/dist/esm/time/Time.js.map +1 -1
  86. package/dist/esm/transaction/Participant.d.ts +3 -3
  87. package/dist/esm/transaction/Participant.d.ts.map +1 -1
  88. package/dist/esm/transaction/Transaction.d.ts +20 -20
  89. package/dist/esm/transaction/Tx.js +3 -3
  90. package/dist/esm/transaction/Tx.js.map +1 -1
  91. package/dist/esm/util/Construction.js +2 -2
  92. package/dist/esm/util/Construction.js.map +1 -1
  93. package/dist/esm/util/DataReadQueue.d.ts +4 -0
  94. package/dist/esm/util/DataReadQueue.d.ts.map +1 -1
  95. package/dist/esm/util/DataReadQueue.js +6 -0
  96. package/dist/esm/util/DataReadQueue.js.map +1 -1
  97. package/dist/esm/util/FormattedText.js +4 -2
  98. package/dist/esm/util/FormattedText.js.map +1 -1
  99. package/dist/esm/util/Observable.d.ts +137 -12
  100. package/dist/esm/util/Observable.d.ts.map +1 -1
  101. package/dist/esm/util/Observable.js +297 -35
  102. package/dist/esm/util/Observable.js.map +2 -2
  103. package/package.json +2 -2
  104. package/src/codec/DnsCodec.ts +1 -1
  105. package/src/log/Console.ts +52 -0
  106. package/src/log/Diagnostic.ts +21 -0
  107. package/src/log/LogDestination.ts +113 -0
  108. package/src/log/LogFormat.ts +39 -36
  109. package/src/log/LogLevel.ts +55 -25
  110. package/src/log/Logger.ts +394 -314
  111. package/src/log/index.ts +1 -0
  112. package/src/time/Time.ts +4 -0
  113. package/src/transaction/Participant.ts +3 -3
  114. package/src/transaction/Transaction.ts +1 -1
  115. package/src/transaction/Tx.ts +3 -3
  116. package/src/util/Construction.ts +2 -2
  117. package/src/util/DataReadQueue.ts +7 -0
  118. package/src/util/FormattedText.ts +4 -2
  119. package/src/util/Observable.ts +453 -47
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) {
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) => 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");
84
- *
85
- * The configuration of the default logger can be adjusted by using the static properties of the Logger class:
22
+ * const logger = Logger.get("loggerName");
23
+ * logger.debug("My debug message", "my extra value to log");
86
24
  *
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
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.
90
27
  *
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:
28
+ * You may adjust log verbosity and format by modifying the properties on destinations. For example:
93
29
  *
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,79 +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
- * Get the logger with the matching identifier.
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
- public static getLoggerforIdentifier(identifier: string) {
138
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
139
- if (logger === undefined) {
140
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
141
- }
142
- return logger;
314
+ public static hasLoggerForIdentifier(identifier: string) {
315
+ return identifier in this.destinations;
143
316
  }
144
317
 
145
318
  /**
146
- * Set log level using configuration-style level name for the default logger.
319
+ * Get the logger with the matching identifier.
320
+ * @param identifier The identifier of the logger
321
+ *
322
+ * @deprecated use {@link destinations}
147
323
  */
148
- static set level(level: number | string) {
149
- if (level === undefined) {
150
- level = LogLevel.DEBUG;
151
- }
152
-
153
- let levelNum;
154
- if (typeof level === "string") {
155
- if (level.match(/^\d+$/)) {
156
- levelNum = Number.parseInt(level);
157
- } else {
158
- levelNum = (LogLevel as unknown as Record<string, number | undefined>)[level.toUpperCase()];
159
- if (levelNum === undefined) {
160
- throw new ImplementationError(`Unsupported log level "${level}"`);
161
- }
162
- }
163
- } else {
164
- levelNum = level;
165
- }
166
-
167
- if (LogLevel[levelNum] === undefined) {
168
- throw new ImplementationError(`Unsupported log level "${level}"`);
324
+ public static getLoggerForIdentifier(identifier: string) {
325
+ const dest = this.destinations[identifier];
326
+ if (dest === undefined) {
327
+ throw new NotImplementedError(`Unknown logger "${identifier}"`);
169
328
  }
170
-
171
- Logger.defaultLogLevel = levelNum;
329
+ return adaptDestinationToLegacy(dest);
172
330
  }
173
331
 
174
332
  /**
175
- * Set logFormatter using configuration-style format name.
176
- *
177
- * @param format the name of the formatter (see Format enum)
333
+ * @deprecated use {@link destinations}
178
334
  */
179
- static set format(format: string) {
180
- Logger.setLogFormatterForLogger("default", logFormatterFor(format));
335
+ public static getLoggerforIdentifier(identifier: string) {
336
+ return this.getLoggerForIdentifier(identifier);
181
337
  }
182
338
 
183
339
  /**
184
340
  * Set facility loglevels for the default logger.
185
341
  * @param levels The levels to set
342
+ *
343
+ * @deprecated use {@link destinations}
186
344
  */
187
345
  public static set logLevels(levels: { [facility: string]: LogLevel }) {
188
346
  Logger.setLogLevelsForLogger("default", levels);
@@ -190,15 +348,19 @@ export class Logger {
190
348
 
191
349
  /**
192
350
  * Get facility loglevels for the default logger.
351
+ *
352
+ * @deprecated use {@link Logger.facilityLevels}
193
353
  */
194
354
  public static get logLevels() {
195
- return Logger.getLoggerforIdentifier("default").logLevels;
355
+ return Logger.getLoggerForIdentifier("default").logLevels;
196
356
  }
197
357
 
198
358
  /**
199
359
  * Set default loglevel for the default logger.
200
360
  *
201
361
  * @param level The level to set
362
+ *
363
+ * @deprecated use {@link Logger.level}
202
364
  */
203
365
  public static set defaultLogLevel(level: LogLevel) {
204
366
  Logger.setDefaultLoglevelForLogger("default", level);
@@ -206,31 +368,39 @@ export class Logger {
206
368
 
207
369
  /**
208
370
  * Get default loglevel for the default logger.
371
+ *
372
+ * @deprecated use {@link destinations}
209
373
  */
210
374
  public static get defaultLogLevel() {
211
- return Logger.getLoggerforIdentifier("default").defaultLogLevel;
375
+ return Logger.getLoggerForIdentifier("default").defaultLogLevel;
212
376
  }
213
377
 
214
378
  /**
215
379
  * Set the log function for the default logger.
216
380
  *
217
381
  * @param log The log function to set
382
+ *
383
+ * @deprecated use {@link destinations}
218
384
  */
219
- public static set log(log: (level: LogLevel, formattedLog: string) => void) {
385
+ public static set log(log: (level: LogLevel, formattedLog: string, facility?: string) => void) {
220
386
  Logger.setLogger("default", log);
221
387
  }
222
388
 
223
389
  /**
224
390
  * Get the log function for the default logger.
391
+ *
392
+ * @deprecated use {@link destinations}
225
393
  */
226
394
  public static get log() {
227
- return Logger.getLoggerforIdentifier("default").log;
395
+ return Logger.getLoggerForIdentifier("default").log;
228
396
  }
229
397
 
230
398
  /**
231
399
  * Set the log formatter for the default logger.
232
400
  *
233
401
  * @param logFormatter
402
+ *
403
+ * @deprecated use {@link destinations}
234
404
  */
235
405
  public static set logFormatter(
236
406
  logFormatter: (now: Date, level: LogLevel, facility: string, nestingPrefix: string, values: any[]) => string,
@@ -240,9 +410,11 @@ export class Logger {
240
410
 
241
411
  /**
242
412
  * Get the log formatter for the default logger.
413
+ *
414
+ * @deprecated use {@link destinations}
243
415
  */
244
416
  public static get logFormatter() {
245
- return Logger.getLoggerforIdentifier("default").logFormatter;
417
+ return Logger.getLoggerForIdentifier("default").logFormatter;
246
418
  }
247
419
 
248
420
  /**
@@ -250,14 +422,11 @@ export class Logger {
250
422
  *
251
423
  * @param identifier The identifier of the logger
252
424
  * @param format the name of the formatter (see Format enum)
425
+ *
426
+ * @deprecated use {@link destinations}
253
427
  */
254
428
  public static setFormatForLogger(identifier: string, format: string) {
255
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
256
- if (logger) {
257
- logger.logFormatter = logFormatterFor(format);
258
- } else {
259
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
260
- }
429
+ this.getLoggerForIdentifier(identifier).logFormatter = logFormatterFor(format);
261
430
  }
262
431
 
263
432
  /**
@@ -265,14 +434,11 @@ export class Logger {
265
434
  *
266
435
  * @param identifier The identifier of the logger
267
436
  * @param level The level to set
437
+ *
438
+ * @deprecated use {@link destinations}
268
439
  */
269
440
  public static setDefaultLoglevelForLogger(identifier: string, level: LogLevel) {
270
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
271
- if (logger) {
272
- logger.defaultLogLevel = level;
273
- } else {
274
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
275
- }
441
+ this.getLoggerForIdentifier(identifier).defaultLogLevel = level;
276
442
  }
277
443
 
278
444
  /**
@@ -280,14 +446,11 @@ export class Logger {
280
446
  *
281
447
  * @param identifier The identifier of the logger
282
448
  * @param levels The levels to set
449
+ *
450
+ * @deprecated use {@link destinations}
283
451
  */
284
452
  public static setLogLevelsForLogger(identifier: string, levels: { [facility: string]: LogLevel }) {
285
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
286
- if (logger) {
287
- logger.logLevels = levels;
288
- } else {
289
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
290
- }
453
+ this.getLoggerForIdentifier(identifier).logLevels = levels;
291
454
  }
292
455
 
293
456
  /**
@@ -295,14 +458,14 @@ export class Logger {
295
458
  *
296
459
  * @param identifier The identifier of the logger
297
460
  * @param log The log function to set
461
+ *
462
+ * @deprecated use {@link destinations}
298
463
  */
299
- public static setLogger(identifier: string, log: (level: LogLevel, formattedLog: string) => void) {
300
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
301
- if (logger) {
302
- logger.log = log;
303
- } else {
304
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
305
- }
464
+ public static setLogger(
465
+ identifier: string,
466
+ log: (level: LogLevel, formattedLog: string, facility?: string) => void,
467
+ ) {
468
+ this.getLoggerForIdentifier(identifier).log = log;
306
469
  }
307
470
 
308
471
  /**
@@ -310,164 +473,14 @@ export class Logger {
310
473
  *
311
474
  * @param identifier The identifier of the logger
312
475
  * @param logFormatter The log formatter to set
476
+ *
477
+ * @deprecated use {@link destinations}
313
478
  */
314
479
  static setLogFormatterForLogger(
315
480
  identifier: string,
316
481
  logFormatter: (now: Date, level: LogLevel, facility: string, nestingPrefix: string, values: any[]) => string,
317
482
  ) {
318
- const logger = Logger.logger.find(logger => logger.logIdentifier === identifier);
319
- if (logger) {
320
- logger.logFormatter = logFormatter;
321
- } else {
322
- throw new NotImplementedError(`Unknown logger "${identifier}"`);
323
- }
324
- }
325
-
326
- /**
327
- * Create a new facility.
328
- *
329
- * @param name the name of the facility
330
- * @returns a new facility
331
- */
332
- static get(name: string) {
333
- return new Logger(name);
334
- }
335
-
336
- /**
337
- * Stringify a value (BigInt aware) as JSON.
338
- *
339
- * @param data the value to stringify
340
- * @returns the stringified value
341
- */
342
- static toJSON(data: any) {
343
- return JSON.stringify(data, (_, value) => {
344
- if (typeof value === "bigint") {
345
- return value.toString();
346
- }
347
- if (value instanceof Uint8Array) {
348
- return Bytes.toHex(value);
349
- }
350
- if (value === undefined) {
351
- return "undefined";
352
- }
353
- return value;
354
- });
355
- }
356
-
357
- /**
358
- * Mask a string with a given character. If unmaskedLength is provided then these number of characters will be
359
- * shown unmasked.
360
- *
361
- * @param str String to mask
362
- * @param maskChar character to mask with
363
- * @param unmaskedLength number of characters to show unmasked in the beginning
364
- */
365
- static maskString(str: string, maskChar = "*", unmaskedLength?: number) {
366
- return str.substring(0, unmaskedLength ?? 0) + str.substring(unmaskedLength ?? 0).replace(/./g, maskChar);
367
- }
368
-
369
- /**
370
- * Perform operations in a nested logging context. Messages will be
371
- * indented while the context executes.
372
- */
373
- static nest<T>(context: () => T): T {
374
- this.nestingLevel++;
375
- try {
376
- return context();
377
- } finally {
378
- this.nestingLevel--;
379
- }
380
- }
381
-
382
- /**
383
- * Async version of nest().
384
- */
385
- static async nestAsync(context: () => Promise<any>) {
386
- this.nestingLevel++;
387
- try {
388
- return await context();
389
- } finally {
390
- this.nestingLevel--;
391
- }
392
- }
393
-
394
- /**
395
- * Unhandled error reporter.
396
- *
397
- * Some environments do not report full error details such as {@link Error#cause} and {@link AggregateError#errors}.
398
- *
399
- * To ensure these details are always recorded somewhere, unhandled errors may be reported here.
400
- *
401
- * To disable this behavior replace this function.
402
- */
403
- static reportUnhandledError(error: Error) {
404
- try {
405
- Logger.get("Logger").fatal("Unhandled error detected:", error);
406
- } catch (e) {
407
- // We do not want to cause yet another error so if logging fails for any reason it goes unreported
408
- }
409
- }
410
-
411
- /**
412
- * Invoke logic and return any log messages produced.
413
- */
414
- static capture(fn: () => void, fromLogger = "default") {
415
- if (!Logger) {
416
- throw new Error("No logger loaded, cannot capture logs");
417
- }
418
- const logger = Logger.getLoggerforIdentifier(fromLogger);
419
- const actualLogSettings = {
420
- logFormatter: logger.logFormatter,
421
- log: logger.log,
422
- defaultLogLevel: logger.defaultLogLevel,
423
- logLevels: { ...logger.logLevels },
424
- };
425
-
426
- try {
427
- Logger.setFormatForLogger(fromLogger, LogFormat.PLAIN);
428
- const captured = new Array<{ level: LogLevel; message: string }>();
429
- Logger.setLogger(fromLogger, (level, message) =>
430
- captured.push({
431
- level,
432
- 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"),
433
- }),
434
- );
435
- fn();
436
- return captured;
437
- } finally {
438
- Logger.setLogFormatterForLogger(fromLogger, actualLogSettings.logFormatter);
439
- Logger.setDefaultLoglevelForLogger(fromLogger, actualLogSettings.defaultLogLevel);
440
- Logger.setLogLevelsForLogger(fromLogger, actualLogSettings.logLevels);
441
- Logger.setLogger(fromLogger, actualLogSettings.log);
442
- }
443
- }
444
-
445
- constructor(name: string) {
446
- this.#name = name;
447
- }
448
-
449
- debug = (...values: any[]) => this.#log(LogLevel.DEBUG, values);
450
- info = (...values: any[]) => this.#log(LogLevel.INFO, values);
451
- notice = (...values: any[]) => this.#log(LogLevel.NOTICE, values);
452
- warn = (...values: any[]) => this.#log(LogLevel.WARN, values);
453
- error = (...values: any[]) => this.#log(LogLevel.ERROR, values);
454
- fatal = (...values: any[]) => this.#log(LogLevel.FATAL, values);
455
- log = (level: LogLevel, ...values: any[]) => this.#log(level, values);
456
-
457
- #log(level: LogLevel, values: any[]) {
458
- for (const logger of Logger.logger) {
459
- if (level < (logger.logLevels[this.#name] ?? logger.defaultLogLevel)) {
460
- return;
461
- }
462
-
463
- if (!logger.context) {
464
- logger.context = Diagnostic.Context();
465
- }
466
-
467
- logger.context.run(() =>
468
- logger.log(level, logger.logFormatter(Time.now(), level, this.#name, nestingPrefix(), values)),
469
- );
470
- }
483
+ this.getLoggerForIdentifier(identifier).logFormatter = logFormatter;
471
484
  }
472
485
  }
473
486
 
@@ -479,13 +492,7 @@ function nestingPrefix() {
479
492
  }
480
493
 
481
494
  Boot.init(() => {
482
- Logger.logger = new Array<LoggerDefinition>({
483
- logIdentifier: "default",
484
- logFormatter: LogFormat.plain,
485
- log: consoleLogger,
486
- defaultLogLevel: LogLevel.DEBUG,
487
- logLevels: {},
488
- });
495
+ Logger.destinations = LogDestinations();
489
496
  Logger.nestingLevel = 0;
490
497
 
491
498
  // Hook for testing frameworks
@@ -495,3 +502,76 @@ Boot.init(() => {
495
502
  });
496
503
 
497
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
+ }