Skip to content

Latest commit

 

History

History
235 lines (169 loc) · 5.98 KB

File metadata and controls

235 lines (169 loc) · 5.98 KB

Logging Guide

This guide explains how to use the structured logging system in the Accellens platform.

Quick Start

Frontend (TypeScript/Next.js)

import { logger } from '@/lib/utils/logger';

// Basic logging
logger.info('User logged in', { userId: user.id });

// With error
logger.error('Failed to load data', { endpoint: '/api/data' }, error);

// Child logger with context
const requestLogger = logger.child({ requestId: '123', userId: '456' });
requestLogger.info('Processing request');

Gateway (TypeScript/Fastify)

import { getLoggerFromRequest } from '@gateway/utils/logger';

// In route handler
fastify.get('/api/v1/projects', async (request, reply) => {
  const logger = getLoggerFromRequest(request);
  logger.info('Fetching projects', { action: 'list-projects' });
  // ... handler logic
});

Python Services (Python/FastAPI)

from utils.logger import logger, set_log_context, update_log_context

# Context is automatically set by middleware, but you can update it
update_log_context({"project_id": project_id})

# Log with context
logger.info("Processing request", extra={"action": "create_project"})

# Log with error
logger.error("Request failed", extra={"endpoint": "/api/v1/projects"}, exc_info=True)

Log Levels

Use appropriate log levels:

  • trace: Very detailed debugging (development only)
  • debug: Detailed debugging information
  • info: General informational messages
  • warn: Warning messages for potentially harmful situations
  • error: Error messages for error events
  • fatal: Critical errors that may cause application failure

Structured Logging

Always use structured logging with context objects:

// ✅ Good
logger.info('User action', { userId: user.id, action: 'click-button', buttonId: 'submit' });

// ❌ Bad
logger.info(`User ${user.id} clicked button ${buttonId}`);

Context

Context is automatically added by middleware:

  • request_id: Unique request identifier
  • user_id: Authenticated user ID
  • organization_id: Organization ID
  • trace_id: OpenTelemetry trace ID
  • span_id: OpenTelemetry span ID

You can add additional context:

// Frontend
const logger = logger.child({ projectId: project.id, scanId: scan.id });

// Gateway
const logger = getLoggerFromRequest(request).child({ projectId: project.id });

// Python
update_log_context({ project_id: project.id, scan_id: scan.id });

Error Logging

Always include error objects when logging errors:

// Frontend
logger.error('Failed to fetch data', { endpoint: '/api/data' }, error);

// Gateway
logger.error('Request handler error', { path: request.url }, error);

// Python
logger.error('Request failed', (extra = { endpoint: '/api/v1/data' }), (exc_info = True));

Performance Logging

Log performance metrics:

// Frontend
const startTime = performance.now();
// ... operation
logger.info('Operation completed', {
  operation: 'data-fetch',
  duration_ms: performance.now() - startTime
});

// Python
import time
start_time = time.time()
# ... operation
logger.info("Operation completed", extra={
    "operation": "data_fetch",
    "duration_ms": (time.time() - start_time) * 1000
})

PII Redaction

Sensitive data is automatically redacted from logs. Never log:

  • Passwords
  • API keys
  • Tokens
  • Credit card numbers
  • Social security numbers

Redacted fields are replaced with [REDACTED] in logs.

Best Practices

  1. Use appropriate log levels: Don't log everything at info level
  2. Include context: Always include relevant IDs and metadata
  3. Structured logging: Use context objects, not string interpolation
  4. Error handling: Always include error objects when logging errors
  5. Performance: Log performance metrics for critical operations
  6. Avoid sensitive data: Never log passwords, tokens, or PII

Integration with Observability

Logs are automatically sent to:

  • Loki: Centralized log aggregation
  • Grafana: Log visualization and dashboards
  • Prometheus: Metrics derived from logs (error rate, log volume)
  • OpenTelemetry: Correlation with traces

Examples

Frontend: API Error Handling

try {
  const data = await apiClient.get('/api/v1/projects');
  logger.info('Projects loaded', { count: data.length });
} catch (error) {
  logger.error('Failed to load projects', { endpoint: '/api/v1/projects' }, error);
  throw error;
}

Gateway: Request Logging

fastify.get('/api/v1/projects', async (request, reply) => {
  const logger = getLoggerFromRequest(request);

  logger.debug('Fetching projects', { filters: request.query });

  try {
    const projects = await projectService.list(request.user.id);
    logger.info('Projects fetched', { count: projects.length });
    return projects;
  } catch (error) {
    logger.error('Failed to fetch projects', {}, error);
    throw error;
  }
});

Python: Service Operation

from utils.logger import logger, update_log_context

async def create_project(project_data: dict):
    update_log_context({"operation": "create_project"})

    logger.info("Creating project", extra={"project_name": project_data["name"]})

    try:
        project = await db.projects.create(project_data)
        logger.info("Project created", extra={"project_id": str(project.id)})
        return project
    except Exception as e:
        logger.error("Failed to create project", extra={"error": str(e)}, exc_info=True)
        raise

Troubleshooting

Logs not appearing in Loki

  1. Check that Loki is running and accessible
  2. Verify environment variables are set correctly
  3. Check Promtail configuration for label matching

Context missing in logs

  1. Ensure middleware is registered correctly
  2. Check that context is set before logging
  3. Verify context variables are not cleared prematurely

Performance issues

  1. Check log level - reduce verbosity in production
  2. Verify sampling is enabled for debug logs
  3. Check Loki endpoint is accessible and not rate-limited