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

@autotracer/logger

v1.0.0-alpha.33

Published

Logging library for auto-tracer

Readme

@autotracer/logger

Structured, theme-able logging for JavaScript applications.

A lightweight, zero-dependency logging library with named instances, configurable themes, performance tracking, and tree-style nested output—perfect for debugging complex applications.

What You Get

  • Named logger instances - Create independent loggers per module/component
  • Flexible theming - Console groups, colored text, or plain output
  • Performance tracking - Built-in enter/exit timing
  • Tree visualization - See call hierarchies at a glance
  • Zero dependencies - Pure JavaScript with TypeScript support

Features

  • Named Logger Instances: Create multiple independent loggers with getLogger(name)
  • Per-Logger Configuration: Each logger has its own log level, theme, and display settings
  • Global Log Level Control: Set minimum log level once, filter all output automatically
  • 8 Log Levels: fatal, error, warn, log, info, debug, verbose, trace
  • Themed Output: Choose between console.group or UTF-8 text modes with optional colors and prefixes
  • Safe Console Wrappers: Never throws, even if console methods fail
  • Performance Tracking: enter/exit with automatic timing measurement and mismatch detection
  • Tree-Style Grouping: Nested logging with visual indentation (└─, ├─, │)
  • Zero Dependencies: Pure JavaScript with TypeScript definitions
  • 100% Test Coverage: Fully tested with Vitest

Installation

pnpm add @autotracer/logger
# or
npm install @autotracer/logger
# or
yarn add @autotracer/logger

Quick Start

Named Loggers (Recommended)

import { getLogger, themes } from "@autotracer/logger";

// Create a named logger
const logger = getLogger("app");

// Configure this logger independently
logger.setLogLevel("debug");
logger.setTheme(themes.emoji);
logger.setShowName(true); // Show [app] prefix

// Log messages
logger.log("Application started");
logger.debug("Debug info");

// Create another independent logger
const dbLogger = getLogger("database");
dbLogger.setLogLevel("error"); // Only errors
dbLogger.setShowName(false); // Hide [database] prefix

Global API

import { log, setLogLevel, setTheme, themes } from "@autotracer/logger";

// Set global log level (default: "log")
setLogLevel("debug");

// Use themed output
setTheme(themes.emoji);

// Log messages
log("Application started");

Named Logger Instances

Named loggers allow you to create multiple independent logger instances, each with its own configuration. This is useful for:

  • Module-specific logging (e.g., "database", "api", "auth")
  • Component-level filtering (show only errors from "payment" module)
  • Per-logger themes (emoji for development logs, minimal for system logs)

Creating Loggers

import { getLogger } from "@autotracer/logger";

const appLogger = getLogger("app");
const dbLogger = getLogger("database");
const apiLogger = getLogger("api");

// Calling getLogger with the same name returns the same instance
const appLogger2 = getLogger("app");
console.log(appLogger === appLogger2); // true

Logger API

Each logger instance has the following methods:

Configuration:

  • setLogLevel(level: LogLevel): void - Set minimum log level for this logger
  • setTheme(theme: Theme): void - Set theme for this logger
  • setShowName(show: boolean): void - Show/hide logger name prefix

Logging Methods:

  • fatal(...args: unknown[]): void
  • error(...args: unknown[]): void
  • warn(...args: unknown[]): void
  • log(...args: unknown[]): void
  • info(...args: unknown[]): void
  • debug(...args: unknown[]): void
  • verbose(...args: unknown[]): void
  • trace(...args: unknown[]): void

Grouping:

  • group(label?: string): void
  • groupEnd(): void

Performance Tracking:

  • enter(label: string, ...optionalParams: unknown[]): ExitHandle
  • exit(handle: ExitHandle, ...optionalParams: unknown[]): void
  • enterStyled(rawLabel: string, styledLabel: string, ...optionalParams: unknown[]): StyledExitHandle
  • exitStyled(handle: StyledExitHandle, styledLabel: string, ...optionalParams: unknown[]): void

Example: Per-Module Configuration

import { getLogger, themes } from "@autotracer/logger";

// Development logger - verbose, with emoji
const devLogger = getLogger("dev");
devLogger.setLogLevel("trace");
devLogger.setTheme(themes.emoji);
devLogger.setShowName(true);

devLogger.trace("Detailed trace"); // → 🔍 [dev] Detailed trace
devLogger.debug("Debug info"); // → 🐛 [dev] Debug info
devLogger.log("Standard message"); // → 📝 [dev] Standard message

// Production logger - errors only, minimal style
const prodLogger = getLogger("prod");
prodLogger.setLogLevel("error");
prodLogger.setTheme(themes.minimal);
prodLogger.setShowName(false);

