@bernierllc/logging
Version:
A comprehensive logging package with Winston integration for audit and system logging
457 lines (338 loc) • 13.4 kB
Markdown
A comprehensive logging package with Winston integration for audit and system logging. This package provides a clean abstraction layer over Winston, with separate loggers for audit events and system events, ensuring proper separation of concerns and type safety.
- **Dual Logger Architecture**: Separate loggers for audit events and system events
- **Type Safety**: Full TypeScript support with comprehensive type definitions
- **Winston Integration**: Built on top of Winston for robust logging capabilities
- **Environment Awareness**: Automatic configuration based on environment
- **Flexible Configuration**: Support for multiple transports and custom configurations
- **Convenience Functions**: Easy-to-use logging methods for common scenarios
- **Request Tracking**: Built-in support for request IDs and correlation
- **File Logging with Rotation**: Production-ready file logging with automatic rotation
- **Structured JSON Logging**: All logs are structured JSON for easy parsing and analysis
```bash
npm install @bernierllc/logging winston
```
```typescript
import { logger, audit } from '@bernierllc/logging';
// System logging
logger.info('Application started');
logger.error('Something went wrong', new Error('Database error'));
// Audit logging
audit({
actorId: 'user123',
action: 'DELETE_PROJECT',
target: 'project456',
ip: '192.168.1.100',
metadata: { reason: 'User request' }
});
```
```typescript
import { createAuditLogger, createSystemLogger, logAudit, logSystem } from '@bernierllc/logging';
// Create custom loggers
const auditLogger = createAuditLogger({
enableFile: true,
filePath: './logs/audit.log',
enableConsole: true
});
const systemLogger = createSystemLogger({
level: 'debug',
enableFile: true,
filePath: './logs/system.log'
});
// Use custom loggers
logAudit(auditLogger, {
actorId: 'admin456',
action: 'CREATE_USER',
target: 'user789'
});
logSystem(systemLogger, {
level: 'info',
message: 'User created successfully',
metadata: { userId: 'user789' }
});
```
The package now includes production-ready file logging with automatic rotation by default:
```typescript
import { createSystemLogger } from '@bernierllc/logging';
// Production configuration (default behavior)
const productionLogger = createSystemLogger({
enableConsole: false, // Disabled in production
enableFile: true, // Enabled in production
filePath: './logs/app.log',
level: 'info',
maxSize: '10m', // Rotate at 10MB
maxFiles: '5', // Keep 5 rotated files
tailable: true, // Enable tailing
zippedArchive: true // Compress old files
});
```
```typescript
const developmentLogger = createSystemLogger({
enableConsole: true, // Enabled in development
enableFile: true, // Also log to file
filePath: './logs/dev.log',
level: 'debug',
maxSize: '5m',
maxFiles: '3',
tailable: true,
zippedArchive: false // Don't compress in development
});
```
By default, logs are written to:
- **System logs**: `./logs/app-YYYY-MM-DD.log` (with rotation)
- **Audit logs**: `./logs/audit.log`
- **Development logs**: `./logs/dev-YYYY-MM-DD.log` (when configured)
To monitor logs in real-time:
```bash
tail -f logs/app-*.log
tail -f logs/dev-*.log
tail -f logs/audit.log
tail -f logs/app-2025-01-15.log
```
The package uses `winston-daily-rotate-file` for automatic log rotation:
```typescript
const logger = createSystemLogger({
enableFile: true,
filePath: './logs/app.log',
maxSize: '10m', // Rotate when file reaches 10MB
maxFiles: '5', // Keep 5 rotated files
tailable: true, // Enable tailing for real-time monitoring
zippedArchive: true, // Compress old log files
datePattern: 'YYYY-MM-DD' // Date pattern for rotated files
});
```
**Rotation Options:**
- `maxSize`: Maximum size before rotation (e.g., '10m', '100k', '1g')
- `maxFiles`: Number of rotated files to keep
- `tailable`: Enable real-time monitoring with `tail -f`
- `zippedArchive`: Compress old log files to save space
- `datePattern`: Date format for rotated file names
## API Reference
### Default Loggers
The package provides pre-configured default loggers for immediate use:
```typescript
import { defaultAuditLogger, defaultSystemLogger } from '@bernierllc/logging';
```
```typescript
import { logger } from '@bernierllc/logging';
logger.error(message: string, error?: Error, metadata?: Record<string, unknown>);
logger.warn(message: string, metadata?: Record<string, unknown>);
logger.info(message: string, metadata?: Record<string, unknown>);
logger.debug(message: string, metadata?: Record<string, unknown>);
```
```typescript
import { audit } from '@bernierllc/logging';
audit(entry: AuditLogEntry): void;
```
Creates a Winston logger configured for audit logging.
**Configuration Options:**
- `level`: Log level (default: 'info')
- `enableConsole`: Enable console transport (default: false)
- `enableFile`: Enable file transport (default: false)
- `filePath`: File path for logging (default: './logs/audit.log')
- `databaseUrl`: Database URL for storage (requires additional transport)
- `collection`: Database collection name (default: 'audit_logs')
- `defaultMeta`: Default metadata for all log entries
#### `createSystemLogger(config?: SystemLoggerConfig): winston.Logger`
Creates a Winston logger configured for system logging.
**Configuration Options:**
- `level`: Log level (default: from LOG_LEVEL env var or 'info')
- `enableConsole`: Enable console transport (default: true in dev, false in prod)
- `enableFile`: Enable file transport (default: false in dev, true in prod)
- `filePath`: File path for logging (default: './logs/system.log')
- `enableSentry`: Enable Sentry transport (default: false)
- `sentryDsn`: Sentry DSN for error tracking
- `defaultMeta`: Default metadata for all log entries
- `maxSize`: Maximum file size before rotation (default: '10m')
- `maxFiles`: Number of rotated files to keep (default: '5')
- `tailable`: Enable tailing for real-time monitoring (default: true)
- `datePattern`: Date pattern for rotated files (default: 'YYYY-MM-DD')
- `zippedArchive`: Compress old log files (default: true)
### Logging Functions
#### `logAudit(logger: winston.Logger, entry: AuditLogEntry): void`
Logs an audit entry using the specified logger.
#### `logSystem(logger: winston.Logger, entry: SystemLogEntry): void`
Logs a system entry using the specified logger.
#### `logError(logger: winston.Logger, message: string, error?: Error, metadata?: Record<string, unknown>): void`
Convenience function for logging errors.
#### `logWarn(logger: winston.Logger, message: string, metadata?: Record<string, unknown>): void`
Convenience function for logging warnings.
#### `logInfo(logger: winston.Logger, message: string, metadata?: Record<string, unknown>): void`
Convenience function for logging info messages.
#### `logDebug(logger: winston.Logger, message: string, metadata?: Record<string, unknown>): void`
Convenience function for logging debug messages.
## Type Definitions
### AuditLogEntry
```typescript
type AuditLogEntry = {
actorId: string; // Who performed the action
action: string; // What action was performed
target: string; // What was acted upon
ip?: string; // IP address of the actor
metadata?: Record<string, unknown>; // Additional context
timestamp?: string; // When the action occurred
userId?: string; // User ID (alternative to actorId)
sessionId?: string; // Session identifier
userAgent?: string; // User agent string
requestId?: string; // Request correlation ID
};
```
```typescript
type SystemLogEntry = {
level: 'error' | 'warn' | 'info' | 'debug';
message: string;
timestamp?: string;
metadata?: Record<string, unknown>;
error?: Error;
context?: string;
requestId?: string;
userId?: string;
};
```
The package automatically adapts to different environments:
- Audit logs are redirected to console (unless explicitly enabled)
- System logs use console transport by default
- Debug level logging is enabled
- File logging is available but not enabled by default
### Production
- Audit logs use file transport by default
- System logs use file transport with rotation by default
- Console logging is disabled by default
- Error tracking can be enabled via Sentry
### Environment Variables
- `NODE_ENV`: Determines environment-specific behavior
- `LOG_LEVEL`: Sets the default log level for system logging
## Examples
### API Route Logging
```typescript
import { logger, audit } from '@bernierllc/logging';
export async function handleUserAction(req, res) {
const requestId = req.headers['x-request-id'];
const userIp = req.headers['x-forwarded-for'];
try {
// Log the action
audit({
actorId: req.user.id,
action: 'UPDATE_PROFILE',
target: 'profile',
ip: userIp,
requestId,
metadata: { changes: req.body }
});
// Process the request
await updateUserProfile(req.user.id, req.body);
logger.info('Profile updated successfully', {
requestId,
userId: req.user.id
});
res.json({ success: true });
} catch (error) {
logger.error('Profile update failed', error, {
requestId,
userId: req.user.id
});
res.status(500).json({ error: 'Update failed' });
}
}
```
```typescript
import { createSystemLogger } from '@bernierllc/logging';
function createServiceLogger(serviceName: string) {
return createSystemLogger({
level: 'info',
enableFile: true,
filePath: `./logs/${serviceName}.log`,
defaultMeta: { service: serviceName }
});
}
const userServiceLogger = createServiceLogger('user-service');
const paymentServiceLogger = createServiceLogger('payment-service');
```
1. **Check file permissions**: Ensure the application has write permissions to the logs directory
2. **Verify configuration**: Make sure `enableFile: true` is set
3. **Check file path**: Verify the `filePath` is correct and accessible
4. **Environment variables**: Ensure `NODE_ENV` and `LOG_LEVEL` are set
1. **Check maxSize**: Ensure `maxSize` is set to a reasonable value (e.g., '10m')
2. **Verify maxFiles**: Make sure `maxFiles` is set to keep rotated files
3. **File permissions**: Ensure the application can create new files in the logs directory
### Performance Issues
1. **Reduce log level**: Set `level` to 'warn' or 'error' in production
2. **Disable console**: Set `enableConsole: false` in production
3. **Compress archives**: Enable `zippedArchive: true` to save disk space
## Best Practices
### 1. Use Appropriate Logger Types
- Use audit logger for security-relevant events (logins, data changes, access attempts)
- Use system logger for application events (startup, errors, performance metrics)
### 2. Include Request Correlation
- Always include `requestId` in logs for traceability
- Use consistent request ID generation across your application
### 3. Structured Metadata
- Use structured metadata instead of string concatenation
- Include relevant context (user ID, IP, timestamps)
### 4. Environment-Specific Configuration
- Configure different transports for different environments
- Use environment variables for sensitive configuration
### 5. Error Handling
- Always include error objects in error logs
- Provide sufficient context for debugging
### 6. File Logging Best Practices
- Use log rotation to prevent disk space issues
- Monitor log file sizes and rotation frequency
- Use compression for archived logs in production
- Set appropriate log levels for different environments
## Testing
```bash
npm test
```
The package includes comprehensive tests for all functionality, including:
- Logger creation and configuration
- Log entry formatting and validation
- Environment-specific behavior
- Type safety validation
- File logging and rotation
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass
6. Submit a pull request
## License
MIT License - see LICENSE file for details.
## Support
For issues and questions, please open an issue in the repository.
## Monorepo Workspaces & Dependency Management
This package is part of a monorepo using npm workspaces. All dependencies are hoisted to the root. Always run `npm install` from the root directory.
## React 19 and Testing Library Compatibility
This package uses React 19.1.0. If you see peer dependency warnings with Testing Library, use:
```bash
npm install --legacy-peer-deps
```
This is a temporary workaround until official support is released.