@logtape/logtape 0.11.0 → 0.12.0-dev.181

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 (171) hide show
  1. package/config.test.ts +591 -0
  2. package/config.ts +421 -0
  3. package/context.test.ts +187 -0
  4. package/context.ts +55 -0
  5. package/deno.json +36 -0
  6. package/dist/_virtual/rolldown_runtime.cjs +30 -0
  7. package/dist/config.cjs +247 -0
  8. package/dist/config.d.cts +189 -0
  9. package/dist/config.d.cts.map +1 -0
  10. package/dist/config.d.ts +189 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +241 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/context.cjs +30 -0
  15. package/dist/context.d.cts +39 -0
  16. package/dist/context.d.cts.map +1 -0
  17. package/dist/context.d.ts +39 -0
  18. package/dist/context.d.ts.map +1 -0
  19. package/dist/context.js +31 -0
  20. package/dist/context.js.map +1 -0
  21. package/dist/filter.cjs +32 -0
  22. package/dist/filter.d.cts +37 -0
  23. package/dist/filter.d.cts.map +1 -0
  24. package/{types → dist}/filter.d.ts +12 -6
  25. package/dist/filter.d.ts.map +1 -0
  26. package/dist/filter.js +31 -0
  27. package/dist/filter.js.map +1 -0
  28. package/dist/formatter.cjs +281 -0
  29. package/dist/formatter.d.cts +338 -0
  30. package/dist/formatter.d.cts.map +1 -0
  31. package/dist/formatter.d.ts +338 -0
  32. package/dist/formatter.d.ts.map +1 -0
  33. package/dist/formatter.js +275 -0
  34. package/dist/formatter.js.map +1 -0
  35. package/dist/level.cjs +64 -0
  36. package/dist/level.d.cts +34 -0
  37. package/dist/level.d.cts.map +1 -0
  38. package/{types → dist}/level.d.ts +7 -5
  39. package/dist/level.d.ts.map +1 -0
  40. package/dist/level.js +62 -0
  41. package/dist/level.js.map +1 -0
  42. package/dist/logger.cjs +351 -0
  43. package/dist/logger.d.cts +501 -0
  44. package/dist/logger.d.cts.map +1 -0
  45. package/dist/logger.d.ts +501 -0
  46. package/dist/logger.d.ts.map +1 -0
  47. package/dist/logger.js +351 -0
  48. package/dist/logger.js.map +1 -0
  49. package/dist/mod.cjs +33 -0
  50. package/dist/mod.d.cts +9 -0
  51. package/dist/mod.d.ts +9 -0
  52. package/dist/mod.js +9 -0
  53. package/dist/record.d.cts +50 -0
  54. package/dist/record.d.cts.map +1 -0
  55. package/dist/record.d.ts +50 -0
  56. package/dist/record.d.ts.map +1 -0
  57. package/dist/sink.cjs +95 -0
  58. package/dist/sink.d.cts +112 -0
  59. package/dist/sink.d.cts.map +1 -0
  60. package/{types → dist}/sink.d.ts +49 -45
  61. package/dist/sink.d.ts.map +1 -0
  62. package/dist/sink.js +94 -0
  63. package/dist/sink.js.map +1 -0
  64. package/dist/util.cjs +9 -0
  65. package/dist/util.d.cts +12 -0
  66. package/dist/util.d.cts.map +1 -0
  67. package/dist/util.d.ts +12 -0
  68. package/dist/util.d.ts.map +1 -0
  69. package/dist/util.deno.cjs +16 -0
  70. package/dist/util.deno.d.cts +12 -0
  71. package/dist/util.deno.d.cts.map +1 -0
  72. package/dist/util.deno.d.ts +12 -0
  73. package/dist/util.deno.d.ts.map +1 -0
  74. package/dist/util.deno.js +16 -0
  75. package/dist/util.deno.js.map +1 -0
  76. package/dist/util.js +9 -0
  77. package/dist/util.js.map +1 -0
  78. package/dist/util.node.cjs +10 -0
  79. package/dist/util.node.d.cts +12 -0
  80. package/dist/util.node.d.cts.map +1 -0
  81. package/dist/util.node.d.ts +12 -0
  82. package/dist/util.node.d.ts.map +1 -0
  83. package/dist/util.node.js +10 -0
  84. package/dist/util.node.js.map +1 -0
  85. package/filter.test.ts +70 -0
  86. package/filter.ts +57 -0
  87. package/fixtures.ts +30 -0
  88. package/formatter.test.ts +530 -0
  89. package/formatter.ts +724 -0
  90. package/level.test.ts +47 -0
  91. package/level.ts +67 -0
  92. package/logger.test.ts +823 -0
  93. package/logger.ts +1124 -0
  94. package/mod.ts +54 -0
  95. package/package.json +35 -23
  96. package/record.ts +49 -0
  97. package/sink.test.ts +219 -0
  98. package/sink.ts +167 -0
  99. package/tsdown.config.ts +24 -0
  100. package/util.deno.ts +19 -0
  101. package/util.node.ts +12 -0
  102. package/util.ts +11 -0
  103. package/esm/_dnt.shims.js +0 -57
  104. package/esm/config.js +0 -297
  105. package/esm/context.js +0 -23
  106. package/esm/filter.js +0 -42
  107. package/esm/formatter.js +0 -370
  108. package/esm/level.js +0 -59
  109. package/esm/logger.js +0 -517
  110. package/esm/mod.js +0 -8
  111. package/esm/nodeUtil.cjs +0 -20
  112. package/esm/nodeUtil.js +0 -2
  113. package/esm/package.json +0 -3
  114. package/esm/record.js +0 -1
  115. package/esm/sink.js +0 -96
  116. package/script/_dnt.shims.js +0 -60
  117. package/script/config.js +0 -331
  118. package/script/context.js +0 -26
  119. package/script/filter.js +0 -46
  120. package/script/formatter.js +0 -380
  121. package/script/level.js +0 -64
  122. package/script/logger.js +0 -548
  123. package/script/mod.js +0 -36
  124. package/script/nodeUtil.js +0 -20
  125. package/script/package.json +0 -3
  126. package/script/record.js +0 -2
  127. package/script/sink.js +0 -101
  128. package/types/_dnt.shims.d.ts +0 -2
  129. package/types/_dnt.shims.d.ts.map +0 -1
  130. package/types/_dnt.test_shims.d.ts.map +0 -1
  131. package/types/config.d.ts +0 -183
  132. package/types/config.d.ts.map +0 -1
  133. package/types/config.test.d.ts.map +0 -1
  134. package/types/context.d.ts +0 -35
  135. package/types/context.d.ts.map +0 -1
  136. package/types/context.test.d.ts.map +0 -1
  137. package/types/deps/jsr.io/@std/assert/0.222.1/_constants.d.ts.map +0 -1
  138. package/types/deps/jsr.io/@std/assert/0.222.1/_diff.d.ts.map +0 -1
  139. package/types/deps/jsr.io/@std/assert/0.222.1/_format.d.ts.map +0 -1
  140. package/types/deps/jsr.io/@std/assert/0.222.1/assert.d.ts.map +0 -1
  141. package/types/deps/jsr.io/@std/assert/0.222.1/assert_equals.d.ts.map +0 -1
  142. package/types/deps/jsr.io/@std/assert/0.222.1/assert_false.d.ts.map +0 -1
  143. package/types/deps/jsr.io/@std/assert/0.222.1/assert_greater_or_equal.d.ts.map +0 -1
  144. package/types/deps/jsr.io/@std/assert/0.222.1/assert_is_error.d.ts.map +0 -1
  145. package/types/deps/jsr.io/@std/assert/0.222.1/assert_less_or_equal.d.ts.map +0 -1
  146. package/types/deps/jsr.io/@std/assert/0.222.1/assert_rejects.d.ts.map +0 -1
  147. package/types/deps/jsr.io/@std/assert/0.222.1/assert_strict_equals.d.ts.map +0 -1
  148. package/types/deps/jsr.io/@std/assert/0.222.1/assert_throws.d.ts.map +0 -1
  149. package/types/deps/jsr.io/@std/assert/0.222.1/assertion_error.d.ts.map +0 -1
  150. package/types/deps/jsr.io/@std/assert/0.222.1/equal.d.ts.map +0 -1
  151. package/types/deps/jsr.io/@std/async/0.222.1/delay.d.ts.map +0 -1
  152. package/types/deps/jsr.io/@std/fmt/0.222.1/colors.d.ts.map +0 -1
  153. package/types/filter.d.ts.map +0 -1
  154. package/types/filter.test.d.ts.map +0 -1
  155. package/types/fixtures.d.ts.map +0 -1
  156. package/types/formatter.d.ts +0 -332
  157. package/types/formatter.d.ts.map +0 -1
  158. package/types/formatter.test.d.ts.map +0 -1
  159. package/types/level.d.ts.map +0 -1
  160. package/types/level.test.d.ts.map +0 -1
  161. package/types/logger.d.ts +0 -573
  162. package/types/logger.d.ts.map +0 -1
  163. package/types/logger.test.d.ts.map +0 -1
  164. package/types/mod.d.ts +0 -9
  165. package/types/mod.d.ts.map +0 -1
  166. package/types/nodeUtil.d.ts +0 -12
  167. package/types/nodeUtil.d.ts.map +0 -1
  168. package/types/record.d.ts +0 -44
  169. package/types/record.d.ts.map +0 -1
  170. package/types/sink.d.ts.map +0 -1
  171. package/types/sink.test.d.ts.map +0 -1
