Logging json-file de Docker para un agente IA: max-size o el host muere
Resumen
Cómo no llenar /var/lib/docker con stdout del bot: logging json-file max-size y max-file en Compose. Distinto de wrangler tail. El driver no rota solo. Techos oficiales Docker json-file, local y none, verificados con curl el 3 de septiembre de 2026.

Qué resuelve
Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.
El agente loguea cada tool. json-file (default) crece sin tope en el host. Disco del volumen es /data. Esto es /var/lib/docker/containers/*/json.log. Fuentes oficiales consultadas el 3 de septiembre de 2026.
Logs runtime cubre Vercel/wrangler/railway CLI. Aquí: el driver del daemon.
La regla
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
30 MB por servicio, no 30 GB. docker logs sigue funcionando.
No none en prod: no hay postmortem. No journald “porque systemd” si no sabes leer journalctl -u docker.
Qué no va al json.log
Secretos. Bodies de Telegram. API keys. El driver no filtra. Recorta en la app (NODE_ENV).
Adjuntos / dumps: no console.log(buffer).
Fly / Railway / Vercel
Ellos retegan. No uses json-file ahí. Esta guía es VPS/Compose. docker logs --tail en el VPS; en Fly fly logs.
Tabla

| Driver | Tope | docker logs |
|---|---|---|
| json-file default | no | sí, hasta llenar disco |
| json-file + max-size | sí | sí |
| local | sí (docs) | sí |
| none | n/a | no |
Errores comunes

| Síntoma | Causa | Fix |
|---|---|---|
| Host 100%, volumen ok | json.log | max-size |
docker logs vacío | driver none | json-file |
| Leak de token en log | app | no loguear env |
| max-size ignorado | mal indent yaml | bajo logging.options |
| Fly “json-file” | no aplica | fly logs |
Relación con el resto
- Volumen sqlite: disco.
- CLI proveedores: logs runtime.
- FDs de archivos log: nofile.
- Restart no rota logs: restart.
Checklist
-
max-size+max-fileen Compose - No secrets en stdout
-
dudejson.logen el host - Ensayo: llena 11 MB de log, el archivo rota
- No driver none en prod
- Documenta
docker logs -f
FAQ
¿local vs json-file? local tiene rotación por default (docs). json-file + options es lo que más tutoriales usan. Elige uno y pon tope.
¿syslog? Otro hop. Empieza por max-size.
¿K8s? El kubelet retega; no es json-file del daemon en el node igual. Distinto runbook.
Dónde está el archivo
/var/lib/docker/containers/<id>/<id>-json.log. docker inspect --format '{{.LogPath}}'. du -h ese path. docker logs --since 1h no borra el archivo.
Un docker compose down no siempre borra logs si el contenedor queda. docker rm sí. Restart policy unless-stopped deja el mismo id y el mismo log (con rotación).
El ensayo: yes | head al stdout del contenedor (Preview) hasta pasar max-size; ls -lh *json.log*.
Un bot verbose a las 3 AM es un ataque de disco accidental. 10m × 3 es barato.
docker system df no sustituye mirar el json.log. Mira el path. docker compose logs lee el mismo driver: si rotó, el historial corto es esperado, no un bug de la app.
json-file: techos oficiales
Driver json-file (hoy): max-size es entero positivo más unidad k / m / g (sin importar mayúsculas). Default -1 (unlimited). Sin esa opción no hay rotación. max-file es entero positivo; default 1. Solo aplica si también hay max-size. Si pones solo max-file: "3", el daemon no rota.
compress de archivos ya rotados: default false. No esperes gzip gratis.
Ejemplo documentado: --log-opt max-size=10m y --log-opt max-file=3 — tres archivos, 10 MB cada uno. En daemon.json las opciones van como strings: "max-file": "3" con comillas. Un número JSON crudo es el bug.
Cambiar daemon.json no mueve contenedores ya creados. Hay que recrearlos. docker compose up -d --force-recreate del servicio, no un reload del daemon.
Default del daemon: json-file. Compruébalo con docker info --format '{{.LoggingDriver}}'. Por contenedor: docker inspect -f '{{.HostConfig.LogConfig.Type}}'.
local vs json-file
Driver local: formato interno, no JSON línea a línea. Default 20m por archivo y 5 archivos = 100 MB por contenedor, con compresión encendida. json-file default es ilimitado y sin compress. Por eso “cambiar a local y olvidarte” funciona; json-file hay que escribir el tope.
docker logs lee ambos. No edites a mano los archivos del driver: la doc avisa interferencia.
En bash, local es palabra reservada. En scripts, cita el driver: --log-driver local.
blocking vs non-blocking
Default: entrega blocking del stdout al driver. Un disco lento bloquea el proceso del bot. mode=non-blocking más max-buffer-size (default 1m, un millón de bytes) evita que el agente se cuelgue escribiendo logs. Buffer lleno: se tiran líneas nuevas. Un agente chatty en non-blocking pierde el postmortem. Para VPS con json-file en disco local, blocking más max-size es el default sano.
Ejemplo documentado: --log-opt mode=non-blocking --log-opt max-buffer-size=4m. No lo copies a prod del webhook sin saber qué estás tirando.
none
--log-driver none: docker logs vacío. No hay postmortem. No lo uses en prod del bot.
Compose logging.driver es por servicio. El ejemplo oficial usa syslog; para el VPS usa json-file o local con options. El default y los valores disponibles son específicos de la plataforma: no copies un driver: syslog de un gist a un VPS sin syslogd.
Recrear, no recargar
El daemon no aplica log-opts nuevos a contenedores vivos. unless-stopped (restart) deja el mismo id y el mismo json.log. Recrear el servicio. Un kill -HUP dockerd no rota el archivo actual.
labels y env del driver json-file se configuran en el daemon, no en el yaml del bot. Sirven para tags avanzados. No meten el token de Telegram en el log: eso lo hace console.log(process.env).
Unidades de max-size: k, m, g. 10mb no es el formato. 10m sí.
Fly, Railway y Vercel retegan ellos. No copies este yaml a wrangler. Esta guía es VPS/Compose. En el VPS, du del json.log; en Fly, fly logs.
Siguiente paso: si el driver ya rota y el volumen sqlite igual se llena, disco. Sin runtime: curso.
Lecturas relacionadas
Sigue explorando Deploy y otras piezas para builders.



