Você já esbarrou na sigla MTTR? Se ainda não, vale 2 minutos para entender por que ela virou o indicador nº 1 em times de operação e produto. No fim deste artigo deixei um adendo simples sobre MTTR — pode conferir depois ou pular direto agora.
O ponto crucial é: reduzir o MTTR exige não esperar o usuário reclamar. É aqui que entra o monitoramento proativo: logs inteligentes que dão contexto e alertas automatizados que acionam a equipe na hora certa.
Neste guia colaborativo, mostramos como implementar isso em Python com padrões prontos para produção: logs JSON estruturados, enriquecimento de contexto, rotação/retenção e um monitor simples com alerta via Slack.
Observabilidade combina logs, métricas e traces. Aqui focamos em logs como base para alertas eficazes, sem lock-in de ferramenta.
Padrões recomendados:
import json, logging, sys
from logging.handlers import RotatingFileHandler
class JsonFormatter(logging.Formatter):
def format(self, record):
base = {
"timestamp": self.formatTime(record, "%Y-%m-%dT%H:%M:%S%z"),
"level": record.levelname,
"message": record.getMessage(),
"logger": record.name,
"service": getattr(record, "service", "app"),
"env": getattr(record, "env", "prod"),
"trace_id": getattr(record, "trace_id", None),
"user_id": getattr(record, "user_id", None),
}
return json.dumps({k: v for k, v in base.items() if v is not None})
def get_logger(name: str = "app") -> logging.Logger:
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)
if logger.handlers:
return logger # evita handlers duplicados
fmt = JsonFormatter()
console = logging.StreamHandler(sys.stdout)
console.setFormatter(fmt)
file_handler = RotatingFileHandler("logs/app.log", maxBytes=2_000_000, backupCount=5)
file_handler.setFormatter(fmt)
logger.addHandler(console)
logger.addHandler(file_handler)
return logger
log = get_logger("orders")
log = logging.LoggerAdapter(log, {"service": "orders", "env": "prod"})
log.info("service_started", extra={"trace_id": "abc123"})
import logging
class ContextFilter(logging.Filter):
def __init__(self, **base):
super().__init__()
self.base = base
def filter(self, record):
for k, v in self.base.items():
setattr(record, k, v)
return True
logger = get_logger("payments")
logger.addFilter(ContextFilter(service="payments", env="prod"))
logger.info("payment_approved", extra={"trace_id": "t-991", "user_id": "u-42", "amount": 129.90})
Boas práticas:
import os, json, time, logging, requests
from collections import deque
SLACK_WEBHOOK = os.getenv("SLACK_WEBHOOK_URL")
LOGFILE = "logs/app.log"
WINDOW_SEC = 60
THRESHOLD = 5
def send_slack(text: str):
if not SLACK_WEBHOOK:
return
requests.post(SLACK_WEBHOOK, json={"text": text}, timeout=5)
def tail_errors(path: str):
with open(path, "r", encoding="utf-8") as f:
f.seek(0, 2)
while True:
line = f.readline()
if not line:
time.sleep(0.5); continue
try:
evt = json.loads(line)
if evt.get("level") in {"ERROR", "CRITICAL"}:
yield evt
except Exception:
continue
def monitor():
window = deque()
for evt in tail_errors(LOGFILE):
now = time.time()
window.append(now)
while window and now - window[0] > WINDOW_SEC:
window.popleft()
if len(window) >= THRESHOLD:
sample = evt.get("message")
send_slack(f"Alerta: {len(window)} erros em {WINDOW_SEC}s no serviço {evt.get('service')}. Ex.: {sample}")
window.clear()
# monitor()
Este artigo é colaborativo. Envie melhorias, exemplos e playbooks reais que funcionaram para você. Podemos incluir:
Para contribuir: envie um e-mail, compartilhe via LinkedIn ou proponha um snippet pronto para inclusão.
MTTR é a sigla para Mean Time To Repair/Recover/Resolve — em português, tempo médio para recuperar ou resolver um incidente. É uma métrica que mostra quanto tempo, em média, um serviço fica indisponível até voltar ao normal após um problema.
Como calcular (bem simples):
MTTR = (tempo total de indisponibilidade no período) ÷ (número de incidentes)
Por que importa:
Exemplo rápido: se, em um mês, seu sistema ficou 2 horas indisponível somando 4 incidentes, o MTTR foi 30 minutos por incidente (2h ÷ 4 = 0,5h).
Como reduzir o MTTR na prática: