@logtape/logtape 0.5.0-dev.67 → 0.5.0-dev.68
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 +4 -535
- package/package.json +2 -2
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
|

|
|
43
40
|

|
|
44
41
|
|
|
@@ -67,536 +64,8 @@ bun add @logtape/logtape # for Bun
|
|
|
67
64
|
~~~~
|
|
68
65
|
|
|
69
66
|
|
|
70
|
-
|
|
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
|
-
|
|
70
|
+
The docs of LogTape is available at <https://logtape.org/>.
|
|
71
|
+
For the API references, see <https://jsr.io/@logtape/logtape>.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logtape/logtape",
|
|
3
|
-
"version": "0.5.0-dev.
|
|
3
|
+
"version": "0.5.0-dev.68+ff42f972",
|
|
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://
|
|
15
|
+
"homepage": "https://logtape.org/",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "git+https://github.com/dahlia/logtape.git"
|