> ## Documentation Index
> Fetch the complete documentation index at: https://docs.deploystack.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Backend Logging & Log Level Configuration

> Complete guide to configuring and using log levels in the DeployStack backend for development and production environments.

The DeployStack backend uses **Pino** logger with **Fastify** for high-performance, structured logging. This guide covers everything you need to know about configuring and using log levels effectively.

## Overview

DeployStack's logging system is built on industry best practices:

* **Pino Logger**: Ultra-fast JSON logger for Node.js
* **Fastify Integration**: Native logging support with request correlation
* **Environment-based Configuration**: Automatic log level adjustment based on NODE\_ENV
* **Structured Logging**: JSON output for production, pretty-printed for development

## Available Log Levels

Log levels are ordered by severity (lowest to highest):

| Level   | Numeric Value | Description             | When to Use                               |
| ------- | ------------- | ----------------------- | ----------------------------------------- |
| `trace` | 10            | Very detailed debugging | Tracing function calls, variable states   |
| `debug` | 20            | Debugging information   | Development debugging, detailed flow      |
| `info`  | 30            | General information     | Important events, startup messages        |
| `warn`  | 40            | Warning messages        | Recoverable errors, deprecation notices   |
| `error` | 50            | Error conditions        | Caught exceptions, failed operations      |
| `fatal` | 60            | Fatal errors            | Unrecoverable errors, application crashes |

## Configuration

### Environment Variables

Set the log level using the `LOG_LEVEL` environment variable:

```bash theme={null}
# Development - show debug information
LOG_LEVEL=debug npm run dev

# Production - show info and above
LOG_LEVEL=info npm run start

# Troubleshooting - show everything
LOG_LEVEL=trace npm run dev

# Quiet mode - only errors and fatal
LOG_LEVEL=error npm run start
```

### Default Behavior

The logger automatically adjusts based on your environment:

```typescript theme={null}
// From src/fastify/config/logger.ts
export const loggerConfig: FastifyServerOptions['logger'] = {
  level: process.env.LOG_LEVEL || (process.env.NODE_ENV === 'production' ? 'info' : 'debug'),
  transport: process.env.NODE_ENV !== 'production'
    ? {
        target: 'pino-pretty',
        options: {
          colorize: true,
          translateTime: 'SYS:standard',
          ignore: 'pid,hostname'
        }
      }
    : undefined
}
```

**Default Levels:**

* **Development**: `debug` (shows debug, info, warn, error, fatal)
* **Production**: `info` (shows info, warn, error, fatal)

## Log Output Formats

### Development Format (Pretty-printed)

```
[2025-07-03 10:48:06.636 +0200] INFO: ✅ Database initialization completed
[2025-07-03 10:48:06.640 +0200] DEBUG: 🔄 Starting global settings initialization...
[2025-07-03 10:48:06.645 +0200] ERROR: ❌ Failed to connect to external service
```

### Production Format (JSON)

```json theme={null}
{"level":30,"time":"2025-07-03T08:48:06.636Z","pid":1234,"hostname":"server","msg":"Database initialization completed"}
{"level":20,"time":"2025-07-03T08:48:06.640Z","pid":1234,"hostname":"server","msg":"Starting global settings initialization..."}
{"level":50,"time":"2025-07-03T08:48:06.645Z","pid":1234,"hostname":"server","msg":"Failed to connect to external service"}
```

## Logger Parameter Injection Pattern

DeployStack follows a consistent pattern for passing logger instances to services and utilities. This ensures proper structured logging throughout the application while maintaining the Fastify logger chain for request correlation.

### ✅ DO: Pass Logger as Parameter to Services

```typescript theme={null}
// ✅ Good - Services accept logger as parameter
class EmailService {
  static async sendEmail(options: SendEmailOptions, logger: FastifyBaseLogger): Promise<EmailSendResult> {
    logger.debug({
      operation: 'send_email',
      recipient: options.to,
      template: options.template
    }, 'Sending email');
    
    try {
      // ... email sending logic
      logger.info({
        operation: 'send_email',
        messageId: result.messageId,
        recipients: result.recipients
      }, 'Email sent successfully');
      
      return result;
    } catch (error) {
      logger.error({
        operation: 'send_email',
        error,
        recipient: options.to,
        template: options.template
      }, 'Failed to send email');
      throw error;
    }
  }
}

// ✅ Good - Database functions accept logger parameter
export async function initializeDatabase(logger: FastifyBaseLogger): Promise<boolean> {
  logger.info({
    operation: 'initialize_database'
  }, 'Database initialization started');
  
  try {
    // ... database initialization logic
    logger.info({
      operation: 'initialize_database'
    }, 'Database initialized successfully');
    return true;
  } catch (error) {
    logger.error({
      operation: 'initialize_database',
      error
    }, 'Failed to initialize database');
    return false;
  }
}
```

### ✅ DO: Pass Logger from Calling Context

```typescript theme={null}
// ✅ Good - Pass logger from server context
await initializeDatabase(server.log);

// ✅ Good - Pass logger from request context in routes
server.post('/api/send-email', async (request, reply) => {
  const result = await EmailService.sendEmail(emailOptions, request.log);
  return result;
});

// ✅ Good - Pass logger in plugin initialization
await pluginManager.initializePlugins(server.log);
```

