
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@stool/logging
Advanced tools
A simple, logging library inspired by Python's logging module. Features include multiple log levels, custom formatters, filters, and handlers.
npm install @stool/logging
import { getLogger, ConsoleHandler, SimpleFormater } from '@stool/logging';
// Get a logger instance
const logger = getLogger('app');
logger.setLevel('DEBUG');
// Add a console handler with custom formatting
const consoleHandler = new ConsoleHandler();
consoleHandler.setFormater(new SimpleFormater('{name} {levelName} {msg}'));
logger.addHandler(consoleHandler);
// Start logging
logger.info('Application started');
logger.error('Something went wrong');
import { getLogger } from '@stool/logging';
// Root logger
const rootLogger = getLogger();
// Named logger
const appLogger = getLogger('app');
// Child logger (inherits from parent)
const dbLogger = getLogger('app.database');
const userLogger = getLogger('app.user');
const logger = getLogger('myapp');
// Set minimum log level
logger.setLevel('INFO'); // or use Levels.INFO
// Logging methods (in order of severity)
logger.debug('Debug information'); // Lowest priority
logger.info('General information');
logger.warn('Warning message'); // or logger.warning()
logger.error('Error occurred');
logger.fatal('Critical error'); // or logger.critical()
// Exception logging
try {
throw new Error('Something failed');
} catch (error) {
logger.exception(error); // Logs error with stack trace
}
const logger = getLogger('app');
// Log with extra context data
logger.info('User login', { userId: 123, ip: '192.168.1.1' });
logger.error('Database error', new Error('Connection failed'), {
query: 'SELECT * FROM users',
duration: 1500
});
Handlers determine where log messages are sent. You can add multiple handlers to a logger.
import { ConsoleHandler, SimpleFormater } from '@stool/logging';
const logger = getLogger('app');
// Basic console handler
const handler = new ConsoleHandler();
logger.addHandler(handler);
// Console handler with custom formatting
const customHandler = new ConsoleHandler();
customHandler.setFormater(new SimpleFormater('{levelName}: {msg}'));
customHandler.setLevel('WARN'); // Only log warnings and above
logger.addHandler(customHandler);
import { BaseHandler, IRecord } from '@stool/logging';
class FileHandler extends BaseHandler {
constructor(private filename: string) {
super();
}
emit(record: IRecord): void {
const message = this.formater.format(record);
// Write to file (implement your file writing logic)
console.log(`Writing to ${this.filename}: ${message}`);
}
}
// Usage
const fileHandler = new FileHandler('app.log');
logger.addHandler(fileHandler);
Formatters control the structure and appearance of log messages.
import { SimpleFormater } from '@stool/logging';
const logger = getLogger('app');
const handler = new ConsoleHandler();
// Predefined formats
handler.setFormater(new SimpleFormater(SimpleFormater.FULL)); // Full details
handler.setFormater(new SimpleFormater(SimpleFormater.BASIC)); // Basic info
handler.setFormater(new SimpleFormater(SimpleFormater.MINIMAL)); // Just message
// Custom format template
handler.setFormater(new SimpleFormater('{created} [{levelName}] {name}: {msg}'));
{created} - ISO timestamp{timestamp} - Unix timestamp{name} - Logger name{level} - Numeric level{levelName} - Level name (DEBUG, INFO, etc.){msg} - Log message{exception} - Exception information{extra} - Extra context dataimport { IFormater, IRecord } from '@stool/logging';
class JsonFormater implements IFormater {
format(record: IRecord): string {
return JSON.stringify({
timestamp: record.timestamp,
level: record.levelName,
logger: record.name,
message: record.msg,
extra: record.extra
});
}
}
// Usage
const handler = new ConsoleHandler();
handler.setFormater(new JsonFormater());
Filters provide fine-grained control over which log records are processed.
import { Filter } from '@stool/logging';
const logger = getLogger('app');
const handler = new ConsoleHandler();
// Only log records from 'app.database' and its children
const filter = new Filter('app.database');
handler.addFilter(filter);
logger.addHandler(handler);
// Function-based filter
const errorOnlyFilter = (record) => record.level >= Levels.ERROR;
handler.addFilter(errorOnlyFilter);
// Class-based filter
class TimeFilter {
constructor(private startHour: number, private endHour: number) {}
filter(record: IRecord): boolean {
const hour = record.created.getHours();
return hour >= this.startHour && hour <= this.endHour;
}
}
// Only log during business hours
handler.addFilter(new TimeFilter(9, 17));
Loggers form a hierarchy based on their names (separated by dots). Child loggers inherit settings from parents and can propagate messages up the hierarchy.
const appLogger = getLogger('app');
const dbLogger = getLogger('app.database');
const userDbLogger = getLogger('app.database.users');
// Add handler to parent
const handler = new ConsoleHandler();
appLogger.addHandler(handler);
// Child loggers will use parent's handler
dbLogger.info('Database connected'); // Will use app's handler
userDbLogger.info('User table ready'); // Will also use app's handler
// Add specific handler to child
const dbHandler = new ConsoleHandler();
dbHandler.setFormater(new SimpleFormater('DB: {msg}'));
dbLogger.addHandler(dbHandler);
// Now dbLogger will use both handlers
dbLogger.info('Query executed'); // Appears in both formats
import {
getLogger,
ConsoleHandler,
SimpleFormater,
Filter,
Levels
} from '@stool/logging';
// Create main application logger
const appLogger = getLogger('myapp');
appLogger.setLevel(Levels.DEBUG);
// Set up console handler with custom formatting
const consoleHandler = new ConsoleHandler();
consoleHandler.setFormater(new SimpleFormater(
'{created} [{levelName}] {name}: {msg} {extra}'
));
appLogger.addHandler(consoleHandler);
// Create specialized loggers
const httpLogger = getLogger('myapp.http');
const dbLogger = getLogger('myapp.database');
// Add filter to only show errors for database
const dbHandler = new ConsoleHandler();
dbHandler.setLevel(Levels.ERROR);
dbHandler.setFormater(new SimpleFormater('DB ERROR: {msg}'));
dbLogger.addHandler(dbHandler);
// Usage
appLogger.info('Application starting');
httpLogger.info('Server listening on port 3000');
dbLogger.info('Database connected'); // Won't show (below ERROR level)
dbLogger.error('Query failed', { query: 'SELECT * FROM users' });
// Exception handling
try {
throw new Error('Something went wrong');
} catch (error) {
appLogger.exception(error);
}
setLevel(level: LevelType) - Set minimum log leveladdHandler(handler: IHandler) - Add output handlerremoveHandler(handler: IHandler) - Remove handlerdebug(msg: string) - Log debug messageinfo(msg: string, extra?: any) - Log info messagewarn(msg: string, exception?: any, extra?: any) - Log warningerror(msg: string, exception?: any, extra?: any) - Log errorfatal(msg: string, exception?: any, extra?: any) - Log fatal errorexception(error: Error) - Log exception with stack traceimport { Levels } from '@stool/logging';
Levels.DEBUG // 1
Levels.INFO // 2
Levels.WARN // 4
Levels.ERROR // 8
Levels.FATAL // 16
Levels.NOTSET // 0
MIT
FAQs
Logger
We found that @stool/logging demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.