onprem-logger
v1.0.3
Published
A powerful, flexible logging utility for on-premise Node.js servers with automatic file rotation, module-specific logs, colored console output, and JSON formatting.
Maintainers
Readme
onprem-logger
A powerful, flexible logging utility designed for on-premise Node.js servers. Features automatic file rotation, module-specific logs, colored console output, JSON formatting, and full TypeScript support.
Why Use This Logger?
- Zero Dependencies - Built entirely with Node.js built-in modules
- Production Ready - Designed for on-premise enterprise server deployments
- Smart Defaults - Works out of the box with sensible defaults
- Highly Configurable - Customize everything via options or environment variables
- Module Isolation - Create separate log files for different parts of your application
- Auto Rotation - Never worry about disk space with automatic log rotation
- Express Ready - Built-in middleware support for API logging
Features
| Feature | Description | |---------|-------------| | 📁 File Logging | Separate error and combined log files | | 🔄 Auto Rotation | Rotate logs when they reach configurable size | | 🎨 Colored Output | Color-coded console logs for easy debugging | | 📊 JSON Format | Structured logs for parsing and analysis | | 🧩 Module-Specific | Separate logs for database, api, scheduler, etc. | | ⚡ Performance Tracking | Built-in duration logging for operations | | 🔧 Express Integration | Middleware-ready request/response logging | | 📝 TypeScript | Full type definitions included |
Installation
npm install onprem-loggerQuick Start
const { createLogger } = require('onprem-logger');
// Create a logger instance
const logger = createLogger({
serverName: 'MyServer'
});
// Start logging!
logger.info('Server started successfully');
logger.warn('Memory usage is high', { usage: '85%' });
logger.error('Database connection failed', { host: 'localhost' });
logger.debug('Processing request...'); // Only in non-productionConfiguration
Environment Variables
Configure the logger using environment variables (perfect for Docker/Kubernetes):
| Variable | Description | Default |
|----------|-------------|---------|
| LOG_DIR | Directory for log files | ./logs |
| SERVER_NAME | Server identifier in logs | server |
| NODE_ENV | Environment (affects debug logging) | development |
Example .env File
LOG_DIR=/var/logs/myapp
SERVER_NAME=Production_API_Server
NODE_ENV=productionConstructor Options
const logger = createLogger({
// Identification
serverName: 'MyServer', // Server name in logs (overrides SERVER_NAME)
moduleName: 'database', // Module name (creates separate log files)
// Paths
logDir: '/var/logs/myapp', // Log directory (overrides LOG_DIR)
// Behavior
environment: 'production', // Environment (overrides NODE_ENV)
consoleOutput: true, // Enable/disable console output
// Rotation Settings
maxLogSize: 10 * 1024 * 1024, // 10MB max file size
maxBackups: 10, // Keep 10 backup files
rotationInterval: 1800000, // Check every 30 minutes
autoRotate: true // Enable auto-rotation
});Log File Naming Convention
Log files are automatically named based on your serverName and moduleName:
| serverName | moduleName | Error Log | Combined Log |
|------------|------------|-----------|--------------|
| MyServer | (default) | MyServer_error.log | MyServer_combined.log |
| MyServer | database | MyServer_database_error.log | MyServer_database_combined.log |
| MyServer | api | MyServer_api_error.log | MyServer_api_combined.log |
| MyServer | scheduler | MyServer_scheduler_error.log | MyServer_scheduler_combined.log |
Usage Examples
Basic Logging
const { createLogger } = require('onprem-logger');
const logger = createLogger({ serverName: 'MyApp' });
// Simple messages
logger.info('Application started');
logger.warn('Cache miss detected');
logger.error('Failed to process request');
logger.debug('Variable value: 42'); // Only in non-production
// With metadata (additional context)
logger.info('User logged in', {
userId: 123,
email: '[email protected]',
loginMethod: 'oauth'
});
logger.error('Payment failed', {
orderId: 'ORD-456',
amount: 99.99,
currency: 'USD',
errorCode: 'INSUFFICIENT_FUNDS'
});Module-Specific Loggers
Create separate log files for different parts of your application:
const { createLogger } = require('onprem-logger');
// Main application logger
const appLogger = createLogger({
serverName: 'MyApp'
});
// Database logger → MyApp_database_error.log, MyApp_database_combined.log
const dbLogger = createLogger({
serverName: 'MyApp',
moduleName: 'database'
});
// API logger → MyApp_api_error.log, MyApp_api_combined.log
const apiLogger = createLogger({
serverName: 'MyApp',
moduleName: 'api'
});
// Scheduler logger → MyApp_scheduler_error.log, MyApp_scheduler_combined.log
const schedulerLogger = createLogger({
serverName: 'MyApp',
moduleName: 'scheduler'
});
// Each logger writes to its own files
dbLogger.info('Connected to PostgreSQL');
apiLogger.info('API server listening on port 3000');
schedulerLogger.info('Daily backup job started');Express Middleware Integration
const express = require('express');
const { createLogger } = require('onprem-logger');
const app = express();
const logger = createLogger({
serverName: 'API',
moduleName: 'http'
});
// Request/Response logging middleware
app.use((req, res, next) => {
const startTime = Date.now();
// Log incoming request
logger.logApiRequest(req, { requestId: req.headers['x-request-id'] });
// Log response when finished
res.on('finish', () => {
const duration = Date.now() - startTime;
logger.logApiResponse(req, res, null, {
duration,
requestId: req.headers['x-request-id']
});
});
next();
});
// Error handling middleware
app.use((err, req, res, next) => {
logger.logHttpError(req, err, {
requestId: req.headers['x-request-id']
});
res.status(err.statusCode || 500).json({
error: 'Internal Server Error'
});
});Error Logging with Stack Traces
const { createLogger } = require('onprem-logger');
const logger = createLogger({ serverName: 'MyApp' });
async function processOrder(orderId) {
try {
// Some operation that might fail
await chargeCustomer(orderId);
} catch (error) {
// Log full error with stack trace and context
logger.logError(error, {
context: 'order-processing',
orderId,
customerId: 'CUST-123'
});
throw error; // Re-throw if needed
}
}Performance Monitoring
const { createLogger } = require('onprem-logger');
const logger = createLogger({ serverName: 'MyApp' });
async function fetchDataFromAPI() {
const startTime = Date.now();
try {
const data = await externalAPICall();
// Log successful operation with timing
logger.logPerformance('external-api-call', Date.now() - startTime, {
endpoint: 'https://api.example.com/data',
recordCount: data.length,
status: 'success'
});
return data;
} catch (error) {
// Log failed operation with timing
logger.logPerformance('external-api-call', Date.now() - startTime, {
endpoint: 'https://api.example.com/data',
status: 'failed',
error: error.message
});
throw error;
}
}Database Module Example
// src/config/database.js
const { createLogger } = require('onprem-logger');
const { Pool } = require('pg');
const logger = createLogger({
serverName: process.env.SERVER_NAME || 'MyApp',
moduleName: 'database'
});
const pool = new Pool({
host: process.env.DB_HOST,
database: process.env.DB_NAME
});
async function connectDatabase() {
const startTime = Date.now();
try {
logger.info('Attempting database connection...', {
host: process.env.DB_HOST,
database: process.env.DB_NAME
});
await pool.connect();
logger.info('Database connected successfully');
logger.logPerformance('database-connect', Date.now() - startTime);
return pool;
} catch (error) {
logger.logError(error, {
operation: 'database-connect',
host: process.env.DB_HOST
});
throw error;
}
}
// Log slow queries
pool.on('query', (query) => {
const start = Date.now();
query.on('end', () => {
const duration = Date.now() - start;
if (duration > 1000) { // Log queries taking more than 1 second
logger.warn('Slow query detected', {
query: query.text?.substring(0, 100),
duration,
threshold: 1000
});
}
});
});
module.exports = { connectDatabase, pool, logger };Log Output Formats
Console Output (Development)
[2024-01-15T10:30:45.123Z] [MyServer:database] INFO: Connected to database
{ host: 'localhost', database: 'myapp' }
[2024-01-15T10:30:45.456Z] [MyServer:api] ERROR: Request failed
{ statusCode: 500, endpoint: '/api/users', error: 'Connection timeout' }File Output (JSON - for log aggregators)
{"timestamp":"2024-01-15T10:30:45.123Z","level":"info","server":"MyServer","module":"database","message":"Connected to database","environment":"production","host":"localhost","database":"myapp"}
{"timestamp":"2024-01-15T10:30:45.456Z","level":"error","server":"MyServer","module":"api","message":"Request failed","environment":"production","statusCode":500,"endpoint":"/api/users","error":"Connection timeout"}API Reference
createLogger(options)
Create a new logger instance.
const logger = createLogger({
serverName: 'MyServer', // Server identifier
moduleName: 'api', // Module identifier
logDir: '/var/logs', // Log directory
environment: 'production', // Environment name
consoleOutput: false, // Disable console in production
maxLogSize: 10485760, // 10MB
maxBackups: 5, // Keep 5 backups
rotationInterval: 3600000, // Check every hour
autoRotate: true // Enable auto-rotation
});Logging Methods
| Method | Description | Example |
|--------|-------------|---------|
| info(message, metadata?) | Log informational message | logger.info('Started', { port: 3000 }) |
| warn(message, metadata?) | Log warning message | logger.warn('High memory', { usage: '90%' }) |
| error(message, metadata?) | Log error message | logger.error('Failed', { code: 500 }) |
| debug(message, metadata?) | Log debug message (non-prod only) | logger.debug('Value:', { x: 42 }) |
Specialized Logging Methods
| Method | Description |
|--------|-------------|
| logApiRequest(req, metadata?) | Log Express request details |
| logApiResponse(req, res, body?, metadata?) | Log Express response details |
| logError(error, metadata?) | Log Error object with stack trace |
| logPerformance(operation, duration, metadata?) | Log operation timing |
| logHttpError(req, error, metadata?) | Log HTTP error with CORS info |
Utility Methods
| Method | Description |
|--------|-------------|
| clearLogs() | Clear all log files |
| getLogSizes() | Get current log file sizes |
| rotateLog(path, maxSize?) | Manually rotate a log file |
| stopAutoRotation() | Stop automatic rotation timer |
| setConsoleOutput(enabled) | Enable/disable console output |
| setEnvironment(env) | Change environment at runtime |
| getLoggerInfo() | Get logger configuration |
Log Rotation
Logs are automatically rotated when they exceed maxLogSize (default: 5MB).
How It Works
- When a log file exceeds the size limit, it's renamed with a timestamp
- A new empty log file is created
- Old backups beyond
maxBackupsare automatically deleted
Backup File Naming
MyServer_combined.log.2024-01-15T10-30-45.123Z.backup
MyServer_combined.log.2024-01-14T08-15-30.456Z.backupManual Rotation
// Force rotation regardless of size
await logger.rotateLog(logger.combinedLogPath, 0);TypeScript Support
Full TypeScript definitions are included:
import { createLogger, LoggerHelper, LoggerOptions, LogSizes } from 'onprem-logger';
const options: LoggerOptions = {
serverName: 'TypedServer',
moduleName: 'api',
maxLogSize: 10 * 1024 * 1024
};
const logger: LoggerHelper = createLogger(options);
// Full IntelliSense support
logger.info('TypeScript is awesome!');
// Get typed log sizes
const sizes: LogSizes | null = await logger.getLogSizes();
if (sizes) {
console.log(`Combined log: ${sizes.combinedLog.sizeInMB} MB`);
}Best Practices
1. Use Module-Specific Loggers
// ✅ Good - Separate loggers for different concerns
const dbLogger = createLogger({ serverName: 'App', moduleName: 'database' });
const apiLogger = createLogger({ serverName: 'App', moduleName: 'api' });
const authLogger = createLogger({ serverName: 'App', moduleName: 'auth' });
// ❌ Avoid - Single logger for everything
const logger = createLogger({ serverName: 'App' });2. Include Contextual Metadata
// ✅ Good - Rich context for debugging
logger.error('Payment failed', {
userId: user.id,
orderId: order.id,
amount: order.total,
paymentMethod: 'credit_card',
errorCode: error.code
});
// ❌ Avoid - No context
logger.error('Payment failed');3. Use Appropriate Log Levels
logger.debug('Entering function X'); // Development only
logger.info('User registered'); // Normal operations
logger.warn('Rate limit approaching'); // Potential issues
logger.error('Database connection lost'); // Errors requiring attention4. Disable Console in Production
const logger = createLogger({
serverName: 'ProdServer',
consoleOutput: process.env.NODE_ENV !== 'production'
});License
MIT © miryasha
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Related Packages
- advanced-trading-statistics - Advanced trading analytics
