npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lindorm/logger

v0.7.0

Published

Type-safe Winston wrapper with hierarchical scopes, correlation metadata, and pluggable filters for sensitive data.

Readme

@lindorm/logger

Type-safe Winston wrapper with hierarchical scopes, correlation metadata, and pluggable filters for sensitive data.

Installation

npm install @lindorm/logger

This package is ESM-only — use import, not require.

Features

  • Typed log methods (error, warn, info, verbose, debug, silly) plus a low-level log() helper.
  • Hierarchical child() loggers that share a single Winston transport but layer their own scope and correlation metadata.
  • filterPath (exact dotted path) and filterKey (string or regex, any depth, including inside arrays) for redacting sensitive fields.
  • Two timer APIs: a time() handle and label-based time(label) / timeEnd(label). Child loggers receive a snapshot of parent-started labelled timers.
  • Automatic Error extraction — passing an Error (or { cause } chain) expands into error, name, message, stack, and recursive cause data.
  • Readable colourised output for development; structured JSON output by default.
  • Drop-in mock factories for Jest and Vitest.
  • Helpers for sanitising JWT/JWE tokens and Authorization headers.

Quick start

import { Logger } from "@lindorm/logger";

const logger = new Logger({
  level: "info",
  readable: process.env.NODE_ENV !== "production",
});

logger.info("Server started");

logger.correlation({ requestId: "4711" });

const http = logger.child(["http"]);
http.verbose("Incoming request", { method: "GET", url: "/" });

logger.filterPath("password");
logger.filterPath("user.jwt", () => "<jwt>");

logger.filterKey("password");
logger.filterKey(/token/i);

http.debug("Login attempt", {
  user: { password: "super-secret" },
  accessToken: "eyJhbGciOi…",
});

Logger

Constructor

new Logger(options?: LoggerOptions);

LoggerOptions:

| Field | Type | Default | Description | | ------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------- | | level | LogLevel | "info" | Minimum log level. One of "error" \| "warn" \| "info" \| "verbose" \| "debug" \| "silly". | | readable | boolean | false | When true, prints colourised human-readable output instead of JSON. | | correlation | LogCorrelation | {} | Initial correlation metadata. Keys are camel-cased on assignment. | | scope | LogScope | [] | Initial scope segments. | | filters | LogFilters | {} | Pre-registered path filters keyed by exact dotted path. |

Logging methods

logger.error(error: Error): void;
logger.error(message: string, context?: LogContent, extra?: Array<LogContent>): void;

logger.warn(message: string, context?: LogContent, extra?: Array<LogContent>): void;
logger.info(message: string, context?: LogContent, extra?: Array<LogContent>): void;
logger.verbose(message: string, context?: LogContent, extra?: Array<LogContent>): void;
logger.debug(message: string, context?: LogContent, extra?: Array<LogContent>): void;
logger.silly(message: string, context?: LogContent, extra?: Array<LogContent>): void;

logger.log({ message, level?, context?, extra? }: Log): void;

log() defaults the level to "info" when omitted. LogContent accepts a plain object, an Error, null, or undefined.

Scope and correlation

logger.scope(["http", "controller"]);
logger.correlation({ requestId: "4711", userId: 42 });

const child = logger.child(["router"]);
const childWithCorrelation = logger.child({ traceId: "abc" });

scope() and correlation() mutate the current logger; child() returns a new logger that shares the underlying Winston transport but layers additional scope/correlation on top. Scope segments are trimmed and camel-cased; correlation keys are camel-cased.

Filters

logger.filterPath("user.password");
logger.filterPath("headers.authorization", (v) => `redacted(${v.length})`);

logger.filterKey("password");
logger.filterKey(/token/i, () => "[Token]");

filterPath matches a single exact dotted path (via object-path). filterKey matches a key name at any depth, including inside arrays — pass either a string (exact match) or a RegExp (pattern match). Both default to replacing the matched value with "[Filtered]" if no callback is supplied.

Timers

Handle-based timer — time() with no label:

const timer = logger.time();
await fetchRemoteData();
timer.info("Remote data fetched", { url });

The returned LoggerTimer exposes error, warn, info, verbose, debug, and silly with the same signatures as the logger; each call emits one entry that includes the elapsed duration.

Label-based timer — time(label) / timeEnd(label):

logger.time("db-query");
await db.query("SELECT ...");
logger.timeEnd("db-query");

logger.time("http-request");
await fetch(url);
logger.timeEnd("http-request", "info", { url, status: 200 });

timeEnd(label) defaults to "debug" level and uses the label as the message. Calling timeEnd on an unknown label emits a warning instead. child() snapshots the parent's labelled timers, so a label started on a parent can be ended on the child, but a label started on a child does not propagate back to the parent.

Other methods

logger.isLevelEnabled(level: LogLevel): boolean;
logger.level;          // getter — current minimum level
logger.level = "debug"; // setter — updates all transports

Static console helper

Logger.std is a typed StdLogger that prints coloured output via the global console:

import { Logger } from "@lindorm/logger";

Logger.std.info("ready");
Logger.std.success("done");
Logger.std.error("fail");

Utilities

import { inspectDictionary, sanitiseAuthorization, sanitiseToken } from "@lindorm/logger";

inspectDictionary(obj, colors?, depth?); // util.inspect with sane defaults

sanitiseAuthorization("Bearer eyJhbGciOiJ….a.b"); // → "Bearer eyJhbGciOiJ….a"
sanitiseAuthorization("Basic dXNlcjpwYXNz");      // → "Basic [Filtered]"

sanitiseToken("a.b.c");     // → "a.b"  (JWT: header + payload only)
sanitiseToken("a.b.c.d.e"); // → "a"    (JWE: header only)

Mocks

Drop-in mock factories live behind dedicated subpaths to avoid loading the test runner at runtime.

Vitest:

import { createMockLogger } from "@lindorm/logger/mocks/vitest";

const logger = createMockLogger();

Jest:

import { createMockLogger } from "@lindorm/logger/mocks/jest";

const logger = createMockLogger();

Both factories return a fully-typed mocked ILogger with child() returning further mocks and time() returning a mocked ILoggerTimer. An optional logFn callback receives every log call for assertions.

Types

@lindorm/logger ships with declaration files. Public type exports include:

  • ILogger, ILoggerTimer — interfaces
  • Logger, LoggerTimer — classes
  • LoggerOptions, Log, LogContent, LogCorrelation, LogScope, LogFilters, LogLevel
  • FilterCallback, StdLogger, TimerLogFn

Note: LogLevel is a string union ("error" | "warn" | ... | "silly"), not an enum.

License

AGPL-3.0-or-later