Skip to main content
This release is 2 versions behind 0.8.1 — the latest version of @logtape/logtape. Jump to latest

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
This package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
This package works with Bun
This package works with Browsers
JSR Score
100%
Published
3 months ago (0.7.1)
Package root>logtape>sink.test.ts
import { 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! `, ); });