Skip to content

denosaurs/log

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

33 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Log

The denosaurs log module is a tiny, cross-platform, drop-in module for handling logs using streams. It has been tested and works in the browser, Deno, Node and Bun with second-class support for all runtimes and environments which implement web streams.

Installation

Log is supported in all runtimes and environments which implement web streams, but installation method may differ between runtimes. It is published to jsr.

Deno

Import it directly from JSR using the jsr protocol.

import { ConsoleReadableStream } from "jsr:@denosaurs/log";

Or add it to your import map or deno.json:

{
  "imports": {
    "log": "jsr:@denosaurs/log"
  }
}

Node and Bun

Add this line to the project's .npmrc file or the global one.

@jsr:registry=https://npm.jsr.io

And install the package using npm or the package manager of your choice.

npm install @jsr/denosaurs__log

If you would like a prettier package name I would suggest changing it in the package.json file to something like @denosaurs/log.

{
  "dependencies": {
-    "@jsr/denosaurs__log": "*"
+    "@denosaurs/log": "npm:@jsr/denosaurs__log"
  }
}

Examples

Note that we use the JsonStringifyStream from the deno standard library in the example. In Node, Bun and other runtimes you can install it from jsr.

Add this line to the project's .npmrc file or the global one.

@jsr:registry=https://npm.jsr.io

And install the package using npm or the package manager of your choice.

npm install @jsr/std__json

If you would like a prettier package name I would suggest changing it in the package.json file to something like @std/json.

{
  "dependencies": {
-    "@jsr/std__json": "*"
+    "@std/json": "npm:@jsr/std__json"
  }
}

The following example demonstrates how to capture and log messages as JSON to stdout.

// Ensure Bun compatibility. [It currently lacks support for TextEncoderStream](https://github.com/oven-sh/bun/issues/5648)
import "@denosaurs/log/transforms/text_encoder_stream";

import { ConsoleReadableStream } from "@denosaurs/log";

import { StdoutWritableStream } from "@denosaurs/log/writables/std";

import { JsonStringifyStream } from "@std/json";

// Capture logs from the console
const stream = new ConsoleReadableStream();
stream
  // Stringify the logs to JSON
  .pipeThrough(new JsonStringifyStream())
  // Encode the output to an UTF-8 byte stream
  .pipeThrough(new TextEncoderStream())
  // Pipe the output to stdout
  .pipeTo(new StdoutWritableStream());

// Log some messages
console.log("Hello, world!");
console.group("Group 1");
console.debug("Debug message");
console.groupEnd();
console.info("Info message");

Sometimes you may want to log messages to multiple destinations. This can be done using teeing.

In the example we also use the OmitLogLevelStream and PickLogLevelStream to filter the logs before they are written to the different destinations.

// Ensure Bun compatibility. [It currently lacks support for TextEncoderStream](https://github.com/oven-sh/bun/issues/5648)
import "@denosaurs/log/transforms/text_encoder_stream";

import { ConsoleReadableStream } from "@denosaurs/log";

import {
  StderrWritableStream,
  StdoutWritableStream,
} from "@denosaurs/log/writables/std";

import { OmitLogLevelStream } from "@denosaurs/log/transforms/omit";
import { PickLogLevelStream } from "@denosaurs/log/transforms/pick";

import { JsonStringifyStream } from "@std/json";

// Capture logs from the console
const stream = new ConsoleReadableStream();
// Split the stream in two
const [a, b] = stream.tee();

a
  // Omit only the error logs
  .pipeThrough(new OmitLogLevelStream("error"))
  // Stringify the logs to JSON
  .pipeThrough(new JsonStringifyStream())
  // Encode the output to an UTF-8 byte stream
  .pipeThrough(new TextEncoderStream())
  // Pipe the output to stdout
  .pipeTo(new StdoutWritableStream());

b
  // Pick only the error logs
  .pipeThrough(new PickLogLevelStream("error"))
  // Stringify the logs to JSON
  .pipeThrough(new JsonStringifyStream())
  // Encode the output to an UTF-8 byte stream
  .pipeThrough(new TextEncoderStream())
  // Pipe the output to stderr
  .pipeTo(new StderrWritableStream());

// Log some messages
console.error("This is going to stderr");
console.trace("This is going to stdout");
console.debug("This is going to stdout");
console.info("This is going to stdout");
console.warn("This is going to stdout");
console.log("This is going to stdout");

Features

The module is still young, with lot's of planned features and improvements. It is far from stable, so expect breaking changes. But anyways, here are some features:

  • Add support for more runtimes and environments
  • Exception and rejection handling
    • Add a fatal log level, which will be used for unhandled exceptions and rejections. Unreachable from the normal console API.
  • Metrics/timings using console.time and console.timeEnd
  • Transforms
    • Filter
    • Omit
    • Pick
    • JSON (Using JsonStringifyStream)
    • Redaction
      • [Symbol.for("log.secret")] (This only works when not using structuredClone because symbols are not cloneable. A future fix for this might be to write our own structuredClone function which keeps symbols.)
      • Exact match
      • Regex
      • fast-redact
    • Request and response metadata
      • [Symbol.for("log.request")] or instanceof Request
      • [Symbol.for("log.response")] or instanceof Response
    • Pretty print
    • Logfmt
  • Destinations
    • Console
    • Stdout
    • Stderr
    • File
      • Single file
      • Rotating file
    • Network
      • Fetch
      • WebSocket
      • UDP
      • TCP
    • Integrations
  • First-class support for popular web-frameworks

Goals

Some goals of this module are:

  • Web Standards - It should to the greatest extent possible follow web standards and try to emulate (and in the case of console extend) the standards we already know and love.
  • Ease of use - It should be easy to use and understand. It should be familiar, or dare I say, effortless to anyone who has used the console.
  • Minimal - It should be as small as possible, with minimal dependencies. Logging doesn't have to be complicated.
  • Performance - It needs to be fast. It should never noticeably slow down the application. Logging is a critical part of the application, but it should never be the bottleneck.
  • Quality - It should be well tested and well documented. It should be reliable and trustworthy.

Maintainers

Contributing

Pull request, issues and feedback are very welcome. Code style is formatted with deno fmt and commit messages are done following Conventional Commits spec.

Please use it! And let us know if you have any issues, feedback or requests.

Licence

Copyright 2024, the Denosaurs team. All rights reserved. MIT license.