@logtape/logtape 1.2.2 → 1.2.4

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.
@@ -1,569 +0,0 @@
1
- import { suite } from "@alinea/suite";
2
- import { assertEquals } from "@std/assert/equals";
3
- import { assertThrows } from "@std/assert/throws";
4
- import { fatal, info } from "./fixtures.ts";
5
- import {
6
- ansiColorFormatter,
7
- defaultConsoleFormatter,
8
- defaultTextFormatter,
9
- type FormattedValues,
10
- getAnsiColorFormatter,
11
- getJsonLinesFormatter,
12
- getTextFormatter,
13
- } from "./formatter.ts";
14
- import type { LogRecord } from "./record.ts";
15
-
16
- const test = suite(import.meta);
17
-
18
- test("getTextFormatter()", () => {
19
- assertEquals(
20
- getTextFormatter()(info),
21
- "2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, 123 & 456!\n",
22
- );
23
- assertEquals(
24
- getTextFormatter({ timestamp: "date" })(info),
25
- "2023-11-14 [INF] my-app·junk: Hello, 123 & 456!\n",
26
- );
27
- assertEquals(
28
- getTextFormatter({ timestamp: "date-time" })(info),
29
- "2023-11-14 22:13:20.000 [INF] my-app·junk: Hello, 123 & 456!\n",
30
- );
31
- assertEquals(
32
- getTextFormatter({ timestamp: "date-time-timezone" })(info),
33
- "2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, 123 & 456!\n",
34
- );
35
- assertEquals(
36
- getTextFormatter({ timestamp: "date-time-tz" })(info),
37
- "2023-11-14 22:13:20.000 +00 [INF] my-app·junk: Hello, 123 & 456!\n",
38
- );
39
- assertEquals(
40
- getTextFormatter({ timestamp: "none" })(info),
41
- "[INF] my-app·junk: Hello, 123 & 456!\n",
42
- );
43
- assertEquals(
44
- getTextFormatter({ timestamp: "disabled" })(info),
45
- "[INF] my-app·junk: Hello, 123 & 456!\n",
46
- );
47
- assertEquals(
48
- getTextFormatter({ timestamp: "rfc3339" })(info),
49
- "2023-11-14T22:13:20.000Z [INF] my-app·junk: Hello, 123 & 456!\n",
50
- );
51
- assertEquals(
52
- getTextFormatter({ timestamp: "time" })(info),
53
- "22:13:20.000 [INF] my-app·junk: Hello, 123 & 456!\n",
54
- );
55
- assertEquals(
56
- getTextFormatter({ timestamp: "time-timezone" })(info),
57
- "22:13:20.000 +00:00 [INF] my-app·junk: Hello, 123 & 456!\n",
58
- );
59
- assertEquals(
60
- getTextFormatter({ timestamp: "time-tz" })(info),
61
- "22:13:20.000 +00 [INF] my-app·junk: Hello, 123 & 456!\n",
62
- );
63
- assertEquals(
64
- getTextFormatter({
65
- timestamp(ts) {
66
- const t = new Date(ts);
67
- return t.toUTCString();
68
- },
69
- })(info),
70
- "Tue, 14 Nov 2023 22:13:20 GMT [INF] my-app·junk: Hello, 123 & 456!\n",
71
- );
72
-
73
- assertEquals(
74
- getTextFormatter({ level: "ABBR" })(info),
75
- "2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, 123 & 456!\n",
76
- );
77
- assertEquals(
78
- getTextFormatter({ level: "FULL" })(info),
79
- "2023-11-14 22:13:20.000 +00:00 [INFO] my-app·junk: Hello, 123 & 456!\n",
80
- );
81
- assertEquals(
82
- getTextFormatter({ level: "L" })(info),
83
- "2023-11-14 22:13:20.000 +00:00 [I] my-app·junk: Hello, 123 & 456!\n",
84
- );
85
- assertEquals(
86
- getTextFormatter({ level: "abbr" })(info),
87
- "2023-11-14 22:13:20.000 +00:00 [inf] my-app·junk: Hello, 123 & 456!\n",
88
- );
89
- assertEquals(
90
- getTextFormatter({ level: "full" })(info),
91
- "2023-11-14 22:13:20.000 +00:00 [info] my-app·junk: Hello, 123 & 456!\n",
92
- );
93
- assertEquals(
94
- getTextFormatter({ level: "l" })(info),
95
- "2023-11-14 22:13:20.000 +00:00 [i] my-app·junk: Hello, 123 & 456!\n",
96
- );
97
- assertEquals(
98
- getTextFormatter({
99
- level(level) {
100
- return level.at(-1) ?? "";
101
- },
102
- })(info),
103
- "2023-11-14 22:13:20.000 +00:00 [o] my-app·junk: Hello, 123 & 456!\n",
104
- );
105
-
106
- assertEquals(
107
- getTextFormatter({ category: "." })(info),
108
- "2023-11-14 22:13:20.000 +00:00 [INF] my-app.junk: Hello, 123 & 456!\n",
109
- );
110
- assertEquals(
111
- getTextFormatter({
112
- category(category) {
113
- return `<${category.join("/")}>`;
114
- },
115
- })(info),
116
- "2023-11-14 22:13:20.000 +00:00 [INF] <my-app/junk>: Hello, 123 & 456!\n",
117
- );
118
-
119
- assertEquals(
120
- getTextFormatter({
121
- value(value) {
122
- return typeof value;
123
- },
124
- })(info),
125
- "2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, number & number!\n",
126
- );
127
-
128
- // Test the inspect parameter fallback
129
- assertEquals(
130
- getTextFormatter({
131
- value(value, inspect) {
132
- // Custom formatting for numbers, fallback to inspect for others
133
- if (typeof value === "number") {
134
- return `NUM(${value})`;
135
- }
136
- return inspect(value);
137
- },
138
- })(info),
139
- "2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, NUM(123) & NUM(456)!\n",
140
- );
141
-
142
- // Test inspect fallback with objects
143
- const recordWithObject: LogRecord = {
144
- level: "info",
145
- category: ["test"],
146
- message: ["Data: ", { foo: "bar", baz: 42 }, ""],
147
- rawMessage: "Data: {}",
148
- timestamp: 1700000000000,
149
- properties: {},
150
- };
151
- const resultWithObject = getTextFormatter({
152
- value(value, inspect) {
153
- // For objects, use inspect without colors
154
- if (typeof value === "object" && value !== null) {
155
- return inspect(value, { colors: false });
156
- }
157
- return String(value);
158
- },
159
- })(recordWithObject);
160
- // Should contain the object keys
161
- assertEquals(resultWithObject.includes("foo"), true);
162
- assertEquals(resultWithObject.includes("bar"), true);
163
- assertEquals(resultWithObject.includes("baz"), true);
164
-
165
- let recordedValues: FormattedValues | null = null;
166
- assertEquals(
167
- getTextFormatter({
168
- format(values) {
169
- recordedValues = values;
170
- const { timestamp, level, category, message } = values;
171
- return `${level} <${category}> ${message} ${timestamp}`;
172
- },
173
- })(info),
174
- "INF <my-app·junk> Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00\n",
175
- );
176
- assertEquals(
177
- recordedValues,
178
- {
179
- timestamp: "2023-11-14 22:13:20.000 +00:00",
180
- level: "INF",
181
- category: "my-app·junk",
182
- message: "Hello, 123 & 456!",
183
- record: info,
184
- },
185
- );
186
-
187
- const longArray = new Array(150).fill(0);
188
- const longStringAndArray: LogRecord = {
189
- level: "info",
190
- category: ["my-app", "junk"],
191
- message: ["Hello, ", "a".repeat(15000), " & ", longArray, "!"],
192
- rawMessage: "Hello, {a} & {b}!",
193
- timestamp: 1700000000000,
194
- properties: {},
195
- };
196
- let longArrayStr = "[\n";
197
- for (let i = 0; i < Math.floor(longArray.length / 12); i++) {
198
- longArrayStr += " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n";
199
- }
200
- for (let i = 0; i < longArray.length % 12; i++) {
201
- if (i < 1) longArrayStr += " 0";
202
- else longArrayStr += ", 0";
203
- if (i === longArray.length % 12 - 1) longArrayStr += "\n";
204
- }
205
- longArrayStr += "]";
206
- // dnt-shim-ignore
207
- if ("Deno" in globalThis) {
208
- assertEquals(
209
- getTextFormatter()(longStringAndArray),
210
- `2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, "${
211
- "a".repeat(15000)
212
- }" & ${longArrayStr}!\n`,
213
- );
214
- } else {
215
- assertEquals(
216
- getTextFormatter()(longStringAndArray),
217
- `2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, '${
218
- "a".repeat(15000)
219
- }' & ${longArrayStr}!\n`,
220
- );
221
- }
222
- });
223
-
224
- test("defaultTextFormatter()", () => {
225
- assertEquals(
226
- defaultTextFormatter(info),
227
- "2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, 123 & 456!\n",
228
- );
229
- assertEquals(
230
- defaultTextFormatter(fatal),
231
- "2023-11-14 22:13:20.000 +00:00 [FTL] my-app·junk: Hello, 123 & 456!\n",
232
- );
233
- });
234
-
235
- test("getAnsiColorFormatter()", () => {
236
- assertEquals(
237
- getAnsiColorFormatter()(info),
238
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
239
- "\x1b[1m\x1b[32mINF\x1b[0m " +
240
- "\x1b[2mmy-app·junk:\x1b[0m " +
241
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
242
- );
243
- assertEquals(
244
- getAnsiColorFormatter({ timestampStyle: "bold" })(info),
245
- "\x1b[1m2023-11-14 22:13:20.000 +00\x1b[0m " +
246
- "\x1b[1m\x1b[32mINF\x1b[0m " +
247
- "\x1b[2mmy-app·junk:\x1b[0m " +
248
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
249
- );
250
- assertEquals(
251
- getAnsiColorFormatter({ timestampStyle: null })(info),
252
- "2023-11-14 22:13:20.000 +00 " +
253
- "\x1b[1m\x1b[32mINF\x1b[0m " +
254
- "\x1b[2mmy-app·junk:\x1b[0m " +
255
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
256
- );
257
-
258
- assertEquals(
259
- getAnsiColorFormatter({ timestampColor: "cyan" })(info),
260
- "\x1b[2m\x1b[36m2023-11-14 22:13:20.000 +00\x1b[0m " +
261
- "\x1b[1m\x1b[32mINF\x1b[0m " +
262
- "\x1b[2mmy-app·junk:\x1b[0m " +
263
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
264
- );
265
- assertEquals(
266
- getAnsiColorFormatter({ timestampColor: null })(info),
267
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
268
- "\x1b[1m\x1b[32mINF\x1b[0m " +
269
- "\x1b[2mmy-app·junk:\x1b[0m " +
270
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
271
- );
272
- assertEquals(
273
- getAnsiColorFormatter({ timestampStyle: null, timestampColor: "cyan" })(
274
- info,
275
- ),
276
- "\x1b[36m2023-11-14 22:13:20.000 +00\x1b[0m " +
277
- "\x1b[1m\x1b[32mINF\x1b[0m " +
278
- "\x1b[2mmy-app·junk:\x1b[0m " +
279
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
280
- );
281
- assertEquals(
282
- getAnsiColorFormatter({ timestampStyle: null, timestampColor: null })(info),
283
- "2023-11-14 22:13:20.000 +00 " +
284
- "\x1b[1m\x1b[32mINF\x1b[0m " +
285
- "\x1b[2mmy-app·junk:\x1b[0m " +
286
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
287
- );
288
-
289
- assertEquals(
290
- getAnsiColorFormatter({ levelStyle: null })(info),
291
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
292
- "\x1b[32mINF\x1b[0m " +
293
- "\x1b[2mmy-app·junk:\x1b[0m " +
294
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
295
- );
296
- assertEquals(
297
- getAnsiColorFormatter({ levelStyle: "dim" })(info),
298
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
299
- "\x1b[2m\x1b[32mINF\x1b[0m " +
300
- "\x1b[2mmy-app·junk:\x1b[0m " +
301
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
302
- );
303
-
304
- assertEquals(
305
- getAnsiColorFormatter({
306
- levelColors: {
307
- trace: null,
308
- debug: "blue",
309
- info: "cyan",
310
- warning: "yellow",
311
- error: "red",
312
- fatal: "magenta",
313
- },
314
- })(info),
315
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
316
- "\x1b[1m\x1b[36mINF\x1b[0m " +
317
- "\x1b[2mmy-app·junk:\x1b[0m " +
318
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
319
- );
320
- assertEquals(
321
- getAnsiColorFormatter({
322
- levelColors: {
323
- trace: null,
324
- debug: "blue",
325
- info: null,
326
- warning: "yellow",
327
- error: "red",
328
- fatal: "magenta",
329
- },
330
- levelStyle: null,
331
- })(info),
332
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m INF " +
333
- "\x1b[2mmy-app·junk:\x1b[0m " +
334
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
335
- );
336
-
337
- assertEquals(
338
- getAnsiColorFormatter({ categoryStyle: "bold" })(info),
339
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
340
- "\x1b[1m\x1b[32mINF\x1b[0m " +
341
- "\x1b[1mmy-app·junk:\x1b[0m " +
342
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
343
- );
344
- assertEquals(
345
- getAnsiColorFormatter({ categoryStyle: null })(info),
346
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
347
- "\x1b[1m\x1b[32mINF\x1b[0m " +
348
- "my-app·junk: " +
349
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
350
- );
351
-
352
- assertEquals(
353
- getAnsiColorFormatter({ categoryColor: "cyan" })(info),
354
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
355
- "\x1b[1m\x1b[32mINF\x1b[0m " +
356
- "\x1b[2m\x1b[36mmy-app·junk:\x1b[0m " +
357
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
358
- );
359
-
360
- let recordedValues: FormattedValues | null = null;
361
- assertEquals(
362
- getAnsiColorFormatter({
363
- format(values) {
364
- recordedValues = values;
365
- const { timestamp, level, category, message } = values;
366
- return `${level} <${category}> ${message} ${timestamp}`;
367
- },
368
- })(info),
369
- "\x1b[1m\x1b[32mINF\x1b[0m " +
370
- "<\x1b[2mmy-app·junk\x1b[0m> " +
371
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m! " +
372
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m\n",
373
- );
374
- assertEquals(
375
- recordedValues,
376
- {
377
- timestamp: "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m",
378
- level: "\x1b[1m\x1b[32mINF\x1b[0m",
379
- category: "\x1b[2mmy-app·junk\x1b[0m",
380
- message: "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!",
381
- record: info,
382
- },
383
- );
384
- });
385
-
386
- test("ansiColorFormatter()", () => {
387
- assertEquals(
388
- ansiColorFormatter(info),
389
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
390
- "\x1b[1m\x1b[32mINF\x1b[0m " +
391
- "\x1b[2mmy-app·junk:\x1b[0m " +
392
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
393
- );
394
- assertEquals(
395
- ansiColorFormatter(fatal),
396
- "\x1b[2m2023-11-14 22:13:20.000 +00\x1b[0m " +
397
- "\x1b[1m\x1b[35mFTL\x1b[0m " +
398
- "\x1b[2mmy-app·junk:\x1b[0m " +
399
- "Hello, \x1b[33m123\x1b[39m & \x1b[33m456\x1b[39m!\n",
400
- );
401
- });
402
-
403
- test("defaultConsoleFormatter()", () => {
404
- assertEquals(
405
- defaultConsoleFormatter(info),
406
- [
407
- "%c22:13:20.000 %cINF%c %cmy-app·junk %cHello, %o & %o!",
408
- "color: gray;",
409
- "background-color: white; color: black;",
410
- "background-color: default;",
411
- "color: gray;",
412
- "color: default;",
413
- 123,
414
- 456,
415
- ],
416
- );
417
- });
418
-
419
- test("getJsonLinesFormatter()", () => {
420
- const logRecord: LogRecord = {
421
- level: "info",
422
- category: ["my-app", "junk"],
423
- message: ["Hello, ", 123, " & ", 456, "!"],
424
- rawMessage: "Hello, {a} & {b}!",
425
- timestamp: 1700000000000,
426
- properties: { userId: "12345", requestId: "abc-def" },
427
- };
428
-
429
- const warningRecord: LogRecord = {
430
- level: "warning",
431
- category: ["auth"],
432
- message: ["Login failed for ", "user@example.com"],
433
- // @ts-ignore: Mimicking a raw message with a template string
434
- rawMessage: ["Login failed for ", ""],
435
- timestamp: 1700000000000,
436
- properties: { attempt: 3 },
437
- };
438
-
439
- { // default options
440
- const formatter = getJsonLinesFormatter();
441
- const result = JSON.parse(formatter(logRecord));
442
-
443
- assertEquals(result["@timestamp"], "2023-11-14T22:13:20.000Z");
444
- assertEquals(result.level, "INFO");
445
- assertEquals(result.message, "Hello, 123 & 456!");
446
- assertEquals(result.logger, "my-app.junk");
447
- assertEquals(result.properties, { userId: "12345", requestId: "abc-def" });
448
- }
449
-
450
- { // warning level converts to WARN
451
- const formatter = getJsonLinesFormatter();
452
- const result = JSON.parse(formatter(warningRecord));
453
- assertEquals(result.level, "WARN");
454
- }
455
-
456
- { // categorySeparator string option
457
- const formatter = getJsonLinesFormatter({ categorySeparator: "/" });
458
- const result = JSON.parse(formatter(logRecord));
459
- assertEquals(result.logger, "my-app/junk");
460
- }
461
-
462
- { // categorySeparator function option
463
- const formatter = getJsonLinesFormatter({
464
- categorySeparator: (category) => category.join("::").toUpperCase(),
465
- });
466
- const result = JSON.parse(formatter(logRecord));
467
- assertEquals(result.logger, "MY-APP::JUNK");
468
- }
469
-
470
- { // categorySeparator function returning array
471
- const formatter = getJsonLinesFormatter({
472
- categorySeparator: (category) => category,
473
- });
474
- const result = JSON.parse(formatter(logRecord));
475
- assertEquals(result.logger, ["my-app", "junk"]);
476
- }
477
-
478
- { // message template option
479
- const formatter = getJsonLinesFormatter({ message: "template" });
480
- const result = JSON.parse(formatter(logRecord));
481
- assertEquals(result.message, "Hello, {a} & {b}!");
482
-
483
- const result2 = JSON.parse(formatter(warningRecord));
484
- assertEquals(result2.message, "Login failed for {}");
485
- }
486
-
487
- { // message template with string rawMessage
488
- const stringRawRecord: LogRecord = {
489
- ...logRecord,
490
- rawMessage: "Simple string message",
491
- };
492
- const formatter = getJsonLinesFormatter({ message: "template" });
493
- const result = JSON.parse(formatter(stringRawRecord));
494
- assertEquals(result.message, "Simple string message");
495
- }
496
-
497
- { // message rendered option (default)
498
- const formatter = getJsonLinesFormatter({ message: "rendered" });
499
- const result = JSON.parse(formatter(logRecord));
500
- assertEquals(result.message, "Hello, 123 & 456!");
501
- }
502
-
503
- { // properties flatten option
504
- const formatter = getJsonLinesFormatter({ properties: "flatten" });
505
- const result = JSON.parse(formatter(logRecord));
506
- assertEquals(result.userId, "12345");
507
- assertEquals(result.requestId, "abc-def");
508
- assertEquals(result.properties, undefined);
509
- }
510
-
511
- { // properties prepend option
512
- const formatter = getJsonLinesFormatter({ properties: "prepend:ctx_" });
513
- const result = JSON.parse(formatter(logRecord));
514
- assertEquals(result.ctx_userId, "12345");
515
- assertEquals(result.ctx_requestId, "abc-def");
516
- assertEquals(result.properties, undefined);
517
- }
518
-
519
- { // properties nest option
520
- const formatter = getJsonLinesFormatter({ properties: "nest:context" });
521
- const result = JSON.parse(formatter(logRecord));
522
- assertEquals(result.context, { userId: "12345", requestId: "abc-def" });
523
- assertEquals(result.properties, undefined);
524
- }
525
-
526
- { // properties nest option (default)
527
- const formatter = getJsonLinesFormatter();
528
- const result = JSON.parse(formatter(logRecord));
529
- assertEquals(result.properties, { userId: "12345", requestId: "abc-def" });
530
- }
531
-
532
- { // invalid properties option - empty prepend prefix
533
- assertThrows(
534
- () => getJsonLinesFormatter({ properties: "prepend:" }),
535
- TypeError,
536
- 'Invalid properties option: "prepend:". It must be of the form "prepend:<prefix>" where <prefix> is a non-empty string.',
537
- );
538
- }
539
-
540
- { // invalid properties option - invalid format
541
- assertThrows(
542
- () =>
543
- getJsonLinesFormatter({
544
- // @ts-ignore: Intentionally invalid type for testing
545
- properties: "invalid:option",
546
- }),
547
- TypeError,
548
- 'Invalid properties option: "invalid:option". It must be "flatten", "prepend:<prefix>", or "nest:<key>".',
549
- );
550
- }
551
-
552
- { // combined options
553
- const formatter = getJsonLinesFormatter({
554
- categorySeparator: "::",
555
- message: "template",
556
- properties: "prepend:prop_",
557
- });
558
- const result = JSON.parse(formatter(logRecord));
559
-
560
- assertEquals(result, {
561
- "@timestamp": "2023-11-14T22:13:20.000Z",
562
- level: "INFO",
563
- message: "Hello, {a} & {b}!",
564
- logger: "my-app::junk",
565
- prop_userId: "12345",
566
- prop_requestId: "abc-def",
567
- });
568
- }
569
- });