0Pricing
Linux Command Line & Bash Scripting Mastery · Lección

Análisis de registros web y de aplicaciones a gran escala

Extraiga códigos de estado, latencias y campos de cliente de registros de acceso mediante grep, cut y awk.

Análisis de registros web y de aplicaciones a gran escala es una lección gratuita de Linux Command Line & Bash Scripting Mastery en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Linux Command Line & Bash Scripting Mastery, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Linux Command Line & Bash Scripting Mastery incluye 4 lecciones en total.

¿Qué es un registro de acceso web?

Cada servidor HTTP —Apache, Nginx, Caddy— escribe una línea en un registro de acceso por cada solicitud. Comprender la estructura de estas líneas es la base de todo el trabajo de análisis de registros.

Una línea típica del formato de registro combinado (CLF) tiene este aspecto:

  • IP del cliente — quién realizó la solicitud
  • Marca de tiempo — cuándo ocurrió
  • Línea de solicitud — método, ruta y protocolo
  • Código de estado — respuesta HTTP (200, 404, 500…)
  • Bytes enviados — tamaño del cuerpo de la respuesta
  • Referer — página de origen
  • User-Agent — cadena del navegador o bot

Línea de ejemplo de /var/log/nginx/access.log:

192.168.1.10 - alice [11/Jun/2026:14:32:01 +0000] "GET /api/orders HTTP/1.1" 200 1482 "-" "curl/7.88.1"

A gran escala, estos archivos llegan a crecer hasta contener millones de líneas al día. El objetivo de esta lección es extraer, filtrar y agregar campos de forma eficiente mediante herramientas BASH estándar.

Muestreo de un registro activo con tail y grep

Antes de escribir una canalización, inspeccione el registro para comprender su estructura. tail permite observar un flujo en directo; grep lo reduce inmediatamente a las líneas relevantes.

Patrones habituales:

  • tail -n 1000 access.log — últimas 1000 líneas
  • tail -f access.log — seguir en tiempo real
  • tail -f access.log | grep '" 5' — solo errores 5xx a medida que llegan

La idea clave es que grep busca coincidencias en la línea completa, por lo que es importante anclar el patrón. Buscar ' 500 ' (con espacios) evita hacer coincidir accidentalmente una ruta URL que contenga la cadena 500.

#!/usr/bin/env bash
# Watch only HTTP 5xx errors arriving in real time
tail -f /var/log/nginx/access.log \
  | grep --line-buffered '" 5[0-9][0-9] '

Extracción del código de estado con cut

cut divide cada línea usando un delimitador e imprime los campos seleccionados. En el formato de registro combinado, el código de estado se encuentra en el campo 9 al dividir por espacios, pero las comillas de la línea de solicitud hacen que sea más seguro contar desde un elemento de referencia conocido.

Un truco fiable: como la línea de solicitud siempre está entre comillas, el código de estado siempre es el primer token después de las comillas de cierre del campo de solicitud. Usar cut -d'"' -f3 aísla todo lo que aparece después de las comillas de la solicitud; después, un segundo cut -d' ' -f2 selecciona el código de estado.

Este cut en dos etapas es un modismo clásico para los registros CLF: es rápido y no requiere dependencias externas.

#!/usr/bin/env bash
# Print only the HTTP status code from each log line
# Input format: ... "GET /path HTTP/1.1" 200 1482 ...
cut -d'"' -f3 /var/log/nginx/access.log \
  | cut -d' ' -f2 \
  | sort \
  | uniq -c \
  | sort -rn

Recuento de códigos de estado con awk

awk es más potente que cut porque puede acumular información entre líneas. El patrón idiomático para contar apariciones consiste en usar un array asociativo indexado por el valor que le interesa.

En CLF, el campo $9 (indexado desde 1 y delimitado por espacios) contiene el código de estado. awk procesa cada línea, incrementa un contador y después imprime un resumen ordenado en el bloque END.

¿Por qué preferir awk a cut | sort | uniq -c? Porque awk lo hace en una sola pasada sin ordenar primero todo el archivo, algo fundamental cuando el registro ocupa cientos de gigabytes.

#!/usr/bin/env bash
# Count HTTP status codes in a single awk pass
awk '{ count[$9]++ }
END {
  for (status in count)
    printf "%6d  %s\n", count[status], status
}' /var/log/nginx/access.log \
  | sort -rn

Filtrado de errores y extracción de IP de clientes

Una de las tareas operativas más habituales es averiguar qué IP de clientes generan más errores. Esto combina el filtrado (solo líneas de error) con la extracción de campos (la IP del campo 1).

La estrategia de la canalización:

  • Use awk para filtrar por el rango de códigos de estado y extraer la IP en un solo paso; evite una pasada independiente con grep
  • Conecte la salida a sort | uniq -c | sort -rn | head para obtener rápidamente una vista de los primeros resultados

Este patrón es suficientemente rápido para ejecutarse en un archivo de registro de 10 GB en un único servidor sin cargarlo en memoria.

