Drivers
Logger providers (also called drivers) are responsible for processing and outputting log messages to various destinations. Vercube includes two built-in providers and makes it easy to create custom ones for any logging backend.
Built-in Providers
ConsoleProvider
The ConsoleProvider outputs colorful, human-readable logs to the console. It's ideal for development and debugging.
Usage:
import { Logger, BaseLogger, ConsoleProvider } from '@vercube/logger';
container.bind(Logger, BaseLogger);
container.get(Logger).configure({
logLevel: 'debug',
providers: [
{
name: 'console',
provider: ConsoleProvider
}
]
});
Output Format:
[12:34:56.789] [DEBUG] Looking up user: abc-123
[12:34:56.801] [INFO ] User found { userId: 'abc-123' }
[12:34:57.123] [WARN ] UserService Rate limit approaching
[12:34:58.456] [ERROR] Database connection failed Error: ...
Disabling Colors:
Set the NO_COLOR environment variable:
NO_COLOR=1 node app.js
JSONProvider
The JSONProvider outputs structured JSON logs suitable for log aggregation systems like ELK, Splunk, or CloudWatch.
Usage:
import { Logger, BaseLogger, JSONProvider } from '@vercube/logger';
container.bind(Logger, BaseLogger);
container.get(Logger).configure({
logLevel: 'info',
providers: [
{
name: 'json',
provider: JSONProvider
}
]
});
Output Format:
{"type":"application_log","level":"debug","args":["Looking up user: abc-123"],"timestamp":1703082896789}
{"type":"application_log","level":"info","args":["User found",{"userId":"abc-123"}],"timestamp":1703082896801}
{"type":"application_log","level":"warn","args":["Rate limit approaching"],"timestamp":1703082897123}
{"type":"application_log","level":"error","args":["Database failed",{"error":"..."}],"timestamp":1703082898456}
JSON Structure:
| Field | Type | Description |
|---|---|---|
type | string | Log type (application_log, access_log) |
level | string | Log level (debug, info, warn, error) |
args | array | Array of log arguments |
timestamp | number | Unix timestamp in milliseconds |
tag | string | Optional tag for categorization |
pid | number | Optional process ID |
Creating Custom Providers
Creating a custom provider allows you to output logs to any destination: files, databases, external services, etc.
Basic Provider Template
import { LoggerProvider } from '@vercube/logger';
import type { LoggerTypes } from '@vercube/logger';
export class CustomProvider extends LoggerProvider {
/**
* Initialize the provider with custom options
*/
public initialize(options: any): void {
// Setup code here
// Connect to external service, open file, etc.
}
/**
* Process a log message
*/
public processMessage(message: LoggerTypes.Message): void {
// Format and output the message
const formatted = this.format(message);
this.output(formatted);
}
private format(message: LoggerTypes.Message): string {
// Your formatting logic
return JSON.stringify(message);
}
private output(formatted: string): void {
// Your output logic
console.log(formatted);
}
}
Message Object Structure
The LoggerTypes.Message object contains:
interface Message {
level: 'debug' | 'info' | 'warn' | 'error';
args: any[]; // Arguments passed to logger method
tag?: string; // Optional tag
timestamp?: number; // Unix timestamp in ms
pid?: number; // Process ID
type?: 'access_log' | 'application_log'; // Log type
}
Provider Configuration
Register Provider in Container
If your provider has dependencies, register it in the container:
import { Container } from '@vercube/di';
import { CustomProvider } from './providers/CustomProvider';
export function setupContainer(container: Container): void {
// Register provider
container.bind(CustomProvider);
// Configure logger to use it
container.get(Logger).configure({
providers: [
{
name: 'custom',
provider: CustomProvider,
options: { ... }
}
]
});
}
Provider with Dependencies
If your provider needs other services:
import { Inject } from '@vercube/di';
import { LoggerProvider } from '@vercube/logger';
import { Database } from './database';
export class DatabaseProvider extends LoggerProvider {
@Inject(Database)
private db!: Database;
public initialize(options: any): void {
// this.db is now available
}
public processMessage(message: LoggerTypes.Message): void {
// Use this.db to write logs
}
}
Async Initialization
If your provider needs async initialization:
export class AsyncProvider extends LoggerProvider {
private connection: Connection;
public async initialize(options: any): Promise<void> {
// Async initialization
this.connection = await connectToService(options);
}
public processMessage(message: LoggerTypes.Message): void {
// Use this.connection
}
}
Using Multiple Providers
Configure multiple providers to output to different destinations:
container.get(Logger).configure({
logLevel: 'debug',
providers: [
// Console for development
{
name: 'console',
provider: ConsoleProvider,
logLevel: 'debug'
},
// File for persistent storage
{
name: 'file',
provider: FileProvider,
logLevel: 'info',
options: {
filename: 'app.log',
directory: './logs'
}
},
// JSON for log aggregation
{
name: 'json',
provider: JSONProvider,
logLevel: 'warn'
},
// HTTP for external monitoring
{
name: 'http',
provider: HTTPProvider,
logLevel: 'error',
options: {
endpoint: 'https://logs.myservice.com/api/logs',
apiKey: process.env.LOGGING_API_KEY
}
}
]
});
Provider Not Outputting Logs
Problem: Provider's processMessage() is not called
Solutions:
- Check log level hierarchy:
// If global level is 'error', only errors reach providers
container.get(Logger).configure({
logLevel: 'debug', // Lower this
providers: [...]
});
- Check provider-specific log level:
providers: [
{
name: 'custom',
provider: CustomProvider,
logLevel: 'debug' // This provider's level
}
]
- Verify provider is registered:
// Make sure provider class is in providers array
providers: [
{
name: 'custom',
provider: CustomProvider // ✅ Correct
}
]
Provider Initialization Error
Problem: "Failed to initialize logger provider"
Solutions:
- Check
initialize()method doesn't throw:
public initialize(options: any): void {
try {
// initialization code
} catch (error) {
console.error('Provider init failed:', error);
// Don't throw - handle gracefully
}
}
- Verify provider is bound in container:
container.bind(CustomProvider);
- Check provider options:
providers: [
{
name: 'custom',
provider: CustomProvider,
options: {
// Make sure all required options are provided
requiredOption: 'value'
}
}
]
Provider Missing Dependency
Problem: Injected dependency is undefined
Solution: Make sure dependency is registered before logger configuration:
// Register dependencies first
container.bind(Database);
container.bind(CustomProvider);
// Then configure logger
container.bind(Logger, BaseLogger);
container.get(Logger).configure({
providers: [
{
name: 'custom',
provider: CustomProvider
}
]
});
Async Provider Not Working
Problem: Async initialize() doesn't complete before logging
Solution: Await logger configuration:
container.bind(Logger, BaseLogger);
const logger = container.get(Logger);
// Await async configuration
await logger.configure({
providers: [
{
name: 'async',
provider: AsyncProvider,
options: { ... }
}
]
});