EventFabric provides a structured logger that outputs consistent, formatted log messages to the console. The logger integrates with Deno’s native OpenTelemetry support for automatic log export to observability backends.
An in Depth Example
This guide also has an in depth example of a working application built with EventFabric. Combining DDD, CQRS and Event Sourcing.
Check out the In Depth Example page to learn how everything is connected and works out in a real-world application.
Configure the logger at application startup using setupLogger():
import {
jsonLogFormatter,
parseLogLevel,
prettyLogFormatter,
setupLogger,
} from "@eventfabric-cqrs/core";
import process from "node:process";
setupLogger({
logLevel: parseLogLevel(process.env.LOG_LEVEL),
formatter:
process.env.LOG_FORMAT === "pretty"
? prettyLogFormatter
: jsonLogFormatter,
useConsoleColors: process.env.LOG_FORMAT === "pretty",
});
| Option | Type | Default | Description |
|---|
logLevel | LogLevel | 'silent' | Minimum level to output |
formatter | LogFormatter | jsonLogFormatter | Function to format log records |
useConsoleColors | boolean | false | Enable colored output (for pretty formatter) |
EventFabric supports the following log levels in order of severity:
| Level | Method | Description |
|---|
debug | console.debug() | Detailed debugging information |
info | console.info() | General information about application flow |
warn | console.warn() | Warning conditions that should be reviewed |
error | console.error() | Error conditions that need attention |
critical | console.error() | Critical failures requiring immediate action |
silent | (none) | Disables all log output |
Messages below the configured log level are silently ignored.
Use parseLogLevel() to safely parse environment variables:
import { parseLogLevel } from "@eventfabric-cqrs/core";
// Returns 'info' if LOG_LEVEL is 'info', otherwise returns default 'silent'
const level = parseLogLevel(process.env.LOG_LEVEL);
Access the logger using getLogger():
import { getLogger } from "@eventfabric-cqrs/core";
const logger = getLogger();
logger.debug({
message: "Processing request",
category: "API",
data: { method: "POST", path: "/users" },
correlationId: "550e8400-e29b-41d4-a716-446655440000",
});
logger.info({
message: "User created successfully",
category: "Users",
data: { userId: "12345" },
});
logger.warn({
message: "Rate limit approaching",
category: "API",
data: { currentRate: 95, maxRate: 100 },
});
logger.error({
message: "Failed to process payment",
category: "Payments",
error: new Error("Payment gateway timeout"),
correlationId: "550e8400-e29b-41d4-a716-446655440000",
});
logger.critical({
message: "Database connection lost",
category: "Database",
error: new Error("Connection refused"),
});
The log input object can contain the following properties:
| Property | Type | Description |
|---|
message | string | Required. The log message |
category | string | Optional category for grouping logs (defaults to 'Default') |
data | Record<string, unknown> | Optional structured data to include |
error | Error | Optional error with stack trace |
correlationId | string | Optional ID for tracing related operations |
EventFabric provides two built-in formatters:
Outputs structured JSON for easy parsing by log aggregation tools:
import { jsonLogFormatter, setupLogger } from "@eventfabric-cqrs/core";
setupLogger({
logLevel: "info",
formatter: jsonLogFormatter,
});
// Output:
// {"timestamp":"2025-01-22T10:00:00.000Z","level":"info","category":"Users","message":"User created","data":{"userId":"123"}}
Outputs human-readable colored logs for development:
import { prettyLogFormatter, setupLogger, getLogger } from "@eventfabric-cqrs/core";
setupLogger({
logLevel: "debug",
formatter: prettyLogFormatter,
useConsoleColors: true,
});
getLogger().debug({
message: "My message",
category: "Category",
data: { userId: "12345" },
});
// Outputs:
// [Category] DEBUG :: My message
// {
// userId: '12345'
// }
When combined with Deno’s native OpenTelemetry support, logs are automatically exported alongside traces and metrics. See the Observability documentation for details on enabling OTEL export.
export OTEL_DENO=true
export OTEL_EXPORTER_OTLP_ENDPOINT="https://your-otlp-endpoint.com/otlp"
export OTEL_SERVICE_NAME=your-service-name
deno run src/main.ts
If setupLogger() is not called, the logger uses these defaults:
const defaultSettings = {
logLevel: "silent",
formatter: jsonLogFormatter,
useConsoleColors: false,
};
This means logs are silent by default - you must explicitly configure the logger to see output.
All EventFabric components (Router, EventBus, etc.) use the same logger configured via setupLogger(). This ensures consistent log formatting and level filtering across your application.
Group related logs with consistent category names:
logger.info({ message: "Query executed", category: "Database" });
logger.info({ message: "Request received", category: "API" });
logger.info({ message: "Email sent", category: "Notifications" });
Always include correlation IDs when available for distributed tracing:
logger.info({
message: "Processing order",
category: "Orders",
data: { orderId: order.id },
correlationId: command.correlationid,
});
Use the dedicated error property for errors to preserve stack traces:
// ✅ Good - Error is properly captured
logger.error({
message: "Failed to save user",
error: error,
correlationId: command.correlationid,
});
// ❌ Bad - Stack trace is lost
logger.error({
message: "Failed to save user",
data: { error: error.message },
});
debug: Detailed info for debugging (disabled in production)
info: Normal application flow
warn: Unexpected but recoverable situations
error: Errors that need investigation
critical: Failures requiring immediate action