Skip to main content

API

The Digital Alchemy logger is automatically injected into every service, providing a powerful and flexible logging interface with built-in context awareness and formatting capabilities.

Getting the Logger

The logger is automatically available in every service through dependency injection:

export function MyService({ logger }: TServiceParams) {
// Your logger is ready to use!
logger.info("Service started successfully");
}

Automatic Context

Every logger instance automatically includes context information about your service:

  • Service Context: Automatically set to {project}:{service} (e.g., my_app:user_service)
  • Color Coding: Context is color-coded based on the log level for easy visual identification
  • Structured Data: Context is included in all log messages for filtering and analysis
export function UserService({ logger }: TServiceParams) {
// This log will automatically include context: "my_app:user_service"
logger.info("Processing user request");

// Output: [INFO] [my_app:user_service] Processing user request
}

Logging Interface

The logger supports flexible parameter combinations for different logging needs:

export function MyService({ logger }: TServiceParams) {

// Simple string message
logger.info("User logged in successfully");

// Object data only
logger.debug({ userId: 123, action: "login" });

// String message with object data
logger.info({ userId: 123 }, "User %s logged in", "john.doe");

// Object data with formatted message
logger.error({ error: "Database connection failed" }, "Failed to process request: %s", error.message);
}

Parameter Order

The logger follows this parameter order:

  1. Data object (optional) - Structured data to include
  2. Message string (optional) - Human-readable message
  3. Format arguments (optional) - Values for string formatting

String Formatting

When you provide a message string, you can use format specifiers that work with Node.js util.format:

logger.info("User %s logged in from %s", username, ipAddress);
logger.debug("Processing %d items, %s remaining", processed, remaining);
logger.error("API call failed with status %d: %s", statusCode, errorMessage);
Format SpecifierDescriptionExample
%sString"hello"
%dNumber42
%iInteger42
%fFloat3.14
%jJSON{"key": "value"}
%oObject (detailed){key: "value"}
%OObject (simple){key: "value"}
%%Literal %%

Log Levels

The logger provides six log levels, each with specific use cases and visual styling:

LevelColorPriorityUse CaseExample
fatal🟣 MagentaHighestApplication crashes, unrecoverable errorsDatabase corruption, system shutdown
error🔴 RedHighRecoverable errors, failed operationsAPI failures, validation errors
warn🟡 YellowMediumPotential issues, deprecation warningsRate limiting, deprecated API usage
info🟢 GreenNormalGeneral application flowUser actions, service startup
debug🔵 BlueLowDetailed debugging informationFunction entry/exit, data transformations
trace⚪ GrayLowestVery detailed debuggingInternal state, performance metrics

When to Use Each Level

export function UserService({ logger }: TServiceParams) {

// trace: Very detailed debugging
logger.trace({ userId: 123, step: "validation" }, "Validating user input");

// debug: Detailed debugging
logger.debug({ userId: 123 }, "Processing user request");

// info: General application flow
logger.info({ userId: 123 }, "User %s logged in successfully", username);

// warn: Potential issues
logger.warn({ userId: 123 }, "User attempted to access restricted resource");

// error: Recoverable errors
logger.error({ userId: 123, error: "Invalid credentials" }, "Login failed");

// fatal: Unrecoverable errors
logger.fatal({ error: "Database corruption detected" }, "Application must shutdown");
}

Bootstrap Configuration Options

You can customize logger behavior through bootstrap options:

MY_APP.bootstrap({
loggerOptions: {
// Enable ALS integration for request context tracking
als: true,

// Add global data to all logs
mergeData: {
service: "my-app",
version: "1.0.0",
environment: process.env.NODE_ENV
},

// Custom timestamp format
timestampFormat: "YYYY-MM-DD HH:mm:ss.SSS",

// Disable pretty formatting (useful for machine parsing)
pretty: false,

// Show milliseconds since last log
ms: true,

// Add incrementing counter to each log
counter: true,

// Disable stdout output (useful when using external log targets)
stdOut: false,

// Override log levels for specific services/modules
levelOverrides: {
"boilerplate": "silent", // Silence framework logs
"my_app": "info", // Set app default
"my_app:debug_service": "trace" // Enable trace for specific service
}
}
});

Configuration Options Reference

OptionTypeDefaultDescription
alsbooleanfalseEnable AsyncLocalStorage integration for request context
mergeDataobject{}Global data to include in all log messages
timestampFormatstring"ddd HH:mm:ss.SSS"Timestamp format using dayjs syntax
prettybooleantrueEnable pretty formatting with colors and symbols
msbooleanfalseShow milliseconds since last log message
counterbooleanfalseAdd incrementing counter to each log
stdOutbooleantrueOutput logs to console/stdout
levelOverridesobject{}Per-service/module log level overrides

Environment-Based Configuration

You can also control logging through environment variables:

# Set global log level
LOG_LEVEL=info

# Disable pretty formatting in production
NODE_ENV=production

Pretty Formatting Features

When pretty: true (default), the logger provides enhanced visual formatting:

  • Color-coded contexts for easy service identification
  • Highlighted symbols like [INFO], [ERROR]
  • Formatted timestamps with consistent styling
  • Structured data with proper indentation
  • Performance timing when ms: true is enabled

Example Output

+12.34ms [Mon 14:30:45.123] [INFO] [my_app:user_service] User john.doe logged in successfully
+1.23ms [Mon 14:30:45.124] [DEBUG] [my_app:user_service] Session created: abc123
+0.45ms [Mon 14:30:45.125] [ERROR] [my_app:auth_service] Invalid token provided

Best Practices

1. Use Appropriate Log Levels

// Good: Clear level progression
logger.trace("Entering function");
logger.debug("Processing data");
logger.info("Operation completed");
logger.warn("Deprecated method called");
logger.error("Operation failed");

// Bad: Inconsistent levels
logger.info("Debug information"); // Should be debug
logger.error("Minor warning"); // Should be warn

2. Include Relevant Context

// Good: Rich context
logger.info({ userId: 123, action: "login", ip: "192.168.1.1" }, "User logged in");

// Bad: Minimal context
logger.info("User logged in");

3. Use Structured Data

// Good: Structured for analysis
logger.error({
error: "Database connection failed",
retryCount: 3,
lastAttempt: new Date().toISOString()
}, "Failed to connect to database");

// Bad: String concatenation
logger.error("Failed to connect to database after 3 attempts");

4. Leverage Format Specifiers

// Good: Clean formatting
logger.info("Processing %d items for user %s", itemCount, username);

// Bad: String concatenation
logger.info("Processing " + itemCount + " items for user " + username);

Integration with External Services

The logger integrates seamlessly with external logging services. See the Log Streams documentation for examples with Datadog, Graylog, and other services.