Pular para o conteúdo principal
Este guia mapeia os sintomas mais comuns em produção para um diagnóstico e correção concretos, para que você possa resolver incidentes com as ferramentas que já possui, sem precisar configurar infraestrutura adicional de observabilidade. Ele cobre o servidor, coletor, painel, assistente de IA, Python SDK, monitoramento de saúde e certificados, backups, análises com ClickHouse e multi-tenancy. As páginas do painel têm escopo por organização em /<org-slug>/…, e o stream de eventos é a página inicial da organização (/<org-slug>/). Os nomes de páginas neste guia (por exemplo, /sessions, /queries) referem-se a essas rotas com escopo de organização.

Visualizando Logs

O AgentEye não inclui uma pilha de logging ou monitoramento. Tanto o servidor quanto o painel escrevem logs estruturados no stdout, para que você possa lê-los diretamente com kubectl ou docker; nenhum agregador é necessário.

Kubernetes

Acompanhe os logs ao vivo do servidor e do painel:
Variações úteis:
ObjetivoComando
Últimas 200 linhas (sem acompanhamento)kubectl logs -n agenteye -l app=server --tail=200 --timestamps
Logs da falha anteriorkubectl logs -n agenteye <pod-name> --previous
Acompanhar todas as réplicas ao mesmo tempokubectl logs -n agenteye -l app=server --max-log-requests=10 -f
Postgres (StatefulSet)kubectl logs -n agenteye postgres-0 -f

Docker Compose

Correlacionando uma única requisição entre painel e servidor

Cada requisição do painel é marcada com um request_id e propagada ao servidor via cabeçalho x-request-id. O servidor o ecoa nos cabeçalhos de resposta e em cada linha de log emitida para aquela requisição. Para rastrear uma requisição de ponta a ponta:
  1. Capture o id do cabeçalho de resposta, por exemplo:
  2. Busque nos logs de ambos os pods esse id:
Você verá as linhas proxy passthrough, withAuth: authorized e upstream response do painel junto com o par http request received / http request completed do servidor, todos compartilhando o mesmo request_id.

Logs JSON e jq

Defina AE_LOG_JSON=1 no painel (ativado por padrão quando NODE_ENV=production) para emitir um objeto JSON por linha. Então filtre estruturalmente:
O servidor Rust emite pares key=value de tracing que funcionam bem com grep sem jq:

Aumentando a verbosidade

ComponenteVariável de ambienteExemplo
ServidorRUST_LOGRUST_LOG=debug ou RUST_LOG=agenteye_server=debug,info
PainelAE_LOG_LEVELAE_LOG_LEVEL=debug
debug no servidor adiciona uma linha api key authenticated por autenticação. debug no painel adiciona linhas upstream request, session validated e proxy passthrough.

Retenção de logs

O stdout do container é efêmero; o kubelet rotaciona os arquivos de log (padrão ~10 MiB por container) e mantém uma quantidade pequena em disco. Uma vez que o pod é excluído, os logs são perdidos. Se você precisar de retenção mais longa ou busca entre pods, aponte seu cluster para um coletor de logs (Loki, CloudWatch, Cloud Logging, Datadog, etc.) que monitore /var/log/containers/. O AgentEye não exige nem prescreve nenhuma escolha específica.

Problemas de Autenticação

docker pull falha com “unauthorized”

Certifique-se de ter autenticado o Docker no GHCR com seu AGENTEYE_TOKEN:
O token deve ter permissão read:packages na organização agenteye-enterprise. Entre em contato com support@exosphere.host se seu token não funcionar.

gh release download retorna 404 ou 401

  • Confirme que AGENTEYE_TOKEN está exportado no seu shell: echo $AGENTEYE_TOKEN
  • Confirme que você está usando GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ... (a CLI ghGITHUB_TOKEN)
  • O token precisa de contents:read em agenteye-enterprise/releases

Problemas no Servidor

Servidor falha com “invalid port number”

O POSTGRES_PASSWORD (ou outra credencial) contém caracteres especiais para URL (/, +, =) que quebram a análise de DATABASE_URL. Regenere a senha usando codificação hexadecimal:
Em seguida, atualize o secret do Kubernetes e a senha dentro do Postgres (ou recrie o .env para Docker Compose) e reinicie o servidor. Veja os passos completos em enterprise-docs/kubernetes-deployment.md § “PostgreSQL credentials”.

Servidor encerra imediatamente na inicialização

Verifique os logs do container:
Causas comuns:
  • DATABASE_URL não definido ou malformado: o servidor registrará o erro e encerrará.
  • Postgres inacessível: confirme que o container do Postgres ou banco de dados gerenciado está em execução e que o host/porta estão corretos.
  • Migrações falharam: verifique os logs por erros SQL.

GET /health retorna não-200 ou expira

O servidor pode ainda estar executando migrações na primeira inicialização. Aguarde alguns segundos e tente novamente:
Se o problema persistir, verifique docker logs agenteye-server por erros.

GET /ready retorna 503

/ready é a sonda de prontidão: retorna 503 quando o servidor não consegue alcançar Postgres ou ClickHouse. O corpo identifica a dependência com falha:
Corrija a dependência reportada como down: o pod do ClickHouse/Postgres está Running? O CLICKHOUSE_URL / DATABASE_URL está correto e acessível? No Kubernetes, o pod fica como NotReady até que /ready se recupere; isso é esperado e é exatamente o sinal que o monitoramento de saúde alerta. Redis nunca é causa: é reportado, mas não falha a prontidão.