### ✅ DO: Use Child Loggers for Persistent Context

```typescript theme={null}
// ✅ Good - Create child logger with persistent context
class UserService {
  static async processUser(userId: string, logger: FastifyBaseLogger) {
    const childLogger = logger.child({ userId, service: 'UserService' });
    
    childLogger.debug('Starting user processing');
    childLogger.info('User data retrieved');
    childLogger.debug('Processing completed');
  }
}
```

### ❌ DON'T: Create Separate Logger Utilities

```typescript theme={null}
// ❌ Bad - Don't create separate logger utility files
// utils/logger.ts
export const logger = createLogger();

// ❌ Bad - Don't import logger utilities in services
import { logger } from '../utils/logger';

class SomeService {
  static async doSomething() {
    logger.info('This bypasses the Fastify logger chain');
  }
}
```

### ❌ DON'T: Use console.\* in Services

```typescript theme={null}
// ❌ Bad - console.* bypasses the logging system
class DatabaseService {
  static async connect() {
    console.log('Connecting to database...'); // No structured logging
    console.error('Connection failed:', error); // No context objects
  }
}

// ✅ Good - Use passed logger parameter
class DatabaseService {
  static async connect(logger: FastifyBaseLogger) {
    logger.info({
      operation: 'database_connect'
    }, 'Connecting to database...');
    
    logger.error({
      operation: 'database_connect',
      error,
      connectionString: config.url
    }, 'Connection failed');
  }
}
```

## Developer Best Practices

### ✅ DO: Use Proper Log Levels

```typescript theme={null}
// ✅ Good - Use appropriate log levels
server.log.debug('🔄 Starting database initialization...');
server.log.info('✅ Database connection established');
server.log.warn('⚠️ Using fallback configuration');
server.log.error('❌ Failed to process request:', error);
server.log.fatal('💀 Critical system failure:', error);
```

### ❌ DON'T: Use Manual Prefixes

```typescript theme={null}
// ❌ Bad - Manual prefixes defeat the purpose
server.log.info('🔄 [DEBUG] Starting database initialization...');
server.log.info('✅ [INFO] Database connection established');

// ✅ Good - Use proper log levels instead
server.log.debug('🔄 Starting database initialization...');
server.log.info('✅ Database connection established');
```

### ✅ DO: Use the Fastify Logger

```typescript theme={null}
// ✅ Good - Use server.log for consistent formatting
server.log.info('User authenticated successfully');

// ❌ Bad - console.log bypasses the logging system
console.log('User authenticated successfully');
```

### ✅ DO: Add Context Objects

Context objects make your logs searchable, filterable, and much more useful for debugging. Always include relevant context that helps identify what happened, where, and to whom.

```typescript theme={null}
// ✅ Good - Structured logging with context
server.log.info({
  userId: 'user123',
  action: 'login',
  ipAddress: '192.168.1.1',
  userAgent: 'Mozilla/5.0...',
  operation: 'user_authentication'
}, 'User login successful');

// ✅ Good - Error logging with full context
server.log.error({
  error: err,
  userId: 'user123',
  operation: 'database_query',
  table: 'users',
  queryType: 'SELECT'
}, 'Database operation failed');

// ✅ Good - Service operations with context
server.log.debug({
  recipient: 'user@example.com',
  template: 'welcome',
  messageId: 'abc123',
  operation: 'send_email'
}, 'Email sent successfully');

// ✅ Good - API operations with context
server.log.warn({
  endpoint: '/api/users',
  method: 'POST',
  statusCode: 429,
  clientIp: '192.168.1.1',
  operation: 'rate_limit_exceeded'
}, 'Rate limit exceeded for client');
```

**Best Practices for Context Objects:**

* **Always include `operation`**: A consistent field that describes what operation was being performed
* **Add identifiers**: Include relevant IDs (userId, orderId, sessionId, etc.) for easy filtering
* **Include request context**: IP addresses, user agents, request IDs for web requests
* **Add timing information**: Duration, timestamps, or performance metrics when relevant
* **Use consistent naming**: Stick to camelCase and consistent field names across your application

**Examples of Good Context Properties:**

* `operation`: What was happening (e.g., 'send\_email', 'user\_login', 'database\_query')
* `userId`, `sessionId`, `requestId`: Identifiers for tracking
* `duration`, `responseTime`: Performance metrics
* `statusCode`, `method`, `endpoint`: HTTP-related context
* `table`, `queryType`: Database-related context
* `recipient`, `template`, `messageId`: Email-related context

### ✅ DO: Use Child Loggers for Context

```typescript theme={null}
// ✅ Good - Child logger with persistent context
function processUser(userId: string) {
  const childLogger = server.log.child({ userId });
  
  childLogger.debug('Starting user processing');
  childLogger.info('User data retrieved');
  childLogger.debug('Processing completed');
}
```

## Common Logging Patterns

### Database Operations

