RFC-008: Observability e Monitoring Standards
| Campo | Valor |
|---|---|
| Status | Draft |
| Author | Time de Tecnologia |
| Created | 2026-02-05 |
| Updated | 2026-02-05 |
| Reunião | A ser agendada |
| Deciders | Todo o time técnico |
Status
🟡 Draft - RFC em elaboração, aguardando apresentação
Contexto e Problema
CloudWatch documentado em docs/observability/, mas falta:
- SLOs/SLAs definidos formalmente
- Golden Signals padronizados (Latency, Traffic, Errors, Saturation)
- Dashboard standards para todos os serviços
- Alert thresholds baseados em dados
- Correlation IDs obrigatórios em todos os logs
Por que resolver isso agora?
- Dificuldade em diagnosticar problemas rapidamente
- Alarmes ruidosos ou ausentes
- Falta visibilidade end-to-end
- SLOs não são medidos consistentemente
- Logs sem correlation dificulta debugging
Impacto de não resolver
- MTTR (Mean Time To Recovery) alto
- Incidentes não detectados rapidamente
- Debugging lento e manual
- SLOs não mensuráveis
- Customer experience degradada sem visibilidade
Documentação relacionada:
- docs/observability/monitoring.md - Dashboards atuais
- docs/observability/cloudwatch.md - Logs e métricas
- docs/observability/alerting.md - Alarmes e severidade
- docs/observability/troubleshooting.md - Guias
- docs/architecture/aws-services.md - Serviços AWS
Proposta de Solução
Observability baseada em Golden Signals, SLOs formais, e correlation IDs obrigatórios.
Golden Signals (Obrigatórios)
1. Latency (quanto tempo leva) - P50, P95, P99 latency por endpoint - Target: P95 < 500ms, P99 < 1s
2. Traffic (quanto está sendo usado) - Requests por segundo (RPS) - Concurrent users - Baseline e trends
3. Errors (o que está falhando) - Error rate % - 4xx vs 5xx - Target: < 1% error rate
4. Saturation (quão cheio está) - Lambda concurrent executions - Database connections - Memory/CPU usage - Target: < 70% utilization
SLOs (Service Level Objectives)
Availability: - Target: 99.9% uptime - Medição: % de requests com status 2xx ou 3xx - Erro budget: 43.2 minutos/mês de downtime
Latency: - Target: P95 < 500ms - Medição: Response time do API Gateway - Por endpoint
Error Rate: - Target: < 0.1% errors - Medição: % de 5xx responses - Excluindo 4xx (client errors)
Dashboards Padronizados
Dashboard: Lambda Function
Widgets:
- Invocations (count)
- Duration (P50, P95, P99)
- Errors (count, %)
- Throttles (count)
- Concurrent Executions
- Memory utilization
Dashboard: API Endpoints
Widgets:
- Request count por endpoint
- Latency (P50, P95, P99) por endpoint
- Status codes (2xx, 4xx, 5xx)
- Error rate %
Dashboard: Database (RDS)
Dashboard: SQS Queues
Structured Logging
Formato obrigatório (JSON):
import structlog
# Configuração
structlog.configure(
processors=[
structlog.stdlib.filter_by_level,
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
structlog.stdlib.PositionalArgumentsFormatter(),
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.StackInfoRenderer(),
structlog.processors.format_exc_info,
structlog.processors.UnicodeDecoder(),
structlog.processors.JSONRenderer()
],
wrapper_class=structlog.stdlib.BoundLogger,
logger_factory=structlog.stdlib.LoggerFactory(),
cache_logger_on_first_use=True,
)
logger = structlog.get_logger()
# Uso
logger.info(
"user_login_successful",
user_id=user.id,
email=user.email,
ip_address=request.client.host,
correlation_id=request.headers.get("X-Correlation-ID")
)
# Output:
{
"event": "user_login_successful",
"user_id": 123,
"email": "user@example.com",
"ip_address": "192.168.1.1",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-02-05T14:30:00.123456Z",
"level": "info",
"logger": "app.auth"
}
Correlation IDs
Geração e propagação:
# Middleware FastAPI
from fastapi import Request
import uuid
@app.middleware("http")
async def add_correlation_id(request: Request, call_next):
# Obter ou gerar correlation ID
correlation_id = request.headers.get("X-Correlation-ID") or str(uuid.uuid4())
# Adicionar ao contexto de logging
with structlog.contextvars.bind_contextvars(correlation_id=correlation_id):
# Adicionar ao response
response = await call_next(request)
response.headers["X-Correlation-ID"] = correlation_id
return response
Propagação para downstream services:
async def call_external_service(url: str):
correlation_id = structlog.contextvars.get_contextvars()["correlation_id"]
response = await httpx.get(
url,
headers={"X-Correlation-ID": correlation_id}
)
return response
Busca de logs por correlation ID:
# CloudWatch Logs Insights
fields @timestamp, @message
| filter correlation_id = "550e8400-e29b-41d4-a716-446655440000"
| sort @timestamp desc
X-Ray Tracing
Instrumentação:
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.ext.flask.middleware import XRayMiddleware
# FastAPI
from aws_xray_sdk.core import patch_all
patch_all() # Patches boto3, requests, etc
@app.middleware("http")
async def xray_middleware(request: Request, call_next):
with xray_recorder.in_segment('fastapi'):
response = await call_next(request)
return response
# Subsegments personalizados
@xray_recorder.capture('database_query')
async def get_user(user_id: int):
# Query é automaticamente traced
return await db.query(User).get(user_id)
Alerting
Alarmes obrigatórios:
# Lambda Error Rate
ErrorRateAlarm:
Metric: Errors / Invocations
Threshold: > 5%
Period: 5 minutes
Severity: P1
Action: SNS → Slack + Email
# API Latency
LatencyAlarm:
Metric: P95 Duration
Threshold: > 1000ms
Period: 5 minutes
Severity: P2
Action: SNS → Slack
# Database CPU
DatabaseCPUAlarm:
Metric: CPUUtilization
Threshold: > 80%
Period: 5 minutes
Evaluation: 2 datapoints
Severity: P1
Action: SNS → Slack + Email
# DLQ Messages
DLQAlarm:
Metric: ApproximateNumberOfMessagesVisible
Threshold: >= 1
Period: 1 minute
Severity: P0
Action: SNS → PagerDuty + Slack
Alternativas Consideradas
Opção 1: Datadog ao invés de CloudWatch
Prós: - Interface melhor - Mais features - APM integrado
Contras: - Custo alto ($15-50/host/mês) - Lock-in de vendor - CloudWatch já está disponível
Por que não escolhemos: CloudWatch + X-Ray é suficiente e já está pago (AWS).
Opção 2: Prometheus + Grafana
Prós: - Open source - Flexível - Grafana poderoso
Contras: - Infraestrutura adicional para manter - Overhead de gestão - CloudWatch já integrado
Por que não escolhemos: Overhead não justificado para serverless.
Opção 3: Logs em plain text
Prós: - Mais simples - Legível para humanos
Contras: - Difícil de query - Parsing manual - Não escalável
Por que não escolhemos: JSON structured logs são necessários para CloudWatch Insights.
Análise de Impacto
Impacto Técnico
- Structured logging obrigatório
- Correlation IDs em todos requests
- X-Ray tracing habilitado
- Dashboards padronizados
Impacto em Negócio
- ✅ MTTR reduzido em 50%
- ✅ Problemas detectados proativamente
- ✅ SLOs mensuráveis e reportáveis
- ✅ Debugging muito mais rápido
- ⚠️ Custo CloudWatch aumenta ~$50-100/mês
Riscos
Risco: Overhead de performance por logging
Mitigação: Logging assíncrono, sampling de X-Ray traces.
Plano de Implementação
Fase 1: Structured Logging (Semana 1)
- Configurar structlog
- Migrar logs principais
- Adicionar correlation IDs
Fase 2: Dashboards (Semana 2)
- Criar dashboards padronizados
- Golden Signals para serviços principais
- Documentar
Fase 3: Alerting (Semana 3)
- Configurar alarmes obrigatórios
- Integrar com Slack
- Testar
Fase 4: X-Ray (Semana 4)
- Habilitar X-Ray tracing
- Instrumentar código
- Treinamento do time
Métricas de Sucesso
Após 1 mês: - ✅ 100% logs estruturados (JSON) - ✅ Correlation IDs em todos requests - ✅ Dashboards funcionais
Após 3 meses: - ✅ MTTR reduzido em 50% - ✅ SLOs medidos e reportados - ✅ Zero incidentes não detectados