@vanilla-bean/log
v7.0.0
Published
A console log wrapper with tags, colors, and verbosity
Readme
Log
Zero-dependency console logging with tags, verbosity control, and unlimited custom log levels.
Why Log
Log follows Unix philosophy: do logging well, let the system handle output routing. Writes to stdout as plain text; containers, process supervisors, and log tails handle the rest.
- Zero runtime dependencies
- Custom methods (
log.success(),log.database()) alongside native console methods, no configuration needed - Tagged loggers, verbosity filtering, color, and global registry in ~1KB, easy to read, easy to fork
Installation
npm install @vanilla-bean/log
# or
bun add @vanilla-bean/logQuick Start
Create tagged loggers that share instances and support unlimited custom methods:
import Log from '@vanilla-bean/log';
// Create tagged logger instances
const api = new Log({ tag: 'api', verbosity: 2, color: true });
const db = new Log({ tag: 'database', verbosity: 1 });
// Use all console methods
api.info('Server started');
api.warn('High memory usage');
api.error('Connection failed');
// Custom methods work automatically
api.success('Request completed');
db.query('SELECT * FROM users');
// Verbosity-gated calls: log(n)('msg') shows when logger verbosity > n
api(1)('Debug info'); // shows when verbosity > 1 (visible here, verbosity is 2)
api(3)('Trace data'); // shows when verbosity > 3 (hidden here, verbosity is 2)
// log('msg') is shorthand for log(0)('msg') — shows when verbosity > 0
api('Request received');Core Features
Tagged Logger Registry
Identical tags return the same logger instance, preventing duplicates and enabling cross-module coordination:
// Module A
const log = new Log({ tag: 'app', verbosity: 1 });
// Module B - gets same logger instance
const log = new Log({ tag: 'app' }); // Inherits verbosity: 1
// Access any logger globally
import { loggers } from '@vanilla-bean/log';
loggers.app.options.verbosity = 3; // Updates everywhereNote: Calling
new Log()without a tag uses the shared__defaultsingleton. Two unrelated modules both doingnew Log()will share the same logger instance and options. Always pass a tag when you want an independent logger.
Verbosity Control
The primary form is log(n)('msg'): logs when the logger's verbosity is greater than n, silent otherwise. Calling log('msg') directly is shorthand for log(0)('msg'): shows when verbosity is greater than 0.
const log = new Log({ verbosity: 3 });
log(1)('High priority'); // shows when verbosity > 1
log(2)('Debug info'); // shows when verbosity > 2
log(5)('Trace data'); // shows when verbosity > 5 (hidden here)
log('Shorthand'); // shorthand for log(0)('Shorthand') — shows when verbosity > 0
// Works the same on any method
log.warn(1)('Important warning');
log.error(0)('Critical error');Gotcha: A lone number is always treated as a verbosity level, never as a message.
log(42)returns a curried function; it does not log the number 42. To log a bare number, pass a second argument:log(42, '').
Unlimited Log Methods
Create unlimited custom log methods alongside native console methods:
const log = new Log({ tag: 'app' });
// Native console methods
log.info('Information');
log.warn('Warning');
log.error('Error');
log.debug('Debug data');
// Custom methods work automatically
log.success('Operation completed');
log.database('Query executed');
log.network('Request sent');
log.cache('Cache hit');
log.security('Auth failed');Color Output
Add color support for enhanced terminal readability:
const log = new Log({ color: true });
log.info('Blue text'); // Built-in blue
log.warn('Yellow text'); // Built-in yellow
log.error('Red text'); // Built-in red
// Custom colors per tag or method
const colorLog = new Log({
color: true,
colorMap: {
success: '\x1b[32m', // Green
critical: '\x1b[91m', // Bright red
},
});Configuration Options
const log = new Log({
tag: 'myapp', // Logger identifier (omit to share the global __default singleton)
verbosity: 0, // Default: 0 (silent). log(n)() shows when n < verbosity; log('msg') shows when verbosity > 0
color: false, // Disable color output
silentTag: false, // Hide [tag] prefix
methodTag: false, // Show [method] label for native methods (info/warn/error); custom methods always show their label
colorMap: {}, // Custom ANSI color codes
});Advanced Usage
Dynamic Configuration
const log = new Log({ tag: 'api', verbosity: 1 });
log(2)('This is hidden');
// Increase verbosity at runtime
log.options.verbosity = 3;
log(2)('Now visible');Tag Management
const log = new Log({ tag: 'init' });
log('Starting up');
// Switch to different tag
log.setTag('runtime');
log('Now running');Global Configuration
Set process-wide defaults before creating loggers, or map custom methods to console methods:
import Log, { setDefaults, setMethodMap } from '@vanilla-bean/log';
setDefaults({ verbosity: 2, color: true });
setMethodMap({ critical: 'error', trace: 'debug' });
const log = new Log({ tag: 'app' }); // inherits verbosity: 2, color: true
log.critical('Fatal error'); // routes to console.errorCross-Module Coordination
// logger.js
import Log from '@vanilla-bean/log';
export const appLog = new Log({ tag: 'app', verbosity: 1 });
// module1.js
import { appLog } from './logger.js';
appLog.info('Module 1 loaded');
// module2.js
import { loggers } from '@vanilla-bean/log';
loggers.app.warn('Module 2 warning'); // Same logger instanceProduction Deployment
Log Aggregation
Log writes human-readable text to stdout. For log aggregation pipelines that expect JSON (ELK, Fluentd, Datadog), you'll need a JSON logger. Log is the right tool when a human is reading the output — development, debugging, process supervision, or simple production tails.
For plain-text pipelines, disable colors and keep tags for pattern matching:
const log = new Log({
tag: 'api',
silentTag: false, // keep [api] prefix for grep/awk
color: false, // no ANSI codes in log files
});
log.info('user_login', { userId: 123, ip: '1.2.3.4' });
// Output: [api] user_login { userId: 123, ip: '1.2.3.4' }Environment Configuration
const log = new Log({
tag: process.env.SERVICE_NAME || 'app',
verbosity: process.env.LOG_LEVEL || 1,
color: process.env.NODE_ENV === 'development',
});Comparison
| Feature | Log | Winston | Pino | Debug | | ----------------- | --------------------- | ---------------------- | ---------------- | ----------- | | Bundle Size | ~1KB | ~2MB | ~1MB | ~8KB | | Dependencies | 0 | Many | Some | 1 | | Log Levels | Unlimited | 6 + custom | 6 standard | 1 | | Verbosity Control | ✓ Core | ✓ | ✓ | Environment | | Tags/Namespaces | ✓ Singleton | ✓ | ✓ | ✓ | | Transports | stdout only | 20+ built-in | Plugin ecosystem | stdout only | | Container-Native | ✓ | Configuration required | ✓ | ✓ |
API Reference
Constructor
new Log(options?: {
tag?: string; // Default: '__default'
verbosity?: number; // Default: 0
color?: boolean; // Default: false
silentTag?: boolean; // Default: false
methodTag?: boolean; // Default: false — shows [method] for native methods; custom methods always show it
colorMap?: object; // Custom colors
})Logger Methods
// Primary form: verbosity-gated, curried
log(verbosity: number): (message: any, ...args: any[]) => void;
log.methodName(verbosity: number): (message: any, ...args: any[]) => void;
// Shorthand: equivalent to log(0)('msg') — shows when verbosity > 0
log(message: any, ...args: any[]): void;
log.methodName(message: any, ...args: any[]): void;Instance Methods
log.setTag(newTag: string): void;
log.options: object; // Mutable configurationGlobal Configuration
setDefaults(options: Partial<LogOptions>): void;
setMethodMap(map: Record<string, string>): void;Exports
import Log, { loggers, defaults, methodMap, setDefaults, setMethodMap } from '@vanilla-bean/log';Contributing
Contributions welcome! Submit Pull Requests for improvements. Open issues first for major changes.
Development Setup
# Clone and setup
git clone https://github.com/fatlard1993/log.git
cd log
bun install
# Development workflow
bun test # Run tests
bun run demo # Run examples
bun run lint # Check code style
bun test --watch # Watch modeLicense
MIT License - see the LICENSE file for details.