Coletor retorna 401 Unauthorized

A chave de API do coletor não tem permissão events:add, ou a chave foi desativada. Crie uma nova chave com a permissão correta:

Requisições autenticadas ficaram lentas de repente (~200ms em vez de ~5ms)

Este é o sintoma de o Redis estar fora do ar enquanto REDIS_URL está definido. Cada chamada ao cache expira após 100ms e recai no Postgres; nos caminhos de autenticação e OTP, a requisição faz duas dessas recaídas. Confirme nos logs do servidor:
Resolução:
  1. redis-cli -h <your-redis> ping para confirmar que o Redis está acessível na rede do cluster.
  2. Se o Redis ficou brevemente fora do ar e voltou, reinicie os pods do servidor. O redis::aio::ConnectionManager não reestabelece de forma confiável após a queda da conexão subjacente; uma reinicialização do pod retoma a nova conexão de forma limpa. O mesmo se aplica ao painel.
  3. Se você não quer executar o Redis agora, remova REDIS_URL do deployment e reinicie. Ambos os serviços funcionam sem o cache (a correção é preservada; a latência volta à linha de base pré-Redis).

Servidor reporta OTP request rate-limited nos logs, mas o usuário diz que tentou apenas uma vez

Verifique se o Redis estava inacessível. O caminho de fallback usa SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes', que vê linhas de OTP geradas anteriormente. Se o usuário ficou clicando em “Reenviar” por uma hora, a janela de 15 minutos ainda pode conter ≥5 códigos. Resolva aguardando a janela expirar ou execute DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes' (console do operador).

Alterei ALLOWED_EMAILS / SESSION_TTL_SECS / OTP_TTL_SECS e reiniciei; nada mudou

Essas variáveis de ambiente são sementes apenas da primeira inicialização. Uma vez que a tabela settings tem uma linha para a chave correspondente, essa linha é a fonte de verdade; a variável de ambiente é lida uma vez na primeira inicialização e ignorada em todas as reinicializações subsequentes. Para alterá-las após a primeira inicialização, faça login no painel e edite-as em /settings. A alteração se aplica em segundos em todas as réplicas; sem necessidade de reinicialização. Se você precisar forçar uma re-semeação a partir do env (raro, tipicamente útil apenas em desenvolvimento), DELETE FROM settings WHERE key = '<key>' e reinicie o servidor. O bootstrap captará o valor atual da variável de ambiente na próxima inicialização. Editar via /settings é o caminho suportado em produção.

Problemas no Coletor

Coletor inicia, mas os eventos não aparecem no painel

  1. Confirme que o coletor está em execução: systemctl status agenteye-collector (Linux) ou verifique o processo.
  2. Confirme que AGENTEYE_URL aponta para http(s)://your-server-host:8080/events (observe: o caminho /events).
  3. Execute um flush único para ver a saída imediata:
  4. Verifique que o Python SDK está de fato escrevendo arquivos: ls ${AGENTEYE_HOME:-~/.agenteye}/events/
  5. Se existirem arquivos em ${AGENTEYE_HOME:-~/.agenteye}/failed/, os uploads estão falhando. Verifique os logs do coletor pelo erro, provavelmente um 4xx (chave incorreta ou URL) ou problema de rede.

Arquivos estão acumulando em $AGENTEYE_HOME/events/ e não estão sendo enviados

  • O coletor pode não estar em execução. Inicie-o: agenteye-collector start; ele automaticamente faz o flush de eventos pré-existentes na inicialização.
  • Verifique a saúde do coletor: agenteye-collector health
  • O coletor pode estar em execução, mas incapaz de alcançar o servidor. Verifique as regras de firewall entre os hosts do coletor e do servidor.

Arquivos em $AGENTEYE_HOME/failed/

Os arquivos são movidos para failed/ após todas as tentativas de retry serem esgotadas (padrão: 5 tentativas com backoff exponencial). Isso significa:
  • O servidor retornou um erro 4xx (chave incorreta, URL errada ou problema de payload)
  • O servidor estava inacessível durante toda a janela de retry
Corrija o problema subjacente e, em seguida, recoloque manualmente na fila:

Coletor reporta network error em cada upload (falha no handshake TLS)

Se curl -k contra AGENTEYE_URL funciona, mas o binário do coletor falha em cada upload com error sending request for url (...), o servidor AgentEye está apresentando um certificado TLS que não foi assinado por uma CA de confiança pública. O caminho de produção é o hostname ACME de ingestão configurado em deploy/base/certificates/domain.env (veja kubernetes-deployment.md Fases 3.1 / 4.2). Uma vez que INGEST_DOMAIN resolve para o LB público do Traefik e o cert-manager emitiu o certificado Let’s Encrypt, os coletores verificam o certificado do servidor contra o store de confiança do sistema sem necessidade de AGENTEYE_TLS_CA; remova-o da sua configuração do coletor se foi definido para um deployment antigo com certificado autoassinado. Sintoma: o coletor funcionava ontem, falha hoje após uma lacuna de ~90 dias. Isso significa que o deployment ainda usa o emissor legado selfsigned para ingest-tls. O certificado de 90 dias foi rotacionado e o arquivo de CA fixado está desatualizado. Corrija permanentemente mudando o cluster para o emissor ACME (Fase 3.1 do guia de deployment). Desbloqueio de curto prazo: re-extraia o certificado atual do servidor e atualize AGENTEYE_TLS_CA:
AGENTEYE_TLS_CA adiciona uma âncora de confiança adicional; as raízes públicas padrão ainda são confiáveis.