#!/usr/bin/env bash
# Top 10 IPs generating HTTP 4xx or 5xx errors
awk '$9 ~ /^[45][0-9][0-9]$/ { print $1 }' \
    /var/log/nginx/access.log \
  | sort \
  | uniq -c \
  | sort -rn \
  | head -10

Análisis de la latencia de respuesta en registros de aplicaciones

Los servidores de aplicaciones (Rails, Gunicorn, Express con morgan, etc.) suelen registrar la duración de las solicitudes. Nginx puede configurarse para emitir $request_time como un campo adicional al final de cada línea.

Ejemplo de un formato de registro personalizado de Nginx en nginx.conf:

log_format timed '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" rt=$request_time';

Una vez que la latencia está en el registro, puede usar awk para calcular el promedio, el máximo y aproximaciones de percentiles en millones de solicitudes sin cargar los datos en una base de datos.

#!/usr/bin/env bash
# Compute average and max request_time from Nginx timed log
# Assumes last field is rt=<seconds> e.g. rt=0.042
awk '{
  # Extract numeric value after rt=
  n = split($NF, a, "=")
  if (n == 2 && a[1] == "rt") {
    t = a[2] + 0
    sum += t
    count++
    if (t > max) max = t
  }
}
END {
  if (count > 0)
    printf "Requests: %d  Avg: %.4fs  Max: %.4fs\n", count, sum/count, max
}' /var/log/nginx/timed_access.log

Creación de un histograma de latencia con awk

Un único promedio oculta la latencia de cola. Un histograma muestra la distribución: si la mayoría de las solicitudes son rápidas y unas pocas muy lentas (cola larga), o si la distribución es uniforme.

El truco consiste en agrupar cada valor en un intervalo redondeado mediante aritmética de enteros dentro de awk. Multiplicar por 1000 (para convertir los segundos en milisegundos) y aplicar después una división entera produce límites de intervalo claros.

Esto genera un histograma de texto que puede leer directamente en un terminal y que, a menudo, resulta más rápido que enviar los datos a Grafana para una investigación rápida.

#!/usr/bin/env bash
# Latency histogram (50ms buckets) from Nginx timed log
awk '{
  n = split($NF, a, "=")
  if (n == 2 && a[1] == "rt") {
    ms = int(a[2] * 1000)      # convert to ms
    bucket = int(ms / 50) * 50 # round down to 50ms boundary
    hist[bucket]++
  }
}
END {
  for (b in hist)
    printf "%6dms  %d\n", b, hist[b]
}' /var/log/nginx/timed_access.log \
  | sort -n

Extracción de User-Agent y detección de bots

El campo User-Agent (campo 6 al dividir por ") identifica a los clientes. Los rastreadores, scrapers y bots maliciosos suelen contaminar las métricas e inflar los recuentos de errores. Filtrarlos ofrece una imagen más limpia del tráfico de usuarios reales.

Firmas habituales de bots: bot, crawler, spider, curl, python-requests, Googlebot, Bingbot.

Use grep -iv (inversión sin distinguir mayúsculas de minúsculas) para excluir bots conocidos, o use awk para dividir por " y hacer coincidir directamente el campo UA.

#!/usr/bin/env bash
# Count top 15 User-Agent strings, excluding known bots
awk -F'"' '{ print $6 }' /var/log/nginx/access.log \
  | grep -iv -e 'bot' -e 'crawler' -e 'spider' -e 'curl' \
              -e 'python' -e 'wget' -e 'Go-http-client' \
  | sort \
  | uniq -c \
  | sort -rn \
  | head -15

Agregación del tráfico por endpoint

Saber qué endpoints reciben más tráfico —y generan más errores— ayuda a priorizar la optimización y la planificación de capacidad. La ruta de la solicitud se encuentra dentro del campo de solicitud entre comillas.

Divida por ", tome el campo 2 (la línea de solicitud) y, después, elimine el método y el protocolo para aislar la ruta. En las API con parámetros de ruta como /users/12345, también puede querer normalizar los identificadores a /users/:id mediante sed o un patrón de awk más complejo.

#!/usr/bin/env bash
# Top 20 requested endpoints (method + path, no query string)
awk -F'"' '{ print $2 }' /var/log/nginx/access.log \
  | awk '{ print $1, $2 }' \
  | sed 's|/[0-9][0-9]*\b|/:id|g' \
  | sort \
  | uniq -c \
  | sort -rn \
  | head -20

Correlación de errores con endpoints mediante awk

El análisis de una sola pasada más potente combina varios campos a la vez: endpoint, código de estado y, opcionalmente, latencia. Los arrays asociativos de awk indexados por valores compuestos hacen que este proceso sea claro y rápido.

El patrón siguiente cuenta los errores 5xx por endpoint en una sola pasada: no utiliza archivos temporales ni ordenaciones intermedias hasta el final. Este es el enfoque utilizado en scripts de observabilidad en producción cuando se necesitan respuestas en menos de un minuto a partir de un registro grande.

#!/usr/bin/env bash
# Count 5xx errors per endpoint path in a single pass
awk -F'"' '{
  # $2 = request line e.g. "GET /api/orders HTTP/1.1"
  # $0 in original space-split: $9 = status
  split($0, fields, " ")
  status = fields[9]
  if (status ~ /^5/) {
    split($2, req, " ")
    path = req[2]
    # Normalise numeric IDs
    gsub(/\/[0-9]+/, "/:id", path)
    errors[path]++
  }
}
END {
  for (p in errors)
    printf "%6d  %s\n", errors[p], p
}' /var/log/nginx/access.log \
  | sort -rn \
  | head -20