package/logger.test.ts ADDED
@@ -0,0 +1,823 @@
1
+ import { suite } from "@hongminhee/suite";
2
+ import { assert } from "@std/assert/assert";
3
+ import { assertEquals } from "@std/assert/equals";
4
+ import { assertFalse } from "@std/assert/false";
5
+ import { assertGreaterOrEqual } from "@std/assert/greater-or-equal";
6
+ import { assertLessOrEqual } from "@std/assert/less-or-equal";
7
+ import { assertStrictEquals } from "@std/assert/strict-equals";
8
+ import { toFilter } from "./filter.ts";
9
+ import { debug, error, info, warning } from "./fixtures.ts";
10
+ import {
11
+ getLogger,
12
+ LoggerCtx,
13
+ LoggerImpl,
14
+ parseMessageTemplate,
15
+ renderMessage,
16
+ } from "./logger.ts";
17
+ import type { LogRecord } from "./record.ts";
18
+ import type { Sink } from "./sink.ts";
19
+
20
+ const test = suite(import.meta);
21
+
22
+ function templateLiteral(tpl: TemplateStringsArray, ..._: unknown[]) {
23
+ return tpl;
24
+ }
25
+
26
+ test("getLogger()", () => {
27
+ assertEquals(getLogger().category, []);
28
+ assertStrictEquals(getLogger(), getLogger());
29
+ assertStrictEquals(getLogger([]), getLogger());
30
+ assertEquals(getLogger("foo").category, ["foo"]);
31
+ assertStrictEquals(getLogger("foo"), getLogger("foo"));
32
+ assertStrictEquals(getLogger("foo"), getLogger(["foo"]));
33
+ assertStrictEquals(getLogger("foo"), getLogger().getChild("foo"));
34
+ assertEquals(getLogger(["foo", "bar"]).category, ["foo", "bar"]);
35
+ assertStrictEquals(
36
+ getLogger(["foo", "bar"]),
37
+ getLogger().getChild(["foo", "bar"]),
38
+ );
39
+ assertStrictEquals(
40
+ getLogger(["foo", "bar"]),
41
+ getLogger().getChild("foo").getChild("bar"),
42
+ );
43
+ });
44
+
45
+ test("Logger.getChild()", () => {
46
+ const foo = getLogger("foo");
47
+ const fooBar = foo.getChild("bar");
48
+ assertEquals(fooBar.category, ["foo", "bar"]);
49
+ assertStrictEquals(fooBar.parent, foo);
50
+ const fooBarBaz = foo.getChild(["bar", "baz"]);
51
+ assertEquals(fooBarBaz.category, ["foo", "bar", "baz"]);
52
+ assertEquals(fooBarBaz.parent, fooBar);
53
+
54
+ const fooCtx = foo.with({ a: 1, b: 2 });
55
+ const fooBarCtx = fooCtx.getChild("bar");
56
+ assertEquals(fooBarCtx.category, ["foo", "bar"]);
57
+ // @ts-ignore: internal attribute:
58
+ assertEquals(fooBarCtx.properties, { a: 1, b: 2 });
59
+ });
60
+
61
+ test("Logger.with()", () => {
62
+ const foo = getLogger("foo");
63
+ const ctx = foo.with({ a: 1, b: 2 });
64
+ assertEquals(ctx.parent, getLogger());
65
+ assertEquals(ctx.category, ["foo"]);
66
+ // @ts-ignore: internal attribute:
67
+ assertEquals(ctx.properties, { a: 1, b: 2 });
68
+ // @ts-ignore: internal attribute:
69
+ assertEquals(ctx.with({ c: 3 }).properties, { a: 1, b: 2, c: 3 });
70
+ });
71
+
72
+ test("LoggerImpl.filter()", () => {
73
+ const root = LoggerImpl.getLogger([]);
74
+ const foo = LoggerImpl.getLogger("foo");
75
+ const fooBar = foo.getChild("bar");
76
+ const fooBaz = foo.getChild("baz");
77
+ const fooBarQux = fooBar.getChild("qux");
78
+ const fooQuux = foo.getChild("quux");
79
+
80
+ try {
81
+ foo.filters.push((log) => log.level === "info");
82
+ fooBar.filters.push((log) => log.message.includes("!"));
83
+ fooBaz.filters.push((log) => log.message.includes("."));
84
+ fooBarQux.filters.push(() => true);
85
+ assert(root.filter(info));
86
+ assert(foo.filter(info));
87
+ assert(fooBar.filter(info));
88
+ assertFalse(fooBaz.filter(info));
89
+ assert(fooBarQux.filter(info));
90
+ assert(fooQuux.filter(info));
91
+ assert(root.filter(debug));
92
+ assertFalse(foo.filter(debug));
93
+ assert(fooBar.filter(debug));
94
+ assertFalse(fooBaz.filter(debug));
95
+ assert(fooBarQux.filter(debug));
96
+ assertFalse(fooQuux.filter(debug));
97
+ } finally {
98
+ root.resetDescendants();
99
+ }
100
+ });
101
+
102
+ test("LoggerImpl.getSinks()", () => {
103
+ const root = LoggerImpl.getLogger([]);
104
+ const foo = LoggerImpl.getLogger("foo");
105
+ const fooBar = foo.getChild("bar");
106
+ const fooBaz = foo.getChild("baz");
107
+ const fooBarQux = fooBar.getChild("qux");
108
+
109
+ try {
110
+ const sinkA: Sink = () => {};
111
+ foo.sinks.push(sinkA);
112
+ const sinkB: Sink = () => {};
113
+ fooBar.sinks.push(sinkB);
114
+ const sinkC: Sink = () => {};
115
+ fooBaz.sinks.push(sinkC);
116
+ const sinkD: Sink = () => {};
117
+ fooBarQux.sinks.push(sinkD);
118
+ assertEquals([...root.getSinks("debug")], []);
119
+ assertEquals([...foo.getSinks("debug")], [sinkA]);
120
+ assertEquals([...fooBar.getSinks("debug")], [sinkA, sinkB]);
121
+ assertEquals([...fooBaz.getSinks("debug")], [sinkA, sinkC]);
122
+ assertEquals([...fooBarQux.getSinks("debug")], [sinkA, sinkB, sinkD]);
123
+ fooBarQux.parentSinks = "override";
124
+ assertEquals([...fooBarQux.getSinks("debug")], [sinkD]);
125
+ } finally {
126
+ root.resetDescendants();
127
+ }
128
+ });
129
+
130
+ test("LoggerImpl.emit()", () => {
131
+ const root = LoggerImpl.getLogger([]);
132
+ const foo = root.getChild("foo");
133
+ const fooBar = foo.getChild("bar");
134
+ const fooBarBaz = fooBar.getChild("baz");
135
+ const fooQux = foo.getChild("qux");
136
+
137
+ const rootRecords: LogRecord[] = [];
138
+ root.sinks.push(rootRecords.push.bind(rootRecords));
139
+ root.filters.push(toFilter("warning"));
140
+ const fooRecords: LogRecord[] = [];
141
+ foo.sinks.push(fooRecords.push.bind(fooRecords));
142
+ foo.filters.push(toFilter("info"));
143
+ const fooBarRecords: LogRecord[] = [];
144
+ fooBar.sinks.push(fooBarRecords.push.bind(fooBarRecords));
145
+ fooBar.filters.push(toFilter("error"));
146
+ const fooQuxRecords: LogRecord[] = [];
147
+ fooQux.sinks.push(fooQuxRecords.push.bind(fooQuxRecords));
148
+
149
+ try {
150
+ root.emit(info);
151
+ assertEquals(rootRecords, []);
152
+ assertEquals(fooRecords, []);
153
+ assertEquals(fooBarRecords, []);
154
+ root.emit(warning);
155
+ assertEquals(rootRecords, [warning]);
156
+ assertEquals(fooRecords, []);
157
+ assertEquals(fooBarRecords, []);
158
+
159
+ foo.emit(debug);
160
+ assertEquals(rootRecords, [warning]);
161
+ assertEquals(fooRecords, []);
162
+ assertEquals(fooBarRecords, []);
163
+ foo.emit(info);
164
+ assertEquals(rootRecords, [warning, info]);
165
+ assertEquals(fooRecords, [info]);
166
+ assertEquals(fooBarRecords, []);
167
+
168
+ fooBar.emit(warning);
169
+ assertEquals(rootRecords, [warning, info]);
170
+ assertEquals(fooRecords, [info]);
171
+ assertEquals(fooBarRecords, []);
172
+ fooBar.emit(error);
173
+ assertEquals(rootRecords, [warning, info, error]);
174
+ assertEquals(fooRecords, [info, error]);
175
+ assertEquals(fooBarRecords, [error]);
176
+ } finally {
177
+ while (rootRecords.length > 0) rootRecords.pop();
178
+ while (fooRecords.length > 0) fooRecords.pop();
179
+ while (fooBarRecords.length > 0) fooBarRecords.pop();
180
+ }
181
+
182
+ const errorSink: Sink = () => {
183
+ throw new Error("This is an error");
184
+ };
185
+ fooBarBaz.sinks.push(errorSink);
186
+
187
+ try {
188
+ fooBarBaz.emit(error);
189
+ assertEquals(rootRecords.length, 2);
190
+ assertEquals(rootRecords[0], error);
191
+ assertEquals(fooRecords, [error]);
192
+ assertEquals(fooBarRecords, [error]);
193
+ assertEquals(rootRecords[1].category, ["logtape", "meta"]);
194
+ assertEquals(rootRecords[1].level, "fatal");
195
+ assertEquals(rootRecords[1].message, [
196
+ "Failed to emit a log record to sink ",
197
+ errorSink,
198
+ ": ",
199
+ rootRecords[1].properties.error,
200
+ "",
201
+ ]);
202
+ assertEquals(rootRecords[1].properties, {
203
+ record: error,
204
+ sink: errorSink,
205
+ error: rootRecords[1].properties.error,
206
+ });
207
+
208
+ root.sinks.push(errorSink);
209
+ fooBarBaz.emit(error);
210
+ } finally {
211
+ while (rootRecords.length > 0) rootRecords.pop();
212
+ while (fooRecords.length > 0) fooRecords.pop();
213
+ while (fooBarRecords.length > 0) fooBarRecords.pop();
214
+ while (root.filters.length > 0) root.filters.pop();
215
+ while (foo.filters.length > 0) foo.filters.pop();
216
+ while (fooBar.filters.length > 0) fooBar.filters.pop();
217
+ root.sinks.pop();
218
+ }
219
+
220
+ root.lowestLevel = "debug";
221
+ foo.lowestLevel = "error";
222
+ fooBar.lowestLevel = "info";
223
+
224
+ try {
225
+ fooBar.emit({ ...debug, category: ["foo", "bar"] });
226
+ assertEquals(rootRecords, []);
227
+ assertEquals(fooRecords, []);
228
+ assertEquals(fooBarRecords, []);
229
+
230
+ const debugRecord = { ...debug, category: ["foo", "qux"] };
231
+ fooQux.emit(debugRecord);
232
+ assertEquals(rootRecords, []);
233
+ assertEquals(fooRecords, []);
234
+ assertEquals(fooQuxRecords, [debugRecord]);
235
+
236
+ foo.emit({ ...debug, category: ["foo"] });
237
+ assertEquals(rootRecords, []);
238
+ assertEquals(fooRecords, []);
239
+
240
+ const debugRecord2 = { ...debug, category: [] };
241
+ root.emit(debugRecord2);
242
+ assertEquals(rootRecords, [debugRecord2]);
243
+
244
+ const infoRecord = { ...info, category: ["foo", "bar"] };
245
+ fooBar.emit(infoRecord);
246
+ assertEquals(rootRecords, [debugRecord2]);
247
+ assertEquals(fooRecords, []);
248
+ assertEquals(fooBarRecords, [infoRecord]);
249
+ } finally {
250
+ root.resetDescendants();
251
+ }
252
+ });
253
+
254
+ test("LoggerImpl.log()", () => {
255
+ const logger = LoggerImpl.getLogger("foo");
256
+
257
+ try {
258
+ const logs: LogRecord[] = [];
259
+ logger.sinks.push(logs.push.bind(logs));
260
+ const before = Date.now();
261
+ logger.log("info", "Hello, {foo}!", { foo: 123 });
262
+ const after = Date.now();
263
+ assertEquals(logs, [
264
+ {
265
+ category: ["foo"],
266
+ level: "info",
267
+ message: ["Hello, ", 123, "!"],
268
+ rawMessage: "Hello, {foo}!",
269
+ timestamp: logs[0].timestamp,
270
+ properties: { foo: 123 },
271
+ },
272
+ ]);
273
+ assertGreaterOrEqual(logs[0].timestamp, before);
274
+ assertLessOrEqual(logs[0].timestamp, after);
275
+
276
+ logs.shift();
277
+ logger.filters.push(toFilter("error"));
278
+ let called = 0;
279
+ logger.log("warning", "Hello, {foo}!", () => {
280
+ called++;
281
+ return { foo: 123 };
282
+ });
283
+ assertEquals(logs, []);
284
+ assertEquals(called, 0);
285
+
286
+ logger.log("error", "Hello, {foo}!", () => {
287
+ called++;
288
+ return { foo: 123 };
289
+ });
290
+ assertEquals(logs, [
291
+ {
292
+ category: ["foo"],
293
+ level: "error",
294
+ message: ["Hello, ", 123, "!"],
295
+ rawMessage: "Hello, {foo}!",
296
+ timestamp: logs[0].timestamp,
297
+ properties: { foo: 123 },
298
+ },
299
+ ]);
300
+ assertEquals(called, 1);
301
+ } finally {
302
+ logger.resetDescendants();
303
+ }
304
+ });
305
+
306
+ test("LoggerImpl.logLazily()", () => {
307
+ const logger = LoggerImpl.getLogger("foo");
308
+
309
+ let called = 0;
310
+ function calc() {
311
+ called++;
312
+ return 123;
313
+ }
314
+
315
+ try {
316
+ const logs: LogRecord[] = [];
317
+ logger.sinks.push(logs.push.bind(logs));
318
+ logger.filters.push(toFilter("error"));
319
+ logger.logLazily("warning", (l) => l`Hello, ${calc()}!`);
320
+ assertEquals(logs, []);
321
+ assertEquals(called, 0);
322
+
323
+ const before = Date.now();
324
+ logger.logLazily("error", (l) => l`Hello, ${calc()}!`);
325
+ const after = Date.now();
326
+ assertEquals(logs, [
327
+ {
328
+ category: ["foo"],
329
+ level: "error",
330
+ message: ["Hello, ", 123, "!"],
331
+ rawMessage: templateLiteral`Hello, ${null}!`,
332
+ timestamp: logs[0].timestamp,
333
+ properties: {},
334
+ },
335
+ ]);
336
+ assertGreaterOrEqual(logs[0].timestamp, before);
337
+ assertLessOrEqual(logs[0].timestamp, after);
338
+ assertEquals(called, 1);
339
+ } finally {
340
+ logger.resetDescendants();
341
+ }
342
+ });
343
+
344
+ test("LoggerImpl.logTemplate()", () => {
345
+ const logger = LoggerImpl.getLogger("foo");
346
+
347
+ function info(tpl: TemplateStringsArray, ...values: unknown[]) {
348
+ logger.logTemplate("info", tpl, values);
349
+ }
350
+
351
+ try {
352
+ const logs: LogRecord[] = [];
353
+ logger.sinks.push(logs.push.bind(logs));
354
+
355
+ const before = Date.now();
356
+ info`Hello, ${123}!`;
357
+ const after = Date.now();
358
+ assertEquals(logs, [
359
+ {
360
+ category: ["foo"],
361
+ level: "info",
362
+ message: ["Hello, ", 123, "!"],
363
+ rawMessage: templateLiteral`Hello, ${null}!`,
364
+ timestamp: logs[0].timestamp,
365
+ properties: {},
366
+ },
367
+ ]);
368
+ assertGreaterOrEqual(logs[0].timestamp, before);
369
+ assertLessOrEqual(logs[0].timestamp, after);
370
+ } finally {
371
+ logger.resetDescendants();
372
+ }
373
+ });
374
+
375
+ test("LoggerCtx.log()", () => {
376
+ const logger = LoggerImpl.getLogger("foo");
377
+ const ctx = new LoggerCtx(logger, { a: 1, b: 2 });
378
+
379
+ try {
380
+ const logs: LogRecord[] = [];
381
+ logger.sinks.push(logs.push.bind(logs));
382
+ const before = Date.now();
383
+ ctx.log("info", "Hello, {a} {b} {c}!", { c: 3 });
384
+ const after = Date.now();
385
+ assertEquals(logs, [
386
+ {
387
+ category: ["foo"],
388
+ level: "info",
389
+ message: ["Hello, ", 1, " ", 2, " ", 3, "!"],
390
+ rawMessage: "Hello, {a} {b} {c}!",
391
+ timestamp: logs[0].timestamp,
392
+ properties: { a: 1, b: 2, c: 3 },
393
+ },
394
+ ]);
395
+ assertGreaterOrEqual(logs[0].timestamp, before);
396
+ assertLessOrEqual(logs[0].timestamp, after);
397
+
398
+ logs.shift();
399
+ logger.filters.push(toFilter("error"));
400
+ let called = 0;
401
+ ctx.log("warning", "Hello, {a} {b} {c}!", () => {
402
+ called++;
403
+ return { c: 3 };
404
+ });
405
+ assertEquals(logs, []);
406
+ assertEquals(called, 0);
407
+
408
+ ctx.log("error", "Hello, {a} {b} {c}!", () => {
409
+ called++;
410
+ return { c: 3 };
411
+ });
412
+ assertEquals(logs, [
413
+ {
414
+ category: ["foo"],
415
+ level: "error",
416
+ message: ["Hello, ", 1, " ", 2, " ", 3, "!"],
417
+ rawMessage: "Hello, {a} {b} {c}!",
418
+ timestamp: logs[0].timestamp,
419
+ properties: { a: 1, b: 2, c: 3 },
420
+ },
421
+ ]);
422
+ assertEquals(called, 1);
423
+ } finally {
424
+ logger.resetDescendants();
425
+ }
426
+ });
427
+
428
+ test("LoggerCtx.logLazily()", () => {
429
+ const logger = LoggerImpl.getLogger("foo");
430
+ const ctx = new LoggerCtx(logger, { a: 1, b: 2 });
431
+
432
+ let called = 0;
433
+ function calc() {
434
+ called++;
435
+ return 123;
436
+ }
437
+
438
+ try {
439
+ const logs: LogRecord[] = [];
440
+ logger.sinks.push(logs.push.bind(logs));
441
+ logger.filters.push(toFilter("error"));
442
+ logger.logLazily("warning", (l) => l`Hello, ${calc()}!`);
443
+ assertEquals(logs, []);
444
+ assertEquals(called, 0);
445
+
446
+ const before = Date.now();
447
+ ctx.logLazily("error", (l) => l`Hello, ${calc()}!`);
448
+ const after = Date.now();
449
+ assertEquals(logs, [
450
+ {
451
+ category: ["foo"],
452
+ level: "error",
453
+ message: ["Hello, ", 123, "!"],
454
+ rawMessage: templateLiteral`Hello, ${null}!`,
455
+ timestamp: logs[0].timestamp,
456
+ properties: { a: 1, b: 2 },
457
+ },
458
+ ]);
459
+ assertGreaterOrEqual(logs[0].timestamp, before);
460
+ assertLessOrEqual(logs[0].timestamp, after);
461
+ assertEquals(called, 1);
462
+ } finally {
463
+ logger.resetDescendants();
464
+ }
465
+ });
466
+
467
+ test("LoggerCtx.logTemplate()", () => {
468
+ const logger = LoggerImpl.getLogger("foo");
469
+ const ctx = new LoggerCtx(logger, { a: 1, b: 2 });
470
+
471
+ function info(tpl: TemplateStringsArray, ...values: unknown[]) {
472
+ ctx.logTemplate("info", tpl, values);
473
+ }
474
+
475
+ try {
476
+ const logs: LogRecord[] = [];
477
+ logger.sinks.push(logs.push.bind(logs));
478
+
479
+ const before = Date.now();
480
+ info`Hello, ${123}!`;
481
+ const after = Date.now();
482
+ assertEquals(logs, [
483
+ {
484
+ category: ["foo"],
485
+ level: "info",
486
+ message: ["Hello, ", 123, "!"],
487
+ rawMessage: templateLiteral`Hello, ${null}!`,
488
+ timestamp: logs[0].timestamp,
489
+ properties: { a: 1, b: 2 },
490
+ },
491
+ ]);
492
+ assertGreaterOrEqual(logs[0].timestamp, before);
493
+ assertLessOrEqual(logs[0].timestamp, after);
494
+ } finally {
495
+ logger.resetDescendants();
496
+ }
497
+ });
498
+
499
+ const methods = ["debug", "info", "warn", "error", "fatal"] as const;
500
+ for (const method of methods) {
501
+ test(`Logger.${method}() [template]`, () => {
502
+ const logger = LoggerImpl.getLogger("foo");
503
+ const ctx = new LoggerCtx(logger, { a: 1, b: 2 });
504
+
505
+ function tpl(tpl: TemplateStringsArray, ...values: unknown[]) {
506
+ logger[method](tpl, ...values);
507
+ }
508
+
509
+ const logs: LogRecord[] = [];
510
+ try {
511
+ logger.sinks.push(logs.push.bind(logs));
512
+ const before = Date.now();
513
+ tpl`Hello, ${123}!`;
514
+ const after = Date.now();
515
+ assertEquals(logs, [
516
+ {
517
+ category: ["foo"],
518
+ level: method === "warn" ? "warning" : method,
519
+ message: ["Hello, ", 123, "!"],
520
+ rawMessage: templateLiteral`Hello, ${null}!`,
521
+ timestamp: logs[0].timestamp,
522
+ properties: {},
523
+ },
524
+ ]);
525
+ assertGreaterOrEqual(logs[0].timestamp, before);
526
+ assertLessOrEqual(logs[0].timestamp, after);
527
+ } finally {
528
+ logs.shift();
529
+ }
530
+
531
+ function ctxTpl(tpl: TemplateStringsArray, ...values: unknown[]) {
532
+ ctx[method](tpl, ...values);
533
+ }
534
+
535
+ try {
536
+ const before = Date.now();
537
+ ctxTpl`Hello, ${123}!`;
538
+ const after = Date.now();
539
+ assertEquals(logs, [
540
+ {
541
+ category: ["foo"],
542
+ level: method === "warn" ? "warning" : method,
543
+ message: ["Hello, ", 123, "!"],
544
+ rawMessage: templateLiteral`Hello, ${null}!`,
545
+ timestamp: logs[0].timestamp,
546
+ properties: { a: 1, b: 2 },
547
+ },
548
+ ]);
549
+ assertGreaterOrEqual(logs[0].timestamp, before);
550
+ assertLessOrEqual(logs[0].timestamp, after);
551
+ } finally {
552
+ logger.resetDescendants();
553
+ }
554
+ });
555
+
556
+ test(`Logger.${method}() [lazy template]`, () => {
557
+ const logger = LoggerImpl.getLogger("foo");
558
+ const ctx = new LoggerCtx(logger, { a: 1, b: 2 });
559
+
560
+ try {
561
+ const logs: LogRecord[] = [];
562
+ logger.sinks.push(logs.push.bind(logs));
563
+ let before = Date.now();
564
+ logger[method]((l) => l`Hello, ${123}!`);
565
+ let after = Date.now();
566
+ assertEquals(logs, [
567
+ {
568
+ category: ["foo"],
569
+ level: method === "warn" ? "warning" : method,
570
+ message: ["Hello, ", 123, "!"],
571
+ rawMessage: templateLiteral`Hello, ${null}!`,
572
+ timestamp: logs[0].timestamp,
573
+ properties: {},
574
+ },
575
+ ]);
576
+ assertGreaterOrEqual(logs[0].timestamp, before);
577
+ assertLessOrEqual(logs[0].timestamp, after);
578
+
579
+ logs.shift();
580
+ before = Date.now();
581
+ ctx[method]((l) => l`Hello, ${123}!`);
582
+ after = Date.now();
583
+ assertEquals(logs, [
584
+ {
585
+ category: ["foo"],
586
+ level: method === "warn" ? "warning" : method,
587
+ message: ["Hello, ", 123, "!"],
588
+ rawMessage: templateLiteral`Hello, ${null}!`,
589
+ timestamp: logs[0].timestamp,
590
+ properties: { a: 1, b: 2 },
591
+ },
592
+ ]);
593
+ assertGreaterOrEqual(logs[0].timestamp, before);
594
+ assertLessOrEqual(logs[0].timestamp, after);
595
+ } finally {
596
+ logger.resetDescendants();
597
+ }
598
+ });
599
+
600
+ test(`Logger.${method}() [eager]`, () => {
601
+ const logger = LoggerImpl.getLogger("foo");
602
+ const ctx = new LoggerCtx(logger, { a: 1, b: 2 });
603
+
604
+ try {
605
+ const logs: LogRecord[] = [];
606
+ logger.sinks.push(logs.push.bind(logs));
607
+ let before = Date.now();
608
+ logger[method]("Hello, {foo}!", { foo: 123 });
609
+ let after = Date.now();
610
+ assertEquals(logs, [
611
+ {
612
+ category: ["foo"],
613
+ level: method === "warn" ? "warning" : method,
614
+ message: ["Hello, ", 123, "!"],
615
+ rawMessage: "Hello, {foo}!",
616
+ timestamp: logs[0].timestamp,
617
+ properties: { foo: 123 },
618
+ },
619
+ ]);
620
+ assertGreaterOrEqual(logs[0].timestamp, before);
621
+ assertLessOrEqual(logs[0].timestamp, after);
622
+
623
+ logs.shift();
624
+ logger[method]("Hello, world!");
625
+ assertEquals(logs, [
626
+ {
627
+ category: ["foo"],
628
+ level: method === "warn" ? "warning" : method,
629
+ message: ["Hello, world!"],
630
+ rawMessage: "Hello, world!",
631
+ timestamp: logs[0].timestamp,
632
+ properties: {},
633
+ },
634
+ ]);
635
+
636
+ logs.shift();
637
+ before = Date.now();
638
+ ctx[method]("Hello, {a} {b} {c}!", { c: 3 });
639
+ after = Date.now();
640
+ assertEquals(logs, [
641
+ {
642
+ category: ["foo"],
643
+ level: method === "warn" ? "warning" : method,
644
+ message: ["Hello, ", 1, " ", 2, " ", 3, "!"],
645
+ rawMessage: "Hello, {a} {b} {c}!",
646
+ timestamp: logs[0].timestamp,
647
+ properties: { a: 1, b: 2, c: 3 },
648
+ },
649
+ ]);
650
+
651
+ logs.shift();
652
+ ctx[method]("Hello, world!");
653
+ assertEquals(logs, [
654
+ {
655
+ category: ["foo"],
656
+ level: method === "warn" ? "warning" : method,
657
+ message: ["Hello, world!"],
658
+ rawMessage: "Hello, world!",
659
+ timestamp: logs[0].timestamp,
660
+ properties: { a: 1, b: 2 },
661
+ },
662
+ ]);
663
+ } finally {
664
+ logger.resetDescendants();
665
+ }
666
+ });
667
+
668
+ test(`Logger.${method}() [lazy]`, () => {
669
+ const logger = LoggerImpl.getLogger("foo");
670
+ const ctx = new LoggerCtx(logger, { a: 1, b: 2 });
671
+
672
+ try {
673
+ const logs: LogRecord[] = [];
674
+ logger.sinks.push(logs.push.bind(logs));
675
+ let before = Date.now();
676
+ logger[method]("Hello, {foo}!", () => {
677
+ return { foo: 123 };
678
+ });
679
+ let after = Date.now();
680
+ assertEquals(logs, [
681
+ {
682
+ category: ["foo"],
683
+ level: method === "warn" ? "warning" : method,
684
+ message: ["Hello, ", 123, "!"],
685
+ rawMessage: "Hello, {foo}!",
686
+ timestamp: logs[0].timestamp,
687
+ properties: { foo: 123 },
688
+ },
689
+ ]);
690
+ assertGreaterOrEqual(logs[0].timestamp, before);
691
+ assertLessOrEqual(logs[0].timestamp, after);
692
+
693
+ logs.shift();
694
+ before = Date.now();
695
+ ctx[method]("Hello, {a} {b} {c}!", () => {
696
+ return { c: 3 };
697
+ });
698
+ after = Date.now();
699
+ assertEquals(logs, [
700
+ {
701
+ category: ["foo"],
702
+ level: method === "warn" ? "warning" : method,
703
+ message: ["Hello, ", 1, " ", 2, " ", 3, "!"],
704
+ rawMessage: "Hello, {a} {b} {c}!",
705
+ timestamp: logs[0].timestamp,
706
+ properties: { a: 1, b: 2, c: 3 },
707
+ },
708
+ ]);
709
+ assertGreaterOrEqual(logs[0].timestamp, before);
710
+ assertLessOrEqual(logs[0].timestamp, after);
711
+ } finally {
712
+ logger.resetDescendants();
713
+ }
714
+ });
715
+
716
+ test(`Logger.${method}() [with no message]`, () => {
717
+ const logger = LoggerImpl.getLogger("foo");
718
+
719
+ try {
720
+ const logs: LogRecord[] = [];
721
+ logger.sinks.push(logs.push.bind(logs));
722
+ const before = Date.now();
723
+ logger[method]({ foo: 123, bar: 456 });
724
+ const after = Date.now();
725
+ assertEquals(logs, [
726
+ {
727
+ category: ["foo"],
728
+ level: method === "warn" ? "warning" : method,
729
+ message: ["", { foo: 123, bar: 456 }, ""],
730
+ rawMessage: "{*}",
731
+ timestamp: logs[0].timestamp,
732
+ properties: { foo: 123, bar: 456 },
733
+ },
734
+ ]);
735
+ assertGreaterOrEqual(logs[0].timestamp, before);
736
+ assertLessOrEqual(logs[0].timestamp, after);
737
+ } finally {
738
+ logger.resetDescendants();
739
+ }
740
+ });
741
+ }
742
+
743
+ test("parseMessageTemplate()", () => {
744
+ assertEquals(parseMessageTemplate("Hello, world!", {}), ["Hello, world!"]);
745
+ assertEquals(
746
+ parseMessageTemplate("Hello, world!", { foo: 123 }),
747
+ ["Hello, world!"],
748
+ );
749
+ assertEquals(
750
+ parseMessageTemplate("Hello, {{world}}!", { foo: 123 }),
751
+ ["Hello, {world}!"],
752
+ );
753
+ assertEquals(
754
+ parseMessageTemplate("Hello, {foo}!", { foo: 123 }),
755
+ ["Hello, ", 123, "!"],
756
+ );
757
+ assertEquals(
758
+ parseMessageTemplate("Hello, { foo\t}!", { " foo\t": 123, foo: 456 }),
759
+ ["Hello, ", 123, "!"],
760
+ );
761
+ assertEquals(
762
+ parseMessageTemplate("Hello, { foo\t}!", { foo: 456 }),
763
+ ["Hello, ", 456, "!"],
764
+ );
765
+ assertEquals(
766
+ parseMessageTemplate("Hello, { foo\t}!", { " foo": 456 }),
767
+ ["Hello, ", undefined, "!"],
768
+ );
769
+ assertEquals(
770
+ parseMessageTemplate("Hello, {{foo}}!", { foo: 123 }),
771
+ ["Hello, {foo}!"],
772
+ );
773
+ assertEquals(
774
+ parseMessageTemplate("Hello, {bar}!", { foo: 123 }),
775
+ ["Hello, ", undefined, "!"],
776
+ );
777
+ assertEquals(
778
+ parseMessageTemplate("Hello, {bar}!", { foo: 123, bar: 456 }),
779
+ ["Hello, ", 456, "!"],
780
+ );
781
+ assertEquals(
782
+ parseMessageTemplate("Hello, {foo}, {bar}!", { foo: 123, bar: 456 }),
783
+ ["Hello, ", 123, ", ", 456, "!"],
784
+ );
785
+ assertEquals(
786
+ parseMessageTemplate("Hello, {foo}, {bar}", { foo: 123, bar: 456 }),
787
+ ["Hello, ", 123, ", ", 456, ""],
788
+ );
789
+ assertEquals(
790
+ parseMessageTemplate("Hello, {*}", { foo: 123, bar: 456 }),
791
+ ["Hello, ", { foo: 123, bar: 456 }, ""],
792
+ );
793
+ assertEquals(
794
+ parseMessageTemplate("Hello, { *\t}", { foo: 123, bar: 456 }),
795
+ ["Hello, ", { foo: 123, bar: 456 }, ""],
796
+ );
797
+ assertEquals(
798
+ parseMessageTemplate("Hello, {*}", { foo: 123, bar: 456, "*": 789 }),
799
+ ["Hello, ", 789, ""],
800
+ );
801
+ assertEquals(
802
+ parseMessageTemplate("Hello, { *\t}", { foo: 123, bar: 456, " *\t": 789 }),
803
+ ["Hello, ", 789, ""],
804
+ );
805
+ assertEquals(
806
+ parseMessageTemplate("Hello, { *\t}", { foo: 123, bar: 456, "*": 789 }),
807
+ ["Hello, ", 789, ""],
808
+ );
809
+ assertEquals(
810
+ parseMessageTemplate("Hello, {{world!", { foo: 123 }),
811
+ ["Hello, {world!"],
812
+ );
813
+ });
814
+
815
+ test("renderMessage()", () => {
816
+ function rm(tpl: TemplateStringsArray, ...values: unknown[]) {
817
+ return renderMessage(tpl, values);
818
+ }
819
+ assertEquals(rm`Hello, world!`, ["Hello, world!"]);
820
+ assertEquals(rm`Hello, ${123}!`, ["Hello, ", 123, "!"]);
821
+ assertEquals(rm`Hello, ${123}, ${456}!`, ["Hello, ", 123, ", ", 456, "!"]);
822
+ assertEquals(rm`Hello, ${123}, ${456}`, ["Hello, ", 123, ", ", 456, ""]);
823
+ });