Certificado ingest-tls está preso em Ready: False após o deploy

Observe os Events e o Order / Challenge referenciado. Causas comuns:
  • DNS não resolvendo para o LB público. O validador HTTP-01 não consegue alcançar INGEST_DOMAIN. Verifique com dig +short INGEST_DOMAIN; deve resolver para o mesmo endereço que o EXTERNAL-IP do LoadBalancer traefik-public. O cert-manager retenta automaticamente quando o DNS se propaga; não é necessário excluir o Certificate.
  • Porta 80 bloqueada no load balancer / security group. HTTP-01 requer que a porta 80 seja acessível pelos validadores públicos do Let’s Encrypt. Se você tem um WAF ou SG restringindo :80, abra-o (a configuração do Traefik redireciona para HTTPS, mas o Boulder segue o redirecionamento e aceita a resposta).
  • dnsNames não substituídos. Se kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}' mostrar INGEST_DOMAIN_PLACEHOLDER, você pulou a etapa do domain.env; crie-o a partir de domain.env.example e reaplique.
  • Rate limiting pelo Let’s Encrypt. Ordens repetidas com falha para o mesmo hostname ativam os limites de certificado duplicado ou validação falhada. Aguarde pelo menos uma hora antes de tentar novamente; verifique o status do Order pela mensagem exata de rate limit.

Certificado dashboard-tls está preso em Ready: False / o navegador ainda mostra um aviso

Mesmo fluxo de diagnóstico que ingest-tls acima (kubectl describe certificate dashboard-tls -n agenteye); as causas de DNS, porta 80, placeholder e rate limit se aplicam, mais duas específicas do painel:
  • DASHBOARD_DOMAIN resolve para o LoadBalancer errado. Deve apontar para o LB do Traefik do painel, não o de ingestão pública. Execute dig +short no hostname e compare com o endereço do LB do painel.
  • A instância Traefik do painel não consegue servir o desafio. Deve ser instalada com o arquivo de valores do painel incluído, que habilita um provedor Ingress com escopo para o solver HTTP-01 do cert-manager. Sem ele, o solver é inacessível e o Order fica em pending para sempre. Atualize a instância com os valores fornecidos; o desafio pendente então se completa por conta própria.
  • O LoadBalancer tinha restrição de IP. Os intervalos de origem se aplicam à porta 80 também, o que bloqueia os validadores do Let’s Encrypt — tanto na emissão inicial quanto em cada renovação de ~75 dias. Reabra o LB, ou coordene um solver DNS-01 com o suporte antes de restringi-lo.
Enquanto a emissão está falhando, o painel continua servindo o certificado anterior (ou o padrão do ingress em uma nova instalação) — o acesso é degradado por um aviso do navegador, nunca interrompido.

A CLI ainda ignora a verificação TLS após o painel obter um certificado confiável

--insecure é persistido em cli.json no login. Uma vez que o painel serve um certificado de confiança pública, faça login novamente com agenteye --base-url https://<your-dashboard-domain> --secure login; a verificação é salva de volta como ativada e o aviso de inicialização desaparece.

Problemas no Painel

Não consigo desativar ou editar o usuário ADMIN_EMAIL

Por design. O usuário correspondente ao ADMIN_EMAIL é marcado como protegido em cada inicialização do servidor: o painel oculta o botão Desativar para aquela linha, e a API rejeita DELETE /users/:id e PUT /users/:id com 403 Forbidden. Um trigger do banco de dados também rejeita instruções UPDATE diretas que desativariam a linha protegida. Para rotacionar o admin de bootstrap, altere ADMIN_EMAIL no seu ambiente e reinicie o servidor. O novo e-mail é inserido/atualizado como protegido. O admin anterior retém o sinalizador de proteção até ser limpo no banco de dados (normalmente está bem, pois o e-mail anterior ainda é um admin válido até você removê-lo explicitamente).

O painel não mostra eventos

  1. Confirme que a URL do servidor e a chave de API estão corretas nas variáveis de ambiente do painel (AGENTEYE_SERVER_URL, AGENTEYE_API_KEY).
  2. A chave de API do painel precisa da permissão events:read.
  3. Confirme que eventos foram realmente ingeridos: curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"

/errors está vazio, mas /events mostra linhas vermelhas

Versões mais recentes do SDK emitem falhas como eventos agent_end / tool_result / hook_completed com outcome: "error" no payload, em vez de uma linha dedicada com event_type: "error". A página /errors agora corresponde a ambos: qualquer linha que o stream /events pinta de vermelho (tipo event_type='error' explícito, outcome/status no conjunto de falhas no payload, is_error: true, ou um campo error verdadeiro) aparece em /errors. Se você anteriormente via “no errors in this window” enquanto linhas vermelhas eram visíveis em /events, atualize o painel + servidor juntos (o filtro ampliado é errored=true em GET /events) e as duas visualizações concordarão.

/models, /tools ou /hooks está lento ou falha ao carregar em intervalos de tempo amplos

