Recopila logs desde archivos, HTTP y contenedores
Configura las tres fuentes de entrada más comunes: un archivo en disco, un endpoint HTTP y todos los contenedores de un host Docker.
La mayoría de los despliegues reales necesitan más de un tipo de fuente de entrada a la vez: una aplicación existente que escribe en un archivo de log, un servicio que puede enviar logs por HTTP y todos los contenedores que se ejecutan en un host. Esta guía configura los tres, apoyándose en la estructura source/filter/match de la guía anterior.
Seguir un archivo de log con tail
El plugin de entrada tail sigue un archivo como lo hace tail -f, recogiendo las líneas nuevas a medida que se escriben:
<source>
@type tail
path /var/log/apache2/access.log
pos_file /var/log/fluent/apache-access.log.pos
tag apache.access
<parse>
@type apache2
</parse>
</source>
Conviene tomarse en serio pos_file, aunque sea fácil omitirlo: es donde Fluentd registra exactamente hasta dónde ha leído ya del archivo. Sin él, reiniciar Fluentd significa releer todo el archivo desde el principio, duplicando todo lo ya enviado. Con él, un reinicio retoma exactamente donde se quedó. La propia documentación del plugin lo describe como muy recomendable precisamente por esta razón.
Aceptar logs por HTTP
No todo puede tener Fluentd instalado al lado. Un servicio administrado en la nube, una función serverless, cualquier cosa fuera de la infraestructura que controlas a nivel de sistema operativo, no puede ejecutar una fuente tail junto a un archivo que está escribiendo. Para esos casos, el plugin de entrada http permite que algo envíe logs a Fluentd en lugar de que Fluentd los lea de ello:
<source>
@type http
port 9880
bind 0.0.0.0
body_size_limit 32m
keepalive_timeout 10s
</source>
Cualquier cosa que pueda hacer una petición HTTP POST, una aplicación personalizada, una librería de logging configurada para reenviar allí, una llamada curl en un script, ya puede entregar datos de log directamente. Conviene definir body_size_limit y keepalive_timeout de forma deliberada en lugar de dejarlos en el valor predeterminado que traiga tu versión, ya que una fuente HTTP está expuesta a cualquier tráfico que llegue hasta ella, y los tamaños de petición ilimitados o las conexiones mantenidas abiertas son justo lo que quieres tener bajo tu propio control en lugar de dejarlo al comportamiento por defecto.
Recopilar los logs de todos los contenedores de un host
Docker (y los runtimes de contenedores en general) escribe el stdout/stderr de cada contenedor en archivos de log con formato JSON en el host, un directorio por contenedor. Apuntar una fuente tail a todos ellos con un comodín basta para recopilar la salida de cada contenedor sin configurar cada uno individualmente:
<source>
@type tail
path /fluentd/log/containers/*/*-json.log
pos_file /var/log/fluent/docker.log.pos
tag docker.*
read_from_head true
<parse>
@type json
</parse>
</source>
Para que esto funcione, el directorio de logs de Docker del host (/var/lib/docker/containers por defecto) debe estar realmente montado en el lugar donde se ejecuta Fluentd, en la ruta a la que apunta el patrón path de la fuente. Así es exactamente como funciona también Fluentd como DaemonSet de Kubernetes: un Pod de Fluentd por nodo, cada uno montando el directorio de logs de contenedores de su propio nodo, de modo que en todo un clúster los contenedores de cada nodo se recopilan de la misma forma sin configuración por contenedor.
read_from_head true le dice a Fluentd que empiece desde el principio de los archivos que aún no ha visto, algo importante para contenedores que ya estaban en ejecución (y ya registrando logs) antes de configurar esta fuente; sin él, Fluentd solo recoge las líneas nuevas desde el momento en que empieza a vigilar un archivo dado.
Enriquecer con contexto: qué contenedor, qué host
Las líneas de log en bruto de un contenedor no dicen por sí solas de qué pod, nodo o contenedor proceden; ese contexto hay que adjuntarlo, normalmente con un filter que use el plugin record_transformer:
<filter docker.**>
@type record_transformer
<record>
hostname "#{Socket.gethostname}"
</record>
</filter>
Esto adjunta el nombre del host actual a cada entrada etiquetada bajo docker., que es lo que te permite más adelante saber de cuál de varias réplicas, detrás de un balanceador de carga o repartidas por un clúster, procede realmente una línea de log dada. El mismo patrón se extiende al nombre del pod, el namespace o cualquier otro metadato que valga la pena adjuntar en el momento de la recopilación en lugar de intentar reconstruirlo después.
Verifica cada fuente de forma independiente
Antes de conectar destinos de salida reales, apunta cada fuente a un simple match @type stdout y confirma que produce la estructura que esperas:
<match apache.access>
@type stdout
</match>
Genera una petición (o escribe una línea en el archivo, o haz un POST al endpoint HTTP, o inicia un contenedor) y observa aparecer la salida analizada y etiquetada. Confirmar cada fuente de forma aislada, antes de añadir filtros o destinos reales encima, hace mucho más fácil saber qué etapa introdujo un problema si algo más adelante en el pipeline no se ve bien.
Guías populares
-
Por qué el logging centralizado: el problema que resuelve Fluentd Qué sale mal cuando los logs viven en decenas de archivos y formatos, y cómo lo arregla el pipeline recopilar-transformar-enviar de Fluentd. -
Fundamentos de configuración de Fluentd: source, filter, match y tags Las directivas con las que se construye toda configuración de Fluentd, cómo las conectan los tags y cómo validar una configuración antes de ejecutarla. -
Envía logs de forma fiable: plugins de salida y buffering Instala un plugin de salida, enruta distintas fuentes a distintos destinos y configura el buffering para que un backend caído no pierda datos.