Logger
walkerOS provides a centralized logging system that enables consistent logging across the collector, sources, and destinations. The logger supports four log levels and provides scoped logging for better debugging.
Configuration
Configure logging when initializing the collector:
import { startFlow } from '@walkeros/collector';
const { collector, elb } = await startFlow({
logger: {
level: 'DEBUG', // 'ERROR' | 'WARN' | 'INFO' | 'DEBUG'
},
});Log levels
| Level | Value | Description |
|---|---|---|
ERROR | 0 | Only errors (default) |
WARN | 1 | Errors and warnings |
INFO | 2 | Errors, warnings, and informational |
DEBUG | 3 | All messages including debug information |
Using the logger
The logger is automatically available in destination and source contexts:
In destinations
const myDestination = {
type: 'my-destination',
config: {},
push(event, { logger }) {
logger.debug('Processing event', { name: event.name });
try {
// Send event to service
sendToService(event);
logger.info('Event sent successfully');
} catch (error) {
if (error.retryable) {
logger.warn('Event send failed, will retry', error);
} else {
logger.error('Failed to send event', error);
}
}
},
};In sources
const mySource = async (config, env) => {
const { logger } = env;
logger.info('Source initialized');
return {
type: 'my-source',
config,
push: async (event) => {
logger.debug('Received event', event);
await env.push(event);
},
};
};Logger API
Methods
| Method | Description |
|---|---|
error(message, context?) | Log an error message |
warn(message, context?) | Log a warning (degraded state, config issues) |
info(message, context?) | Log an informational message |
debug(message, context?) | Log a debug message |
throw(message, context?) | Log an error and throw an exception (returns never) |
json(data) | Output structured JSON data |
scope(name) | Create a scoped logger with a prefixed scope |
Error handling
The logger accepts Error objects directly and automatically extracts relevant
information:
try {
await riskyOperation();
} catch (error) {
// Error properties (message, name, stack, cause) are extracted automatically
logger.error(error);
// Or with additional context
logger.error('Operation failed', { error, operation: 'sync' });
}Boundary error logs
When an exception escapes the inner pipeline of collector.push or
collector.command, the collector emits a structured error log and
increments collector.status.failed. The messages are 'push failed'
and 'command failed' respectively, with the full event/ingest or
command/data context as structured fields. See
Status — What failed counts for details and
PII implications.
Internal pipeline failures from mapping, source startup, transformer
init, and destination init are scoped under 'source',
'transformer:<type>', or the destination type. User-callback throws
from on subscriptions are scoped under 'on'. The full list of error
verbs and scopes is documented in
Status — What failed counts.
Throwing errors
Use logger.throw() to log an error and throw in a single call:
function validateConfig(config) {
if (!config.apiKey) {
// Logs the error AND throws - returns 'never' type
logger.throw('API key is required');
}
// TypeScript knows apiKey exists here due to 'never' return type
return config.apiKey;
}Scoped loggers
Scoped loggers prefix log messages with context information, making it easier to trace logs to their origin:
// In a destination, the logger is already scoped: [google-gtag:myGtag]
push(event, { logger }) {
logger.info('Processing'); // Output: [google-gtag:myGtag] Processing
// Create nested scope
const ga4Logger = logger.scope('ga4');
ga4Logger.debug('Sending to GA4'); // Output: [google-gtag:myGtag:ga4] Sending to GA4
}Custom handler
For advanced use cases like sending logs to external services, configure a custom handler:
import { startFlow } from '@walkeros/collector';
const { collector, elb } = await startFlow({
logger: {
level: 'INFO',
handler: (level, message, context, scope, originalHandler) => {
// Send to external logging service
loggingService.log({
level,
message,
context,
scope: scope.join(':'),
timestamp: Date.now(),
});
// Optionally call the original console handler
originalHandler(level, message, context, scope);
},
},
});The handler receives:
| Parameter | Type | Description |
|---|---|---|
level | Level | Log level enum (ERROR=0, WARN=1, INFO=2, DEBUG=3) |
message | string | The log message |
context | LogContext | Additional context object |
scope | string[] | Array of scope names |
originalHandler | DefaultHandler | The default console handler |
Testing
Use the mock logger utility for testing destinations and sources:
import { createMockLogger } from '@walkeros/core';
describe('MyDestination', () => {
it('logs events correctly', async () => {
const mockLogger = createMockLogger();
await myDestination.push(testEvent, {
config: {},
logger: mockLogger,
});
expect(mockLogger.info).toHaveBeenCalledWith(
'Event sent successfully'
);
});
});The mock logger provides jest mock functions for all logger methods plus:
scopedLoggers: Array of scoped loggers created viascope()