This release is 2 versions behind 0.8.1 — the latest version of @logtape/logtape. Jump to latest
Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
Built and signed on GitHub Actions
Simple logging library with zero dependencies for Deno/Node.js/Bun/browsers
This package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers




JSR Score
100%
Published
3 months ago (0.7.1)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227import { assertEquals } from "jsr:/@std/assert@^0.222.1/assert-equals"; import { assertThrows } from "jsr:/@std/assert@^0.222.1/assert-throws"; import makeConsoleMock from "npm:consolemock@^1.1.0"; import fs from "node:fs"; import { isDeno } from "https://deno.land/x/which_runtime@0.2.0/mod.ts"; import { debug, error, fatal, info, warning } from "./fixtures.ts"; import { defaultTextFormatter } from "./formatter.ts"; import type { LogLevel } from "./level.ts"; import type { LogRecord } from "./record.ts"; import { type FileSinkDriver, getConsoleSink, getFileSink, getStreamSink, type Sink, withFilter, } from "./sink.ts"; Deno.test("withFilter()", () => { const buffer: LogRecord[] = []; const sink = withFilter(buffer.push.bind(buffer), "warning"); sink(debug); sink(info); sink(warning); sink(error); sink(fatal); assertEquals(buffer, [warning, error, fatal]); }); interface ConsoleMock extends Console { history(): unknown[]; } Deno.test("getStreamSink()", async () => { let buffer: string = ""; const decoder = new TextDecoder(); const sink = getStreamSink( new WritableStream({ write(chunk: Uint8Array) { buffer += decoder.decode(chunk); return Promise.resolve(); }, }), ); sink(debug); sink(info); sink(warning); sink(error); sink(fatal); await sink[Symbol.asyncDispose](); assertEquals( buffer, `\ 2023-11-14 22:13:20.000 +00:00 [DBG] my-app·junk: Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00 [WRN] my-app·junk: Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00 [ERR] my-app·junk: Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00 [FTL] my-app·junk: Hello, 123 & 456! `, ); }); Deno.test("getConsoleSink()", () => { // @ts-ignore: consolemock is not typed const mock: ConsoleMock = makeConsoleMock(); const sink = getConsoleSink({ console: mock }); sink(debug); sink(info); sink(warning); sink(error); sink(fatal); assertEquals(mock.history(), [ { DEBUG: [ "%c22:13:20.000 %cDBG%c %cmy-app·junk %cHello, %o & %o!", "color: gray;", "background-color: gray; color: white;", "background-color: default;", "color: gray;", "color: default;", 123, 456, ], }, { INFO: [ "%c22:13:20.000 %cINF%c %cmy-app·junk %cHello, %o & %o!", "color: gray;", "background-color: white; color: black;", "background-color: default;", "color: gray;", "color: default;", 123, 456, ], }, { WARN: [ "%c22:13:20.000 %cWRN%c %cmy-app·junk %cHello, %o & %o!", "color: gray;", "background-color: orange; color: black;", "background-color: default;", "color: gray;", "color: default;", 123, 456, ], }, { ERROR: [ "%c22:13:20.000 %cERR%c %cmy-app·junk %cHello, %o & %o!", "color: gray;", "background-color: red; color: white;", "background-color: default;", "color: gray;", "color: default;", 123, 456, ], }, { ERROR: [ "%c22:13:20.000 %cFTL%c %cmy-app·junk %cHello, %o & %o!", "color: gray;", "background-color: maroon; color: white;", "background-color: default;", "color: gray;", "color: default;", 123, 456, ], }, ]); assertThrows( () => sink({ ...info, level: "invalid" as LogLevel }), TypeError, "Invalid log level: invalid.", ); // @ts-ignore: consolemock is not typed const mock2: ConsoleMock = makeConsoleMock(); const sink2 = getConsoleSink({ console: mock2, formatter: defaultTextFormatter, }); sink2(debug); sink2(info); sink2(warning); sink2(error); sink2(fatal); assertEquals(mock2.history(), [ { DEBUG: [ "2023-11-14 22:13:20.000 +00:00 [DBG] my-app·junk: Hello, 123 & 456!", ], }, { INFO: [ "2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, 123 & 456!", ], }, { WARN: [ "2023-11-14 22:13:20.000 +00:00 [WRN] my-app·junk: Hello, 123 & 456!", ], }, { ERROR: [ "2023-11-14 22:13:20.000 +00:00 [ERR] my-app·junk: Hello, 123 & 456!", ], }, { ERROR: [ "2023-11-14 22:13:20.000 +00:00 [FTL] my-app·junk: Hello, 123 & 456!", ], }, ]); }); Deno.test("getFileSink()", () => { const path = Deno.makeTempFileSync(); let sink: Sink & Disposable; if (isDeno) { const driver: FileSinkDriver<Deno.FsFile> = { openSync(path: string) { return Deno.openSync(path, { create: true, append: true }); }, writeSync(fd, chunk) { fd.writeSync(chunk); }, flushSync(fd) { fd.syncSync(); }, closeSync(fd) { fd.close(); }, }; sink = getFileSink(path, driver); } else { const driver: FileSinkDriver<number> = { openSync(path: string) { return fs.openSync(path, "a"); }, writeSync: fs.writeSync, flushSync: fs.fsyncSync, closeSync: fs.closeSync, }; sink = getFileSink(path, driver); } sink(debug); sink(info); sink(warning); sink(error); sink(fatal); sink[Symbol.dispose](); assertEquals( Deno.readTextFileSync(path), `\ 2023-11-14 22:13:20.000 +00:00 [DBG] my-app·junk: Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00 [INF] my-app·junk: Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00 [WRN] my-app·junk: Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00 [ERR] my-app·junk: Hello, 123 & 456! 2023-11-14 22:13:20.000 +00:00 [FTL] my-app·junk: Hello, 123 & 456! `, ); });