@arborship/logger
v1.0.164
Published
Structured logging for Marsman ecosystem with correlation ID support
Maintainers
Readme
@arborship/logger
Structured JSON logging for the Levi ecosystem with correlation ID support.
OTEL Scope (MAR-41)
This package is responsible for structured log emission only. It depends on
@opentelemetry/api (the zero-dependency facade) to read the active span and inject
trace_id / span_id fields into log lines when tracing is active.
In scope for this package:
- Structured NDJSON log records emitted to stdout via pino.
- Automatic
trace_id/span_idinjection when an active OTEL span is present. correlationIdfallback when no OTEL span is active.
Out of scope (handled by @arborship/otel):
- OTEL SDK initialisation (
NodeSDK.start/shutdown). - Span creation, propagation, or OTLP export.
- Metrics collection or export.
Services that want distributed tracing must call initOtel() from
@arborship/otel before the first log call. If the SDK is absent the api
falls back to a no-op provider and logs carry only correlationId.
Installation
npm install @arborship/loggerQuick Start
import { createLogger, setCorrelationId } from '@arborship/logger';
const logger = createLogger({ component: 'levi' });
logger.info({ vmName: 'job-123' }, 'VM spawned');
// Output: {"level":"INFO","time":"...","component":"levi","vmName":"job-123","msg":"VM spawned"}
// With correlation ID
setCorrelationId('job-abc');
logger.info('Job started');
// Output: {"level":"INFO","time":"...","component":"levi","correlationId":"job-abc","msg":"Job started"}Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| LOG_LEVEL | info | Log level: trace, debug, info, warn, error, fatal |
| LOG_FORMAT | json | Output format: json or pretty |
Features
- Structured JSON logging - Easy to parse and query
- Correlation ID propagation - Trace requests across components
- Component attribution - Know which service logged what
- Child loggers - Add persistent context to log groups
- Pino-powered - Fast, low-overhead logging
Components
All Levi ecosystem components use the same logger:
levi- Supervisor API serverlevi- VM orchestrator CLIvm-agent- Worker agent in spawned VMsstackenv- Tool configuration manager
API Reference
createLogger(config)
Create a logger instance.
createLogger({
component: 'levi', // Required: component name
level: 'debug', // Optional: log level
format: 'json', // Optional: 'json' or 'pretty'
baseFields: { env: 'prod' }, // Optional: additional fields
});setCorrelationId(id) / getCorrelationId(id)
Manage correlation ID for cross-component tracing.
setCorrelationId('job-abc-123');
const id = getCorrelationId(); // 'job-abc-123'childLogger(logger, context)
Create a child logger with persistent context.
const vmLogger = childLogger(logger, { vmName: 'job-123' });
vmLogger.info('VM starting'); // Always includes vmNameLog Format
All logs are structured JSON:
{
"level": "INFO",
"time": "2025-01-16T22:30:00.000Z",
"component": "levi",
"correlationId": "job-abc-123",
"vmName": "job-123",
"msg": "VM spawned"
}Log format with active OTEL span
When @arborship/otel has been initialised and a span is active, logs include
trace_id and span_id instead of correlationId:
{
"level": "INFO",
"time": "2025-01-16T22:30:00.000Z",
"component": "leviathan",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"jobId": "job-abc",
"msg": "Job dispatched"
}See @arborship/otel for the full OTEL scope decision and span boundary policy.
License
Apache-2.0 — see the LICENSE file in this package.
