Возможность анализировать журналы в реальном времени критически важна для приложений в продакшне. ClickHouse отлично подходит для хранения и анализа данных журналов благодаря превосходному сжатию (до 170x для журналов) и способности быстро агрегировать большие объёмы данных.
В этом руководстве показано, как использовать популярный конвейер данных Vector для отслеживания файла журнала Nginx и отправки данных в ClickHouse. Приведённые ниже шаги аналогичны для отслеживания любого файла журнала.
Предварительные требования:
- У вас уже есть работающий ClickHouse
- У вас установлен Vector
Создайте базу данных и таблицу
Создайте таблицу для хранения событий журнала:
- Начните с создания новой базы данных
nginxdb:
CREATE DATABASE IF NOT EXISTS nginxdb- Вставьте всё событие лога как одну строку. Очевидно, это не лучший формат для анализа логов, но ниже мы решим эту проблему с помощью materialized views.
CREATE TABLE IF NOT EXISTS nginxdb.access_logs (
message String
)
ENGINE = MergeTree()
ORDER BY tuple()Настройка Nginx
На этом шаге показано, как настроить ведение журналов в Nginx.
- Следующее свойство
access_logнаправляет журнал в/var/log/nginx/my_access.logв формате combined. Это значение нужно указать в разделеhttpфайлаnginx.conf:
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;
}-
Обязательно перезапустите Nginx, если вам пришлось изменить
nginx.conf. -
Откройте страницы на вашем веб-сервере, чтобы сгенерировать несколько событий в журнале доступа. Записи журнала в формате combined выглядят следующим образом:
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"Настройка Vector
Vector собирает, преобразует и маршрутизирует журналы, метрики и трассировки (так называемые источники) в различные системы назначения (так называемые приемники), включая встроенную совместимость с ClickHouse. Источники и приемники задаются в файле конфигурации vector.toml.
- Следующий файл vector.toml определяет источник типа file, который читает новые записи с конца файла my_access.log, а также приемник — таблицу access_logs, определенную выше:
[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-
Запустите Vector, используя приведённую выше конфигурацию. Подробнее о настройке источников и приёмников см. в документации Vector.
-
Убедитесь, что журналы доступа записываются в ClickHouse, выполнив следующий запрос. В таблице должны появиться журналы доступа:
SELECT * FROM nginxdb.access_logs
Разбор журналов
Хранить журналы в ClickHouse удобно, однако запись каждого события в виде одной строки существенно ограничивает возможности анализа данных. Далее рассмотрим, как разобрать события журнала с помощью materialized view.
Materialized view работает аналогично триггеру вставки в SQL. Когда строки данных вставляются в исходную таблицу, materialized view выполняет некоторое преобразование этих строк и вставляет результаты в целевую таблицу. Materialized view можно настроить для получения разобранного представления событий журнала в access_logs. Пример одного такого события журнала приведён ниже:
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 есть различные функции для разбора приведённой выше строки. Функция splitByWhitespace разбивает строку по пробельным символам и возвращает каждый токен в виде массива.
Для демонстрации выполните следующую команду:
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"')["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\""]В некоторых строках есть лишние символы, а user agent (сведения о браузере) не нуждался в разборе, однако результирующий массив близок к тому, что требуется.
Аналогично splitByWhitespace, функция splitByRegexp разбивает строку на массив по регулярному выражению.
Выполните следующую команду, которая возвращает две строки.
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"')Обратите внимание, что вторая возвращённая строка — это user agent, успешно извлечённый из лога:
["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\""]Прежде чем рассмотреть финальную команду CREATE MATERIALIZED VIEW, ознакомимся ещё с несколькими функциями для очистки данных.
Например, значение RequestMethod равно "GET и содержит лишнюю двойную кавычку.
Для её удаления можно воспользоваться функцией trimBoth (alias trim):
SELECT trim(LEADING '"' FROM '"GET')Строка времени начинается с символа [ и не имеет формата, который ClickHouse может разобрать как дату.
Однако если изменить разделитель с двоеточия (:) на запятую (,), разбор выполняется корректно:
SELECT parseDateTimeBestEffort(replaceOne(trim(LEADING '[' FROM '[12/Oct/2021:15:32:43'), ':', ' '))Теперь можно определить materialized view.
Приведённое ниже определение включает POPULATE, что означает: существующие строки в access_logs будут обработаны и вставлены немедленно.
Выполните следующий SQL-оператор:
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)Теперь убедитесь, что всё работает. Журналы доступа должны быть аккуратно разобраны по столбцам:
SELECT * FROM nginxdb.access_logs_view
С помощью Vector, для которого нужны лишь простая установка и быстрая настройка, вы можете отправлять журналы с сервера Nginx в таблицу ClickHouse. С помощью materialized view можно разобрать эти журналы на столбцы для более удобной аналитики.