This guide explains how to use the structured logging system in the Accellens platform.
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');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
});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)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
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 is automatically added by middleware:
request_id: Unique request identifieruser_id: Authenticated user IDorganization_id: Organization IDtrace_id: OpenTelemetry trace IDspan_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 });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));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
})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.
- Use appropriate log levels: Don't log everything at
infolevel - Include context: Always include relevant IDs and metadata
- Structured logging: Use context objects, not string interpolation
- Error handling: Always include error objects when logging errors
- Performance: Log performance metrics for critical operations
- Avoid sensitive data: Never log passwords, tokens, or PII
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
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;
}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;
}
});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- Check that Loki is running and accessible
- Verify environment variables are set correctly
- Check Promtail configuration for label matching
- Ensure middleware is registered correctly
- Check that context is set before logging
- Verify context variables are not cleared prematurely
- Check log level - reduce verbosity in production
- Verify sampling is enabled for debug logs
- Check Loki endpoint is accessible and not rate-limited