Vector es un agente de observabilidad escrito en Rust que recoge logs y métricas, los transforma y los envía a uno o varios destinos con un consumo de recursos muy bajo. Su configuración se organiza en fuentes (sources), transformaciones (transforms) y destinos (sinks), y las transformaciones se escriben en VRL (Vector Remap Language). En este tutorial instalarás Vector en Ubuntu 24.04, leerás los logs de acceso de Nginx, los convertirás en eventos estructurados, descartarás el ruido y los enviarás a Grafana Loki.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Vector funciona con 512 MB de RAM libres para cargas moderadas.
- Un usuario no root con privilegios
sudo. - Nginx instalado y sirviendo tráfico, que será la fuente de logs del ejemplo. Si no lo tienes, instálalo con
sudo apt install nginx. - Opcional para el paso 6: un servidor Grafana Loki accesible desde este servidor. Si todavía no tienes uno, puedes completar los pasos 1 a 5 enviando los eventos a la consola.
Paso 1: Instalar Vector desde su repositorio oficial
Vector publica paquetes .deb en un repositorio APT mantenido por Datadog. La forma soportada de configurarlo es un script que añade las claves GPG y el archivo de origen de APT. Descárgalo y revísalo antes de ejecutarlo:
curl -fsSL -o setup-vector.sh https://setup.vector.dev
less setup-vector.sh
El script crea /etc/apt/sources.list.d/vector.list apuntando a https://apt.vector.dev/ y guarda las claves en /usr/share/keyrings/datadog-archive-keyring.gpg. Ejecútalo (pedirá sudo cuando lo necesite) e instala el paquete:
bash setup-vector.sh
sudo apt install -y vector
Comprueba la versión instalada:
vector --version
vector 0.50.0 (x86_64-unknown-linux-gnu)
El número de versión será el más reciente disponible cuando hagas la instalación. El paquete crea el usuario de sistema vector, lo añade a los grupos adm y systemd-journal para que pueda leer /var/log y el journal, e instala la unidad vector.service, que lee la configuración de /etc/vector/vector.yaml.
Paso 2: Entender la configuración de ejemplo
El paquete incluye un vector.yaml de demostración que genera logs de prueba en formato syslog, los analiza y los imprime. Guárdalo como referencia antes de sustituirlo:
sudo mv /etc/vector/vector.yaml /etc/vector/vector.yaml.example
Toda configuración de Vector tiene la misma forma:
sources: de dónde vienen los eventos (archivos, journald, syslog, Docker, Kafka, HTTP).transforms: qué se hace con ellos (analizar, filtrar, enriquecer, muestrear). Cada transformación declara eninputsde qué componentes recibe eventos.sinks: a dónde se envían (Loki, Elasticsearch, S3, la consola). También declaran susinputs.
Cada componente tiene un identificador que eliges tú, y los inputs enlazan unos con otros para formar la topología.
Paso 3: Leer y analizar los logs de Nginx
Crea la nueva configuración con una fuente que lee el log de acceso de Nginx, una transformación que lo analiza y un destino de consola para comprobar el resultado:
sudo nano /etc/vector/vector.yaml
api:
enabled: true
address: "127.0.0.1:8686"
sources:
nginx_access:
type: file
include:
- /var/log/nginx/access.log
read_from: end
transforms:
parse_nginx:
type: remap
inputs:
- nginx_access
source: |
parsed, err = parse_nginx_log(.message, "combined")
if err != null {
abort
}
. = merge(., parsed)
del(.message)
sinks:
console:
type: console
inputs:
- parse_nginx
encoding:
codec: json
Qué hace cada bloque:
apiactiva la API local de Vector en127.0.0.1:8686, que usan las herramientasvector topyvector tap. Solo escucha en localhost.- La fuente
filesigueaccess.logy guarda su posición en/var/lib/vector, así que tras un reinicio continúa donde se quedó. Conread_from: endignora las líneas anteriores al primer arranque. - La transformación
remapejecuta VRL.parse_nginx_logcon el formatocombined(el predeterminado de Nginx) devuelve campos comoclient,method,path,status,size,refereryagent. Si una línea no encaja, el evento se descarta conabort. VRL obliga a tratar ese posible error: por eso la función se llama con la formaparsed, err = ...en lugar de ignorarlo.
Valida la configuración antes de aplicarla. vector validate comprueba la sintaxis, los tipos de VRL y que los componentes estén bien enlazados:
sudo -u vector vector validate /etc/vector/vector.yaml
√ Loaded ["/etc/vector/vector.yaml"]
√ Component configuration
√ Health check "console"
------------------------------------
Validated
Ejecutarlo como el usuario vector confirma además que ese usuario puede leer los archivos. Reinicia el servicio:
sudo systemctl restart vector
sudo systemctl status vector --no-pager
● vector.service - Vector
Loaded: loaded (/usr/lib/systemd/system/vector.service; enabled; preset: enabled)
Active: active (running) since ...
Paso 4: Comprobar los eventos procesados
Genera algo de tráfico contra Nginx:
curl -s -o /dev/null http://localhost/
curl -s -o /dev/null http://localhost/no-existe
El destino console escribe en la salida estándar, que systemd guarda en el journal. Mira los últimos eventos:
sudo journalctl -u vector -n 2 --no-pager -o cat
{"agent":"curl/8.5.0","client":"127.0.0.1","file":"/var/log/nginx/access.log","host":"your_hostname","method":"GET","path":"/","protocol":"HTTP/1.1","size":615,"source_type":"file","status":200,"timestamp":"2026-09-25T10:12:03Z"}
{"agent":"curl/8.5.0","client":"127.0.0.1","file":"/var/log/nginx/access.log","host":"your_hostname","method":"GET","path":"/no-existe","protocol":"HTTP/1.1","size":162,"source_type":"file","status":404,"timestamp":"2026-09-25T10:12:04Z"}
La línea de texto de Nginx se ha convertido en un objeto con tipos: status y size son números, y timestamp es la hora de la petición, no la de lectura.
Para inspeccionar el flujo en directo sin tocar la configuración, usa vector tap, que se conecta a la API y muestra los eventos que salen de un componente:
vector tap parse_nginx
Y para ver el rendimiento de cada componente (eventos por segundo, errores), vector top. Sal de ambos con Ctrl+C o q.
Paso 5: Filtrar el ruido y añadir campos
Los health checks y las peticiones de monitorización suelen ser la mayoría de las líneas y no aportan nada. Añade una transformación filter que los descarte y otra remap que clasifique cada petición por su código de estado. Edita el archivo:
sudo nano /etc/vector/vector.yaml
Sustituye la sección transforms y cambia el inputs del destino console para que reciba eventos de la última transformación:
transforms:
parse_nginx:
type: remap
inputs:
- nginx_access
source: |
parsed, err = parse_nginx_log(.message, "combined")
if err != null {
abort
}
. = merge(., parsed)
del(.message)
drop_healthchecks:
type: filter
inputs:
- parse_nginx
condition: '!includes(["/health", "/healthz", "/favicon.ico"], .path)'
classify:
type: remap
inputs:
- drop_healthchecks
source: |
status = to_int(.status) ?? 0
.level = if status >= 500 {
"error"
} else if status >= 400 {
"warning"
} else {
"info"
}
sinks:
console:
type: console
inputs:
- classify
encoding:
codec: json
filter deja pasar solo los eventos cuya condición VRL es verdadera. En classify, el operador ?? da un valor por defecto si la conversión falla, algo que VRL exige para compilar: no permite ignorar errores posibles.
Valida y recarga. La unidad de systemd ejecuta vector validate y envía SIGHUP, por lo que la configuración se aplica sin perder eventos:
sudo -u vector vector validate /etc/vector/vector.yaml
sudo systemctl reload vector
Repite las peticiones del paso 4 y añade una a /health. En el journal verás los dos primeros eventos con el campo level (info y warning) y ninguno para /health.
Paso 6: Enviar los logs a Grafana Loki
Cuando el pipeline produce los eventos que quieres, añade un destino real. Sustituye your_loki_host por la dirección de tu servidor Loki y añade este bloque dentro de sinks:
loki:
type: loki
inputs:
- classify
endpoint: http://your_loki_host:3100
encoding:
codec: json
labels:
job: nginx
host: "{{ host }}"
level: "{{ level }}"
Usa como etiquetas de Loki solo campos con pocos valores distintos (job, host, level). Campos como path o client tienen miles de valores y degradan Loki; déjalos dentro de la línea JSON, donde puedes filtrarlos con LogQL.
Antes de recargar, comprueba que Loki responde desde este servidor:
curl http://your_loki_host:3100/ready
ready
Valida y recarga Vector:
sudo -u vector vector validate /etc/vector/vector.yaml
sudo systemctl reload vector
vector validate ejecuta también el health check del destino de Loki, así que un error de conexión aparecerá aquí. Cuando todo funcione, puedes quitar el destino console para no llenar el journal. En Grafana, una consulta como {job="nginx", level="error"} mostrará las respuestas 5xx.
Consejosi Loki está en otra red, envía los logs por la red privada o pon Loki tras un proxy con TLS y autenticación. El destino
lokiadmiteauthconstrategy: basicpara ese caso.
Solución de problemas
Permission denied al leer /var/log/nginx/access.log. El usuario vector debe pertenecer al grupo adm. Compruébalo con id vector; si falta, ejecuta sudo usermod -aG adm vector y reinicia el servicio (una recarga no aplica cambios de grupo).
El servicio no arranca tras un cambio. La unidad ejecuta vector validate antes de iniciar, y si falla no arranca. Lee el motivo con sudo journalctl -u vector -n 50 --no-pager; los errores de VRL señalan la línea exacta del programa y el motivo.
No llega nada al destino. Usa vector tap parse_nginx y luego vector tap classify para ver en qué componente desaparecen los eventos. Si vector tap no conecta, revisa que la sección api esté activada.
Eventos perdidos cuando Loki no está disponible. Por defecto, cada destino usa un búfer en memoria de 500 eventos. Para cortes largos, configura en el destino un búfer en disco con buffer.type: disk y buffer.max_size en bytes.
Conclusión
Tienes Vector en Ubuntu 24.04 leyendo los logs de acceso de Nginx, convirtiéndolos en eventos estructurados con VRL, descartando el ruido y enviándolos a Grafana Loki, con validación antes de cada recarga. Como siguientes pasos puedes añadir una fuente journald para los logs de systemd, generar métricas a partir de los logs con la transformación log_to_metric o archivar una copia comprimida en un bucket S3 compatible con el destino aws_s3.
