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¶
- Procure
webhook_receivede resposta HTTP no intervalo.whatsapp_signature_invalid,bad_inputeinternal_payload_rejected_in_cloud_modeexplicam rejeições antes do processamento. - Para texto aceito, relacione receipt/ID do provider e mensagem SQS. Operadores e conversas humanas podem ser tratados no webhook, sem passar pelo agente.
- Procure
orchestrator_event,immediate_turns_done,process_message_done,process_message_replayedouprocess_immediate_turn_failed. Uma resposta superada pode ser descartada legitimamente. - Procure
llm_timeout,llm_4xx,llm_5xx, reparo do parser ellm_failure_handoffpara distinguir provider de contrato. - Confirme outbound por ID e resultado do adapter;
whatsapp_send_failedexige investigar entrega antes de reprocessar. - 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.