Este artículo presenta el procedimiento (muy simple) de instalación y configuración del agente Telegraf para el monitoreo de logs de accesos y errores de Apache utilizando el plugin "Tail". Incluye la carga de datos en una base InfluxDB para crear gráficas y tablas en Grafana.

Instalación de Telegraf

Obtener la URL de descarga de la última versión estable de Telegraf desde el portal de descargas de InfluxData. Descargar e instalar:

# wget https://dl.influxdata.com/telegraf/releases/telegraf_1.17.0-1_amd64.deb
# dpkg -i telegraf_1.17.0-1_amd64.deb

Al menos en Debian 10 no requiere la instalación de paquetes adicionales (si fuera necesario, ejecutar apt-get --fix-broken install).

Prueba de funcionamiento del plugin tail

Se utiliza el plugin "tail" en lugar de "logparser", ya que este último se encuentra oficialmente deprecated en la última versión de Telegraf.

La configuración por defecto de Telegraf incluye inputs que (inicialmente) no deseamos monitorear si actualmente están cubiertos por collectd:

root@debian:~# grep -v '^  #' /etc/telegraf/telegraf.conf | grep -v '^#' | grep -v '^$'
[global_tags]
[agent]
  interval = "10s"
  round_interval = true
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  collection_jitter = "0s"
  flush_interval = "10s"
  flush_jitter = "0s"
  precision = ""
  hostname = ""
  omit_hostname = false
[[outputs.influxdb]]
[[inputs.cpu]]
  percpu = true
  totalcpu = true
  collect_cpu_time = false
  report_active = false
[[inputs.disk]]
  ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
[[inputs.diskio]]
[[inputs.kernel]]
[[inputs.mem]]
[[inputs.processes]]
[[inputs.swap]]
[[inputs.system]]

Crear un archivo de configuración vacío, ya que se dispone una copia del actual en el archivo telegraf.conf.sample:

root@debian:~# cd /etc/telegraf/
root@debian:/etc/telegraf# ll
total 556
-rw-r--r-- 1 root root 278943 Dec 28 08:36 telegraf.conf
-rw-r--r-- 1 root root 278943 Dec 18 19:53 telegraf.conf.sample
drwxr-xr-x 2 root root   4096 Dec 18 19:53 telegraf.d
root@debian:/etc/telegraf# ll telegraf.d
total 0
root@debian:/etc/telegraf# > telegraf.conf

Editar el nuevo archivo vacío:

root@debian:/etc/telegraf# nano telegraf.conf

Definir una configuración inicial del plugin "tail" que levante todos los logs de Apache (no desde el inicio) y escriba por salida estándar:

[[inputs.tail]]
  ## file(s) to tail:
  files = ["/var/log/apache2/*.log"]
  from_beginning = false

  ## name of the metric:
  name_override = "apache"

  grok_patterns = ["%{COMBINED_LOG_FORMAT}"]
  data_format = "grok"

[[outputs.file]]
  ## Files to write to, "stdout" is a specially handled file.
  files = ["stdout"]

Probar el plugin tail lanzando Telegraf en modo interactivo y con salida estándar:

root@debian:/var/log/apache2# telegraf --config /etc/telegraf/telegraf.conf
2020-12-28T12:31:01Z I! Starting Telegraf 1.17.0
2020-12-28T12:31:01Z I! Loaded inputs: tail
2020-12-28T12:31:01Z I! Loaded aggregators: 
2020-12-28T12:31:01Z I! Loaded processors: 
2020-12-28T12:31:01Z I! Loaded outputs: file
2020-12-28T12:31:01Z I! Tags enabled: host=debian.linuxito.com
2020-12-28T12:31:01Z I! [agent] Config: Interval:10s, Quiet:false, Hostname:"debian.linuxito.com", Flush Interval:10s
apache,host=debian.linuxito.com,path=/var/log/apache2/apache.log,resp_code=200,verb=GET agent="Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",auth="-",http_version=1.1,resp_bytes=6823i,referrer="-",client_ip="181.197.199.132",ident="-",request="/login" 1609158673000000000
apache,host=debian.linuxito.com,path=/var/log/apache2/apache.log,resp_code=200,verb=GET agent="Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",client_ip="181.197.199.132",auth="-",request="/favicon.ico",resp_bytes=1525i,referrer="-",ident="-",http_version=1.1 1609158674000000000
^C2020-12-28T12:31:52Z I! [agent] Hang on, flushing any cached metrics before shutdown

Se observa cómo las entradas son parseadas y generadas correctamente. El siguiente paso consiste definir la conexión con InfluxDB para que estos datos sean cargados en la base de monitoreo (en vez de salida estándar).

Agregar al usuario "telegraf" al grupo "adm" para que pueda leer los logs de Apache:

root@debian:/etc/telegraf# usermod -a -G adm telegraf

Conexión con InfluxDB

Configurar la carga de datos en InfluxDB. En el servidor de monitoreo, crear una base de datos y usuario para Telegraf y dar acceso de lectura a Grafana:

