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

keelog

v1.0.6

Published

A lightweight zero-config console logger with automatic context, clean tree output, and production-ready JSON.

Readme

Why keelog?

  • Automatic context – file, function, and line number are captured without any manual setup.
  • Fluent API – chain .depth(n) and .options({ label, ctx }) on every log call.
  • Structured by default – objects are pretty‑printed as Unicode trees with syntax colors.
  • Dual‑mode output – beautiful TTY in development, formatted JSON in production (NODE_ENV=production).
  • Lightweight dependencies – picocolors and prettyoutput (both tiny and fast).
  • Smart level filtering via LOG_LEVEL env variable.
  • Simple default log – call log("message") for a clean, prefix‑free output.

Installation

npm install keelog
# or
bun add keelog

Quick Start

import { log } from "keelog";

// Plain, clean output
log("Hello, world!");
log("User data", { id: 1, name: "Ada" });

// Leveled, contextual logs
log.info("Server started", { port: 3000 });
log.error("Database connection failed", { code: "ECONNREFUSED" });

Output (development)

Hello, world!
User data
id: 1
name: Ada

[/app.ts:5 main] INFO Server started
port: 3000

[/app.ts:6 main] ERROR Database connection failed
code: ECONNREFUSED

Output (production)

{
  "level": "log",
  "message": "Hello, world!",
  "ctx": {
    "file": "/app.ts",
    "func": "main",
    "line": 2
  }
}
{
  "level": "log",
  "message": "User data",
  "data": {
    "id": 1,
    "name": "Ada"
  },
  "ctx": {
    "file": "/app.ts",
    "func": "main",
    "line": 3
  }
}
{
  "level": "info",
  "message": "Server started",
  "data": {
    "port": 3000
  },
  "ctx": {
    "file": "/app.ts",
    "func": "main",
    "line": 5
  }
}
{
  "level": "error",
  "message": "Database connection failed",
  "data": {
    "code": "ECONNREFUSED"
  },
  "ctx": {
    "file": "/app.ts",
    "func": "main",
    "line": 6
  }
}

API

Simple Log

log(message?, data?)

A label‑less, context‑free log. Always prints regardless of LOG_LEVEL.
Ideal for quick debugging or output that should never be filtered.

  • log("message") → plain text
  • log("message", data) → plain text + formatted object tree
  • log(data) → just the object tree
  • log() → empty line

Chaining works as usual:

log("Complex data", deepObj).depth(2);
log("Just data", obj).options({ ctx: true }); // you can optionally enable context

Leveled Logs

log.debug(), log.info(), log.warn(), log.error()

These respect the LOG_LEVEL environment variable and include the level label and caller context by default.

Each accepts the same argument patterns:

  • (message: string, data?: any)
  • (data: any) – message becomes undefined
  • () – just the level and context
log.info("User fetched", { id: 42 });
log.warn({ diskUsage: "90%" });
log.error();

Fluent Modifiers

.depth(n: number)

Control how many levels of nested objects are displayed.
Default: Infinity (unlimited).

log.info("Shallow view", deepObject).depth(2);

.options({ label?: boolean, ctx?: boolean })

Toggle visibility of the level label or the file/line context.
Both default to true for leveled logs; false for log().

log.info("Simple message").options({ ctx: false });
log.warn("No label").options({ label: false });
log.error("Bare").options({ label: false, ctx: false });

Modifiers can be chained:

log.info("Data", obj).depth(3).options({ ctx: false });

Configuration

LOG_LEVEL

Set the minimum log level for leveled methods.
Valid values: debug, info, warn, error.
Default: info.

LOG_LEVEL=debug bun run app.ts

log() is not affected by LOG_LEVEL – it always prints.

NODE_ENV

When set to production, logs are output as formatted JSON suitable for log aggregators.

NODE_ENV=production node app.js

Features in Detail

  • Context extraction – uses the V8 stack trace API to automatically detect the caller’s file, function, and line number. No child() or manual naming required.
  • Pretty‑printing – leverages prettyoutput for Unicode tree diagrams with syntax highlighting (strings yellow, numbers cyan, booleans magenta, etc.).
  • Deferred output – logs without .depth() are flushed after a microtask, so they can still receive options later. Calling .depth() outputs immediately.
  • Error object handling – errors are fully expanded with stack traces when passed as data.
  • Zero impact on suppressed logs – chaining .depth() on a suppressed log level is safe and does nothing.

Examples

Quick debugging

log("Reached this point");
log("Current state", { user, session });

Full control

const complexData = { users: [{ name: "Alice" }, { name: "Bob" }] };

log.info("User list", complexData).options({ ctx: false }).depth(1);
// Output: INFO  User list
// users: [Array]

Debug with context

function processTask(taskId: string) {
  log.debug("Processing", { taskId });
}
// [/src/tasks.ts:2 processTask] DEBUG  Processing
// taskId: abc-123

Simple output with chaining

log("Important data", { key: "value" }).depth(1);
// Output: Important data
// key: value