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

@lyleunderwood/isomorphic-logger

v1.0.3

Published

An isomorphic logger with pino-inspired API for browser and Node.js

Downloads

37

Readme

@lyleunderwood/isomorphic-logger

An isomorphic logger with a pino-inspired API for browser and Node.js environments. Features automatic environment detection, structured logging, and comprehensive error handling with full stack traces.

Features

  • 🌐 Isomorphic: Works seamlessly in both Node.js and browser environments
  • 📝 Pino-inspired API: Familiar interface with fixed log levels (trace, debug, info, warn, error, fatal)
  • 🔧 Smart Formatting: Pretty-printing in development, JSON in production
  • 🎨 Color Support: Automatic terminal color detection with level-specific colors
  • 🚨 Advanced Error Handling: Full error serialization with stack traces and error cause chains
  • 👶 Child Loggers: Create contextual loggers with bound data
  • 📦 Zero Dependencies: Lightweight with no external dependencies
  • 🔌 Bundler Friendly: Works with webpack, Vite, and other modern bundlers
  • 📘 TypeScript: Fully typed with comprehensive type definitions

Installation

npm install @lyleunderwood/isomorphic-logger

Quick Start

Node.js

import createLogger from '@lyleunderwood/isomorphic-logger'

const logger = createLogger({ level: 'debug' })

logger.info('Hello from Node.js!')
logger.debug({ userId: '123', action: 'login' }, 'User logged in')
logger.error(new Error('Something went wrong'), 'Operation failed')

Browser

import createLogger from '@lyleunderwood/isomorphic-logger'

const logger = createLogger({ level: 'debug' })

logger.info('Hello from the browser!')
logger.warn({ componentId: 'UserList' }, 'Component rendered with warnings')

CommonJS

const createLogger = require('@lyleunderwood/isomorphic-logger')

const logger = createLogger()
logger.info('Hello from CommonJS!')

API Reference

Creating a Logger

const logger = createLogger(options)

Options

  • level?: LogLevel - Minimum log level (default: 'info')
  • prettyPrint?: boolean - Force pretty-printing on/off (default: auto-detect development)
  • useColors?: boolean - Force colors on/off (default: auto-detect terminal support)
  • bindings?: Record<string, any> - Default properties to include in all log entries

Log Levels

  • trace (10) - Detailed debug information
  • debug (20) - Debug information
  • info (30) - General information
  • warn (40) - Warning messages
  • error (50) - Error messages
  • fatal (60) - Fatal error messages

Logging Methods

Each method supports multiple call signatures:

// String message
logger.info('Simple message')

// String message with additional arguments
logger.info('User action', 'arg1', 'arg2')

// Object context
logger.info({ userId: '123', action: 'login' })

// Object context with message
logger.info({ userId: '123' }, 'User logged in')

// Error objects (automatically serialized)
logger.error(new Error('Something failed'))
logger.error(error, 'Operation failed')
logger.error({ error, userId: '123' }, 'User operation failed')

Child Loggers

Create child loggers with persistent context:

const requestLogger = logger.child({ 
  requestId: 'req-123',
  userId: '456' 
})

requestLogger.info('Processing request') 
// Output includes requestId and userId in every log

const serviceLogger = requestLogger.child({ 
  service: 'user-service' 
})

serviceLogger.debug('Database query executed')
// Output includes requestId, userId, and service

Environment Detection

The logger automatically detects the environment and adjusts formatting:

Development Mode (Pretty-printed with colors):

[2024-01-15T10:30:45.123Z] INFO: User logged in {
  "userId": "123",
  "action": "login"
}

Production Mode (JSON):

{"level":30,"time":1642249845123,"msg":"User logged in","userId":"123","action":"login"}

Development is detected when:

  • NODE_ENV === 'development' (Node.js)
  • localhost, 127.0.0.1, or file: protocol (Browser)

Color Support

The logger automatically detects terminal color support and adds colors to improve readability:

Color Detection:

  • Enabled: TTY terminals, FORCE_COLOR=1, GitHub Actions
  • Disabled: NO_COLOR set, NODE_DISABLE_COLORS set, non-TTY environments, CI (except GitHub Actions)

Level Colors:

  • TRACE: Dim gray
  • DEBUG: Cyan
  • INFO: Green
  • WARN: Yellow
  • ERROR: Red
  • FATAL: Bright red
// Force colors on/off
const colorLogger = createLogger({ useColors: true })
const noColorLogger = createLogger({ useColors: false })

