Pular para conteúdo

Observabilidade

O sistema escreve eventos JSON para stdout, consumidos pelo CloudWatch nas Lambdas, e mantém um buffer local para a dashboard. O objetivo operacional é relacionar recebimento, processamento, persistência e efeitos externos de uma conversa sem distribuir seu conteúdo cadastral.

Logging e categorias

src/shared/logging.py fornece get_logger(__name__), configura o root handler e serializa timestamp, level, logger, message e campos adicionais. src/shared/log_buffer.py guarda até 500 registros; recent_records() retorna por padrão até 200 e permite filtro por since.

As categorias da dashboard são error, warn, llm_request, llm_response, orchestration, stub, agent, kb e info. Elas são derivadas do nível, logger e nome do evento, não de uma classificação de severidade de negócio. Um registro httpx é classificado como llm_request pelo helper, mesmo sem inspeção do destino.

{
  "timestamp": "2026-09-14T12:00:00+00:00",
  "level": "INFO",
  "logger": "orchestrator.app",
  "message": "process_message_done",
  "phone_number": "<TELEFONE_MASCARADO>",
  "state_after": "HANDOFF_PENDING"
}

Scrubbing e limites de privacidade

_scrub() substitui valores de chaves como cpf, cnpj, email, nome, telefone, endereco, cep, cadastral_data, egestor_payload e hubspot_payload, recursivamente em mapas/listas. Também aplica regex a e-mails, CPF e CNPJ em strings.

Isso não é anonimização completa. phone_number não pertence à lista de chaves removidas e pode permanecer identificável; regex podem mascarar alguns formatos incidentalmente. exc_info é formatado sem passar por _scrub(), tanto no JSON quanto no buffer local. Segredos arbitrários e PII fora dos padrões não são garantidamente removidos. Não copie logs ou tracebacks brutos para tickets públicos.

O histórico no DynamoDB contém conteúdo necessário ao atendimento, sob controles de acesso do ambiente. Consulte por session_id, message_id e intervalo de tempo; substitua telefone por identificador de caso na evidência compartilhada.

IDs e rastreamento

Identificador Escopo
request_id Invocação Lambda, obtido de context.aws_request_id em eventos de entrada
messageId Registro/evento SQS
provider_message_id ID inbound/outbound do provider, útil para deduplicação e entrega
session_id Conversa lógica e item de projeção CRM
correlation_id Resposta de provider quando disponível, preservada por probes/smokes CRM

Não há propagação automática de um único trace ID por todos os módulos. request_id aparece nos eventos que o incluem; não é injetado em cada log. Não foi identificada configuração Tracing/X-Ray no SAM.

Investigar webhook → fila → aplicação → provider

  1. Procure webhook_received e resposta HTTP no intervalo. whatsapp_signature_invalid, bad_input e internal_payload_rejected_in_cloud_mode explicam rejeições antes do processamento.
  2. Para texto aceito, relacione receipt/ID do provider e mensagem SQS. Operadores e conversas humanas podem ser tratados no webhook, sem passar pelo agente.
  3. Procure orchestrator_event, immediate_turns_done, process_message_done, process_message_replayed ou process_immediate_turn_failed. Uma resposta superada pode ser descartada legitimamente.
  4. Procure llm_timeout, llm_4xx, llm_5xx, reparo do parser e llm_failure_handoff para distinguir provider de contrato.
  5. Confirme outbound por ID e resultado do adapter; whatsapp_send_failed exige investigar entrega antes de reprocessar.
  6. Para CRM, consulte projeção e métricas próprias. O estado humano no DynamoDB pode estar correto mesmo com CRM atrasado.

Exemplos de observação, usando conta/região autorizadas:

aws logs tail /aws/lambda/gogenetic-agent-webhook-staging --region sa-east-1 --since 30m
aws logs tail /aws/lambda/gogenetic-agent-orchestrator-staging --region sa-east-1 --since 30m
aws logs tail /aws/lambda/gogenetic-agent-crm-sync-staging --region sa-east-1 --since 30m

Consulta de CloudWatch Logs Insights sobre grupos escolhidos:

fields @timestamp, level, logger, message, request_id, session_id, provider_message_id
| filter session_id = "<SESSION_ID>"
| sort @timestamp asc
| limit 200

Nem todos os registros contêm session_id; use a janela temporal e IDs complementares para completar a cadeia, sem presumir que uma consulta vazia significa ausência de execução.

Métricas e alarmes SAM

Alarme Métrica / limiar
WebhookErrorsAlarm, OrchestratorErrorsAlarm AWS/Lambda Errors, soma >= 1 em 300 s
EGestorUnsafeCustomerLookupAlarm GoGenetic/eGestor UnsafeCustomerLookup, soma >= 1 em 300 s
CrmSyncBlockedAlarm GoGenetic/CRM Blocked, máximo >= 1 em 60 s
CrmSyncUncertainAlarm GoGenetic/CRM Uncertain, máximo >= 1 em 60 s
CrmSyncAgeAlarm GoGenetic/CRM OldestPendingSeconds, máximo > 900 em 60 s
CrmSyncErrorsAlarm AWS/Lambda Errors, soma >= 1 em 60 s

Todos usam uma avaliação e TreatMissingData=notBreaching; notificação depende de AlertsSnsTopicArn. O template referencia um tópico existente, não cria tópico nem subscription. Ausência de dados não alarma nesses recursos.

O worker CRM emite Pending, Blocked, Uncertain, OldestPendingSeconds com dimensão FunctionName. Apesar do nome, o cálculo de idade percorre repo.problems(), incluindo bloqueados/incertos, e não somente linhas PENDING.

SQS e DLQ

Observe ApproximateNumberOfMessagesVisible, ApproximateNumberOfMessagesNotVisible e ApproximateAgeOfOldestMessage na fila. Para uma URL obtida dos outputs:

aws sqs get-queue-attributes --region sa-east-1 --queue-url '<QUEUE_URL>' --attribute-names ApproximateNumberOfMessagesVisible ApproximateNumberOfMessagesNotVisible RedrivePolicy

A DLQ é gogenetic-agent-debounce-dlq-<ambiente>.fifo. Não há alarme DLQ declarado no template. Consultar atributos é observação; receber mensagens pode alterar visibilidade e redrive é reprocessamento com possíveis efeitos externos. Preserve evidência, corrija a causa e revise recibos antes de reprocessar.

Diagnóstico CRM sem escrita

python scripts/diagnose_crm_sync.py --table gogenetic-agent-staging --region sa-east-1
python scripts/diagnose_crm_sync.py --table gogenetic-agent-staging --region sa-east-1 --crm-snapshot export.json --stage-map etapas.json

Sem snapshot, a ferramenta verifica somente projeção local; SYNCED não comprova que alguém não mudou o CRM depois. Snapshot aceita [{"id":"<DEAL_ID>","properties":{"dealstage":"<STAGE_ID>"}}]; mapa relaciona nomes como atendimento_humano aos IDs. A ferramenta reporta LEGACY_UNVERIFIED para sessões humanas sem projeção e pode apontar REMOTE_HUMAN_WITHOUT_KNOWN_LINK em comparação completa. Nenhum desses resultados autoriza apagar cards.

Testes: tests/unit/shared/test_logging_scrubbing.py, tests/unit/application/test_crm_sync.py, tests/unit/lambdas/test_crm_sync.py, tests/unit/lambdas/test_emulator.py. Veja troubleshooting.