Sintoma: em uma tabela de eventos grande (milhões de linhas), abrir /models, /tools ou /hooks — ou ampliar o intervalo de tempo para 7d, 30d ou all — os gráficos giram e então mostram um erro de carregamento. O servidor registra um MEMORY_LIMIT_EXCEEDED do ClickHouse (Código 241) ou um timeout de consulta para a requisição latency_aggregate. Causa: builds mais antigas calculavam os rollups de latência e distribuição dessas páginas com uma consulta que lia o payload completo de eventos brutos e emparelhava eventos de requisição/resposta com uma classificação e junção na memória. O pico de memória da consulta crescia portanto com o tamanho da janela, então em um tenant ocupado um intervalo amplo poderia exceder o teto de memória por consulta do ClickHouse. Correção: atualize para um build que inclua essa correção. O rollup agora lê apenas as colunas compactas promovidas e emparelha eventos com uma agregação em streaming, então o pico de memória não escala mais com o payload bruto — intervalos amplos ficam bem dentro do teto de memória e retornam em uma fração do tempo. A melhoria é inteiramente do lado da consulta: aplica-se a todos os dados existentes no próximo carregamento de página, sem re-ingestão ou backfill.

Painel falha ao carregar / página em branco

Verifique os logs do container do painel:
A causa mais comum é AGENTEYE_SERVER_URL ou AGENTEYE_API_KEY ausentes ou apontando para um servidor inacessível.

Analytics / telemetria do painel

