> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> Cómo seguir un archivo de logs y enviarlo a ClickHouse con Vector

# Integración de Vector con ClickHouse

export const PartnerBadge = () => {
  return <div className="PartnerBadge">
            <div className="PartnerBadgeIcon">
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <polyline points="12.5 9.5 10 12 6 11 2.5 8.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1" />
                    <polyline points="4.54 4.41 8 3.5 11.46 4.41" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1" />
                    <path d="M2.15,3.78 L0.55,6.95 A0.5,0.5 0,0,0 0.77,7.62 L2.5,8.5 L4.54,4.41 L2.82,3.55 A0.5,0.5 0,0,0 2.15,3.78 Z" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1" />
                    <path d="M13.5,8.5 L15.23,7.62 A0.5,0.5 0,0,0 15.45,6.95 L13.85,3.78 A0.5,0.5 0,0,0 13.18,3.55 L11.46,4.41 Z" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1" />
                    <path d="M11.5,4.5 L9,4.5 L6.15,7.27 A0.5,0.5 0,0,0 6.24,8.05 C7.33,8.74 8.81,8.72 10,7.5 L12.5,9.5 L13.5,8.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1" />
                    <polyline points="7.75 13.5 5.15 12.85 3.5 11.67" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1" />
                </svg>
            </div>
            Integración de partner
        </div>;
};

export const Image = ({img, alt, size = "lg"}) => {
  const normalizedSize = ["sm", "md", "lg"].includes(size) ? size : "lg";
  return <div className={`ch-image-${normalizedSize}`}>
      <Frame>
        <img src={img} alt={alt} />
      </Frame>
    </div>;
};

<PartnerBadge />

