Hackable console logger for Node.js applications with 17 out-of-the-box logger types and advanced features including integrated timers, scoped loggers, secrets filtering, and custom pluggable loggers.
—
Integrated timer functionality for measuring operation duration with automatic labeling and formatted output. Timers provide a convenient way to measure and log execution time for operations with clear visual indicators.
Start and stop timers with automatic or custom labeling.
/**
* Start a timer with optional custom label
* @param label - Optional timer label (auto-generated if not provided)
* @returns The timer label used for this timer
*/
function time(label?: string): string;
/**
* Stop a timer and display the elapsed time
* @param label - Optional timer label (uses most recent unlabeled timer if not provided)
* @returns Object containing the timer label and elapsed time in milliseconds, or undefined if timer not found
*/
function timeEnd(label?: string): {label: string, span: number} | undefined;Simple timer operations with automatic labeling.
Usage Examples:
const signale = require('signale');
// Start timer with auto-generated label
const label1 = signale.time();
// Output: ▶ timer_0 Initialized timer...
const label2 = signale.time();
// Output: ▶ timer_1 Initialized timer...
// Simulate some work
setTimeout(() => {
// End most recent timer (timer_1)
const result1 = signale.timeEnd();
// Output: ◼ timer_1 Timer run for: 1.02s
console.log(result1); // {label: 'timer_1', span: 1020}
// End specific timer (timer_0)
const result2 = signale.timeEnd('timer_0');
// Output: ◼ timer_0 Timer run for: 1.15s
console.log(result2); // {label: 'timer_0', span: 1150}
}, 1000);Use meaningful labels for better organization and readability.
Usage Examples:
const signale = require('signale');
// Start named timers
signale.time('database-query');
// Output: ▶ database-query Initialized timer...
signale.time('file-processing');
// Output: ▶ file-processing Initialized timer...
signale.time('api-request');
// Output: ▶ api-request Initialized timer...
// End specific timers by label
setTimeout(() => {
signale.timeEnd('database-query');
// Output: ◼ database-query Timer run for: 245ms
signale.timeEnd('file-processing');
// Output: ◼ file-processing Timer run for: 1.35s
signale.timeEnd('api-request');
// Output: ◼ api-request Timer run for: 892ms
}, 1000);Capture and use timer results programmatically.
Usage Examples:
const signale = require('signale');
async function processData() {
const timerLabel = signale.time('data-processing');
// Simulate data processing
await new Promise(resolve => setTimeout(resolve, 1500));
const result = signale.timeEnd(timerLabel);
if (result) {
const { label, span } = result;
if (span > 1000) {
signale.warn(`Operation ${label} took ${span}ms - consider optimization`);
} else {
signale.success(`Operation ${label} completed efficiently in ${span}ms`);
}
}
}
processData();
// Output: ▶ data-processing Initialized timer...
// ◼ data-processing Timer run for: 1.50s
// ⚠ warning Operation data-processing took 1500ms - consider optimizationHandle multiple concurrent timers with different strategies.
Usage Examples:
const signale = require('signale');
// Start multiple timers
const dbTimer = signale.time('database');
const cacheTimer = signale.time('cache');
const autoTimer1 = signale.time(); // timer_0
const autoTimer2 = signale.time(); // timer_1
setTimeout(() => {
// End timers in different order
signale.timeEnd('cache'); // End by name
signale.timeEnd(); // End most recent auto-timer (timer_1)
signale.timeEnd('database'); // End by name
signale.timeEnd(); // End remaining auto-timer (timer_0)
}, 800);
// Output:
// ▶ database Initialized timer...
// ▶ cache Initialized timer...
// ▶ timer_0 Initialized timer...
// ▶ timer_1 Initialized timer...
// ◼ cache Timer run for: 800ms
// ◼ timer_1 Timer run for: 800ms
// ◼ database Timer run for: 800ms
// ◼ timer_0 Timer run for: 800msTimers automatically format display based on duration.
Usage Examples:
const signale = require('signale');
// Short duration (milliseconds)
signale.time('short');
setTimeout(() => {
signale.timeEnd('short');
// Output: ◼ short Timer run for: 150ms
}, 150);
// Medium duration (seconds with decimals)
signale.time('medium');
setTimeout(() => {
signale.timeEnd('medium');
// Output: ◼ medium Timer run for: 2.35s
}, 2350);
// Long duration (seconds with decimals)
signale.time('long');
setTimeout(() => {
signale.timeEnd('long');
// Output: ◼ long Timer run for: 15.67s
}, 15670);Handle cases where timers don't exist or have issues.
Usage Examples:
const signale = require('signale');
// Try to end non-existent timer
const result = signale.timeEnd('non-existent');
console.log(result); // undefined (no output, no error)
// Try to end timer when no auto-timers exist
const result2 = signale.timeEnd();
console.log(result2); // undefined (no output, no error)
// Start and end the same timer twice
signale.time('duplicate-test');
const first = signale.timeEnd('duplicate-test');
console.log(first); // {label: 'duplicate-test', span: ...}
const second = signale.timeEnd('duplicate-test');
console.log(second); // undefined (timer already ended)Timers work with scoped loggers and inherit timer state.
Usage Examples:
const signale = require('signale');
// Start timer on main instance
signale.time('main-timer');
// Create scoped logger - inherits timer state
const scoped = signale.scope('module');
// Timer state is shared
scoped.timeEnd('main-timer');
// Output: [module] › ◼ main-timer Timer run for: 1.23s
// Start timer on scoped logger
scoped.time('scoped-timer');
// End from main instance - timers are shared
signale.timeEnd('scoped-timer');
// Output: ◼ scoped-timer Timer run for: 456msCommon patterns for using timers in applications.
Usage Examples:
const signale = require('signale');
// Function timing wrapper
function timeFunction(name, fn) {
return async (...args) => {
const timer = signale.time(name);
try {
const result = await fn(...args);
signale.timeEnd(timer);
return result;
} catch (error) {
signale.timeEnd(timer);
signale.error(`Function ${name} failed after timing`);
throw error;
}
};
}
// Usage
const timedOperation = timeFunction('data-fetch', async () => {
// Simulate async operation
await new Promise(resolve => setTimeout(resolve, 1000));
return 'data';
});
timedOperation();
// Output: ▶ data-fetch Initialized timer...
// ◼ data-fetch Timer run for: 1.00s
// Nested timing
async function complexOperation() {
signale.time('total');
signale.time('phase1');
await new Promise(resolve => setTimeout(resolve, 500));
signale.timeEnd('phase1');
signale.time('phase2');
await new Promise(resolve => setTimeout(resolve, 300));
signale.timeEnd('phase2');
signale.timeEnd('total');
}
complexOperation();
// Output: ▶ total Initialized timer...
// ▶ phase1 Initialized timer...
// ◼ phase1 Timer run for: 500ms
// ▶ phase2 Initialized timer...
// ◼ phase2 Timer run for: 300ms
// ◼ total Timer run for: 800msInstall with Tessl CLI
npx tessl i tessl/npm-signale