O painel envia analytics de uso de produto anônimos para o PostHog por padrão, roteados pelo próprio caminho /ingest do painel (um proxy reverso para https://us.i.posthog.com). Enviá-los como first-party significa que bloqueadores de anúncios do navegador não os descartam. Isso é independente da funcionalidade principal do painel:
  • O container do painel (não o navegador) é quem alcança o PostHog. Se seu acesso de saída para https://us.i.posthog.com estiver bloqueado, a telemetria silenciosamente não opera; o painel funciona normalmente e nenhum erro é exibido aos usuários.
  • Nenhum dado de agente, sessão ou evento é incluído, apenas o uso da UI do painel.
  • Para desativar a telemetria completamente, defina AE_ANALYTICS_DISABLED=1 no container do painel e reinicie. Veja Telemetry & privacy no guia de deployment.

Analytics / telemetria da CLI

A CLI agenteye envia analytics de uso anônimos para o PostHog por padrão: quais comandos são executados, status de sucesso/saída e duração. Isso é independente da funcionalidade da CLI:
  • A máquina que executa a CLI alcança https://us.i.posthog.com diretamente. Se seu acesso de saída estiver bloqueado, a telemetria silenciosamente não opera (o envio tem limite de tempo, então nunca atrasa um comando) e a CLI funciona normalmente.
  • Nenhum dado de agente, sessão ou evento é incluído: argumentos de comandos e valores de flags (URL do painel, token, e-mail, ids de sessão, filtros de consulta) nunca são enviados.
  • Para desativá-la, defina AGENTEYE_ANALYTICS_DISABLED=1 (ou o cross-tool DO_NOT_TRACK=1) no ambiente da CLI. Veja Telemetry & privacy no guia da CLI.

Problemas no Assistente de IA

Veja enterprise-docs/assistant.md para configuração completa.

O botão do assistente não aparece

O botão fica oculto a menos que todos esses critérios sejam atendidos:
  • O usuário conectado tem a permissão agent:use.
  • AGENTEYE_AGENT_URL está definido no painel e o serviço agent está acessível.
  • Um endpoint LLM está configurado no serviço agent (ANTHROPIC_API_KEY, um gateway via ANTHROPIC_BASE_URL, ou Bedrock/Vertex). Com nenhum definido, o agente reporta “not configured” e o botão permanece oculto.
Verifique a saúde do agente a partir do host do painel: curl http://agent:9100/health deve retornar {"status":"ok","llm_configured":true,...}.

O assistente diz que não consegue ler algo

As ferramentas são controladas por usuário. Se um usuário não tem evaluations:read (ou events:read, dashboards:read), as ferramentas correspondentes não são oferecidas e o assistente dirá que não consegue ler aquele dado. Conceda a permissão de leitura relevante.

”assistant not configured” (HTTP 503) ao enviar

O container agent não tem endpoint LLM configurado, ou o AGENTEYE_AGENT_TOKEN do painel não corresponde ao do agente. Defina ambos e reinicie.

O container agent reinicia / fica sem memória sob carga

Cada conversa gera um processo filho de curta duração. Certifique-se de que o container executa com um processo init (a imagem usa tini; no Compose defina init: true) e forneça limites de memória adequados. Reduza AGENTEYE_AGENT_MAX_STEPS se necessário.

Problemas na CLI

agenteye falha ao iniciar com ModuleNotFoundError: No module named 'click'

Uma instalação nova da CLI agenteye na versão 0.1.6 pode travar na inicialização com:
A versão 0.1.6 dependia de click ser instalado indiretamente pelo typer; versões atuais do typer não o incluem mais, então um ambiente limpo acaba sem o pacote. Atualize para a versão 0.1.7 ou mais recente, que depende de click diretamente:
Veja enterprise-docs/cli.md para orientações de instalação.

Problemas no Python SDK

Nenhum arquivo aparecendo em $AGENTEYE_HOME/events/

O SDK armazena eventos em buffer e faz flush a cada 500 ms por padrão. Se o processo encerrar antes do flush, os eventos podem ser perdidos. Chame agenteye.configure(flush_interval=0.1) para flush mais rápido em scripts de curta duração, ou garanta que seu processo execute por tempo suficiente para um ciclo de flush. Se AGENTEYE_HOME estiver definido, verifique se o SDK está escrevendo em $AGENTEYE_HOME/events/ e não em ~/.agenteye/events/ (requer SDK ≥ 0.0.1b5).

ValueError: Reserved field names cannot be used as custom fields

Os nomes timestamp, type e environment são reservados e não podem ser usados como campos personalizados. Passá-los gera:
Renomeie o campo personalizado com problema. Observe que session_id e agent_id são parâmetros explícitos da chamada de evento, não campos personalizados; passar qualquer um deles novamente como campo personalizado gera TypeError.

Problemas no Monitoramento de Saúde

Nenhum alerta chegando no Slack (Robusta)

O alerta de saúde do Robusta é opt-in; não envia nada até ser instalado e apontado para um canal do Slack. Verifique o release e seu sink:
Causas comuns: api_key / slack_channel do Slack não foram definidos (ou o token foi revogado); o api_key é um token de relay em nuvem do Robusta (robusta integrations slack), mas o disableCloudRouting: true incluído precisa de um bot token do Slack auto-hospedado (xoxb-…), ou defina disableCloudRouting: false; o scope do sink exclui o namespace onde seus pods estão (os valores incluídos limitam a agenteye); ou nenhuma falha ocorreu ainda. Force um alerta de teste derrubando um pod:
Veja enterprise-docs/health-monitoring.md para instalação e configuração.

Servidor continua alternando entre NotReady

A sonda de prontidão atinge /ready, que falha quando Postgres ou ClickHouse está inacessível. Se o servidor alterna entre NotReady, uma dependência está intermitentemente indisponível; verifique os pods do ClickHouse e Postgres e os valores CLICKHOUSE_URL / DATABASE_URL do servidor. Confirme o que /ready reporta:
Essa sonda é deliberadamente tolerante (limite de falha generoso), então alternâncias sustentadas indicam um problema real de dependência em vez de uma sonda muito agressiva. A liveness permanece em /health, então a alternância de prontidão não reiniciará o pod.

Problemas no Monitoramento de Certificados

CronJob não está enviando notificações para o Slack

O CronJob cert-renewal-check requer uma URL de webhook do Slack armazenada em um Secret. Verifique se existe:
Se estiver faltando, crie-o:
Sem o secret, o CronJob ainda executa e registra os resultados no stdout. Verifique os logs com:

Certificado do cliente expirou antes de uma notificação ser recebida

O CronJob executa a cada 12 horas. Se não esteve em execução, verifique seu status:
Dispare uma verificação manual:
Para reemitir o certificado expirado imediatamente:
Em seguida, aplique o collector-mtls-secret.yaml regenerado nos clusters que executam seus coletores e reinicie-os:

Problemas de Backup

agenteye-backup falha com “No space left on device”

O CronJob agenteye-backup despeja Postgres + ClickHouse em um volume de rascunho emptyDir chamado backup-tmp (padrão 30Gi), depois transmite em streaming o arquivo tar diretamente para o S3 — o arquivo comprimido nunca é gravado de volta no rascunho, então o rascunho só precisa conter os dumps brutos, não dumps + uma segunda cópia de arquivo em disco. Um pod despejado / No space left on device portanto significa que os dumps brutos excedem o tamanho do rascunho (o dump de events do ClickHouse domina e cresce ao longo do tempo). Verifique os logs do job com falha:
Correção: no seu overlay, aumente o sizeLimit do emptyDir backup-tmp do CronJob acima do total de dumps brutos, e certifique-se de que o armazenamento efêmero do nó pode realmente armazená-lo (sizeLimit é um limite, não uma reserva). Se os dumps ultrapassarem o disco de um único nó, substitua o emptyDir por um PVC (EBS/PD) para backup-tmp, ou comprima os dumps na fonte.
Versões mais antigas gravavam o .tar.gz no mesmo rascunho de 20Gi dos dumps, então dumps + arquivo o estouravam e o pod era despejado antes do upload ser executado — o que parece uma falha do S3, mas na verdade é disco. A transmissão em streaming do upload remove esse problema de duplicação.

agenteye-backup falha ao instalar curl

O job executa na imagem postgres:16 e instala curl na inicialização para o dump HTTP do ClickHouse. Em um cluster sem acesso de saída aos mirrors de pacotes Debian, a etapa apt-get falha. Permita esse acesso de saída do pod de backup, ou inclua curl em uma imagem de backup espelhada/personalizada e referencie-a no seu overlay.

agenteye-backup executa, mas nada chega ao armazenamento de objetos

A base vem com um BACKUP_BUCKET real (ts-prod-agenteye/backups) e a ServiceAccount agenteye-backup. O job transmite em streaming o arquivo para o S3 (tar cz … | aws s3 cp - s3://…). Se o pod de backup não tem acesso de escrita ao bucket, o upload falha — e porque o script executa sob set -euo pipefail, uma falha em qualquer ponto desse pipe falha todo o job na etapa upload em vez de silenciosamente não fazer nada (o trap EXIT do pod registra backup FAILED during step: upload). Esta também é a etapa que você alcança após corrigir um despejo por espaço em disco, então se os backups eram anteriormente despejados na etapa de arquivo, verifique se o upload agora chega. Busque nos logs do job com falha o erro de acesso ao S3:
Correção: no seu overlay defina BACKUP_BUCKET para um bucket que você possui e anote a ServiceAccount agenteye-backup existente com acesso de escrita (IRSA / Workload Identity / Pod Identity). Veja a seção Backups de enterprise-docs/kubernetes-deployment.md.

Avaliações / sessões / queries com ClickHouse

A barra lateral da página /queries está vazia após a atualização

Três tabelas (events, evaluations, agent_sessions) são esperadas. Se a barra lateral do SchemaBrowser estiver vazia após a atualização, o servidor falhou ao aplicar o DDL do ClickHouse na inicialização. Verifique os logs do servidor por failed to apply CH DDL statement:
A causa mais comum é o ClickHouse estar inacessível enquanto as migrações executam. O servidor recusa iniciar se não conseguir alcançar o CH, então um pod travado geralmente tem um CrashLoopBackOff em vez de uma página de queries silenciosamente quebrada, mas um DDL parcialmente aplicado (um statement OK, os próximos com 5xx) deixa o schema incompleto. Reinicie o pod do servidor após verificar que o CH está acessível:

Novas avaliações não aparecem em /sessions ou /queries

Após a atualização, novas avaliações são escritas no ClickHouse, não no Postgres, e aparecem em /sessions (controlado por evaluations:read) e em /queries. Se não aparecerem:
  1. Confirme que o pipeline do avaliador está habilitado (EVALUATOR_ENDPOINT definido no servidor) e produzindo resultados terminais; verifique linhas de log evaluation_finalized.
  2. Confirme que o CH está acessível a partir do servidor: kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping.
  3. Faça uma verificação pontual na tabela CH: kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'.

Queries falham sob carga com “Memory limit exceeded”, ou ClickHouse tem OOMKilled

Sintoma: sob carga pesada de painel/queries, páginas analíticas (stream de eventos, /sessions, visualização de modelos/latência, editor SQL) começam a falhar ou expirar; o servidor alterna brevemente para NotReady; e o pod do ClickHouse mostra contagem de reinicializações crescente. Isso é quase sempre memória, não CPU ou disco. Confirme que é memória (não um problema de throughput que replicação resolveria):
  1. Verifique se o pod teve kills por falta de memória:
    Reason: OOMKilled / Exit Code: 137 com contagem de reinicializações crescente é o indicador.
  2. Pergunte ao ClickHouse o que ele está rejeitando:
    Uma contagem grande de MEMORY_LIMIT_EXCEEDED é a assinatura. A mensagem diz “maximum: N GiB” — esse N é 0,9 × o limite de memória do pod (o max_server_memory_usage_to_ram_ratio em deploy/base/clickhouse/configmap.yaml). Se suas leituras pesadas precisam de mais que N, são rejeitadas.
  3. Descarte as coisas que não são o problema — se CPU, contagem de partes e disco estão todos baixos, adicionar réplicas/sharding seria custo desperdiçado:
Causa: o limite de memória do pod do ClickHouse é muito pequeno para o conjunto de trabalho analítico. As leituras mais pesadas puxam a coluna payload JSON bruta, executam JSONExtract* sobre ela e usam FINAL — cada uma pode precisar de vários GiB. Se os caches configurados (mark_cache_size + uncompressed_cache_size) são maiores que o pod, eles agravam: caches são cobrados contra o mesmo orçamento e competem com a memória de queries. Correção — escale a memória do ClickHouse:
  1. Aumente o limite de memória do ClickHouse no seu overlay fazendo patch nos resources do container do StatefulSet clickhouse (o mesmo mecanismo de overlay usado para resources de outros componentes). O orçamento utilizável do servidor é 0,9 × limite, então um limite de 6Gi dá ~5,4 GiB, 16Gi dá ~14 GiB. Defina requests.memory como um piso real também, para que o scheduler o reserve. Aplicar isso recria o pod do CH (réplica única → ~30–60s de tempo de inatividade de analytics); faça-o em uma janela de baixo tráfego.
  2. Mantenha os caches em deploy/base/clickhouse/configmap.yaml proporcionais ao limite — caches pequenos (algumas centenas de MiB) são seguros em um pod pequeno; aumente-os apenas junto com um aumento correspondente no limite de memória. O max_memory_usage por query é definido explicitamente no perfil users.xml (veja a seção de nó fixo abaixo) e é mantido abaixo do limite em nível de servidor (0,9 × limite) para que nenhuma query única possa usar mais RAM que o container tem.
  3. Se o próprio nó é o teto, verifique a memória do host que o ClickHouse consegue ver:
    Se isso for apenas um pouco acima do limite do pod, mova o ClickHouse para um nó maior (otimizado para memória) — via seletor de nó/affinity no seu overlay — antes de aumentar o limite ainda mais.
Quando você não pode adicionar memória: execute queries na RAM e falhe rapidamente — não derrame em um disco lento. Se o nó é fixo e o pod não pode crescer, limite o que qualquer query pode usar (para que uma query não tome o nó inteiro) e, em um disco de dados lento (não-SSD), não permita que grandes agregações/ordenações derramem em disco. Derramar em um disco lento é mais lento que o timeout de leitura do cliente do servidor, então uma query derramando retorna um 500 do painel no meio do caminho enquanto o ClickHouse continua processando — manter queries na RAM e rejeitar rapidamente a rara que excede o orçamento (MEMORY_LIMIT_EXCEEDED, sub-segundo) é o que restaura o carregamento. Observe uma peculiaridade do ClickHouse ao aplicar estas configurações:
  • Estas são configurações de perfil, e o ClickHouse lê <profiles> apenas de users_config (users.xml / users.d/*.xml) — nunca de config.d. Um bloco <profiles> colocado em config.d/agenteye.xml é silenciosamente ignorado (max_execution_time, max_memory_usage, etc. simplesmente não se aplicam). A configuração incluída portanto as fornece como uma chave users.xml no ConfigMap clickhouse-config, montada em /etc/clickhouse-server/users.d/agenteye.xml.
  • Os padrões incluídos: max_memory_usage (teto por query — uma query não pode consumir todo o orçamento do servidor), max_bytes_before_external_group_by / max_bytes_before_external_sort = 0 (derrame desativado) para que queries fiquem na RAM em vez de arrastar no disco lento, e max_execution_time (proteção contra runaway, alinhado com o timeout de leitura do cliente do servidor).
  • Verifique se estão ativos (assim você também detecta o problema do config.d):
    Espere um max_memory_usage diferente de zero e max_bytes_before_external_group_by = 0. Se max_memory_usage mostrar 0/padrão, o perfil não está sendo aplicado — verifique se as configurações estão em um mount users.d, não em config.d.
Trade-off: com derrame desativado, uma query cujo conjunto de trabalho excede max_memory_usage é rejeitada (MEMORY_LIMIT_EXCEEDED) em vez de completar lentamente — em um disco lento essa rejeição rápida é preferível, porque uma query derramando excederia o timeout do cliente e falharia de qualquer forma. Se seu disco de dados é rápido (SSD), você pode em vez disso aumentar os limites max_bytes_before_external_* para permitir que queries grandes derramem para disco e completem.

Multi-tenancy (organizações)

Erros durante a atualização que habilita organizações (pods mistos antigos/novos)

Sintoma: durante um deploy em rolagem da versão que habilita organizações, algumas requisições falham: os logs do servidor mostram there is no unique or exclusion constraint matching the ON CONFLICT specification no caminho de api_keys, e/ou canais de alerta/Slack/webhook param de disparar enquanto o rollout está em andamento. Causa: a atualização substitui o antigo índice único de escopo de instância em api_keys(name) por índices parciais por organização, e move as configurações de canal de alerta (e default_user_permissions) da tabela global settings para org_settings por organização. Um pod antigo do servidor ainda emite ON CONFLICT (name) (agora sem constraint correspondente) e ainda lê a configuração de canal das antigas linhas de settings (agora vazias). Pods antigos e novos não podem coexistir com segurança nesses dois caminhos. Correção: não faça um rollout lento desta atualização específica entre versões mistas. Faça a transição de forma limpa: escale o servidor antigo para zero (ou use uma breve janela de manutenção) e suba a nova versão junto com suas migrações, em vez de executar réplicas antigas e novas lado a lado. O tráfego normal e a ingestão retomam imediatamente após a transição; isso afeta apenas a janela de transição de versão.

O provisionamento de uma organização falha em CREATE USER / CREATE ROW POLICY, ou uma organização consegue ler os dados de outra

Sintoma: criar uma organização retorna um erro mencionando CREATE USER, CREATE ROW POLICY ou “access management is disabled”; ou, pior, membros de uma organização veem eventos/avaliações de outra no editor SQL ou assistente. Causa: o isolamento por organização é aplicado por um usuário ClickHouse dedicado + política de linha por organização. Isso requer que o gerenciamento de acesso SQL esteja habilitado e que users_without_row_policies_can_read_rows=false esteja configurado no ClickHouse. Com o gerenciamento de acesso desativado, o provisionamento não consegue criar o usuário/política; com o padrão da política de linha deixado no seu valor permissivo, um usuário que tem SELECT mas nenhuma política lê todas as linhas (falha aberta). Correção: use a configuração incluída em deploy/base/clickhouse/, que define ambos. Se você usa sua própria configuração do ClickHouse, habilite o gerenciamento de acesso SQL no usuário interno do servidor e defina users_without_row_policies_can_read_rows=false (veja deploy/base/clickhouse/configmap.yaml), depois reinicie o ClickHouse e re-crie a organização com a CLI agenteye-orgctl (veja enterprise-docs/tenant-management.md).

Usuários da organização perdem acesso ao ClickHouse após alterar ORG_CH_SECRET

Sintoma: o editor SQL e o assistente de IA de repente retornam falhas de autenticação do ClickHouse para todas as organizações, imediatamente após ORG_CH_SECRET ser alterado ou definido de forma inconsistente entre réplicas. Causa: a senha do ClickHouse de cada organização é derivada como um HMAC de ORG_CH_SECRET. Rotacioná-lo (ou executar réplicas com valores diferentes) invalida a credencial ClickHouse armazenada de cada organização; a senha derivada não corresponde mais ao usuário provisionado. Correção: defina ORG_CH_SECRET como um único valor forte antes de provisionar uma segunda organização e mantenha-o estável e idêntico em cada réplica do servidor. A reconciliação de inicialização do servidor re-provisiona o usuário ClickHouse de cada organização a partir do secret atual na inicialização, então uma reinicialização do servidor em todas as réplicas (com o secret consistente) corrige os usuários órfãos. Trate o valor como um secret de longa duração; não o rotacione casualmente. Como rede de segurança, se ORG_CH_SECRET for deixado no valor padrão de desenvolvimento integrado (ou seja, não definido), a reconciliação de inicialização ignora organizações não-padrão e registra um erro em vez de reescrever suas credenciais ClickHouse para o valor de desenvolvimento conhecido publicamente, então uma única réplica que reinicia sem o secret não pode quebrar as outras réplicas. Defina o secret de forma consistente e reinicie para provisionar essas organizações.

O assistente de IA retorna 400 / recusa conversar após habilitar organizações

Sintoma: o dock do assistente carrega, mas cada mensagem retorna um erro (HTTP 400), e o agente registra uma requisição /chat sem organização rejeitada. Causa: o agente é ciente de organização e falha de forma fechada; ele rejeita um /chat que não carrega contexto de organização. Isso acontece durante um rollout de transição onde o agente foi atualizado, mas o painel que envia a requisição ainda não está ciente de organização. Correção: conclua o rollout para que o painel envie contexto de organização (o estado final normal, nenhum flag necessário). Para cobrir o período enquanto um painel não ciente de organização fala com um agente ciente de organização, defina AGENTEYE_AGENT_ALLOW_NO_ORG=1 no serviço agent para que ele recue para a organização default em vez de recusar, e limpe-o assim que a atualização do painel chegar. Veja a referência de variáveis de ambiente em enterprise-docs/assistant.md.

Auditorias

Uma auditoria nunca é executada (próxima execução continua adiando, sem histórico de execução)

Sintoma: a página de auditoria mostra last run: never, ou next run continua avançando para o futuro sem que apareça uma linha no histórico de execução. Causa: a auditoria está desativada (auditorias desativadas não têm entrada na fila), ou os workers de auditoria do servidor estão falhando ao reivindicar trabalho. Correção: confirme que a auditoria está habilitada (o botão executar agora requer isso). Então verifique os logs do servidor por audits pipeline started na inicialização e por erros audits: — uma linha claim_due failed aponta para conectividade do Postgres. AUDIT_WORKERS padrão é 1; deve ser ≥ 1 para qualquer auditoria executar.

Execuções de auditoria têm sucesso, mas não encontram nada

Sintoma: o histórico de execução mostra succeeded com findings: 0 mesmo que /errors claramente mostre falhas. Causa: a janela de varredura não cobre as falhas, ou os filtros de escopo as excluem. Correção: verifique a janela da linha de execução (window_from → window_to) contra quando as falhas ocorreram — no modo since_last, cada execução só varre desde a última execução bem-sucedida, então falhas mais antigas são vistas apenas pela primeira execução ou por uma auditoria de janela fixed. Amplie scope (ambientes / ids de agente). As estatísticas de execução mostram policy_hits (quantas políticas determinísticas dispararam) e improvements (quantos a investigação de IA registrou) — se ambos são 0, a janela/escopo genuinamente não viu nada.

A execução diz analysis_unavailable e produz apenas descobertas de política

Sintoma: as estatísticas de execução incluem analysis_unavailable e as únicas descobertas são kind: policy; nenhuma melhoria de IA aparece. Causa: a investigação agêntica não pôde executar: o servidor não consegue alcançar o serviço agent (AGENTEYE_AGENT_URL / AGENTEYE_AGENT_TOKEN não definidos no servidor — a auditoria reutiliza a conexão do assistente), o serviço assistente não tem LLM configurado, ou a chamada errou/expirou (a string analysis_unavailable tem o detalhe). A passagem de política determinística é o piso — sempre executa — então a auditoria ainda tem sucesso com suas descobertas de segurança. Correção: defina AGENTEYE_AGENT_URL (por exemplo, http://agent:9100) e AGENTEYE_AGENT_TOKEN no servidor — os mesmos valores que o assistente do painel já usa (os manifestos/compose incluídos agora os conectam) — e configure um LLM no serviço assistente (veja assistant.md), depois execute novamente. Uma investigação grande pode precisar de um AUDIT_LLM_TIMEOUT_MS maior (servidor) — mantenha-o acima do AGENTEYE_AUDIT_TIMEOUT_MS do agente.

O sandbox de código da auditoria está desativado (sandbox_available: false)

Sintoma: o /health do agente mostra sandbox_available: false, e as execuções de auditoria observam que o sandbox está indisponível; a IA investiga apenas com SQL. Causa: o sandbox bubblewrap dentro do pod precisa de namespaces de usuário não privilegiados, que o perfil seccomp do pod ou o kernel do nó está bloqueando. Correção: defina seccompProfile: Unconfined (k8s) ou security_opt: [seccomp:unconfined] (compose) no agente, e confirme que o kernel do nó permite namespaces de usuário não privilegiados (algumas imagens gerenciadas, como GKE COS, os desativam). Onde você não pode habilitá-lo, isso é esperado e seguro — o auditor degrada para SQL apenas automaticamente. Veja deployment.md.

Relatório de e-mail de auditoria não entregue

Sintoma: uma auditoria revelou novas descobertas, mas nenhum e-mail chegou. Causa: a auditoria não tem um canal de e-mail anexado, o e-mail está desativado em toda a organização em alerts.enabled_channels, não há destinatários, ou o SMTP não está configurado. Correção: anexe um canal de e-mail à auditoria, certifique-se de que email está em alerts.enabled_channels, defina destinatários (no canal ou via alerts.email_default_recipients) e configure o SMTP (o mesmo transporte que os e-mails de alertas + OTP usam). O e-mail é enviado apenas quando uma execução produz pelo menos uma nova descoberta.

Um padrão silenciado ou descartado mantém sua página de descoberta antiga, mas nunca é re-classificado

Sintoma: após silenciar uma descoberta, execuções posteriores nunca surfaceiam aquele padrão novamente — mesmo que ele ainda ocorra. Causa: esse é o comportamento projetado: silenciar/descartar são supressões duráveis codificadas pela impressão digital do padrão. Correção: abra a descoberta e use reopen para limpar a supressão; a próxima execução classificará o padrão novamente. Use resolve (não silenciar) para padrões “corrigidos” sobre os quais você gostaria de ser notificado se regredirem.

Obtendo Ajuda

Entre em contato com support@exosphere.host com:
  • Sua versão do AgentEye (da tag de release)
  • Logs relevantes do container (docker logs <container>)
  • Uma descrição do problema e o que você já tentou