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

@christian-wechsel/logger

v0.4.0

Published

A lightweight, dependency-free TypeScript logging library for Node.js with console, file, and storage loggers. The file logger supports daily rotation, JSON/text formats, and backpressure-safe writes.

Readme

@christian-wechsel/logger

A lightweight, dependency-free TypeScript logging library for Node.js with console, file, and storage loggers. The file logger supports daily rotation, JSON/text formats, and backpressure-safe writes.

Installation

npm install @christian-wechsel/logger

Quick Start

import { ConsoleLogger, FileLogger } from "@christian-wechsel/logger";

const consoleLogger = new ConsoleLogger("my-app");
consoleLogger.info("Application started");
consoleLogger.warn("Low memory", "SystemMonitor");
consoleLogger.error("Connection failed", "DatabaseClient");

const fileLogger = new FileLogger("my-app", {
  pathFolder: "./logs",
  extension: "log",
});
fileLogger.info("Application started");
await fileLogger.close();

Every log line is formatted as:

2024-01-15:10:30:45.123 [my-app] [DatabaseClient] error: Connection failed

API

Logger (interface)

The common contract implemented by every logger:

interface Logger {
  info(message: string, context?: string): void;
  warn(message: string, context?: string): void;
  error(message: string, context?: string): void;
  debug(message: string, context?: string): void;
}

context is optional and is rendered as [Context] right before the log level, e.g. for tagging the originating module/class.

ConsoleLogger

Writes formatted log lines to the standard console methods (console.log/warn/error/debug).

import { ConsoleLogger } from "@christian-wechsel/logger";

const logger = new ConsoleLogger("my-app");
logger.debug("Cache miss", "Repository");

Throws if appName is empty or blank.

FileLogger

Writes formatted log lines to a file on disk.

import { FileLogger } from "@christian-wechsel/logger";

const logger = new FileLogger(
  "my-app",
  { pathFolder: "./logs", extension: "log" },
  "json", // optional, defaults to "text"
);

logger.info("Application started");

// Always close the logger during shutdown to flush and release the file handle.
await logger.close();

Constructor: new FileLogger(appName, file, format?)

| Parameter | Type | Description | | ----------------- | --------------------------------------- | -------------------------------------------------------------------- | | appName | string | Non-empty application identifier, included in every log line. | | file.pathFolder | string | Folder the log files are written to (must already exist). | | file.extension | string | File extension appended to the generated file name (e.g. "log"). | | format | "text" \| "json" (default "text") | Rendering format for each log entry. |

Throws if appName, file.pathFolder, or file.extension is empty or blank.

Behavior:

  • File naming & daily rotation: files are named <appName>.<yyyy-mm-dd>.<extension> (UTC date). The logger automatically rotates to a new file the moment the UTC day changes — no restart required.
  • Format: "text" produces the same human-readable line as ConsoleLogger; "json" produces one JSON object per line (JSON Lines / .jsonl-style), e.g. {"timestamp":"...","appName":"my-app","level":"info","message":"..."}.
  • Backpressure handling: if the underlying write stream can't keep up, the logger buffers a single warning ("Backpressure detected, write stream is full.") and drops the log lines that couldn't be written, instead of buffering unbounded amounts of data in memory. This is a deliberate trade-off favoring process stability (bounded memory) over completeness of logs — it targets low/medium-traffic workloads where sustained backpressure is rare. Once the stream drains, normal writing resumes and the buffered warning is flushed.
  • close() resolves once all pending writes have been flushed and the file handle closed. Always call it before your process exits.

StorageLogger

Uploads log entries in batches to a storage adapter provided by the application.

import { StorageLogger } from "@christian-wechsel/logger";

const storageLogger = new StorageLogger(
  "my-app",
  {
    upload: async (entries) => {
      const response = await fetch("https://logs.example.com", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify(entries),
      });

      if (!response.ok) {
        throw new Error(`Log upload failed: ${response.status}`);
      }
    },
  },
  { batch: { threshold: 100 } },
);

storageLogger.onError((error) => {
  console.error("Could not upload log batch", error);
});

storageLogger.info("Application started");
storageLogger.warn("Low memory", "SystemMonitor");

// Stop logging before closing so all entries are included in the final flush.
await storageLogger.close();

Constructor: new StorageLogger(appName, storage, options?)

| Parameter | Type | Description | | --- | --- | --- | | appName | string | Non-empty application identifier included in each log entry. | | storage.upload | (entries: LogEntry[]) => Promise<void> | Uploads a batch. Reject the promise when the upload fails. | | options.batch.threshold | number (default 1000) | Number of entries that triggers a batch upload. |

Behavior:

  • Entries are uploaded when the batch threshold is reached. close() uploads any remaining entries and waits for uploads already in progress.
  • Upload failures are suppressed so logging can continue. Register onError(callback) to receive upload errors; the callback is for notification and does not retry the failed batch.
  • Call close() after stopping new log calls, and await it before the process exits. The logger buffers batches in memory; it does not provide durable storage if the process terminates unexpectedly.

AbstractLogger

Base class for building custom loggers (e.g. to ship logs to an external service). Extend it and implement info/warn/error/debug; the protected helpers createLogEntry, formatMessage, and formatMessageAsJson are available for formatting.

import { AbstractLogger, type LogEntry } from "@christian-wechsel/logger";

class HttpLogger extends AbstractLogger {
  info(message: string, context?: string): void {
    this.send(this.createLogEntry("info", message, context));
  }
  warn(message: string, context?: string): void {
    this.send(this.createLogEntry("warn", message, context));
  }
  error(message: string, context?: string): void {
    this.send(this.createLogEntry("error", message, context));
  }
  debug(message: string, context?: string): void {
    this.send(this.createLogEntry("debug", message, context));
  }

  private send(entry: LogEntry): void {
    // e.g. fetch("https://logs.example.com", { method: "POST", body: this.formatMessageAsJson(entry) });
  }
}

Types

Exported for consumers building custom loggers or handling log data:

| Type | Shape | | ----------------- | ---------------------------------------------------------------------------- | | LogLevel | "info" \| "warn" \| "error" \| "debug" | | LogEntry | { timestamp: Date; level: LogLevel; message: string; context?: string } | | LogFormat | "text" \| "json" | | FileLoggerFile | { pathFolder: string; extension: string } |