prodLogger.trace("Hidden"); // (not shown)
prodLogger.error("Critical issue"); // → [ERROR] Critical issue

// Database logger - info level, monochrome
const dbLogger = getLogger("database");
dbLogger.setLogLevel("info");
dbLogger.setTheme(themes.monochrome);
dbLogger.setShowName(true);

dbLogger.debug("Query details"); // (not shown - below info)
dbLogger.info("Connection opened"); // → [i] [database] Connection opened

Example: Component-Level Filtering

import { getLogger } from "@autotracer/logger";

function processPayment(amount: number) {
  const logger = getLogger("payment");
  logger.setLogLevel("info");

  logger.info("Processing payment:", amount);
  logger.debug("Detailed payment info"); // Hidden (below info)
  logger.error("Payment failed"); // Shown
}

function renderUI() {
  const logger = getLogger("ui");
  logger.setLogLevel("debug"); // More verbose for UI

  logger.debug("Rendering component"); // Shown
  logger.trace("Render timing details"); // Hidden (below debug)
}

API Reference

Named Logger API

Creating Loggers:

import { getLogger } from "@autotracer/logger";

const logger = getLogger("module-name");

Logger Interface:

Each logger has these methods:

  • Configuration: setLogLevel(), setTheme(), setShowName()
  • Logging: fatal(), error(), warn(), log(), info(), debug(), verbose(), trace()
  • Grouping: group(), groupEnd()
  • Tracking: enter(), exit()

See "Named Logger Instances" section above for detailed examples.


Global API

You can also use standalone functions instead of logger instances.

Log Levels

Log levels form a hierarchy. Setting a level enables all messages at that level and below:

fatal < error < warn < log < info < debug < verbose < trace

Functions:

  • fatal(...args: unknown[]): void - Critical failures (always shown)
  • error(...args: unknown[]): void - Errors
  • warn(...args: unknown[]): void - Warnings
  • log(...args: unknown[]): void - Standard output
  • info(...args: unknown[]): void - Informational messages
  • debug(...args: unknown[]): void - Debug output
  • verbose(...args: unknown[]): void - Verbose details
  • trace(...args: unknown[]): void - Finest-grained tracing

Example:

import {
  setLogLevel,
  fatal,
  error,
  info,
  debug,
  trace,
} from "@autotracer/logger";

setLogLevel("info");

fatal("Critical error"); // ✅ Shown
error("Error occurred"); // ✅ Shown
info("Info message"); // ✅ Shown
debug("Debug details"); // ❌ Hidden
trace("Trace data"); // ❌ Hidden

Global Log Level

Set the minimum log level:

import { setLogLevel } from "@autotracer/logger";

setLogLevel("debug"); // Show debug, info, log, warn, error, fatal (hide verbose, trace)

Get the current log level:

import { getLogLevel } from "@autotracer/logger";

const level = getLogLevel(); // Returns LogLevel

Grouping

Create collapsible or visually nested log sections:

Functions:

  • group(label?: string): void - Start a group
  • groupEnd(): void - End the current group

Example (console.group mode):

import { group, groupEnd, log, setLogLevel } from "@autotracer/logger";

setLogLevel("log");

group("Processing items");
log("Item 1");
log("Item 2");
groupEnd();

Example (text mode with UTF-8 box drawing):

import { setTheme, themes, group, groupEnd, log } from "@autotracer/logger";

setTheme(themes.minimal);

group("Outer");
log("Level 1");
group("Inner");
log("Level 2");
groupEnd();
groupEnd();

// Output:
// ├─ Outer
// │  Level 1
// │  ├─ Inner
// │  │  Level 2

Theming

