@brmorillo/logger
v2.1.1
Published
A flexible and extensible logging library with file persistence, rotation, and compression - supports Pino, Winston, and Console
Maintainers
Readme
@brmorillo/logger
A flexible and extensible logging library for TypeScript/JavaScript applications, supporting multiple logger implementations (Pino, Winston, Console) with automatic file persistence, rotation, and compression.
Note: This library is now licensed under the permissive MIT License, allowing you to use it freely in any project, including commercial applications.
🚀 Quick Start
bun add @brmorillo/loggerimport { LogService } from '@brmorillo/logger';
const logger = LogService.getInstance({
type: 'pino',
level: 'info',
prettyPrint: true,
});
logger.info('Hello, world!', { user: 'Bruno' });With File Persistence
import { LogService } from '@brmorillo/logger';
const logger = LogService.getInstance({
type: 'pino',
level: 'info',
fileTransport: {
logDir: './logs',
rotationInterval: 'hourly',
maxRetentionDays: 7,
compress: true,
},
});
logger.info('Logs saved to console AND files!');✨ Features
🚀 High Performance
- Pino Logger Included: High-performance JSON logging pre-installed
- Zero Dependencies: Pino comes bundled, Winston is optional
- Fast & Lightweight: Minimal overhead for production workloads
📁 File Persistence
- Automatic Rotation: Hourly or daily log file rotation
- Compression: Auto-compress old logs to
.log.gz(saves ~85% space) - Smart Cleanup: Configurable retention policy (e.g., keep 7 days)
- Dual Output: Write to console AND files simultaneously
🔧 Developer Experience
- Simple API: Unified interface for all logger types
- TypeScript First: Full type safety with comprehensive types
- Multiple Loggers: Pino (default), Winston (optional), Console
- *📦 Installation
# Bun (recommended)
bun add @brmorillo/logger
# npm
npm install @brmorillo/logger
# yarn
yarn add @brmorillo/logger
# pnpm
pnpm add @brmorillo/loggerOptional: Install Winston only if needed
bun add winstonNote: Pino comes pre-installed. Winston is only needed for advanced transport features.ort { LogService } from '@brmorillo/logger';
// Get logger instance with default configuration (Pino) const logger = LogService.getInstance();
// Log messages logger.info('Application started'); logger.warn('This is a warning'); logger.error('An error occurred', { error: new Error('Test') }); logger.debug('Debug information', { userId: 123 });
## Configuration
### Basic Configuration
```typescript
import { LogService } from '@brmorillo/logger';
const logger = LogService.getInstance({
type: 'pino', // 'pino' | 'winston' | 'console'
level: 'info', // 'error' | 'warn' | 'info' | 'debug'
prettyPrint: true, // Enable formatted output
});File Persistence Configuration
Enable automatic file persistence with rotation and compression:
imp⚙️ Configuration
### Basic Setup
```typescript
import { LogService } from '@brmorillo/logger';
const logger = LogService.getInstance({
type: 'pino', // 'pino' | 'winston' | 'console'
level: 'info', // 'error' | 'warn' | 'info' | 'debug'
prettyPrint: true, // Formatted output (dev only)
});Production Setup (with File Persistence)
import { LogService } from '@brmorillo/logger';
const logger = LogService.getInstance({
type: 'pino',
level: 'info',
prettyPrint: false,
fileTransport: {
logDir: './logs',
rotationInterval: 'hourly', // or 'daily'
maxRetentionDays: 7,
compress: true,
fileNamePattern: 'app', // app-2025-12-21-14.log
},
});File Structure Example:
logs/
├── app-2025-12-21-14.log # Current hour (active)
├── app-2025-12-21-13.log.gz # Compressed
├── app-2025-12-21-12.log.gz
└── app-2025-12-21-11.log.gzEnvironment-Based Configuration
const isProd = process.env.NODE_ENV === 'production';
const logger = LogService.getInstance({
type: 'pino',
level: process.env.LOG_LEVEL || 'info',
prettyPrint: !isProd,
fileTransport: isProd ? {
logDir: './logs',
rotationInterval: 'hourly',
maxRetentionDays: 7,
compress: true,
} : undefined,
});FileTransport Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| logDir | string | required | Directory to store log files |
| rotationInterval | 'hourly' \| 'daily' | 'hourly' | Rotation frequency |
| maxRetentionDays | number | 7 | Days to keep logs |
| compress | boolean | true | Gzip compression |
| fileNamePattern | string | 'app' | File name prefix |
logger.info('User action', {
userId: '12345',
action: 'purchase',
amount: 99.99
});
logger.error('Payment failed', {
orderId: 'ORD-001',
error: error.message,
stack: error.stack
});Express.js Integration
imp📝 Usage Examples
### Basic Logging
```typescript
import { LogService } from '@brmorillo/logger';
const logger = LogService.getInstance();
logger.info('User logged in');
logger.warn('High memory usage detected');
logger.error('Failed to connect to database');
logger.debug('Request details', { method: 'GET', path: '/api/users' });W
});
app.get('/', (req, res) => { logger.debug('Home route accessed'); res.send('Hello World!'); });
### NestJS Integration
Custom Logger
```typescript
import { Injectable, LoggerService as NestLoggerService } from '@nestjs/common';
import { LogService } from '@brmorillo/logger';
@Injectable()
export class LoggerService implements NestLoggerService {
private logger = LogService.getInstance({
type: 'pino',
level: 'info',
prettyPrint: process.env.NODE_ENV !== 'production',
fileTransport: process.env.NODE_ENV === 'production' ? {
logDir: './logs'
app.use((req, res, next) => {
logger.info('Request', { method: req.method, path: req.path, ip: req.ip error(message: string, trace?: string, context?: string) {
this.logger.error(message, { trace, context });
}
warn(message: string, context?: string) {
this.logger.warn(message, { context });
}
debug(message: string, context?: string) {
this.logger.debug(message, { context });
}
}Fastify Integration
import Fastify from 'fastify';
import { LogService } from '@brmorillo/logger';
const logger = LogService.getInstance({
type: 'pino',
level: 'info',
});
const fastifHook
```typescript
import Fastify from 'fastify';
import { LogService } from '@brmorillo/logger';
const logger = LogService.getInstance({ type: 'pino', level: 'info' });
const fastify = Fastify();
fastify.addHook('onRequest', (request, reply, done) => {
logger.info('Request', { method: request.method, url: request.url });
done();
});
fastify.get('/', async () => {
logger.debug('Hof LogService.
```typescript
const logger = LogService.getInstance({
type: 'pino',
level: 'info',
prettyPrint: true,
});configure(options: LoggerOptions): void
📚 API Reference
LogService Methods
// Get singleton instance
const logger = LogService.getInstance(options?: LoggerOptions);
// Reconfigure at runtime
logger.configure(options: LoggerOptions);
// Logging methods
logger.info(message: string, ...meta: any[]);
logger.warn(message: string, ...meta: any[]);
logger.error(message: string, ...meta: any[]);
logger.debug(message: string, ...meta: any[]);LoggerOptions Interface
interface LoggerOptions {
type?: 'pino' | 'winston' | 'console'; // Default: 'pino'
level?: 'error' | 'warn' | 'info' | 'debug'; // Default: 'info'
prettyPrint?: boolean; // Default: false
fileTransport?: FileTransportConfig; // Optional
}
interface FileTransportConfig {
logDir: string; // Required
rotationInterval?: 'hourly' | 'daily'; // Default: 'hourly'
maxRetentionDays?: number; // Default: 7
compress?: boolean; // Default: true
fileNamePattern?: string; // Default: 'app'
}st BUCKET_NAME = 'my-app-logs';
async function uploadLogs() {
const files = await readdir(LOG_DIR);
// Upload only .log.gz files (compressed logs)
for (const file of files) {
if (file.endsWith('.log.gz')) {
const filePath = join(LOG_DIR, file);
const fileContent = await readFile(filePath);
await s3Client.send(
new PutObjectCommand({
Bucket: BUCKET_NAME,
Key: `logs/${file}`,
Body: fileContent,
ContentType: 'application/gzip',
})
);
// Delete local file after successful upload
await unlink(filePath);
console.log(`Uploaded and deleted: ${file}`);
}
}
}
uploadLogs().catch(console.error);Schedule with cron to run every hour:
# Crontab: Run 5 minutes after each hour
5 * * * * cd /path/to/app && bun run scripts/upload-logs.tsPerformance Considerations
- Pino: Fastest logger, recommended for production. Uses JSON format by default.
- Winston: Feature-rich, slightly slower than Pino. Good for complex logging needs.
- Console: Simple and lightweight, best for development or simple applications.
Compatibility
- ✅ Node.js >= 18
- ✅ Bun >= 1.0
- ✅ TypeScript >= 5.0
- ✅🚀 Advanced Usage
Upload Logs to S3
// scripts/upload-logs.ts
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { readdir, readFile, unlink } from 'fs/promises';
const s3 = new S3Client({ region: 'us-east-1' });
async function uploadLogs() {
const files = await readdir('./logs');
for (const file of files) {
if (file.endsWith('.log.gz')) {
const content = await readFile(`./logs/${file}`);
await s3.send(new PutObjectCommand({
Bucket: 'my-app-logs',
Key: `logs/${file}`,
Body: content,
ContentType: 'application/gzip',
}));
await unlink(`./logs/${file}`);
console.log(`Uploaded: ${file}`);
}
}
}
uploadLogs();Schedule with cron:
5 * * * * cd /app && bun run scripts/upload-logs.tsPerformance Tips
| Logger | Performance | Use Case | |--------|-------------|----------| | Pino | ⚡ Fastest | Production, high-throughput | | Winston | 🚀 Fast | Complex transports, legacy | | Console | 💻 Simple | Development, debugging |📋 Requirements
- Node.js >= 18
- Bun >= 1.0
- TypeScript >= 5.0
Supports both ES Modules and CommonJS.
📖 Documentation
- File Persistence Guide - Complete guide for log rotation & compression
- Examples - Working code examples
🤝 Contributing
Contributions welcome! Please submit a Pull Request.
📄 License
MIT © Bruno Morillo
🔗 Links
Made with ❤️ by Bruno Morillo