root@influx:~# influx -username admin -password ''
password: 
Connected to http://localhost:8086 version 1.6.4
InfluxDB shell version: 1.6.4
> create database telegraf
> alter retention policy autogen on telegraf duration 365d;
> grant read on "telegraf" to "grafana"
> create user telegraf with password '****'
> grant all privileges on "telegraf" to "telegraf"
> quit

Configuración del plugin tail

Modificar la configuración de Telegraf:

root@debian:/etc/telegraf# nano telegraf.conf
[agent]
  interval = "10s"
  round_interval = true
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  collection_jitter = "0s"
  flush_interval = "10s"
  flush_jitter = "0s"
  precision = "1s"

[[inputs.tail]]
  ## file(s) to tail:
  files = ["/var/log/apache2/*.log"]
  from_beginning = false

  watch_method = "inotify"

  ## name of the metric:
  name_override = "apache2"
  grok_patterns = ["%{COMBINED_LOG_FORMAT}"]
  data_format = "grok"
  grok_custom_pattern_files = []
  grok_custom_patterns = '''
'''

  grok_timezone = 'America/Argentina/Buenos_Aires'

[[outputs.influxdb]]
  ## The full HTTP or UDP endpoint URL for your InfluxDB instance.
  urls = ["http://192.168.56.103:8086"] # required
  ## The target database for metrics (telegraf will create it if not exists).
  database = "telegraf" # required
  ## Credentials
  username = 'telegraf'
  password = '****'
  ## Write timeout (for the InfluxDB client), formatted as a string.
  timeout = "5s"

Es importante aclarar que si el timezone no coincide con el de Apache, grok no será capaz de recolectar las entradas de forma correcta. Las variables grok_custom_pattern_files y grok_custom_patterns deben quedar configurada vacías exactamente como se observan en el ejemplo.

Antes de iniciar Telegraf, es necesario habilitar el acceso a InfluxDB al puerto 8086. Esto se debe a que Telegraf tiene una forma de conectarse a InfluxDB diferente a collectd (se conecta directo a la API rest).

Iniciar Telegraf:

root@debian:/etc/telegraf# service telegraf start

Verificar la carga de datos en InfluxDB:

root@influx:~# influx -username telegraf -password ''
password: 
Connected to http://localhost:8086 version 1.6.4
InfluxDB shell version: 1.6.4
> use telegraf
Using database telegraf
> show measurements
name: measurements
name
----
apache2
> show series
key
---
apache2,host=debian,path=/var/log/apache2/apache.log,resp_code=200,verb=GET
apache2,host=debian,path=/var/log/apache2/apache.log,resp_code=303,verb=GET
apache2,host=debian,path=/var/log/apache2/apache.log,resp_code=404,verb=GET

Los datos se han cargado correctamente y vemos las primeras series y mediciones.

Grafana

Desde Grafana, agregar un nuevo datasource:

Tal como se observa en la salida de prueba para una entrada del log:

apache,host=debian.linuxito.com,path=/var/log/apache2/apache.log,resp_code=200,verb=GET agent="Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0",client_ip="1.2.3.4",auth="-",request="/favicon.ico",resp_bytes=1525i,referrer="-",ident="-",http_version=1.1 1609158674000000000

Se dispone de los siguientes campos (con valores de ejemplo):

agent="Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"
client_ip="1.2.3.4"
auth="-"
request="/favicon.ico"
resp_bytes=1525i
referrer="-"
ident="-"
http_version=1.1

Seleccionando cualquiera de ellos y aplicando la función de agregación count() es posible contabilizar accesos por respuesta:

Si se opta por una tabla, es posible visualizar todas las solicitudes y aplicar filtros con variables a nivel panel:

Luego de pulir bastante los paneles (configurar variables, definir transformaciones "Outer join", crear "Overrides" para el ancho de columnas, etc.) se pueden lograr visualizaciones realmente impresionantes:

Respuestas por código HTTP:

SELECT count("request") FROM "apache2" WHERE ("host" = 'www.linuxito.com' AND "path" = '/var/log/apache2/access.log' AND "resp_code" = '200') AND $timeFilter GROUP BY time($__interval) fill(null)

Entradas en logs por código de respuesta, método y log:

SELECT "request" AS "Request", "client_ip" AS "IP", "resp_bytes" AS "Bytes", "referrer" AS "Referrer", "http_version" AS "HTTP", "agent" AS "User-Agent" FROM "apache2" WHERE ("host" = 'www.linuxito.com' AND "path" =~ /^$logfile$/ AND "resp_code" =~ /^$code$/ AND "verb" =~ /^$method$/) AND $timeFilter

La parte superior de esta gráfica aglomera las solicitudes en el período seleccionado y computa el tamaño promedio, máximo para el 99% de las solicitudes y máximo. En la parte inferior se muestran las entradas en el log seleccionado por código de respuesta y método HTTP. Estas variables permiten seleccionar todos los códigos de respuesta y todos los métodos utilizando la opción "All".

El ícono de embudo a la derecha de cada cabecera de la tabla permite aplicar filtros en cada campo. Esta opción es de gran utilidad para hacer un seguimiento de requisitos por IP, recurso, código de error, etc. Lo único que le faltaría para ser perfecto sería la posibilidad de aplicar expresiones regulares en los filtros.

Referencias

Compartí este artículo