Procesamiento de registros rotados y comprimidos

En la mayoría de los servidores, los registros se rotan a diario. Los archivos antiguos se comprimen con gzip como access.log.1.gz, access.log.2.gz, etc. Las herramientas estándar no pueden leerlos directamente, pero hay dos enfoques que funcionan correctamente:

  • zcat — descomprime en la salida estándar y conecta el resultado a la canalización
  • zgrep — ejecuta grep directamente dentro de los archivos gzip sin extraerlos

Para analizar una semana completa de registros que incluya archivos sin comprimir y comprimidos, use la sustitución de procesos o concatene con zcat. El fragmento siguiente procesa los últimos 7 archivos rotados y el registro activo actual en una sola invocación de awk, sin necesidad de archivos temporales.

#!/usr/bin/env bash
# Aggregate status codes across a week of rotated logs
# Handles both plain and gzip-compressed rotation files

LOG_DIR="/var/log/nginx"

{
  cat  "${LOG_DIR}/access.log" 2>/dev/null
  zcat "${LOG_DIR}/access.log".*.gz 2>/dev/null
} | awk '
{ count[$9]++ }
END {
  for (s in count)
    printf "%6d  %s\n", count[s], s
}' | sort -rn

¿Qué campo de awk contiene el código de estado HTTP en el formato de registro combinado?

Está escribiendo una línea de awk para filtrar únicamente las respuestas HTTP 4xx de un registro de acceso estándar de Nginx en Combined Log Format (delimitado por espacios y con la línea de solicitud entre comillas). ¿Qué número de campo identifica correctamente el código de estado HTTP?

Resumen de la lección: canalizaciones de análisis de registros

En esta lección ha creado un kit de herramientas completo para analizar registros web y de aplicaciones a gran escala utilizando únicamente utilidades estándar de BASH.

Técnicas principales:

  • La estructura es lo primero — Combined Log Format tiene una disposición de campos predecible; conocerla le permite dividir los datos de forma fiable con cut -d'"' o referencias a campos de awk.
  • Extracción del código de estado — awk '{ count[$9]++ }' cuenta todos los códigos en una sola pasada; utilice $9 ~ /^5/ para filtrar los errores del servidor.
  • Análisis de latencia — analice el campo personalizado rt= con awk para calcular promedios, máximos e intervalos de histogramas sin ninguna herramienta externa.
  • Análisis de clientes y bots — divida por " con -F'"' para acceder al campo User-Agent; use una tubería con grep -iv para excluir los bots antes de realizar la agregación.
  • Normalización de endpoints — utilice gsub(/\/[0-9]+/, "/:id") dentro de awk para agrupar las rutas parametrizadas antes de contarlas.
  • Registros rotados — combine cat y zcat en un subshell para enviar todos los archivos de rotación a una sola pasada de la canalización.

Estos patrones se pueden combinar: puede encadenar el filtrado, la extracción, la normalización y la agregación en una sola canalización que procese cientos de millones de líneas en hardware convencional. Si domina estas primitivas, rara vez necesitará un servicio específico de agregación de registros para investigar incidentes puntuales.

Preguntas frecuentes

¿La lección «Análisis de registros web y de aplicaciones a gran escala» es gratis?

Sí — el texto completo de «Análisis de registros web y de aplicaciones a gran escala» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Linux Command Line & Bash Scripting Mastery, actualiza a CoddyKit PRO. El curso de Linux Command Line & Bash Scripting Mastery incluye 4 lecciones en total.

¿Qué aprenderé en «Análisis de registros web y de aplicaciones a gran escala»?

Extraiga códigos de estado, latencias y campos de cliente de registros de acceso mediante grep, cut y awk. Practicas Linux Command Line & Bash Scripting Mastery con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Linux Command Line & Bash Scripting Mastery?

No se requiere experiencia previa. Linux Command Line & Bash Scripting Mastery en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «Análisis de registros web y de aplicaciones a gran escala»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Linux Command Line & Bash Scripting Mastery?

Sí. Cada lección de Linux Command Line & Bash Scripting Mastery incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Análisis de registros web y de aplicaciones a gran escala
  2. Seguimiento de registros en tiempo real y alertas en streaming
  3. Consulta de journald con journalctl en scripts
  4. Cálculo de métricas e histogramas a partir de flujos de registros
← Volver a Linux Command Line & Bash Scripting Mastery