Themes control visual output with colors and prefixes using console %c directives. Each theme has three properties:

  • groupMode: "default" (console.group) or "text" (UTF-8 box-drawing)
  • colors: CSS color values (e.g., #ff0000) applied via %c directive for each log level
  • prefixes: Text/emoji prefixes prepended to log messages

Set a theme:

import { setTheme, themes } from "@autotracer/logger";

setTheme(themes.emoji);

Get the current theme:

import { getTheme } from "@autotracer/logger";

const theme = getTheme();

Built-in Themes

1. default - No styling

setTheme(themes.default);
// Minimal overhead, raw console output
log("Hello"); // → Hello

2. minimal - Text prefixes only

setTheme(themes.minimal);
// Text prefixes, no colors
fatal("Critical error"); // → [FATAL] Critical error
error("Error occurred"); // → [ERROR] Error occurred
warn("Warning message"); // → [WARN] Warning message
log("Log message"); // → [LOG] Log message
info("Info message"); // → [INFO] Info message
debug("Debug data"); // → [DEBUG] Debug data
verbose("Verbose output"); // → [V] Verbose output
trace("Trace detail"); // → [T] Trace detail

3. emoji - Colors + emoji prefixes

setTheme(themes.emoji);
// console.group mode with colored emoji prefixes
fatal("Critical"); // → 🔥 Critical      (red: #ff0000)
error("Error"); // → ❌ Error         (red: #ff4444)
warn("Warning"); // → ⚠️  Warning      (yellow: #ffaa00)
log("Message"); // → 📝 Message       (gray: #888888)
info("Info"); // → ℹ️  Info         (blue: #00aaff)
debug("Debug"); // → 🐛 Debug         (cyan: #00ffaa)
verbose("Verbose"); // → 💬 Verbose       (gray: #999999)
trace("Trace"); // → 🔍 Trace         (gray: #666666)

const h = enter("Task"); // → ▶️ Task
// ... work ...
exit(h); // → ◀️ Task (elapsed: 12.34ms)

4. monochrome - ASCII prefixes, no colors

setTheme(themes.monochrome);
// ASCII-safe prefixes for environments without color support
fatal("Critical"); // → [X] Critical
error("Error"); // → [!] Error
warn("Warning"); // → [*] Warning
log("Message"); // → [ ] Message
info("Info"); // → [i] Info
debug("Debug"); // → [d] Debug
verbose("Verbose"); // → [v] Verbose
trace("Trace"); // → [t] Trace

How Theme Styling Works

Themes apply colors using the console %c directive:

// When theme.colors.error = "#ff0000" and theme.prefixes.error = "❌"
error("Something failed", data);

// Outputs to console as:
console.error("%c❌ Something failed", "color: #ff0000", data);

User-provided %c directives coexist with theme styling:

setTheme(themes.emoji);
error("Status: %cOK%c", "color: green", "");
// → ❌ Status: OK  (emoji is red, OK is green)

The theme's %c directive is always first, followed by user-provided directives in order.

Custom theme:

import { setTheme } from "@autotracer/logger";
import type { Theme } from "@autotracer/logger";

const myTheme: Theme = {
  groupMode: "text",
  colors: {
    error: "#FF0000",
    warn: "#FFA500",
  },
  prefixes: {
    error: "[ERR]",
    warn: "[WRN]",
    enter: ">>",
    exit: "<<",
  },
};

setTheme(myTheme);

Built-in Themes

themes.default (default)

  • groupMode: "default" (console.group)
  • No colors or prefixes

themes.minimal

  • groupMode: "text"
  • Text prefixes: [FATAL], [ERROR], [WARN], ,

themes.emoji

  • groupMode: "default"
  • HTML colors for all levels
  • Emoji prefixes: 🔥💥⚠️📝ℹ️🐛📊🔍▶◀

themes.monochrome

  • groupMode: "text"
  • ASCII prefixes: [!], [X], [*], >, <
  • No colors

Performance Tracking

Track execution time of code sections with automatic timing and enter/exit matching.

Functions:

  • enter(label: string, level?: LogLevel): ExitHandle - Start performance tracking
  • exit(handle: ExitHandle): void - End tracking and log elapsed time

Parameters:

  • label: Description of the tracked section
  • level: Log level for enter/exit messages (default: "trace")

Returns:

  • ExitHandle: Object with { label: string, startTime: number, level: LogLevel }

Example:

import { enter, exit, setLogLevel } from "@autotracer/logger";

setLogLevel("trace");

function processData() {
  const handle = enter("processData");

  // ... do work ...

  exit(handle);
}

// Output:
// ▶ Enter: processData
// (nested logs here)
// ◀ Exit: processData (elapsed: 123.45 ms)

Mismatch Detection:

If exit is called with a different label than the most recent enter, a warning is logged:

const h1 = enter("A");
const h2 = enter("B");
exit(h1); // ⚠️ Warning: Expected to exit "B", but got "A"

Styled Enter/Exit API

The styled enter/exit API allows you to provide both raw and styled labels, enabling use cases where:

  • The raw label is needed for identification/matching
  • The styled label contains presentation formatting (icons, colors, etc.)
  • Exit messages can be re-themed differently from enter messages

This is useful when building higher-level tracing libraries that need to apply different theming to enter vs. exit messages.

Functions:

  • enterStyled(rawLabel: string, styledLabel: string, ...optionalParams: unknown[]): StyledExitHandle
  • exitStyled(handle: StyledExitHandle, styledLabel: string, ...optionalParams: unknown[]): void

Key Differences from enter/exit:

| Feature | enter/exit | enterStyled/exitStyled | |---------|----------------|----------------------------| | Label storage | Single label | Both raw and styled labels | | Exit label | Reuses enter label | Caller provides exit label | | Use case | Simple tracking | Custom theming per message | | Handle type | ExitHandle | StyledExitHandle (extends ExitHandle with rawLabel) |

Example: Custom Enter/Exit Icons

import { getLogger } from "@autotracer/logger";

const logger = getLogger("tracer");
logger.setLogLevel("trace");

function myFunction() {
  // Enter with → icon
  const handle = logger.enterStyled(
    "myFunction",              // Raw label (for matching)
    "→ myFunction",            // Styled label (with icon)
    "color: blue"              // Optional styling
  );

  // ... do work ...

  // Exit with ← icon (different from enter!)
  logger.exitStyled(
    handle,
    "← myFunction",            // Different styled label for exit
    "color: green"             // Different styling
  );
}

// Output:
// → myFunction (in blue)
// ← myFunction (elapsed: 123ms) (in green)

Example: Storing Parameters

const logger = getLogger("app");

const handle = logger.enterStyled(
  "processData",
  "%cprocessData",
  "font-weight: bold",
  { id: 123 }
);

// Exit reuses stored params if no override provided
logger.exitStyled(handle, "%cprocessData completed");
// Output: processData completed (elapsed: 45ms) font-weight: bold {id: 123}

// OR override params
logger.exitStyled(handle, "%cprocessData completed", "color: green");
// Output: processData completed (elapsed: 45ms) color: green

Use Cases:

  1. Different enter/exit theming: Apply → for enter, ← for exit
  2. Custom formatting: Store raw name, display formatted version
  3. Conditional styling: Enter in blue, exit in green/red based on result
  4. Higher-level tracers: Build framework-specific tracers with custom icons/colors

Type: StyledExitHandle

interface StyledExitHandle extends ExitHandle {
  readonly rawLabel: string; // Original unformatted label
}

The StyledExitHandle extends ExitHandle with a rawLabel field that stores the original unformatted label, while label stores the styled version.

Types

LogLevel

type LogLevel =
  | "fatal"
  | "error"
  | "warn"
  | "log"
  | "info"
  | "debug"
  | "verbose"
  | "trace";

Theme

interface Theme {
  groupMode: "default" | "text";
  colors: Partial<Record<LogLevel, string>>;
  prefixes: Partial<Record<LogLevel | "enter" | "exit", string>>;
}

ExitHandle

interface ExitHandle {
  label: string;
  startTime: number;
  level: LogLevel;
}

Usage Examples

Basic Logging

import { log, info, error } from "@autotracer/logger";

log("Server started on port 3000");
info("User logged in:", { userId: 123 });
error("Failed to connect:", new Error("Timeout"));

Level Filtering

import { setLogLevel, debug, trace } from "@autotracer/logger";

setLogLevel("debug");

debug("This appears"); // ✅
trace("This is hidden"); // ❌ (trace is below debug)

Nested Groups with Text Mode

import { setTheme, themes, group, groupEnd, log, debug } from "@autotracer/logger";

setTheme(themes.minimal);

group("HTTP Request");
log("URL: /api/users");
debug("Method: GET");
group("Headers");
log("Content-Type: application/json");
debug("Authorization: Bearer token");
groupEnd();
group("Response");
log("Status: 200");
debug("Body size: 1024 bytes");
groupEnd();
groupEnd();

// Output:
// ├─ HTTP Request
// │  URL: /api/users
// │  Method: GET
// │  ├─ Headers
// │  │  Content-Type: application/json
// │  │  Authorization: Bearer token
// │  ├─ Response
// │  │  Status: 200
// │  │  Body size: 1024 bytes

Note: In text mode, all log messages (debug, info, log, etc.) inside a group are automatically indented to match the group nesting level. This provides clear visual hierarchy for nested operations.

Performance Tracking

import { enter, exit, setLogLevel } from "@autotracer/logger";

setLogLevel("debug");

async function fetchData() {
  const h = enter("fetchData", "debug");

  const response = await fetch("/api/data");
  const data = await response.json();

  exit(h);

  return data;
}

// Output:
// ▶ Enter: fetchData
// ◀ Exit: fetchData (elapsed: 234.56 ms)

Custom Theme

import { setTheme, fatal, error, warn } from "@autotracer/logger";
import type { Theme } from "@autotracer/logger";

const prodTheme: Theme = {
  groupMode: "text",
  colors: {},
  prefixes: {
    fatal: "[FATAL]",
    error: "[ERROR]",
    warn: "[WARN]",
  },
};

setTheme(prodTheme);

fatal("System failure"); // [FATAL] System failure
error("Request failed"); // [ERROR] Request failed
warn("Deprecated API"); // [WARN] Deprecated API

Testing

The package has 100% test coverage with 115 unit tests using Vitest.

Run tests:

pnpm --filter @autotracer/logger test

Build:

pnpm --filter @autotracer/logger build

License

MIT