// Auto-detect (default)
const autoLogger = createLogger()

Advanced Error Handling

The logger provides comprehensive error handling with full serialization:

Basic Error Logging

const error = new Error('Database connection failed')
logger.error(error)
// Logs with full stack trace and error properties

Error Cause Chains

const rootCause = new Error('Network timeout')
const serviceError = new Error('Service unavailable')
serviceError.cause = rootCause

logger.error(serviceError)
// Logs complete error chain with all stack traces

Custom Error Properties

const error = new Error('Validation failed')
error.code = 'VALIDATION_ERROR'
error.statusCode = 400
error.details = { field: 'email', value: 'invalid' }

logger.error(error, 'Request validation failed')
// All custom properties are preserved in the log

Nested Errors in Context

logger.error({
  operation: 'user-registration',
  userId: '123',
  error: serviceError,
  metadata: { 
    attempt: 3,
    nestedError: anotherError 
  }
}, 'Registration failed after retries')
// All errors in the object tree are properly serialized

Output Examples

Development Output (Pretty)

[2024-01-15T10:30:45.123Z] INFO: User operation completed {
  "userId": "123",
  "operation": "login",
  "duration": 150
}

[2024-01-15T10:30:46.456Z] ERROR: Database operation failed {
  "message": "Connection timeout",
  "name": "Error",
  "stack": "Error: Connection timeout\n    at Database.connect (/app/db.js:15:13)\n    ...",
  "code": "ECONNREFUSED",
  "cause": {
    "message": "Network unreachable",
    "name": "NetworkError",
    "stack": "NetworkError: Network unreachable\n    at TCPSocket.connect (/app/net.js:42:8)\n    ..."
  }
}

Production Output (JSON)

{"level":30,"time":1642249845123,"msg":"User operation completed","userId":"123","operation":"login","duration":150}
{"level":50,"time":1642249846456,"msg":"Database operation failed","message":"Connection timeout","name":"Error","stack":"Error: Connection timeout\n    at Database.connect (/app/db.js:15:13)\n    ...","code":"ECONNREFUSED","cause":{"message":"Network unreachable","name":"NetworkError","stack":"NetworkError: Network unreachable\n    at TCPSocket.connect (/app/net.js:42:8)\n    ..."}}

TypeScript Support

The library is written in TypeScript and provides full type definitions:

import createLogger, { Logger, LogLevel, LoggerOptions } from '@lyleunderwood/isomorphic-logger'

const options: LoggerOptions = {
  level: 'debug',
  prettyPrint: false,
  bindings: { service: 'api' }
}

const logger: Logger = createLogger(options)

// All methods are fully typed
logger.info({ userId: string, action: string }, 'User action')

Browser Compatibility

  • Modern Browsers: ES2020+ (Chrome 80+, Firefox 72+, Safari 13.1+)
  • Build Size: ~5KB minified
  • Dependencies: Zero

Node.js Compatibility

  • Node.js: 16.0+
  • Build Size: ~6KB
  • Dependencies: Zero

Best Practices

1. Use Structured Logging

// Good: Structured data
logger.info({ userId, action, duration }, 'User action completed')

// Avoid: String interpolation
logger.info(`User ${userId} completed ${action} in ${duration}ms`)

2. Use Child Loggers for Context

// Good: Child logger with persistent context
const requestLogger = logger.child({ requestId, userId })
requestLogger.info('Request started')
requestLogger.info('Validation completed')
requestLogger.info('Request completed')

// Avoid: Repeating context
logger.info({ requestId, userId }, 'Request started')
logger.info({ requestId, userId }, 'Validation completed')
logger.info({ requestId, userId }, 'Request completed')

3. Log Errors with Context

// Good: Error with operation context
logger.error({ 
  error, 
  operation: 'user-creation',
  userId,
  requestId 
}, 'User creation failed')

// Avoid: Error without context
logger.error(error)

4. Use Appropriate Log Levels

logger.trace('Entering function with params', { params })  // Detailed debugging
logger.debug('Cache hit for key', { key })                 // Debug information
logger.info('User logged in', { userId })                  // General information
logger.warn('Rate limit approaching', { current, limit })  // Warnings
logger.error(error, 'Operation failed')                    // Errors
logger.fatal(error, 'Service shutting down')               // Fatal errors

Development

# Install dependencies
npm install

# Run tests
npm test

# Build package
npm run build

# Type checking
npm run typecheck

License

MIT © Lyle Underwood