```typescript theme={null}
// Database initialization
server.log.debug('🔄 Initializing database connection...');
server.log.info('✅ Database connected successfully');

// Query operations
server.log.debug('Executing user query', { userId, query: 'SELECT * FROM users' });
server.log.warn('Slow query detected', { duration: '2.5s', query: 'complex_query' });
```

### Authentication & Security

```typescript theme={null}
// Authentication events
server.log.info('User login attempt', { email: user.email, ipAddress });
server.log.warn('Failed login attempt', { email, ipAddress, reason: 'invalid_password' });
server.log.error('Security violation detected', { ipAddress, action: 'brute_force' });
```

### API Requests

```typescript theme={null}
// Request processing (handled automatically by Fastify)
// Custom business logic logging
server.log.debug('Processing payment request', { amount, currency, userId });
server.log.info('Payment processed successfully', { transactionId, amount });
server.log.error('Payment failed', { error, userId, amount });
```

### Plugin System

```typescript theme={null}
// Plugin lifecycle
server.log.debug('Loading plugin', { pluginId, version });
server.log.info('Plugin loaded successfully', { pluginId });
server.log.warn('Plugin deprecated', { pluginId, deprecationDate });
server.log.error('Plugin failed to load', { pluginId, error });
```

## Fixing Console.log Issues

<Warning>
  **Important**: Replace all `console.log` statements with proper Pino logger calls to ensure consistent formatting and log level filtering.
</Warning>

### Problem: Inconsistent Log Output

```typescript theme={null}
// ❌ Problem - Mixed logging approaches
console.log('✅ [GlobalSettingsInitService] Operation completed');  // No timestamp
server.log.info('✅ Database initialization completed');             // With timestamp
```

### Solution: Use Proper Logger

```typescript theme={null}
// ✅ Solution - Consistent logging
class GlobalSettingsInitService {
  private static logger = server.log.child({ service: 'GlobalSettingsInitService' });
  
  static async loadSettings() {
    this.logger.debug('Loading settings definitions...');
    this.logger.info('Settings loaded successfully');
  }
}
```

### Passing Logger to Classes

```typescript theme={null}
// ✅ Good - Pass logger instance to classes
class PluginManager {
  constructor(private logger: FastifyBaseLogger) {}
  
  async loadPlugin(pluginId: string) {
    this.logger.debug('Loading plugin', { pluginId });
    this.logger.info('Plugin loaded successfully', { pluginId });
  }
}

// Usage
const pluginManager = new PluginManager(server.log.child({ component: 'PluginManager' }));
```

## Environment-Specific Configuration

### Development Environment

```bash theme={null}
# .env file for development
NODE_ENV=development
LOG_LEVEL=debug
```

**Features:**

* Pretty-printed, colorized output
* Shows debug and trace information
* Includes timestamps and emojis
* Easier to read during development

### Production Environment

```bash theme={null}
# Production environment variables
NODE_ENV=production
LOG_LEVEL=info
```

**Features:**

* Structured JSON output
* Optimized for log aggregation
* Excludes debug information
* Better performance

### Testing Environment

```bash theme={null}
# Testing environment
NODE_ENV=test
LOG_LEVEL=error
```

**Features:**

* Minimal log output during tests
* Only shows errors and fatal messages
* Reduces test noise

## Troubleshooting

### Debug Mode Not Working

If debug logs aren't showing:

1. **Check LOG\_LEVEL**: Ensure it's set to `debug` or `trace`
2. **Check NODE\_ENV**: Development mode enables debug by default
3. **Restart Server**: Environment changes require restart

```bash theme={null}
# Force debug mode
LOG_LEVEL=debug npm run dev
```

### Performance Issues

If logging is impacting performance:

1. **Increase Log Level**: Use `info` or `warn` in production
2. **Remove Debug Logs**: Clean up excessive debug statements
3. **Use Async Logging**: Pino handles this automatically

### Log Aggregation

For production log management:

```typescript theme={null}
// Add correlation IDs for request tracking
server.addHook('onRequest', async (request) => {
  request.log = request.log.child({ 
    requestId: request.id,
    userAgent: request.headers['user-agent']
  });
});
```

## Migration Guide

### From Manual Prefixes

```typescript theme={null}
// Before
server.log.info('🔄 [DEBUG] Starting operation...');
server.log.info('✅ [INFO] Operation completed');
server.log.info('❌ [ERROR] Operation failed');

// After
server.log.debug('🔄 Starting operation...');
server.log.info('✅ Operation completed');
server.log.error('❌ Operation failed');
```

### From Console.log

```typescript theme={null}
// Before
console.log('User logged in:', userId);
console.error('Database error:', error);

// After
server.log.info('User logged in', { userId });
server.log.error('Database error', { error, userId });
```

## Summary

* **Use proper log levels** instead of manual prefixes
* **Replace console.log** with server.log for consistency
* **Add structured context** to make logs searchable
* **Configure LOG\_LEVEL** via environment variables
* **Use child loggers** for persistent context
* **Follow the patterns** shown in this guide

With proper log level configuration, you'll have a production-ready logging system that scales from development to enterprise deployments.