Poder analizar los logs en tiempo real es fundamental para las aplicaciones en producción.
ClickHouse destaca en el almacenamiento y análisis de logs gracias a su excelente compresión (hasta [170x](https://clickhouse.com/blog/log-compression-170x) para logs)
y a su capacidad para agregar rápidamente grandes volúmenes de datos.

Esta guía te muestra cómo usar el popular pipeline de datos [Vector](https://vector.dev/docs/introduction/) para seguir un archivo de logs de Nginx y enviarlo a ClickHouse.
Los pasos siguientes son similares para seguir cualquier tipo de archivo de logs.

**Requisitos previos:**

* Ya tienes ClickHouse en funcionamiento
* Tienes Vector instalado

<Steps>
  <Step title="Crear una base de datos y una tabla" id="1-create-a-database-and-table">
    Defina una tabla para almacenar los eventos de log:

    1. Comience con una nueva base de datos llamada `nginxdb`:

    ```sql theme={null}
    CREATE DATABASE IF NOT EXISTS nginxdb
    ```

    2. Inserte todo el evento de log como una sola cadena. Obviamente, este no es un buen formato para realizar análisis sobre los datos de log, pero resolveremos esa parte más abajo usando ***vistas materializadas***.

    ```sql theme={null}
    CREATE TABLE IF NOT EXISTS  nginxdb.access_logs (
      message String
    )
    ENGINE = MergeTree()
    ORDER BY tuple()
    ```

    <Note>
      **ORDER BY** se establece en **tuple()** (una tupla vacía), ya que todavía no se necesita una clave primaria.
    </Note>
  </Step>

  <Step title="Configurar Nginx" id="2--configure-nginx">
    En este paso, se muestra cómo configurar el registro de Nginx.

    1. La siguiente propiedad `access_log` envía los logs a `/var/log/nginx/my_access.log` en formato **combined**.
       Este valor va en la sección `http` de su archivo `nginx.conf`:

    ```bash theme={null}
    http {
      include       /etc/nginx/mime.types;
      default_type  application/octet-stream;
      access_log  /var/log/nginx/my_access.log combined;
      sendfile        on;
      keepalive_timeout  65;
      include /etc/nginx/conf.d/*.conf;
    }
    ```

    2. Asegúrate de reiniciar Nginx si tuviste que modificar `nginx.conf`.

    3. Genera algunos eventos en el log de acceso visitando páginas de tu servidor web.
       Los logs en formato **combined** se ven así:

    ```bash theme={null}
    192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
    192.168.208.1 - - [12/Oct/2021:03:31:44 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "http://localhost/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
    192.168.208.1 - - [12/Oct/2021:03:31:49 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
    ```
  </Step>

  <Step title="Configurar Vector" id="3-configure-vector">
    Vector recopila, transforma y enruta logs, métricas y trazas (denominados **fuentes**) a muchos proveedores distintos (denominados **destinos**), incluida la compatibilidad nativa con ClickHouse.
    Las fuentes y los destinos se definen en un archivo de configuración llamado **vector.toml**.

    1. El siguiente archivo **vector.toml** define una **fuente** de tipo **file** que sigue las nuevas entradas al final de **my\_access.log**, y también define un **destino** como la tabla **access\_logs** definida anteriormente:

    ```bash theme={null}
    [sources.nginx_logs]
    type = "file"
    include = [ "/var/log/nginx/my_access.log" ]
    read_from = "end"

    [sinks.clickhouse]
    type = "clickhouse"
    inputs = ["nginx_logs"]
    endpoint = "http://clickhouse-server:8123"
    database = "nginxdb"
    table = "access_logs"
    skip_unknown_fields = true
    ```

    2. Inicie Vector con la configuración anterior. Consulte la [documentación](https://vector.dev/docs/) de Vector para obtener más información sobre cómo definir fuentes y destinos.

    3. Verifique que los logs de acceso se estén insertando en ClickHouse ejecutando la siguiente consulta. Debería ver los logs de acceso en la tabla:

    ```sql theme={null}
    SELECT * FROM nginxdb.access_logs
    ```

    <Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/vector_01.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=17d0b62d95271cb39b27558a8391172a" size="lg" border alt="Ver los logs de ClickHouse en formato tabular" width="2364" height="776" data-path="images/integrations/data-ingestion/etl-tools/vector_01.webp" />
  </Step>

  <Step title="Procesar los logs" id="4-parse-the-logs">
    Tener los logs en ClickHouse es muy útil, pero almacenar cada evento como una cadena de texto única no permite realizar un análisis de datos exhaustivo.
    A continuación, veremos cómo parsear los eventos de log mediante una [vista materializada](/docs/es/concepts/features/materialized-views/incremental-materialized-view).

    Una **vista materializada** funciona de manera similar a un insert trigger en SQL. Cuando se insertan filas de datos en una tabla de origen, la vista materializada aplica alguna transformación a esas filas e inserta los resultados en una tabla de destino.
    La vista materializada puede configurarse para generar una representación analizada de los eventos de log en **access\_logs**.
    A continuación se muestra un ejemplo de uno de estos eventos de log:

    ```bash theme={null}
    192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"
    ```

    ClickHouse dispone de diversas funciones para analizar la cadena anterior. La función [`splitByWhitespace`](/docs/es/reference/functions/regular-functions/splitting-merging-functions#splitByWhitespace) divide una cadena por espacios en blanco y devuelve cada token en un array.
    Para demostrarlo, ejecute el siguiente comando:

    ```sql title="Query" theme={null}
    SELECT splitByWhitespace('192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')
    ```

    ```text title="Response" theme={null}
    ["192.168.208.1","-","-","[12/Oct/2021:15:32:43","+0000]","\"GET","/","HTTP/1.1\"","304","0","\"-\"","\"Mozilla/5.0","(Macintosh;","Intel","Mac","OS","X","10_15_7)","AppleWebKit/537.36","(KHTML,","like","Gecko)","Chrome/93.0.4577.63","Safari/537.36\""]
    ```

    Algunas de las cadenas tienen caracteres adicionales y el user agent (los detalles del navegador) no necesitaba procesarse, pero
    el array resultante es cercano a lo que se necesita.

    Al igual que `splitByWhitespace`, la función [`splitByRegexp`](/docs/es/reference/functions/regular-functions/splitting-merging-functions#splitByRegexp) divide una cadena en un array basándose en una expresión regular.
    Ejecute el siguiente comando, que devuelve dos cadenas.

    ```sql theme={null}
    SELECT splitByRegexp('\S \d+ "([^"]*)"', '192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36"')
    ```

    Observe que la segunda cadena devuelta es el user agent extraído correctamente del registro:

    ```text theme={null}
    ["192.168.208.1 - - [12/Oct/2021:15:32:43 +0000] \"GET / HTTP/1.1\" 30"," \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36\""]
    ```

    Antes de ver el comando final `CREATE MATERIALIZED VIEW`, revisemos un par de funciones adicionales que se utilizan para limpiar los datos.
    Por ejemplo, el valor de `RequestMethod` es `"GET`, que contiene una comilla doble no deseada.
    Puede usar la función [`trimBoth` (alias `trim`)](/docs/es/reference/functions/regular-functions/string-functions#trimBoth) para eliminar la comilla doble:

    ```sql theme={null}
    SELECT trim(LEADING '"' FROM '"GET')
    ```

    La cadena de tiempo comienza con un `[` y, además, no tiene un formato que ClickHouse pueda interpretar como fecha.
    Sin embargo, si cambiamos el separador de dos puntos (**:**) por una coma (**,**), el análisis funciona perfectamente:

    ```sql theme={null}
    SELECT parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM '[12/Oct/2021:15:32:43'), ':', ' '))
    ```

    Ya estamos listos para definir la vista materializada.
    La definición a continuación incluye `POPULATE`, lo que significa que las filas existentes en **access\_logs** se procesarán e insertarán de inmediato.
    Ejecute la siguiente sentencia SQL:

    ```sql theme={null}
    CREATE MATERIALIZED VIEW nginxdb.access_logs_view
    (
      RemoteAddr String,
      Client String,
      RemoteUser String,
      TimeLocal DateTime,
      RequestMethod String,
      Request String,
      HttpVersion String,
      Status Int32,
      BytesSent Int64,
      UserAgent String
    )
    ENGINE = MergeTree()
    ORDER BY RemoteAddr
    POPULATE AS
    WITH
      splitByWhitespace(message) as split,
      splitByRegexp('\S \d+ "([^"]*)"', message) as referer
    SELECT
      split[1] AS RemoteAddr,
      split[2] AS Client,
      split[3] AS RemoteUser,
      parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM split[4]), ':', ' ')) AS TimeLocal,
      trim(LEADING '"' FROM split[6]) AS RequestMethod,
      split[7] AS Request,
      trim(TRAILING '"' FROM split[8]) AS HttpVersion,
      split[9] AS Status,
      split[10] AS BytesSent,
      trim(BOTH '"' from referer[2]) AS UserAgent
    FROM
      (SELECT message FROM nginxdb.access_logs)
    ```

    Ahora verifique que funcionó.
    Debería ver los registros de acceso correctamente parseados en columnas:

    ```sql theme={null}
    SELECT * FROM nginxdb.access_logs_view
    ```

    <Image img="https://mintcdn.com/private-7c7dfe99/pIetLsS_hOGHqoPJ/images/integrations/data-ingestion/etl-tools/vector_02.webp?fit=max&auto=format&n=pIetLsS_hOGHqoPJ&q=85&s=975c0592f270bafe012c4fdbae48fb49" size="lg" border alt="Ver los logs de ClickHouse analizados en formato de tabla" width="2824" height="1180" data-path="images/integrations/data-ingestion/etl-tools/vector_02.webp" />

    <Note>
      La lección anterior almacenó los datos en dos tablas, pero podrías cambiar la tabla inicial `nginxdb.access_logs` para que use el motor de tabla [`Null`](/docs/es/reference/engines/table-engines/special/null).
      Los datos analizados seguirán llegando a la tabla `nginxdb.access_logs_view`, pero los datos sin procesar no se almacenarán en ninguna tabla.
    </Note>
  </Step>
</Steps>

> Al usar Vector, que solo requiere una instalación sencilla y una configuración rápida, puedes enviar logs desde un servidor Nginx a una tabla de ClickHouse. Al usar una vista materializada, puedes desglosar esos logs en columnas para facilitar el análisis.
