@lyleunderwood/isomorphic-logger
v1.0.3
Published
An isomorphic logger with pino-inspired API for browser and Node.js
Downloads
37
Maintainers
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-loggerQuick 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 informationdebug(20) - Debug informationinfo(30) - General informationwarn(40) - Warning messageserror(50) - Error messagesfatal(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 serviceEnvironment 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, orfile: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_COLORset,NODE_DISABLE_COLORSset, non-TTY environments, CI (except GitHub Actions)
Level Colors:
TRACE: Dim grayDEBUG: CyanINFO: GreenWARN: YellowERROR: RedFATAL: 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 propertiesError 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 tracesCustom 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 logNested 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 serializedOutput 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 errorsDevelopment
# Install dependencies
npm install
# Run tests
npm test
# Build package
npm run build
# Type checking
npm run typecheckLicense
MIT © Lyle Underwood
