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

@peter.naydenov/log

v1.1.2

Published

Controlable log message system

Readme

Log (@peter.naydenov/log)

version license

A small logging system with a single point of control: filter messages by activity level and route them to any sink you want — the console, an external service, or your own logic.

  • Level-based filtering — set a threshold once and messages above it are dropped.
  • Pluggable handler — the default routes to console; swap in anything.
  • Zero dependencies, works in Node, browsers, and bundlers.
  • TypeScript-ready — ships with .d.ts declarations.

Why?

You want debug messages during development but not in production. log lets you set one threshold to silence everything (level: 0) and tune verbosity without touching call sites.

It's also abstract enough to drive non-logging workflows — see Alternative Ideas.

Installation

npm install @peter.naydenov/log

ESM:

import createLog from '@peter.naydenov/log'

CommonJS:

const createLog = require('@peter.naydenov/log')

Quick start

import createLog from '@peter.naydenov/log'

const log = createLog()                       // defaults → logs everything
const result = log({ message: 'hello' })
// console: [Debug]: hello
// result === '[Debug]: hello'                ← default handler returns the formatted string

// Silence everything
const silent = createLog({ level: 0 })
silent({ message: 'never logged' })           // -> null, nothing printed

API

createLog(options?, logFunction?) → log

Creates and returns a log function.

options

| Property | Type | Default | Description | | --- | --- | --- | --- | | level | number \| string \| string[] | 1000 | Threshold. Calls whose level is higher are ignored. Use 0 to silence everything (with the default handler). | | type | string | 'log' | Default message type. The default handler routes 'warn'console.warn, 'error'console.error, anything else → console.log. | | defaultMessageLevel | number \| string \| string[] | 1 | Level applied when a call does not provide its own level. |

Any extra properties on options are forwarded to logFunction as part of each payload.

logFunction

type LogFunction = (payload: LogPayload) => unknown

Custom handler invoked for each call. Receives the merged payload (options defaults + per-call input, with logLevel injected). Its return value is propagated back to the caller of log, so it may return a Promise.

Return: log(input)

type LogInput = {
  message: string
  type?: string
  level?: number | string | string[]
  [key: string]: unknown
}

log(input: LogInput): unknown

| Field | Type | Description | | --- | --- | --- | | message | string | Required. The message text. | | level | number \| string \| string[] | Per-call level. Falls back to defaultMessageLevel. | | type | string | Per-call type override. Falls back to the type option. | | extra | unknown | Any additional properties are forwarded to logFunction. |

Both level and type also accept null (or undefined), which means "not provided" and triggers the fallback.

Activity levels

The default numeric scheme is straightforward:

  • Lower threshold = more verbose. level: 1000 (default) lets everything through; level: 1 shows only the most important messages.
  • level: 0 is silent — the default handler treats it as a special "stop everything" signal and returns null.
  • Default message level is 1 — most calls can omit level and still be processed.
  • level: 0 is preserved if you pass it explicitly on a call (it is not treated as missing).

Custom schemes

Anything works as a level — numbers, strings, or arrays. Here's a string-based "verbosity" scheme:

const log = createLog(
  {
    level: 'basic',
    defaultMessageLevel: ['basic', 'warning', 'all'],
  },
  ({ message, level, logLevel }) => {
    if (Array.isArray(level) && level.includes(logLevel)) return message
    return null
  }
)

log({ message: 'x', level: ['basic', 'warning', 'all'] })  // 'x'
log({ message: 'y', level: ['warning', 'all'] })           // null  — 'basic' not in list
log({ message: 'z' })                                     // 'z'   — defaultMessageLevel kicks in

Message types

With the default handler, the type field routes to a specific console method:

  • 'warn'console.warn
  • 'error'console.error
  • anything else (including the default 'log') → console.log

The default handler formats messages as [Debug]: <message> and also returns that string from the call. Custom handlers are free to ignore type entirely.

TypeScript

The package ships with full type definitions in dist/log.d.ts — no @types/... package needed.

import createLog from '@peter.naydenov/log'
import type { LogFunction, LogInput, LogPayload } from '@peter.naydenov/log'

const log = createLog({ level: 5 })
log({ message: 'hi', level: 1 })                          // typed LogInput

Available exports: LogLevel, CreateLogOptions, LogInput, LogPayload, LogFunction.

Alternative Ideas

Because the handler is just a function, you can drive any conditional workflow — not just logging. A common pattern is gating code by user role:

let a = 'not changed'
const user = { role: 'guest' }

const roleSpecific = createLog(
  {
    defaultMessageLevel: ['admin', 'owner', 'guest'],
    level: user.role,
  },
  ({ level, logLevel, fn }) => {
    if (Array.isArray(level) && level.includes(logLevel)) return fn()
    return null
  }
)

roleSpecific({ level: ['admin', 'owner'], fn: () => (a = 'admin changed') })
// a === 'not changed'  — guest role not in the level list

roleSpecific({ level: ['guest'], fn: () => (a = 'guest changed') })
// a === 'guest changed'

roleSpecific({ fn: () => (a = 'general code') })
// a === 'general code'  — uses defaultMessageLevel

Credits

@peter.naydenov/log was created and is maintained by Peter Naydenov.

License

Released under the MIT License.