Structured Logging
Structured Logging
Structured logging outputs logs in a machine-parseable format (JSON).
Why Structured?
Unstructured:
2024-01-15 10:00:00 INFO Order 123 created for user 456
Structured:
{
"timestamp": "2024-01-15T10:00:00Z",
"level": "INFO",
"message": "Order created",
"order_id": "123",
"user_id": "456",
"service": "order-service"
}
Structured: Searchable, analyzable, aggregatable
Implementation
import json
from datetime import datetime
class StructuredLogger:
def __init__(self, service_name):
self.service = service_name
def _log(self, level, message, **kwargs):
entry = {
'timestamp': datetime.utcnow().isoformat() + 'Z',
'level': level,
'service': self.service,
'message': message,
**kwargs
}
print(json.dumps(entry))
def info(self, message, **kwargs):
self._log('INFO', message, **kwargs)
def error(self, message, error=None, **kwargs):
if error:
kwargs['error'] = str(error)
kwargs['stack_trace'] = traceback.format_exc()
self._log('ERROR', message, **kwargs)
logger = StructuredLogger('payment-service')
logger.info('Payment processed', payment_id='789', amount=99.99)
Best Practices
- Always use JSON format
- Include timestamp (UTC)
- Include service name
- Include correlation ID
- Don't log sensitive data (PII, passwords)
Log Levels
Log Levels
Level Definitions
| Level | When to Use | Example |
|---|---|---|
| DEBUG | Detailed debugging info | Variable values, function entry/exit |
| INFO | Normal operations | Request processed, order created |
| WARN | Unexpected but handled | Retry attempt, fallback used |
| ERROR | Errors requiring attention | Failed to connect, exception occurred |
| FATAL | System-threatening | Out of memory, unrecoverable error |
Level Configuration
import logging
# Set level based on environment
log_level = os.getenv('LOG_LEVEL', 'INFO')
logging.basicConfig(
level=getattr(logging, log_level),
format='%(asctime)s %(levelname)s %(message)s'
)
# Production: INFO or WARN
# Development: DEBUG
# Testing: WARNING
Level Usage
def process_order(order):
logger.debug(f'Processing order: {order.id}') # Detailed
try:
validate(order)
logger.info(f'Order validated: {order.id}') # Normal
if order.amount > 10000:
logger.warn(f'Large order amount: {order.amount}') # Unusual
save(order)
except ValidationError as e:
logger.error(f'Validation failed: {e}', order_id=order.id) # Error
raise
except Exception as e:
logger.fatal(f'Unexpected error: {e}') # Critical
raise
Best Practices
- DEBUG: Detailed, verbose, development only
- INFO: Normal operations, business events
- WARN: Handled anomalies, worth monitoring
- ERROR: Failures requiring attention
- FATAL: System-threatening, immediate action
Centralized Logging
Centralized Logging
Why Centralize?
Distributed System:
- Multiple services
- Multiple servers
- Multiple logs
Problem: Can't search across logs!
Solution: Centralized logging
- All logs → Central store
- Search across all services
- Correlate events
Architecture
Service 1 → [Agent] ─┐
Service 2 → [Agent] ─┼→ [Log Aggregator] → [Storage] → [Search UI]
Service 3 → [Agent] ─┘
Agents: Filebeat, Fluentd, Fluent Bit
Aggregator: Logstash, Fluentd
Storage: Elasticsearch, Loki
UI: Kibana, Grafana
ELK Stack
Elasticsearch: Storage and search
Logstash: Processing and enrichment
Kibana: Visualization and search
Flow:
Apps → Filebeat → Logstash → Elasticsearch → Kibana
Loki (Lightweight)
# Loki + Promtail config
scrape_configs:
- job_name: app
static_configs:
- targets: ['localhost']
labels:
job: myapp
host: server1
Log Enrichment
class LogEnricher:
def __init__(self):
self.metadata = {
'hostname': socket.gethostname(),
'service': os.getenv('SERVICE_NAME'),
'environment': os.getenv('ENVIRONMENT')
}
def enrich(self, log_entry):
return {
**self.metadata,
**log_entry,
'trace_id': get_trace_id(),
'correlation_id': get_correlation_id()
}
Best Practices
- Use structured logging
- Centralize all logs
- Enrich with context
- Set retention policies
- Index important fields
- Monitor log volumes
Practice Problems
Design a scalable Logging system. Cover high-level architecture, data model, and API design.
Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliabilityHow would you scale Logging to handle 10x the current load? Identify bottlenecks and solutions.
Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decompositionAnalyze potential failure modes for Logging and design mitigation strategies.
Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradationQuiz
1. What is structured logging?
2. When should you use WARN level?
3. What is centralized logging?
4. What is log enrichment?
5. Why use JSON for logging?
Flashcards
Question
What is structured logging?
Click to reveal answer
Answer
Logging in machine-parseable JSON format with consistent fields for searchability
Question
Log levels order?
Click to reveal answer
Answer
DEBUG < INFO < WARN < ERROR < FATAL (least to most severe)
Question
When use WARN vs ERROR?
Click to reveal answer
Answer
WARN: unexpected but handled. ERROR: failure requiring attention.
Question
Centralized logging benefits?
Click to reveal answer
Answer
Search across services, correlate events, analyze patterns, debug distributed issues
Question
Log enrichment?
Click to reveal answer
Answer
Adding context (hostname, service, trace ID) to logs for better debugging and correlation
Revision Notes
Key Takeaways
- 1.Use structured JSON logging for searchability
- 2.Use appropriate log levels (DEBUG to FATAL)
- 3.Centralize logs for distributed debugging
- 4.Enrich logs with context (hostname, trace ID)
- 5.Never log sensitive data (PII, passwords)
Interview Tips
- •Explain structured vs unstructured logging
- •Discuss log level usage guidelines
- •Mention centralized logging architecture
- •Talk about log enrichment and correlation
Cheat Sheet
Cheat Sheet: Logging
Structured Logging
- JSON format
- Searchable, analyzable
- Consistent fields
Log Levels
- DEBUG: Detailed
- INFO: Normal ops
- WARN: Handled anomaly
- ERROR: Failure
- FATAL: Critical
Centralized
- All logs → Central store
- ELK or Loki
- Search across services
Enrichment
- Add hostname, service
- Add trace/correlation IDs
- Don't log PII