Skip to main content

Dozzle (log viewer)

Dozzle — visor de logs en tiempo real para los contenedores del stack. ⬆ Documentación AITHA

Dozzle expone los logs de todos los contenedores del host desde el navegador. Está pensado para leer el JSON estructurado de los tres backends Python — chat-server, user-service y things_extensions (eventos, req_id, duration_ms) —, pero muestra igual los servicios que emiten texto plano. Los tres emiten el mismo JSON: mismos campos de correlación (req_id, process, level, event, message, duration_ms) y la misma disciplina de niveles, así que una traza cruzada entre servicios es posible buscando el mismo req_id en los logs de ambos contenedores.

Acceso​

  • URL pública: https://logs.<PUBLIC_BASE_DOMAIN> (p. ej. https://logs.aitha.es).
  • Local: http://localhost:3090.
  • Login: usuario admin; la contraseña es GLOBAL_DOZZLE_ADMIN_PASSWORD (.env.secrets local / Ansible Vault remoto).
  • La sesión dura 48h (DOZZLE_AUTH_TTL); el logout cierra la sesión de Dozzle.
  • La UI es de solo lectura: DOZZLE_ENABLE_ACTIONS=false y DOZZLE_ENABLE_SHELL=false (no hay botones de stop/restart ni shell).

Consultas que resuelven el 90% de los casos​

  1. Seguir un request completo por req_id: pega el req_id en el buscador y ordena por tiempo. Verás la narrativa en orden: pipeline.started → identity.* → llm.resolved → prompt.built → mode.classified → execution.* → llm.call.* → response.emitted → usage.recorded → pipeline.finished.

  2. Filtrar errores: filtro level=error (los niveles canónicos info, debug, trace también funcionan).

  3. Etapas lentas: el buscador filtra por cualquier campo; para ver las etapas que pasan de 1s usa duration_ms > 1000 en el panel SQL (SELECT message.event, message.duration_ms FROM logs WHERE message.duration_ms > 1000).

  4. Traza cruzada por req_id entre backends: el mismo req_id viaja de chat-server a user-service/things_extensions cuando los llaman, así que una petición se sigue entera buscando ese id en cada contenedor. En terminal:

    docker logs user-service 2>&1 | jq -c 'select(.req_id=="<id>") | {t:.timestamp, ev:.event, ms:.duration_ms}'
    docker logs things_extensions 2>&1 | jq -c 'select(.req_id=="<id>") | {t:.timestamp, ev:.event, ms:.duration_ms}'

    Y en Dozzle, SQL: SELECT message.event, message.req_id, message.duration_ms FROM logs WHERE message.level = 'info' ORDER BY message.timestamp.

Los campos sensibles se muestran redactados (***) porque la redacción ocurre en los backends (app/utils/logger.py) antes de emitir la línea; Dozzle solo pinta lo que llega.

En la terminal, sin Dozzle​

./infra logs <proyecto> colorea el JSON automáticamente (reordena TIMESTAMP LEVEL [logger] event key=val … y deja intacto lo que no es JSON). Si quieres el equivalente directo sobre el contenedor:

docker logs -f chat-server | jq -R -r -f deployment/scripts/utils/pretty_logs.jq

Requiere jq en el host (ya se instala vía roles/common en los servidores).

Operación​

  • ./infra up dozzle genera data/users.yml (bcrypt) en el primer arranque desde GLOBAL_DOZZLE_ADMIN_PASSWORD. En el deploy remoto lo renderiza Ansible con mode: 0600; el hash nunca sube desde el controlador.
  • ./infra clean dozzle --data borra data/ (usuarios + ajustes).
  • El visor sobrevive a ./infra down all (SKIP_BULK_STOP=true).