Package Exports
- nexting
- nexting/client
- nexting/server
Readme
Professional Logging System
A complete, extensible, and configurable logging system for TypeScript server applications.
Features
- ✅ Multiple log levels (ERROR, WARN, INFO, DEBUG, TRACE)
- ✅ Extensible formatters (JSON, Pretty, Simple)
- ✅ Modular transports (Console, File)
- ✅ Hierarchical contexts with child loggers
- ✅ Structured metadata for rich logs
- ✅ Specialized request logging for APIs
- ✅ Full TypeScript with strict types
- ✅ Tests included with complete coverage
- ✅ Automatic file rotation
- ✅ Request ID tracking for traceability
Installation
npm install nexting
# or
yarn add nexting
# or
pnpm add nexting
Quick Start
import { createLogger, LogLevel } from 'nexting';
const logger = createLogger({
level: LogLevel.INFO,
context: 'APP',
});
await logger.info('Application started');
await logger.error('Connection error', { database: 'primary' });
Basic Usage
import { createLogger, LogLevel } from './logger';
// Basic logger
const logger = createLogger({
level: LogLevel.INFO,
context: 'APP',
});
await logger.info('Application started');
await logger.error('Connection error', { database: 'primary' });
Request Logging
import { createRequestLogger } from './logger';
const requestLogger = createRequestLogger();
// In your API handler
export async function handleRequest(request: Request) {
const requestId = await requestLogger.logRequest(request);
try {
const startTime = Date.now();
// Your logic here...
const result = await processRequest(request);
const duration = Date.now() - startTime;
await requestLogger.logResponse(requestId, 200, duration);
return result;
} catch (error) {
await requestLogger.logError(requestId, error);
throw error;
}
}
Advanced Configuration
Logger with JSON format for production
import { createLogger, LogLevel, JsonFormatter } from './logger';
const prodLogger = createLogger({
level: LogLevel.WARN,
context: 'PROD',
formatter: new JsonFormatter(),
});
Logger with multiple transports
import {
createLogger,
ConsoleTransport,
FileTransport,
PrettyFormatter
} from './logger';
const logger = createLogger({
level: LogLevel.DEBUG,
context: 'APP',
formatter: new PrettyFormatter(),
transports: [
new ConsoleTransport(),
new FileTransport({
filename: './logs/app.log',
maxFileSize: 50 * 1024 * 1024, // 50MB
maxFiles: 10
})
],
});
Child Loggers
Child loggers inherit configuration from the parent but extend the context:
const mainLogger = createLogger({ context: 'APP' });
const authLogger = mainLogger.child('AUTH');
const dbLogger = mainLogger.child('DATABASE');
await authLogger.info('User authenticated'); // [APP:AUTH]
await dbLogger.error('Connection lost'); // [APP:DATABASE]
Log Levels
// In priority order (ERROR = highest priority)
await logger.error('Critical error'); // Always shown
await logger.warn('Warning'); // Shown if level >= WARN
await logger.info('Information'); // Shown if level >= INFO
await logger.debug('Debug info'); // Shown if level >= DEBUG
await logger.trace('Detailed trace'); // Shown if level >= TRACE
Metadata and Request IDs
// With metadata
await logger.info('User logged in', {
userId: '123',
ip: '192.168.1.1',
userAgent: 'Mozilla/5.0...'
});
// With request ID for tracking
await logger.error('Processing error', { error: 'timeout' }, 'req_123');
Available Formatters
PrettyFormatter (Development)
2023-12-01T10:30:00.000Z [INFO] [APP] [req_123] User authenticated
Metadata: {
"userId": "123",
"method": "POST"
}
JsonFormatter (Production)
{
"timestamp": "2023-12-01T10:30:00.000Z",
"level": "INFO",
"message": "User authenticated",
"context": "APP",
"requestId": "req_123",
"metadata": {
"userId": "123",
"method": "POST"
}
}
SimpleFormatter (Minimalist)
2023-12-01T10:30:00.000Z [INFO] [APP] User authenticated
Environment Configuration
const isDevelopment = process.env.NODE_ENV !== 'production';
const logger = createLogger({
level: isDevelopment ? LogLevel.DEBUG : LogLevel.INFO,
context: 'SERVER',
formatter: isDevelopment ? new PrettyFormatter() : new JsonFormatter(),
transports: isDevelopment
? [new ConsoleTransport()]
: [
new ConsoleTransport(),
new FileTransport({ filename: './logs/app.log' })
]
});
Extensibility
Custom Formatter
import { LogFormatter, LogEntry } from './logger-types';
class CustomFormatter implements LogFormatter {
format(entry: LogEntry): string {
return `[${entry.level}] ${entry.message}`;
}
}
logger.setFormatter(new CustomFormatter());
Custom Transport
import { LogTransport, LogEntry } from './logger-types';
class DatabaseTransport implements LogTransport {
async log(formattedMessage: string, entry: LogEntry): Promise<void> {
// Send to database, external service, etc.
await this.sendToDatabase(entry);
}
}
logger.addTransport(new DatabaseTransport());
API Reference
Logger Interface
interface Logger {
error(message: string, metadata?: Record<string, any>, requestId?: string): Promise<void>;
warn(message: string, metadata?: Record<string, any>, requestId?: string): Promise<void>;
info(message: string, metadata?: Record<string, any>, requestId?: string): Promise<void>;
debug(message: string, metadata?: Record<string, any>, requestId?: string): Promise<void>;
trace(message: string, metadata?: Record<string, any>, requestId?: string): Promise<void>;
child(context: string): Logger;
setLevel(level: LogLevel): void;
setFormatter(formatter: LogFormatter): void;
addTransport(transport: LogTransport): void;
}
RequestLogger Interface
interface RequestLogger {
logRequest(request: Request): Promise<string>;
logResponse(requestId: string, status: number, duration: number): Promise<void>;
logError(requestId: string, error: Error | unknown): Promise<void>;
}
Configuration Types
interface LoggerConfig {
level: LogLevel;
context: string;
formatter?: LogFormatter;
transports?: LogTransport[];
}
enum LogLevel {
ERROR = 0,
WARN = 1,
INFO = 2,
DEBUG = 3,
TRACE = 4
}
Best Practices
- Use descriptive contexts to facilitate debugging
- Include relevant metadata instead of concatenating strings
- Use appropriate levels based on message importance
- Configure file rotation to avoid huge files
- Use JSON in production for automatic parsing
- Track requests with unique IDs for complete traceability
- Create child loggers for different modules/components
- Structure metadata consistently across your application
- Avoid logging sensitive information like passwords or API keys
- Use async logging to prevent blocking operations
API Integration
// middleware.ts
import { requestLogger } from './logger';
export async function loggingMiddleware(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
const requestId = await requestLogger.logRequest(request);
const startTime = Date.now();
try {
const response = await next(request);
const duration = Date.now() - startTime;
await requestLogger.logResponse(
requestId,
response.status,
duration
);
return response;
} catch (error) {
await requestLogger.logError(requestId, error);
throw error;
}
}
Performance Considerations
- Async Operations: All logging operations are asynchronous to prevent blocking
- Memory Efficient: Transports handle buffering and batching internally
- File Rotation: Automatic rotation prevents disk space issues
- Context Reuse: Child loggers reuse parent configuration for efficiency
- Metadata Serialization: Efficient JSON serialization for structured data
Testing
Run the test suite:
npm test
# or
yarn test
# or
pnpm test
Run tests with coverage:
npm run test:coverage
# or
yarn test:coverage
# or
pnpm test:coverage
Troubleshooting
Common Issues
Issue: Logs not appearing
- Check if the log level is appropriate for your message level
- Verify transport configuration
- Ensure async operations are properly awaited
Issue: File transport not working
- Check file permissions for the log directory
- Verify disk space availability
- Ensure the directory exists or can be created
Issue: High memory usage
- Configure file rotation with appropriate limits
- Check for circular references in metadata
- Consider using structured logging instead of large objects
Issue: Performance problems
- Use appropriate log levels in production
- Avoid logging in tight loops
- Consider batching for high-volume scenarios
Debug Mode
Enable debug logging to troubleshoot issues:
const logger = createLogger({
level: LogLevel.DEBUG,
context: 'DEBUG',
});
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Development Setup
# Clone the repository
git clone https://github.com/rrios-dev/nexting.git
cd nexting
# Install dependencies
npm install
# Run tests
npm test
# Build the project
npm run build
Code Style
- Follow TypeScript best practices
- Use meaningful variable and function names
- Add JSDoc comments for public APIs
- Maintain test coverage above 90%
- Follow the existing code formatting
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
v1.0.0
- Initial release with core logging functionality
- Support for multiple formatters and transports
- Request logging capabilities
- Full TypeScript support
- Comprehensive test suite
v1.1.0
- Added file rotation support
- Improved performance for high-volume logging
- Enhanced error handling
- Added more configuration options
Support
If you encounter any issues or have questions:
- Check the troubleshooting section
- Search existing issues
- Create a new issue with detailed information
- For urgent issues, contact the maintainers
Acknowledgments
- Inspired by popular logging libraries like Winston and Pino
- Built with TypeScript for type safety
- Designed for modern Node.js applications
- Community feedback and contributions