@logtape/logtape 0.5.0-dev.67 → 0.5.0-dev.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,9 +36,6 @@ The highlights of LogTape are:
36
36
 
37
37
  - *Dead simple sinks*: You can easily add your own sinks to LogTape.
38
38
 
39
- Currently, LogTape provides only few sinks, but [you can easily add your own
40
- sinks.](#sinks)
41
-
42
39
  ![](./screenshots/web-console.png)
43
40
  ![](./screenshots/terminal-console.png)
44
41
 
@@ -67,536 +64,8 @@ bun add @logtape/logtape # for Bun
67
64
  ~~~~
68
65
 
69
66
 
70
- Quick start
71
- -----------
72
-
73
- Set up LogTape in the entry point of your application (if you are composing
74
- a library, you should not set up LogTape in the library itself; it is up to
75
- the application to set up LogTape):
76
-
77
- ~~~~ typescript
78
- import { configure, getConsoleSink } from "@logtape/logtape";
79
-
80
- await configure({
81
- sinks: { console: getConsoleSink() },
82
- filters: {},
83
- loggers: [
84
- { category: "my-app", level: "debug", sinks: ["console"] }
85
- ]
86
- });
87
- ~~~~
88
-
89
- And then you can use LogTape in your application or library:
90
-
91
- ~~~~ typescript
92
- import { getLogger } from "@logtape/logtape";
93
-
94
- const logger = getLogger(["my-app", "my-module"]);
95
-
96
- export function myFunc(value: number): void {
97
- logger.debug `Hello, ${value}!`;
98
- }
99
- ~~~~
100
-
101
-
102
- How to log
103
- ----------
104
-
105
- There are total 5 log levels: `debug`, `info`, `warning`, `error`, `fatal` (in
106
- the order of verbosity). You can log messages with the following syntax:
107
-
108
- ~~~~ typescript
109
- logger.debug `This is a debug message with ${value}.`;
110
- logger.info `This is an info message with ${value}.`;
111
- logger.warn `This is a warning message with ${value}.`;
112
- logger.error `This is an error message with ${value}.`;
113
- logger.fatal `This is a fatal message with ${value}.`;
114
- ~~~~
115
-
116
- You can also log messages with a function call. In this case, log messages
117
- are structured data:
118
-
119
- ~~~~ typescript
120
- logger.debug("This is a debug message with {value}.", { value });
121
- logger.info("This is an info message with {value}.", { value });
122
- logger.warn("This is a warning message with {value}.", { value });
123
- logger.error("This is an error message with {value}.", { value });
124
- logger.fatal("This is a fatal message with {value}.", { value });
125
- ~~~~
126
-
127
- Sometimes, values to be logged are expensive to compute. In such cases, you
128
- can use a function to defer the computation so that it is only computed when
129
- the log message is actually logged:
130
-
131
- ~~~~ typescript
132
- logger.debug(l => l`This is a debug message with ${computeValue()}.`);
133
- logger.debug("Or you can use a function call: {value}.", () => {
134
- return { value: computeValue() };
135
- });
136
- ~~~~
137
-
138
- When using the function call, the way to log single curly braces `{` is to
139
- double the brace `{{`:
140
-
141
- ~~~~ typescript
142
- logger.debug("This logs {{single}} curly braces.");
143
- ~~~~
144
-
145
-
146
- Categories
147
- ----------
148
-
149
- LogTape uses a hierarchical category system to manage loggers. A category is
150
- a list of strings. For example, `["my-app", "my-module"]` is a category.
151
-
152
- When you log a message, it is dispatched to all loggers whose categories are
153
- prefixes of the category of the logger. For example, if you log a message
154
- with the category `["my-app", "my-module", "my-submodule"]`, it is dispatched
155
- to loggers whose categories are `["my-app", "my-module"]` and `["my-app"]`.
156
-
157
- This behavior allows you to control the verbosity of log messages by setting
158
- the log level of loggers at different levels of the category hierarchy.
159
-
160
- Here's an example of setting log levels for different categories:
161
-
162
- ~~~~ typescript
163
- import { configure, getConsoleSink } from "@logtape/logtape";
164
-
165
- await configure({
166
- sinks: {
167
- console: getConsoleSink(),
168
- },
169
- filters: {},
170
- loggers: [
171
- { category: ["my-app"], level: "info", sinks: ["console"] },
172
- { category: ["my-app", "my-module"], level: "debug", sinks: ["console"] },
173
- ],
174
- })
175
- ~~~~
176
-
177
-
178
- Contexts
179
- --------
180
-
181
- *Contexts are available since LogTape 0.5.0.*
182
-
183
- LogTape provides a context system to reuse the same properties across log
184
- messages. A context is a key-value map. You can set a context for a logger
185
- and log messages with the context. Here's an example of setting a context
186
- for a logger:
187
-
188
- ~~~~ typescript
189
- const logger = getLogger(["my-app", "my-module"]);
190
- const ctx = logger.with({ userId: 1234, requestId: "abc" });
191
- ctx.info `This log message will have the context (userId & requestId).`;
192
- ctx.warn("Context can be used inside message template: {userId}, {requestId}.");
193
- ~~~~
194
-
195
- The context is inherited by child loggers. Here's an example of setting a
196
- context for a parent logger and logging messages with a child logger:
197
-
198
- ~~~~ typescript
199
- const logger = getLogger(["my-app"]);
200
- const parentCtx = logger.with({ userId: 1234, requestId: "abc" });
201
- const childCtx = parentCtx.getLogger(["my-module"]);
202
- childCtx.debug("This log message will have the context: {userId} {requestId}.");
203
- ~~~~
204
-
205
- Contexts are particularly useful when you want to do structured logging.
206
-
207
-
208
- Sinks
209
- -----
210
-
211
- A sink is a destination of log messages. LogTape currently provides a few
212
- sinks: console and stream. However, you can easily add your own sinks.
213
- The signature of a sink is:
214
-
215
- ~~~~ typescript
216
- export type Sink = (record: LogRecord) => void;
217
- ~~~~
218
-
219
- Here's a simple example of a sink that writes log messages to console:
220
-
221
- ~~~~ typescript
222
- import { configure } from "@logtape/logtape";
223
-
224
- await configure({
225
- sinks: {
226
- console(record) {
227
- console.log(record.message);
228
- }
229
- },
230
- // Omitted for brevity
231
- });
232
- ~~~~
233
-
234
- ### Console sink
235
-
236
- Of course, you don't have to implement your own console sink because LogTape
237
- provides a console sink:
238
-
239
- ~~~~ typescript
240
- import { configure, getConsoleSink } from "@logtape/logtape";
241
-
242
- await configure({
243
- sinks: {
244
- console: getConsoleSink(),
245
- },
246
- // Omitted for brevity
247
- });
248
- ~~~~
249
-
250
- See also [`getConsoleSink()`] function and [`ConsoleSinkOptions`] interface
251
- in the API reference for more details.
252
-
253
- [`getConsoleSink()`]: https://jsr.io/@logtape/logtape/doc/~/getConsoleSink
254
- [`ConsoleSinkOptions`]: https://jsr.io/@logtape/logtape/doc/~/ConsoleSinkOptions
255
-
256
- ### Stream sink
257
-
258
- Another built-in sink is a stream sink. It writes log messages to
259
- a [`WritableStream`]. Here's an example of a stream sink that writes log
260
- messages to the standard error:
261
-
262
- ~~~~ typescript
263
- // Deno:
264
- await configure({
265
- sinks: {
266
- stream: getStreamSink(Deno.stderr.writable),
267
- },
268
- // Omitted for brevity
269
- });
270
- ~~~~
271
-
272
- ~~~~ typescript
273
- // Node.js:
274
- import stream from "node:stream";
275
-
276
- await configure({
277
- sinks: {
278
- stream: getStreamSink(stream.Writable.toWeb(process.stderr)),
279
- },
280
- // Omitted for brevity
281
- });
282
- ~~~~
283
-
284
- > [!NOTE]
285
- > Here we use `WritableStream` from the Web Streams API. If you are using
286
- > Node.js, you cannot directly pass `process.stderr` to `getStreamSink` because
287
- > `process.stderr` is not a `WritableStream` but a [`Writable`], which is a
288
- > Node.js stream. You can use [`Writable.toWeb()`] method to convert a Node.js
289
- > stream to a `WritableStream`.
290
-
291
- See also [`getStreamSink()`] function and [`StreamSinkOptions`] interface
292
- in the API reference for more details.
293
-
294
- [`WritableStream`]: https://developer.mozilla.org/en-US/docs/Web/API/WritableStream
295
- [`Writable`]: https://nodejs.org/api/stream.html#class-streamwritable
296
- [`Writable.toWeb()`]: https://nodejs.org/api/stream.html#streamwritabletowebstreamwritable
297
- [`getStreamSink()`]: https://jsr.io/@logtape/logtape/doc/~/getStreamSink
298
- [`StreamSinkOptions`]: https://jsr.io/@logtape/logtape/doc/~/StreamSinkOptions
299
-
300
- ### File sink
301
-
302
- > [!NOTE]
303
- > File sink is unavailable in the browser environment.
304
-
305
- LogTape provides a file sink as well. Here's an example of a file sink that
306
- writes log messages to a file:
307
-
308
- ~~~~ typescript
309
- import { getFileSink } from "@logtape/logtape";
310
-
311
- await configure({
312
- sinks: {
313
- file: getFileSink("my-app.log"),
314
- },
315
- // Omitted for brevity
316
- });
317
- ~~~~
318
-
319
- See also [`getFileSink()`] function and [`FileSinkOptions`] interface
320
- in the API reference for more details.
321
-
322
- > [!NOTE]
323
- > On Deno, you need to have the `--allow-write` flag and the `--unstable-fs`
324
- > flag to use the file sink.
325
-
326
- [`getFileSink()`]: https://jsr.io/@logtape/logtape/doc/~/getFileSink
327
- [`FileSinkOptions`]: https://jsr.io/@logtape/logtape/doc/~/FileSinkOptions
328
-
329
- ### Rotating file sink
330
-
331
- > [!NOTE]
332
- > Rotating file sink is unavailable in the browser environment.
333
-
334
- A rotating file sink is a file sink that rotates log files. It creates a new
335
- log file when the current log file reaches a certain size. Here's an example
336
- of a rotating file sink that writes log messages to a file:
337
-
338
- ~~~~ typescript
339
- import { getRotatingFileSink } from "@logtape/logtape";
340
-
341
- await configure({
342
- sinks: {
343
- file: getRotatingFileSink("my-app.log", {
344
- maxFileSize: 1024 * 1024, // 1 MiB
345
- maxFiles: 5,
346
- }),
347
- },
348
- // Omitted for brevity
349
- });
350
- ~~~~
351
-
352
- Rotated log files are named with a suffix like *.1*, *.2*, *.3*, and so on.
353
-
354
- For more details, see [`getRotatingFileSink()`] function and
355
- [`RotatingFileSinkOptions`] interface in the API reference.
356
-
357
- > [!NOTE]
358
- > On Deno, you need to have the `--allow-write` flag and the `--unstable-fs`
359
- > flag to use the rotating file sink.
360
-
361
- [`getRotatingFileSink()`]: https://jsr.io/@logtape/logtape/doc/~/getRotatingFileSink
362
- [`RotatingFileSinkOptions`]: https://jsr.io/@logtape/logtape/doc/~/RotatingFileSinkOptions
363
-
364
- ### Text formatter
365
-
366
- A stream sink and a file sink write log messages in a plain text format.
367
- You can customize the format by providing a text formatter. The type of a
368
- text formatter is:
369
-
370
- ~~~~ typescript
371
- export type TextFormatter = (record: LogRecord) => string;
372
- ~~~~
373
-
374
- Here's an example of a text formatter that writes log messages in a [JSON Lines]
375
- format:
376
-
377
- ~~~~ typescript
378
- await configure({
379
- sinks: {
380
- stream: getFileSink("log.jsonl", {
381
- formatter(log) {
382
- return JSON.stringify(log) + "\n",
383
- }
384
- }),
385
- },
386
- // Omitted for brevity
387
- })
388
- ~~~~
389
-
390
- > [!TIP]
391
- > If you want to monitor log messages formatted in JSON Lines in real-time
392
- > readably, you can utilize the `tail` and [`jq`] commands:
393
- >
394
- > ~~~~ sh
395
- > tail -f log.jsonl | jq .
396
- > ~~~~
397
-
398
- [JSON Lines]: https://jsonlines.org/
399
- [`jq`]: https://jqlang.github.io/jq/
400
-
401
- ### OpenTelemetry sink
402
-
403
- If you have an [OpenTelemetry] collector running, you can use the OpenTelemetry
404
- sink to send log messages to the collector using [@logtape/otel] package.
405
-
406
- For more details, see the documentation of [@logtape/otel].
407
-
408
- [OpenTelemetry]: https://opentelemetry.io/
409
- [@logtape/otel]: https://github.com/dahlia/logtape-otel
410
-
411
- ### Disposable sink
412
-
413
- > [!TIP]
414
- > If you are unfamiliar with the concept of disposables, see also the proposal
415
- > of *[ECMAScript Explicit Resource Management]*.
416
-
417
- A disposable sink is a sink that can be disposed of. They are automatically
418
- disposed of when the configuration is reset or the program exits. The type
419
- of a disposable sink is: `Sink & Disposable`. You can create a disposable
420
- sink by defining a `[Symbol.dispose]` method:
421
-
422
- ~~~~ typescript
423
- const disposableSink: Sink & Disposable = (record: LogRecord) => {
424
- console.log(record.message);
425
- };
426
- disposableSink[Symbol.dispose] = () => {
427
- console.log("Disposed!");
428
- };
429
- ~~~~
430
-
431
- A sink can be asynchronously disposed of as well. The type of an asynchronous
432
- disposable sink is: `Sink & AsyncDisposable`. You can create an asynchronous
433
- disposable sink by defining a `[Symbol.asyncDispose]` method:
434
-
435
- ~~~~ typescript
436
- const asyncDisposableSink: Sink & AsyncDisposable = (record: LogRecord) => {
437
- console.log(record.message);
438
- };
439
- asyncDisposableSink[Symbol.asyncDispose] = async () => {
440
- console.log("Disposed!");
441
- };
442
- ~~~~
443
-
444
- [ECMAScript Explicit Resource Management]: https://github.com/tc39/proposal-explicit-resource-management
445
-
446
- ### Explicit disposal
447
-
448
- You can explicitly dispose of a sink by calling the [`dispose()`] method. It is
449
- useful when you want to flush the buffer of a sink without blocking returning
450
- a response in edge functions. Here's an example of using the `dispose()`
451
- with [`ctx.waitUntil()`] in Cloudflare Workers:
452
-
453
- ~~~~ typescript
454
- import { configure, dispose } from "@logtape/logtape";
455
-
456
- export default {
457
- async fetch(request, env, ctx) {
458
- await configure({ /* ... */ });
459
- // ...
460
- ctx.waitUntil(dispose());
461
- }
462
- }
463
- ~~~~
464
-
465
- [`dispose()`]: https://jsr.io/@logtape/logtape/doc/~/dispose
466
- [`ctx.waitUntil()`]: https://developers.cloudflare.com/workers/runtime-apis/context/#waituntil
467
-
468
-
469
- Filters
470
- -------
471
-
472
- A filter is a function that filters log messages. A filter takes a log record
473
- and returns a boolean value. If the filter returns `true`, the log record is
474
- passed to the sinks; otherwise, the log record is discarded. Its signature is:
475
-
476
- ~~~~ typescript
477
- export type Filter = (record: LogRecord) => boolean;
478
- ~~~~
479
-
480
- For example, the following filter discards log messages whose property `elapsed`
481
- is less than 100 milliseconds:
482
-
483
- ~~~~ typescript
484
- import { configure, type LogRecord } from "@logtape/logtape";
485
-
486
- await configure({
487
- // Omitted for brevity
488
- filters: {
489
- tooSlow(record: LogRecord) {
490
- return "elapsed" in record.properties && record.properties.elapsed >= 100;
491
- },
492
- },
493
- loggers: [
494
- {
495
- category: ["my-app", "database"],
496
- level: "debug",
497
- sinks: ["console"],
498
- filters: ["tooSlow"],
499
- }
500
- ]
501
- });
502
- ~~~~
503
-
504
- ### Level filter
505
-
506
- LogTape provides a built-in level filter. You can use the level filter to
507
- filter log messages by their log levels. The level filter factory takes
508
- a [`LogLevel`] string and returns a level filter. For example, the following
509
- level filter discards log messages whose log level is less than `info`:
510
-
511
- ~~~~ typescript
512
- import { getLevelFilter } from "@logtape/logtape";
513
-
514
- await configure({
515
- filters: {
516
- infoOrHigher: getLevelFilter("info");
517
- },
518
- // Omitted for brevity
519
- });
520
- ~~~~
521
-
522
- [`LogLevel`]: https://jsr.io/@logtape/logtape/doc/~/LogLevel
523
-
524
- ### Sink filter
525
-
526
- A sink filter is a filter that is applied to a specific sink. You can add a
527
- sink filter to a sink by decorating the sink with [`withFilter()`]:
528
-
529
- ~~~~ typescript
530
- import { getConsoleSink, withFilter } from "@logtape/logtape";
531
-
532
- await configure({
533
- sinks: {
534
- filteredConsole: withFilter(
535
- getConsoleSink(),
536
- log => "elapsed" in log.properties && log.properties.elapsed >= 100,
537
- ),
538
- },
539
- // Omitted for brevity
540
- });
541
- ~~~~
542
-
543
- The `filteredConsoleSink` only logs messages whose property `elapsed` is greater
544
- than or equal to 100 milliseconds to the console.
545
-
546
- > [!TIP]
547
- > The `withFilter()` function can take a [`LogLevel`] string as the second
548
- > argument. In this case, the log messages whose log level is less than
549
- > the specified log level are discarded.
550
-
551
- [`withFilter()`]: https://jsr.io/@logtape/logtape/doc/~/withFilter
552
-
553
-
554
- Testing
555
- -------
556
-
557
- Here are some tips for testing your application or library with LogTape.
558
-
559
- ### Reset configuration
560
-
561
- You can reset the configuration of LogTape to its initial state. This is
562
- useful when you want to reset the configuration between tests. For example,
563
- the following code shows how to reset the configuration after a test
564
- (regardless of whether the test passes or fails) in Deno:
565
-
566
- ~~~~ typescript
567
- import { configure, reset } from "@logtape/logtape";
568
-
569
- Deno.test("my test", async (t) => {
570
- await t.step("set up", async () => {
571
- await configure({ /* ... */ });
572
- });
573
-
574
- await t.step("run test", () => {
575
- // Run the test
576
- });
577
-
578
- await t.step("tear down", async () => {
579
- await reset();
580
- });
581
- });
582
- ~~~~
583
-
584
- ### Buffer sink
585
-
586
- For testing purposes, you may want to collect log messages in memory. Although
587
- LogTape does not provide a built-in buffer sink, you can easily implement it:
588
-
589
- ~~~~ typescript
590
- import { type LogRecord, configure } from "@logtape/logtape";
591
-
592
- const buffer: LogRecord[] = [];
593
-
594
- await configure({
595
- sinks: {
596
- buffer: buffer.push.bind(buffer),
597
- },
598
- // Omitted for brevity
599
- });
600
- ~~~~
67
+ Docs
68
+ ----
601
69
 
602
- <!-- cSpell: ignore otel -->
70
+ The docs of LogTape is available at <https://logtape.org/>.
71
+ For the API references, see <https://jsr.io/@logtape/logtape>.
package/esm/config.js CHANGED
@@ -86,7 +86,7 @@ export async function configure(config) {
86
86
  if (cfg.level !== undefined)
87
87
  logger.filters.push(toFilter(cfg.level));
88
88
  for (const filterId of cfg.filters ?? []) {
89
- const filter = config.filters[filterId];
89
+ const filter = config.filters?.[filterId];
90
90
  if (filter === undefined) {
91
91
  await reset();
92
92
  throw new ConfigError(`Filter not found: ${filterId}.`);
@@ -102,7 +102,7 @@ export async function configure(config) {
102
102
  if (Symbol.dispose in sink)
103
103
  disposables.add(sink);
104
104
  }
105
- for (const filter of Object.values(config.filters)) {
105
+ for (const filter of Object.values(config.filters ?? {})) {
106
106
  if (filter == null || typeof filter === "string")
107
107
  continue;
108
108
  if (Symbol.asyncDispose in filter) {
package/esm/formatter.js CHANGED
@@ -11,10 +11,12 @@ const levelAbbreviations = {
11
11
  };
12
12
  /**
13
13
  * A platform-specific inspect function. In Deno, this is {@link Deno.inspect},
14
- * and in Node.js/Bun it is {@link util.inspect}. If neither is available, it
14
+ * and in Node.js/Bun it is `util.inspect()`. If neither is available, it
15
15
  * falls back to {@link JSON.stringify}.
16
16
  *
17
17
  * @param value The value to inspect.
18
+ * @param options The options for inspecting the value.
19
+ * If `colors` is `true`, the output will be ANSI-colored.
18
20
  * @returns The string representation of the value.
19
21
  */
20
22
  const inspect =
@@ -23,13 +25,13 @@ const inspect =
23
25
  // @ts-ignore: Deno global
24
26
  typeof globalThis.Deno.inspect === "function"
25
27
  // @ts-ignore: Deno global
26
- ? globalThis.Deno.inspect
28
+ ? globalThis.Deno.inspect.bind(globalThis.Deno)
27
29
  // @ts-ignore: Node.js global
28
30
  : "util" in dntShim.dntGlobalThis && "inspect" in globalThis.util &&
29
31
  // @ts-ignore: Node.js global
30
32
  globalThis.util.inspect === "function"
31
33
  // @ts-ignore: Node.js global
32
- ? globalThis.util.inspect
34
+ ? globalThis.util.inspect.bind(globalThis.util)
33
35
  : JSON.stringify;
34
36
  /**
35
37
  * The default text formatter. This formatter formats log records as follows:
@@ -53,6 +55,44 @@ export function defaultTextFormatter(record) {
53
55
  const category = record.category.join("\xb7");
54
56
  return `${ts.toISOString().replace("T", " ").replace("Z", " +00:00")} [${levelAbbreviations[record.level]}] ${category}: ${msg}\n`;
55
57
  }
58
+ const RESET = "\x1b[0m";
59
+ const BOLD = "\x1b[1m";
60
+ const DIM = "\x1b[2m";
61
+ const levelColors = {
62
+ debug: "\x1b[34m", // Blue
63
+ info: "\x1b[32m", // Green
64
+ warning: "\x1b[33m", // Yellow
65
+ error: "\x1b[31m", // Red
66
+ fatal: "\x1b[35m", // Magenta
67
+ };
68
+ /**
69
+ * A text formatter that uses ANSI colors to format log records.
70
+ *
71
+ * ![A preview of ansiColorFormatter.](https://i.imgur.com/I8LlBUf.png)
72
+ *
73
+ * @param record The log record to format.
74
+ * @returns The formatted log record.
75
+ * @since 0.5.0
76
+ */
77
+ export const ansiColorFormatter = (record) => {
78
+ const ts = new Date(record.timestamp);
79
+ const timeString = ts.toISOString().replace("T", " ").replace("Z", " +00");
80
+ const category = record.category.join("·");
81
+ const levelColor = levelColors[record.level];
82
+ const levelAbbr = levelAbbreviations[record.level];
83
+ let message = "";
84
+ for (let i = 0; i < record.message.length; i++) {
85
+ if (i % 2 === 0) {
86
+ message += record.message[i];
87
+ }
88
+ else {
89
+ message += inspect(record.message[i], { colors: true });
90
+ }
91
+ }
92
+ return `${DIM}${timeString}${RESET} ` +
93
+ `${BOLD}${levelColor}${levelAbbr}${RESET} ` +
94
+ `${DIM}${category}:${RESET} ${message}\n`;
95
+ };
56
96
  /**
57
97
  * The styles for the log level in the console.
58
98
  */
package/esm/mod.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { ConfigError, configure, dispose, getConfig, reset, } from "./config.js";
2
2
  export { getFileSink, getRotatingFileSink } from "./filesink.node.js";
3
3
  export { getLevelFilter, toFilter, } from "./filter.js";
4
- export { defaultConsoleFormatter, defaultTextFormatter, } from "./formatter.js";
4
+ export { ansiColorFormatter, defaultConsoleFormatter, defaultTextFormatter, } from "./formatter.js";
5
5
  export { isLogLevel, parseLogLevel } from "./level.js";
6
6
  export { getLogger } from "./logger.js";
7
7
  export { getConsoleSink, getStreamSink, withFilter, } from "./sink.js";
package/esm/sink.js CHANGED
@@ -73,17 +73,33 @@ export function getConsoleSink(options = {}) {
73
73
  const console = options.console ?? globalThis.console;
74
74
  return (record) => {
75
75
  const args = formatter(record);
76
- if (record.level === "debug")
77
- console.debug(...args);
78
- else if (record.level === "info")
79
- console.info(...args);
80
- else if (record.level === "warning")
81
- console.warn(...args);
82
- else if (record.level === "error" || record.level === "fatal") {
83
- console.error(...args);
76
+ if (typeof args === "string") {
77
+ const msg = args.replace(/\r?\n$/, "");
78
+ if (record.level === "debug")
79
+ console.debug(msg);
80
+ else if (record.level === "info")
81
+ console.info(msg);
82
+ else if (record.level === "warning")
83
+ console.warn(msg);
84
+ else if (record.level === "error" || record.level === "fatal") {
85
+ console.error(msg);
86
+ }
87
+ else
88
+ throw new TypeError(`Invalid log level: ${record.level}.`);
89
+ }
90
+ else {
91
+ if (record.level === "debug")
92
+ console.debug(...args);
93
+ else if (record.level === "info")
94
+ console.info(...args);
95
+ else if (record.level === "warning")
96
+ console.warn(...args);
97
+ else if (record.level === "error" || record.level === "fatal") {
98
+ console.error(...args);
99
+ }
100
+ else
101
+ throw new TypeError(`Invalid log level: ${record.level}.`);
84
102
  }
85
- else
86
- throw new TypeError(`Invalid log level: ${record.level}.`);
87
103
  };
88
104
  }
89
105
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logtape/logtape",
3
- "version": "0.5.0-dev.67+55ad4652",
3
+ "version": "0.5.0-dev.69+c1bead95",
4
4
  "description": "Simple logging library with zero dependencies for Deno/Node.js/Bun/browsers",
5
5
  "keywords": [
6
6
  "logging",
@@ -12,7 +12,7 @@
12
12
  "email": "hong@minhee.org",
13
13
  "url": "https://hongminhee.org/"
14
14
  },
15
- "homepage": "https://github.com/dahlia/logtape",
15
+ "homepage": "https://logtape.org/",
16
16
  "repository": {
17
17
  "type": "git",
18
18
  "url": "git+https://github.com/dahlia/logtape.git"
package/script/config.js CHANGED
@@ -116,7 +116,7 @@ async function configure(config) {
116
116
  if (cfg.level !== undefined)
117
117
  logger.filters.push((0, filter_js_1.toFilter)(cfg.level));
118
118
  for (const filterId of cfg.filters ?? []) {
119
- const filter = config.filters[filterId];
119
+ const filter = config.filters?.[filterId];
120
120
  if (filter === undefined) {
121
121
  await reset();
122
122
  throw new ConfigError(`Filter not found: ${filterId}.`);
@@ -132,7 +132,7 @@ async function configure(config) {
132
132
  if (Symbol.dispose in sink)
133
133
  disposables.add(sink);
134
134
  }
135
- for (const filter of Object.values(config.filters)) {
135
+ for (const filter of Object.values(config.filters ?? {})) {
136
136
  if (filter == null || typeof filter === "string")
137
137
  continue;
138
138
  if (Symbol.asyncDispose in filter) {
@@ -23,6 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.ansiColorFormatter = void 0;
26
27
  exports.defaultTextFormatter = defaultTextFormatter;
27
28
  exports.defaultConsoleFormatter = defaultConsoleFormatter;
28
29
  const dntShim = __importStar(require("./_dnt.shims.js"));
@@ -38,10 +39,12 @@ const levelAbbreviations = {
38
39
  };
39
40
  /**
40
41
  * A platform-specific inspect function. In Deno, this is {@link Deno.inspect},
41
- * and in Node.js/Bun it is {@link util.inspect}. If neither is available, it
42
+ * and in Node.js/Bun it is `util.inspect()`. If neither is available, it
42
43
  * falls back to {@link JSON.stringify}.
43
44
  *
44
45
  * @param value The value to inspect.
46
+ * @param options The options for inspecting the value.
47
+ * If `colors` is `true`, the output will be ANSI-colored.
45
48
  * @returns The string representation of the value.
46
49
  */
47
50
  const inspect =
@@ -50,13 +53,13 @@ const inspect =
50
53
  // @ts-ignore: Deno global
51
54
  typeof globalThis.Deno.inspect === "function"
52
55
  // @ts-ignore: Deno global
53
- ? globalThis.Deno.inspect
56
+ ? globalThis.Deno.inspect.bind(globalThis.Deno)
54
57
  // @ts-ignore: Node.js global
55
58
  : "util" in dntShim.dntGlobalThis && "inspect" in globalThis.util &&
56
59
  // @ts-ignore: Node.js global
57
60
  globalThis.util.inspect === "function"
58
61
  // @ts-ignore: Node.js global
59
- ? globalThis.util.inspect
62
+ ? globalThis.util.inspect.bind(globalThis.util)
60
63
  : JSON.stringify;
61
64
  /**
62
65
  * The default text formatter. This formatter formats log records as follows:
@@ -80,6 +83,45 @@ function defaultTextFormatter(record) {
80
83
  const category = record.category.join("\xb7");
81
84
  return `${ts.toISOString().replace("T", " ").replace("Z", " +00:00")} [${levelAbbreviations[record.level]}] ${category}: ${msg}\n`;
82
85
  }
86
+ const RESET = "\x1b[0m";
87
+ const BOLD = "\x1b[1m";
88
+ const DIM = "\x1b[2m";
89
+ const levelColors = {
90
+ debug: "\x1b[34m", // Blue
91
+ info: "\x1b[32m", // Green
92
+ warning: "\x1b[33m", // Yellow
93
+ error: "\x1b[31m", // Red
94
+ fatal: "\x1b[35m", // Magenta
95
+ };
96
+ /**
97
+ * A text formatter that uses ANSI colors to format log records.
98
+ *
99
+ * ![A preview of ansiColorFormatter.](https://i.imgur.com/I8LlBUf.png)
100
+ *
101
+ * @param record The log record to format.
102
+ * @returns The formatted log record.
103
+ * @since 0.5.0
104
+ */
105
+ const ansiColorFormatter = (record) => {
106
+ const ts = new Date(record.timestamp);
107
+ const timeString = ts.toISOString().replace("T", " ").replace("Z", " +00");
108
+ const category = record.category.join("·");
109
+ const levelColor = levelColors[record.level];
110
+ const levelAbbr = levelAbbreviations[record.level];
111
+ let message = "";
112
+ for (let i = 0; i < record.message.length; i++) {
113
+ if (i % 2 === 0) {
114
+ message += record.message[i];
115
+ }
116
+ else {
117
+ message += inspect(record.message[i], { colors: true });
118
+ }
119
+ }
120
+ return `${DIM}${timeString}${RESET} ` +
121
+ `${BOLD}${levelColor}${levelAbbr}${RESET} ` +
122
+ `${DIM}${category}:${RESET} ${message}\n`;
123
+ };
124
+ exports.ansiColorFormatter = ansiColorFormatter;
83
125
  /**
84
126
  * The styles for the log level in the console.
85
127
  */
package/script/mod.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.withFilter = exports.getStreamSink = exports.getConsoleSink = exports.getLogger = exports.parseLogLevel = exports.isLogLevel = exports.defaultTextFormatter = exports.defaultConsoleFormatter = exports.toFilter = exports.getLevelFilter = exports.getRotatingFileSink = exports.getFileSink = exports.reset = exports.getConfig = exports.dispose = exports.configure = exports.ConfigError = void 0;
3
+ exports.withFilter = exports.getStreamSink = exports.getConsoleSink = exports.getLogger = exports.parseLogLevel = exports.isLogLevel = exports.defaultTextFormatter = exports.defaultConsoleFormatter = exports.ansiColorFormatter = exports.toFilter = exports.getLevelFilter = exports.getRotatingFileSink = exports.getFileSink = exports.reset = exports.getConfig = exports.dispose = exports.configure = exports.ConfigError = void 0;
4
4
  var config_js_1 = require("./config.js");
5
5
  Object.defineProperty(exports, "ConfigError", { enumerable: true, get: function () { return config_js_1.ConfigError; } });
6
6
  Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return config_js_1.configure; } });
@@ -14,6 +14,7 @@ var filter_js_1 = require("./filter.js");
14
14
  Object.defineProperty(exports, "getLevelFilter", { enumerable: true, get: function () { return filter_js_1.getLevelFilter; } });
15
15
  Object.defineProperty(exports, "toFilter", { enumerable: true, get: function () { return filter_js_1.toFilter; } });
16
16
  var formatter_js_1 = require("./formatter.js");
17
+ Object.defineProperty(exports, "ansiColorFormatter", { enumerable: true, get: function () { return formatter_js_1.ansiColorFormatter; } });
17
18
  Object.defineProperty(exports, "defaultConsoleFormatter", { enumerable: true, get: function () { return formatter_js_1.defaultConsoleFormatter; } });
18
19
  Object.defineProperty(exports, "defaultTextFormatter", { enumerable: true, get: function () { return formatter_js_1.defaultTextFormatter; } });
19
20
  var level_js_1 = require("./level.js");
package/script/sink.js CHANGED
@@ -80,17 +80,33 @@ function getConsoleSink(options = {}) {
80
80
  const console = options.console ?? globalThis.console;
81
81
  return (record) => {
82
82
  const args = formatter(record);
83
- if (record.level === "debug")
84
- console.debug(...args);
85
- else if (record.level === "info")
86
- console.info(...args);
87
- else if (record.level === "warning")
88
- console.warn(...args);
89
- else if (record.level === "error" || record.level === "fatal") {
90
- console.error(...args);
83
+ if (typeof args === "string") {
84
+ const msg = args.replace(/\r?\n$/, "");
85
+ if (record.level === "debug")
86
+ console.debug(msg);
87
+ else if (record.level === "info")
88
+ console.info(msg);
89
+ else if (record.level === "warning")
90
+ console.warn(msg);
91
+ else if (record.level === "error" || record.level === "fatal") {
92
+ console.error(msg);
93
+ }
94
+ else
95
+ throw new TypeError(`Invalid log level: ${record.level}.`);
96
+ }
97
+ else {
98
+ if (record.level === "debug")
99
+ console.debug(...args);
100
+ else if (record.level === "info")
101
+ console.info(...args);
102
+ else if (record.level === "warning")
103
+ console.warn(...args);
104
+ else if (record.level === "error" || record.level === "fatal") {
105
+ console.error(...args);
106
+ }
107
+ else
108
+ throw new TypeError(`Invalid log level: ${record.level}.`);
91
109
  }
92
- else
93
- throw new TypeError(`Invalid log level: ${record.level}.`);
94
110
  };
95
111
  }
96
112
  /**
package/types/config.d.ts CHANGED
@@ -14,7 +14,7 @@ export interface Config<TSinkId extends string, TFilterId extends string> {
14
14
  * The filters to use. The keys are the filter identifiers, and the values
15
15
  * are either {@link Filter}s or {@link LogLevel}s.
16
16
  */
17
- filters: Record<TFilterId, FilterLike>;
17
+ filters?: Record<TFilterId, FilterLike>;
18
18
  /**
19
19
  * The loggers to configure.
20
20
  */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAkB,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,MAAM,CAAC,OAAO,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM;IACtE;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC7B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAEvC;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;IAE5C;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAC3B,OAAO,SAAS,MAAM,EACtB,SAAS,SAAS,MAAM;IAExB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE5B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;IAEtB;;;OAGG;IACH,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CACzB;AAwBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,SAAS,CAC7B,OAAO,SAAS,MAAM,EACtB,SAAS,SAAS,MAAM,EACxB,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFnD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAEzD;AAED;;GAEG;AACH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3C;AAED;;GAEG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAS7C;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC;;;OAGG;gBACS,OAAO,EAAE,MAAM;CAI5B"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAkB,KAAK,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,MAAM,CAAC,OAAO,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM;IACtE;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC7B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAExC;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;IAE5C;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAC3B,OAAO,SAAS,MAAM,EACtB,SAAS,SAAS,MAAM;IAExB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE5B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;IAEtB;;;OAGG;IACH,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CACzB;AAwBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,SAAS,CAC7B,OAAO,SAAS,MAAM,EACtB,SAAS,SAAS,MAAM,EACxB,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFnD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAEzD;AAED;;GAEG;AACH,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3C;AAED;;GAEG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAS7C;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC;;;OAGG;gBACS,OAAO,EAAE,MAAM;CAI5B"}
@@ -18,6 +18,16 @@ export type TextFormatter = (record: LogRecord) => string;
18
18
  * @returns The formatted log record.
19
19
  */
20
20
  export declare function defaultTextFormatter(record: LogRecord): string;
21
+ /**
22
+ * A text formatter that uses ANSI colors to format log records.
23
+ *
24
+ * ![A preview of ansiColorFormatter.](https://i.imgur.com/I8LlBUf.png)
25
+ *
26
+ * @param record The log record to format.
27
+ * @returns The formatted log record.
28
+ * @since 0.5.0
29
+ */
30
+ export declare const ansiColorFormatter: TextFormatter;
21
31
  /**
22
32
  * A console formatter is a function that accepts a log record and returns
23
33
  * an array of arguments to pass to {@link console.log}.
@@ -1 +1 @@
1
- {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,MAAM,CAAC;AAoC1D;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAW9D;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,SAAS,OAAO,EAAE,CAAC;AAazE;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,OAAO,EAAE,CA2B7E"}
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,MAAM,CAAC;AAsC1D;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,CAW9D;AAcD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAqBhC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,SAAS,OAAO,EAAE,CAAC;AAazE;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,OAAO,EAAE,CA2B7E"}
package/types/mod.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { type Config, ConfigError, configure, dispose, getConfig, type LoggerConfig, reset, } from "./config.js";
2
2
  export { getFileSink, getRotatingFileSink } from "./filesink.node.js";
3
3
  export { type Filter, type FilterLike, getLevelFilter, toFilter, } from "./filter.js";
4
- export { type ConsoleFormatter, defaultConsoleFormatter, defaultTextFormatter, type TextFormatter, } from "./formatter.js";
4
+ export { ansiColorFormatter, type ConsoleFormatter, defaultConsoleFormatter, defaultTextFormatter, type TextFormatter, } from "./formatter.js";
5
5
  export { isLogLevel, type LogLevel, parseLogLevel } from "./level.js";
6
6
  export { getLogger, type Logger } from "./logger.js";
7
7
  export type { LogRecord } from "./record.js";
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EACX,WAAW,EACX,SAAS,EACT,OAAO,EACP,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,GACN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EACL,KAAK,MAAM,EACX,KAAK,UAAU,EACf,cAAc,EACd,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,gBAAgB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACrD,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,cAAc,EACd,aAAa,EACb,KAAK,uBAAuB,EAC5B,KAAK,IAAI,EACT,KAAK,iBAAiB,EACtB,UAAU,GACX,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EACX,WAAW,EACX,SAAS,EACT,OAAO,EACP,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,GACN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EACL,KAAK,MAAM,EACX,KAAK,UAAU,EACf,cAAc,EACd,QAAQ,GACT,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACrD,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,cAAc,EACd,aAAa,EACb,KAAK,uBAAuB,EAC5B,KAAK,IAAI,EACT,KAAK,iBAAiB,EACtB,UAAU,GACX,MAAM,WAAW,CAAC"}
package/types/sink.d.ts CHANGED
@@ -71,9 +71,10 @@ export declare function getStreamSink(stream: WritableStream, options?: StreamSi
71
71
  */
72
72
  export interface ConsoleSinkOptions {
73
73
  /**
74
- * The console formatter to use. Defaults to {@link defaultConsoleFormatter}.
74
+ * The console formatter or text formatter to use.
75
+ * Defaults to {@link defaultConsoleFormatter}.
75
76
  */
76
- formatter?: ConsoleFormatter;
77
+ formatter?: ConsoleFormatter | TextFormatter;
77
78
  /**
78
79
  * The console to log to. Defaults to {@link console}.
79
80
  */
@@ -1 +1 @@
1
- {"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,aAAa,CAAC;AACxD,OAAO,EACL,KAAK,gBAAgB,EAGrB,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAK/D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAE1B;;OAEG;IACH,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,iBAAsB,GAC9B,IAAI,GAAG,eAAe,CAgBxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAE7B;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,kBAAuB,GAAG,IAAI,CAYrE;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,KAAK;IACnC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAE9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAE9C;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,GAC/C,IAAI,GAAG,UAAU,CAUnB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,KAAK,CAAE,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC1E;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzC;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACpD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,uBAAuB,GAAG,sBAAsB,CAAC,KAAK,CAAC,GAC/D,IAAI,GAAG,UAAU,CAwCnB"}
1
+ {"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,aAAa,CAAC;AACxD,OAAO,EACL,KAAK,gBAAgB,EAGrB,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAK/D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAE1B;;OAEG;IACH,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;KAAE,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,iBAAsB,GAC9B,IAAI,GAAG,eAAe,CAgBxB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,gBAAgB,GAAG,aAAa,CAAC;IAE7C;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,kBAAuB,GAAG,IAAI,CAsBrE;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,KAAK;IACnC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAE9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAE9C;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,GAC/C,IAAI,GAAG,UAAU,CAUnB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,KAAK,CAAE,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC1E;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzC;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACpD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,uBAAuB,GAAG,sBAAsB,CAAC,KAAK,CAAC,GAC/D,IAAI,GAAG,UAAU,CAwCnB"}