Использовать будем Grafana версии 10.2, Promtail и Loki версии 2.9.2. Если кто-то вообще ничего не знает про используемый стек, посмотрите краткое описание вот здесь. Работать все будет под Windows, для Linux изменения должны быть чисто косметические. Статья написана для быстрого старта, поэтому здесь не будет разбираться быстродействие, настройка прав доступа, разнообразие визуализаций Grafana и прочее.
Подготовка
Скачиваем бинарники Grafana вот здесь. Если выбрана Enterpise лицензия, то можно вместо бинарников получить ошибку Sorry, our service is currently not available in your region. В этом случае выбирайте OSS.
Бинарники Loki и Promtail лежат вот здесь
Если кому-то не нравятся бинарники, то вот подробная документация по установке Promtail и Loki. Дефолтный конфиг версии 2.9.2 для Promtail здесь, а для Loki тут. Если нужна другая версия, меняйте в ссылках v2.9.2 на нужную.
Логи будут такого формата
[dateTime] [tenantId] [severity] [module] [message]
Пример записи в логе
[01.11.2023 17:07:59] [node001] [INFO] [Export.Csv] [rsvp_flow_stateMachine: entering]
Обратите особое внимание на свой формат даты и времени. Часовой пояс может быть явно указан в логах, можно настроить часовой пояс через конфиг promtail. Здесь он будет в конфиге. В разных часовых поясах легко запутаться, особенно если логи собираются на разных серверах и вдвойне легко запутаться если все происходит в облаке.
Для тестирования я себе делал генератор логов. Выдает он более-менее осмысленный контент нужного мне формата и нужного мне количества. У кого нет готовых логов для тестов, желательно заранее сделать файлик в котором будет хотя бы сотня записей. А для настройки Promtail достаточно вообще одной строки.
Настройка Promtail
У Promtail есть два параметра, которые сильно помогут в настройке
--dry-run данные не отправляются в Loki, также логфайл будет читаться с одного и того же места при каждом запуске. Можно не добавлять новые записи при каждом изменении конфига и запуске Promtail, достаточно одной строки.
--inspect в консоль выводится отладочная информация.
Для настройки Promtail добавляем в логфайл одну запись и запускаем Promtail. Конфиг меняем с каждым запуском для тестирования изменений.
Выглядит это вот так
promtail-windows-amd64 --dry-run --inspect --config.file=promtail-local-config.yaml
[01.11.2023 17:07:59] [node001] [INFO] [Export.Csv] [rsvp_flow_stateMachine: entering state SESSIONED]
[inspect: regex stage]:
{stages.Entry}.Extracted["module"]:
+: Export.Csv
{stages.Entry}.Extracted["msg"]:
+: rsvp_flow_stateMachine: entering state SESSIONED
{stages.Entry}.Extracted["severity"]:
+: INFO
{stages.Entry}.Extracted["tenantid"]:
+: node001
{stages.Entry}.Extracted["time"]:
+: 01.11.2023 17:07:59
[inspect: labels stage]:
{stages.Entry}.Entry.Labels:
-: {filename="c:\\LogManagement\\logs\\test.log", job="logs"}
+: {filename="c:\\LogManagement\\logs\\test.log", job="logs", module="Export.Csv", severity="INFO", tenantid="node001"}
[inspect: timestamp stage]:
{stages.Entry}.Entry.Entry.Timestamp:
-: 2023-11-03 16:32:11.2903454 +0700 +07
+: 2023-11-01 17:07:59 +0700 +07
[inspect: labeldrop stage]:
{stages.Entry}.Entry.Labels:
-: {filename="c:\\LogManagement\\logs\\test.log", job="logs", module="Export.Csv", severity="INFO", tenantid="node001"}
+: {job="logs", module="Export.Csv", severity="INFO", tenantid="node001"}
[inspect: template stage]:
{stages.Entry}.Extracted["msgData"]:
+: rsvp_flow_stateMachine: entering state SESSIONED
[inspect: output stage]:
{stages.Entry}.Entry.Entry.Line:
-: [01.11.2023 17:07:59] [node001] [INFO] [Export.Csv] [rsvp_flow_stateMachine: entering state SESSIONED]
+: rsvp_flow_stateMachine: entering state SESSIONED
2023-11-01T17:07:59+0700{job="logs", module="Export.Csv", severity="INFO", tenantid="node001"} rsvp_flow_stateMachine: entering state SESSIONED
Теперь будет настройка конфига по частям. Если удобнее смотреть все сразу, то дальше весь конфиг целиком.
Для настройки берем дефолтный конфиг, вот эту часть оставляем как есть
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://localhost:3100/loki/api/v1/push
Дальше меняем path и job.
job logs метка для имени конфигурации (конфигураций может быть несколько)
path путь к файлу (или файлам) логов. Если у вас настроен log file rotation, то хорошо проверьте шаблон, чтобы promtail точно находил новые файлы.
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: logs
__path__: c:\LogManagement\logs\test.log
Дальше настраиваем непосредственно разбор логов. Разбор происходит по определенным стадиям/этапам, подробности в документации. Для разбора строки используем регулярку с именованными группами. Имя группы будет использовано на следующих этапах. Для json или logfmt есть стандартные настройки, изобретать регулярки для разбора json не нужно.
pipeline_stages:
- regex:
expression:
\[(?P<time>.*?)\] \[(?P<tenantid>.*?)\] \[(?P<severity>.*?)\] \[(?P<module>.*?)\] \[(?P<msg>.*?)\]
Результат разбора
[01.11.2023 17:07:59] [node001] [INFO] [Export.Csv] [rsvp_flow_stateMachine: entering state SESSIONED]
[inspect: regex stage]:
{stages.Entry}.Extracted["module"]:
+: Export.Csv
{stages.Entry}.Extracted["msg"]:
+: rsvp_flow_stateMachine: entering state SESSIONED
{stages.Entry}.Extracted["severity"]:
+: INFO
{stages.Entry}.Extracted["tenantid"]:
+: node001
{stages.Entry}.Extracted["time"]:
+: 01.11.2023 17:07:59
Дальше стадия меток, тут мы указываем какие метки будут у записи.
- labels:
tenantid:
severity:
module:
Результат ниже, обратите внимание на то, какие были метки до, и какие стали после.
[inspect: labels stage]:
{stages.Entry}.Entry.Labels:
-: {filename="c:\\LogManagement\\logs\\test.log", job="logs"}
+: {filename="c:\\LogManagement\\logs\\test.log", job="logs", module="Export.Csv", severity="INFO", tenantid="node001"}
Теперь очень важная часть - установка времени для записи. В моем примере в логах часовой пояс явно не указан, поэтому часовой пояс выставлен через конфиг. Если у вас не так, location выкидываете, format меняете под свой. В Promtail используется Go формат для времени и дат. Кто с этим форматом незнаком, вот шпаргалка. Коды таймзон для конфига можно посмотреть здесь.
- timestamp:
format: 02.01.2006 15:04:05
source: time
location: Asia/Krasnoyarsk
Результат работы этапа ниже, обратите внимание что дата поменялась на 2 дня. В файле логов дата 1 ноября, обработка происходит 3 ноября. По умолчанию в записи будет проставлено время обработки лога. Тщательно протестируйте этот этап, особенно если логи создаются в облаке.
[inspect: timestamp stage]:
{stages.Entry}.Entry.Entry.Timestamp:
-: 2023-11-03 16:32:11.2903454 +0700 +07
+: 2023-11-01 17:07:59 +0700 +07
Дальше выкидываем лишние метки, filename нам не нужен, time тоже не нужен, потому что со временем записи в логе мы разобрались на предыдущей стадии.
- labeldrop:
- filename
- time
Результат работы этапа
[inspect: labeldrop stage]:
{stages.Entry}.Entry.Labels:
-: {filename="c:\\LogManagement\\logs\\test.log", job="logs", module="Export.Csv", severity="INFO", tenantid="node001"}
+: {job="logs", module="Export.Csv", severity="INFO", tenantid="node001"}
Теперь создадим новое поле msgData используя шаблон, данные для нового поля будут из старого поля msg. Выглядит немного кривовато, но это сделано специально. Для того чтобы показать как можно менять строковое содержания логов еще при работе Promtail, до того как они попадут в Loki. Здесь из строки выкидываются tenant, severity, node и time, т.к. эти данные все равно будут в метках. Если надо оставить строку как есть, тогда этот и следующий этап можно просто убрать из конфига.
- template:
source: msgData
template: '{{ .msg }}'
Результат работы этапа - строка лога
[inspect: template stage]:
{stages.Entry}.Extracted["msgData"]:
+: rsvp_flow_stateMachine: entering state SESSIONED
Заключительный этап - указываем источник данных для строки лога, это поле из предыдущего этапа.
- output:
source: msgData
Итоговая запись - строка и метки
[inspect: output stage]:
{stages.Entry}.Entry.Entry.Line:
-: [01.11.2023 17:07:59] [node001] [INFO] [Export.Csv] [rsvp_flow_stateMachine: entering state SESSIONED]
+: rsvp_flow_stateMachine: entering state SESSIONED
2023-11-01T17:07:59+0700{job="logs", module="Export.Csv", severity="INFO", tenantid="node001"} rsvp_flow_stateMachine: entering state SESSIONED
Конфиг целиком
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://localhost:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: logs
__path__: c:\LogManagement\logs\test.log
pipeline_stages:
- regex:
expression:
\[(?P<time>.*?)\] \[(?P<tenantid>.*?)\] \[(?P<severity>.*?)\] \[(?P<module>.*?)\] \[(?P<msg>.*?)\]
- labels:
tenantid:
severity:
module:
- timestamp:
format: 02.01.2006 15:04:05
source: time
location: Asia/Krasnoyarsk
- labeldrop:
- filename
- time
- template:
source: msgData
template: '{{ .msg }}'
- output:
source: msgData
У Promtail есть свой простенький веб-клиент, порт по умолчанию 9080, можно использовать для проверки работоспособности и администрирования, выглядит клиент вот так
Настройка Loki
Здесь все просто, используете дефолтный конфигурационный файл и все работает. По умолчанию Loki отсылает какую-то статистику на свои сервера. Чтобы это отключить раскомментируйте эти строчки
#analytics:
# reporting_enabled: false
Для проверки работоспособности Loki зайдите в браузере (или в любом веб клиенте) по ссылке http://localhost:3100/ready. В ответе должно быть ready, еще может быть такой ответ Ingester not ready: waiting for 15s after being ready, подождите указанные 15 секунд и попробуйте еще раз. У Loki есть свое API, cправка тут. Из полезного на начальной стадии может быть ендпойнт для метрик http://localhost:3100/metrics.
Настройка Grafana
Запускаем файл grafana-10.2.0\bin\grafana-server.exe и заходим на http://localhost:3000. Логин пароль при первом запуске admin/admin, Grafana сразу предложит его сменить. Loki должен быть запущен и в нем должны быть данные.
Добавляем Loki Datasource
В меню Home Connections Data sources жмем на кнопку Add new data source
Там выбираем Loki
В поле Connection вводим http://127.0.0.1:3100
Внизу формы жмем на Save & Test и дожидаемся подтверждения успешно установленного соединения
В правом верхнем углу жмем на кнопку explore data
Откроется форма для создания и редактирования запросов
Кликнув по кнопке Label browser можно посмотреть какие метки и какие у них значения есть в базе, составить и выполнить запрос
Если у вас в базе есть данные, то выглядеть это будет примерно как на картинке ниже. Это основное место для написания и отладки запросов
Создаем панель Raw Logs
Сначала нужно создать дашборд, в меню Home Dashboards жмем на кнопку New, в выпадающем списке выбираем New dashboard.
Дальше жмем на кнопку Add visualization.
Выбираем созданный на предыдущем шаге Loki datasource.
В правом верхнем углу меняем тип визуализации на Logs
Меняем Panel title на Raw logs и включаем галочки Time и Enable log details
Жмем на кнопку Apply
Заходим в свойства дашборда
Здесь заходим на вкладку Variables и жмем на кнопку Add variable, имя переменной tenantid, остальное как на картинке ниже
Создаем еще одну переменную, все тоже самое, только для nodeid.
Создаем третью переменную с названием filter и типом Text box
Панель теперь выглядит так. Жмем edit чтобы поменять запрос
Запрос будет такой. Обратите внимание на line_format, так можно менять отображение записей лога.
{job="logs", tenantid=~"$tenantid", severity=~"$severity"} |= "$filter" | line_format "{{.tenantid}} {{.module}} {{.severity}} {{__line__}}"
В итоге выглядеть все будет как на картинке ниже, можно выбирать tenant, severity и отфильтровать по содержимому лога.
Создаем панель Pie Chart
Жмем на кнопку Add выбираем Visualization
Выставляем свойства как указано на картинке ниже
Запрос будет такой
sum by(severity) (count_over_time({job="logs"} [$__range]))
Обратите внимание что в запросе нет переменных, которые есть в запросе для панели Raw Logs. Поэтому в чарте будут использоваться все данные за выбранный промежуток времени, фильтрации не будет. При желании можно в запрос добавить переменные и тогда данные в чарте и в панели Raw Logs будут одинаковые.
Цвета для конкретных значений можно выбрать кликнув по тонкой цветной полоске
на легенде
Или добавив нужные значение на вкладке Overrides в свойствах чарта
В итоге наш чарт будет выглядеть вот так
Заключение
Grafana классный инструмент для визуализации данных, Loki и Promtail дают возможность достаточно просто настроить сбор и хранение логов. Сочетание этих инструментов дает очень хороший результат при небольших усилиях. Надеюсь статья будет полезной.
Комментарии (4)
DonAlPAtino
17.11.2023 11:28Небольшой лог на 15 тыс строк с внутреннего портала. 7 лейблов.
error="server returned HTTP status 429 Too Many Requests (429): Maximum active stream limit exceeded, reduce the number of active streams (reduce labels or reduce label values), or contact your Loki administrator to see if the limit can be increased, user: 'fake'"
чего-то как-то быстро оно сдохло :-(
DonAlPAtino
А это нормально что Promtail за localhost в google DNS пошел? Вроде у меня больше никто так не делает и все корректно настроено.
piton_nsk Автор
Вообще говоря это странно. Чтобы именно промтейле ходил в гугль. Как вы его вычислили, могу у себя проверить.
DonAlPAtino
в promtail-local-config.yaml
clients:
- url: http://localhost:3100/loki/api/v1/push
прописал и получил "error DNS resolve 8.8.8.8 53".
Очень удивился, погуглил и поставил 127.0.0.1:3100. Все заработало