VictoriaLogs: знайомство, запуск в Kubernetes, LogsQL та Grafana

Автор |  05/09/2024
 

VictoriaLogs – відносно нова система для збору та аналізу логів, схожа на Grafana Loki, але – як і VictoriaMetrics в порівнянні з “ванільним” Prometheus – менш вибаглива до ресурсів CPU/Memory.

Особисто я користуюсь Grafana Loki років 5, але до неї іноді буває дуже багато питань – і по документації, і по загальній складності системи, бо багато компонентів, і по перформансу – бо як я її не тюнив (див. Grafana Loki: оптимізація роботи – Recording Rules, кешування та паралельні запити), але іноді на відносно невеликих запитах Grafana повертає 504 від Loki Gateway, і я, якщо чесно, вже втомився з цим розбиратись.

Ну а оскільки у нас сам моніторинг побудований на VictoriaMetrics, і до VictoriaLogs вже “завезли” підтримку Grafana data source – то прийшов час спробувати її в роботі, і порівняти з Grafana Loki.

Чого у VictoriaLogs поки що нема:

  • підтримки AWS S3 бекенду – але обіцяють зробити в листопаді 2024 (до того, ж якоюсь “магічною” автоматизацією – коли старі дані з локального диску автоматично будуть перенесені до відповідного S3)
  • поки що нема аналога Loki RecordingRules – коли з логів створюємо звичайні метрики, їх записуємо в VictoriaMetrics/Prometheus, а потім робимо алерти в VMAlert та дашборди в Grafana, але знов-таки скоро має бути – жовтень-листопад 2024
  • Grafana data source теж ще в Beta, тому є складності з побудовою графіків в Grafana

І прям біда з всякими ChatGPT для генерації запитів – але про це поговоримо далі.

Документація – як завжди у VictoriaMetrcis чудова – VictoriaLogs.

Ще про останні апдейти VictoriaLogs говорили на мітапі VictoriaMetrics Meetup June 2024 – VictoriaLogs Update.

Цікаві скріншоти з бенчмарками VictoriaLogs vs ELK vs Grafana Loki – Benchmark for VictoriaLogs.

Roadmap по VictoriaLogs – тут>>>.

Тож що будемо сьогодні робити:

  • запустимо VictoriaLogs в Kubernetes
  • подивимось на можливості її LogsQL
  • підключимо Grafana data source
  • подивимось, як можна створити дашборду в Grafana

VictoriaLogs Helm chart

Деплоїти будемо з Helm-чарта vm/victoria-logs-single.

Такоє є підтримка в VictoriaMetrics Operator (див. VLogs).

Ми на проекті використовуємо власний чарт для нашого моніторингу (див. VictoriaMetrics: створення Kubernetes monitoring stack з власним Helm-чартом), в якому через Helm dependency встановлюється чарт victoria-metrics-k8s-stack + всякі додаткові сервіси типу Promtail, k8s-event-logger etc. В цей же чарт додамо victoria-logs-single.

Для початку зробимо все руками, спочатку з якимись дефолтними values, потім подивимось, що воно нам встановить в Kubernetes і як воно працює – а потім будемо додавати в автоматизацію.

В чарті VictoriaLogs є можливість відразу запустити Fluetbit DaemonSet, але в нас вже є Promtail, тому будемо використовувати його.

Всі values є в документації до чарту, а з того, що може бути цікаве зараз:

  • extraVolumeMounts та extraVolumes: можемо створити власний окремий persistentVolume з AWS EBS, та підключати його до VictoriaLogs
  • persistentVolume.enabled та persistentVolume.storageClassName: або можемо просто вказати, що його треба створювати, і при потребі задати власний storageClass з RelaimPolicy retain
  • ingress: в моєму випадку частина логів пишеться з AWS Lambda, тому потрібно буде створювати AWS ALB з типом Internal

Встановлення чарту

Додаємо репозиторій:

$ helm repo add vm https://victoriametrics.github.io/helm-charts/
$ helm repo update

Встановлюємо чарт в окремий Kubernetes Namespace ops-test-vmlogs-ns:

$ helm -n ops-test-vmlogs-ns upgrade --install vlsingle vm/victoria-logs-single

Перевіряємо Kubernetes Pod:

$ kk get pod
NAME                                     READY   STATUS    RESTARTS   AGE
vlsingle-victoria-logs-single-server-0   1/1     Running   0          36s

І глянемо на ресурси:

$ kk top pod
NAME                                     CPU(cores)   MEMORY(bytes)   
vlsingle-victoria-logs-single-server-0   1m           3Mi             

3 мегабайти пам’яті 🙂

Забігаючи наперед – після підключення запису логів з Promtail до VictoriaLogs ресурсів буде використовуватись не набагато більше.

Відкриваємо доступ до UI:

$ kk -n ops-test-vmlogs-ns port-forward svc/vlsingle-victoria-logs-single-server 9428

В браузері заходимо на http://localhost:9428.

Як і інші сервіси від VictoriaMetrics – попадаємо на сторінку з усіма необхідними посиланнями:

Переходимо на  http://localhost:9428/select/vmui/ – поки що тут пусто:

Додамо відправку логів з Promtail.

Налаштування Promtail

До VictoriaLogs можна писати логи в форматі Elasticsearch, ndjson або Loki – див. Data ingestion.

Власне нас цікавить саме Loki, і логи ми пишемо з Promtail. Приклад конфігурації Promtail для VictoriaLogs див. у Promtail setup.

У нас Promtail встановлюється з його власного чарту, який створює Kubernetes Secret з promtail.yml.

Оновлюємо values чарту, в config.clients додаємо ще один URL – в моєму випадку він буде неймспейсом з ops-test-vmlogs-ns.svc, бо VictoriaLogs запущена в іншому неймспейсі, ніж Loki:

...
promtail:
  config:
    clients:
      - url: http://atlas-victoriametrics-loki-gateway/loki/api/v1/push
      - url: http://vlsingle-victoria-logs-single-server.ops-test-vmlogs-ns.svc:9428/insert/loki/api/v1/push
...

Деплоїмо зміни, чекаємо рестарту подів з Promtail, і ще раз перевіряємо логи в VictoriaLogs:

VictoriaLogs Log Streams

Під час запису логів до VicrotiaLogs ми можемо задати додаткові параметри – див. HTTP parameters.

З того, що може бути цікавим зараз – це спробувати створити власні Log Stream, аби по ним потім робити фільтрацію логів для більш швидкої їх обробки. див. Stream fields.

Якщо лог-стрім не заданий – то VictoriaLogs пише все в один дефолтний стрім {}, як ми бачили на скріні вище.

Наприклад, у нас в кластері всі аплікейшени розбиті по власним Kubernetes Namespaces – dev-backend-api-ns, prod-backend-api-ns, ops-monitoring-ns і т.д.

Давайте створимо окремий стрім на кожен неймспейс – до url додаємо ?_stream_fields=namespace:

...
  config:
    clients:
      - url: http://atlas-victoriametrics-loki-gateway/loki/api/v1/push
      - url: http://vlsingle-victoria-logs-single-server.ops-test-vmlogs-ns.svc:9428/insert/loki/api/v1/push?_stream_fields=namespace
...

Деплоїмо, і тепер маємо окремі стріми на кожен неймспейс:

VicrotiaLogs vs Loki: ресурси CPU/Memory

Давайте просто глянемо на ресурси, які зараз в мене споживають всі поди для роботи Loki::

$ kk -n ops-monitoring-ns top pod | grep loki
atlas-victoriametrics-loki-chunks-cache-0                         2m           824Mi          
atlas-victoriametrics-loki-gateway-6bd7d496f5-9c2fh               1m           12Mi            
atlas-victoriametrics-loki-results-cache-0                        1m           32Mi            
loki-backend-0                                                    50m          202Mi           
loki-backend-1                                                    8m           214Mi           
loki-backend-2                                                    12m          248Mi           
loki-canary-gzjxh                                                 1m           15Mi            
loki-canary-h9d6s                                                 1m           17Mi            
loki-canary-hkh4f                                                 2m           17Mi            
loki-canary-nh9mf                                                 2m           16Mi            
loki-canary-pbs4x                                                 1m           17Mi            
loki-read-55bcffc9fb-7j4tg                                        12m          255Mi           
loki-read-55bcffc9fb-7qtns                                        45m          248Mi           
loki-read-55bcffc9fb-s7rpq                                        10m          244Mi           
loki-write-0                                                      42m          262Mi           
loki-write-1                                                      27m          261Mi           
loki-write-2                                                      26m          258Mi           

Та ресурси VictoriaLogs:

$ kk top pod
NAME                                     CPU(cores)   MEMORY(bytes)   
vlsingle-victoria-logs-single-server-0   2m           14Mi            

При тому, що пишеться однакова кількість логів.

Так – в Loki зараз є пачка RecordingRules, так – є пара дашборд в Grafana, які виконують запити напряму до Loki для графіків, але ж ну камон! Це небо і земля!

Можливо, це ще й мої криві руки, які не змогли нормально затюнити Loki – проте VictoriaLogs зараз запущена взагалі без всякого тюнингу.

LogsQL

Окей – маємо інстанс VictoriaLogs, маємо логи, які в неї пишуться.

Давайте спробуємо “покверяти” і розібратися з LogsQL взагалі, та трохи порівняти з LogQL від Loki.

Документація по LogsQL для VictoriaLogs – тут>>>.

Запити ми можемо робити з VM UI, з CLI та з Grafana – див. Querying.

Запити з HTTP API

У VictoriaLogs дуже приємний API, з яким можна отримати всі необхідні дані.

Наприклад, для пошуку по логам за допомогою curl можемо зробити запит до /select/logsql/query, а потім через unix pipe передати до jq.

Все ще маємо запущений kubectl port-forward, робимо запит з пошуком всіх логів зі словом “error“:

$ curl -s localhost:9428/select/logsql/query -d 'query=error' | head | jq
{
  "_time": "2024-09-02T12:23:40.890465823Z",
  "_stream_id": "0000000000000000195443555522d86dcbf56363e06426e2",
  "_stream": "{namespace=\"staging-backend-api-ns\"}",
  "_msg": "[2024-09-02 12:23:40,890: WARNING/ForkPoolWorker-6] {\"message\": \"Could not execute transaction\", \"error\": \"TransactionCanceledException('An error occurred (TransactionCanceledException) when calling the TransactWriteItems operation: Transaction cancelled, please refer cancellation reasons for specific reasons [None, None, ConditionalCheckFailed]')\", \"logger\": \"core.storage.engines.dynamodb_transactions\", \"level\": \"warning\", \"lineno\": 124, \"func_name\": \"_commit_transaction\", \"filename\": \"dynamodb_transactions.py\", \"pid\": 2660, \"timestamp\": \"2024-09-02T12:23:40.890294\"}",
  "app": "backend-celery-workers",
  "component": "backend",
  "container": "backend-celery-workers-container",
  "filename": "/var/log/pods/staging-backend-api-ns_backend-celery-workers-deployment-66b879bfcc-8pw52_46eaf32d-8956-4d44-8914-7f2afeda41ad/backend-celery-workers-container/0.log",
  "hostname": "ip-10-0-42-56.ec2.internal",
  "job": "staging-backend-api-ns/backend-celery-workers",
  "logtype": "kubernetes",
  "namespace": "staging-backend-api-ns",
  "node_name": "ip-10-0-42-56.ec2.internal",
  "pod": "backend-celery-workers-deployment-66b879bfcc-8pw52",
  "stream": "stderr"
}
...

І в результаті маємо всі поля та Log Stream, який задали вище – по полю Namespace.

Ще з цікавих ендпоінтів – можливість отримати всі стріми, в логах яких є ключове слово, наприклад:

$ curl -s localhost:9428/select/logsql/streams -d "query=error" | jq
{
  "values": [
    {
      "value": "{namespace=\"ops-monitoring-ns\"}",
      "hits": 5012
    },
    {
      "value": "{namespace=\"staging-backend-api-ns\"}",
      "hits": 542
    },
...

Запити з VM UI

Тут все просто – пишемо запит в полі Log queiry, отримуємо результат.

Результат можемо сформувати в форматі Group by, Table та JSON – його ми вже бачили в HTTP API.

В форматі Group by результат виводиться по кожному стріму:

А в форматі Table – колонками по іменам полей з логів:

Синтаксис LogsQL

Взагалі, можливостей прям дуже багато – див. всі в документації LogsQL.

Але давайте глянемо хоча б основні, аби мати уяву що ми можемо робити.

Самий простий приклад запитів з LogsQL ми вже бачили – просто по слову “error“.

Аби виконати пошук по фразі – “загортаємо” її в лапки:

Сортування

Важливий нюанс – результати повертаються у довільному порядку з метою покращення перформансу, тому рекомендується використовувати sort pipe по полю _time:

_time:5m error | sort by (_time)

Comments

Дуже прикольно, що ми в запити можемо додавати коментарі, наприклад:

_time:5m | app:="backend-api" AND namespace:="prod-backend-api-ns" # this is a comment
| unpack_json | keep path, duration, _msg, _time # and an another one comment
| stats by(path) avg(duration) avg_duration | path:!"" | limit 10

Оператори

В LogsQL вони називаються Logical filter – AND, OR, NOT.

Наприклад, використати AND можемо так – шукаємо запис, в якому є строка “Received request” та ID “dada85f9246d4e788205ee1670cfbc6f“:

"Received request" AND "dada85f9246d4e788205ee1670cfbc6f"

Або зробити пошук по “Received request” тільки зі стриму namespace="prod-backend-api-ns":

"Received request" AND _stream:{namespace="prod-backend-api-ns"}

Або по полю pod:

"Received request" AND pod:="backend-api-deployment-98fcb6bcb-w9j26"

При чому оператор AND можна не задавати явно, тото запит:

"Received request" pod:="backend-api-deployment-98fcb6bcb-w9j26"

Буде відпрацьований аналогічно попередньому.

Але в прикладах далі я все ж буду додавати AND  для ясності.

Фільтри

Будь-який запит LogsQL має містити хоча б один фільтр.

Коли ми робимо запит на кшталт “Received request” – то фактично ми використовуємо фільтр Phrase filter, який за замовченням застосовується до поля _msg.

А в запиті _stream:{namespace="prod-backend-api-ns"} ми використовуємо Stream filter.

Інші цікаві фільтри:

  • Time filter – можна задати проміжок часу в хвилинах/годинах або датах
  • Day та Week range filter – або виконати пошук по конкретним датам чи дням тижня
  • Prefix filter – пошук по неповному слову або фразі
  • Case-insensitive filter – пошук без урахування регістру
  • Regexp filter – регулярні вирази в пошуку
  • IPv4 range filter – це прям кілер-фіча – готовий фільтрі для IP-адрес

Давайте швиденько глянемо кілька прикладів.

Time filter

Вибрати всі записи за останню хвилину:

"Received request" AND _time:1m

Або за 1.09.2024:

"Received request" AND _time:2024-09-01

Або за проміжок часу – 30-го серпня по 2 вересня включно:

"Received request" AND _time:[2024-08-30, 2024-09-02]

Або без записів за 2024-08-30 – тобто, починаючи з 31-го числа – міняємо [ на (:

"Received request" AND _time:(2024-08-30, 2024-09-02]

Day range filter

Фільтри по годинам дня.

Наприклад, всі записи між 14:00 і 18:00 сьогодні:

"Received request" AND _time:day_range[14:00, 18:00]

Аналогічно до Time filter – використовуємо () та [] аби включити або виключити початок чи кінець range.

Week range filter

Подібний до Day range filter, але по днях тижня:

"Received request" AND _time:week_range[Mon, Fri]

Prefix filter

За допомогою “*” вказуємо, що нам потрібні всі логи, які починаються з фрази “ForkPoolWorker-1” – тобто, всі воркери з 1, 12, 19 і т.д:

"ForkPoolWorker-1"*

Аналогічно можемо використовувати цей фільтр для значень в полях записів.

Наприклад, вибрати всі записи, де поле container має значення “backend-celery“:

app:"backend-celery-"*

Або ж використати Substring filter:

app:~"backend-celery"

Regexp filter

Пошук з регуляркою, також можна комбінувати з Substring filter.

Наприклад, знайти всі записи з “Received request” АБО “ForkPoolWorker“:

~"Received request|ForkPoolWorker"

Pipes

Ще цікава можливість в LogsQL – використання pipes, через які можна виконувати додаткові операції.

Наприклад, в Grafana мені доволі часто потрібно було робити перейменування імені поля з метрики або лога.

З LogsQL це можна зробити за допомогою | copy або | rename:

  • є поле logtype: kubernetes
  • хочемо його зробити source: kubernetes

Виконуємо такий запит:

~"ForkPoolWorker" | rename logtype as source

Інші цікаві pipes:

  • delete pipe: видалити поле з результатів
  • extract pipe: створити нове поле зі значенням із записів в логах
  • field_names pipe: поверне всі поля з додавання кількості записів
  • fields pipe: повернути в результатах тільки обрані поля
  • filter pipe: фільтрувати результати з додатковими умовами
  • limit pipe: вивести тільки зазначені кількість результатів (див. також top)
  • math pipe: виконати математичні операції
  • offset pipe: теж прикольна штука – зробити “зміщення” на кількість результатів
  • pack_json pipe: “запакувати” всі поля з результатів в JSON (див. також pack_logfmt та unpack_json)
  • replace pipe: замінити слово/фразу в результатах на інше (маскувати паролі)
  • sort pipe: операції сортування в результатах
  • stats pipe: вивести статистику

Я вже не буду тут описувати приклади, бо в цілому вони – і багато іншого – є в документації, але давайте глянемо приклад запиту для Loki, і спробуємо переписати його для VictoriaLogs – і там як раз спробуємо pipes в ділі.

Приклад: Loki to VictoriaLogs query

Є у нас такий запит для Loki RecordingRules:

- record: eks:pod:backend:api:path_duration:avg
  expr: |
    topk (10,
        avg_over_time (
            {app="backend-api"} | json | regexp "https?://(?P<domain>([^/]+))" | line_format "{{.path}}: {{.duration}}"  | unwrap duration [5m]
        ) by (domain, path, node_name)
    )

З логів Kubernetes Pods нашого бекенду створює метрику eks:pod:backend:api:path_duration:avg, в якій відображає середній час відповіді по ендпоінтам.

В ньому маємо:

  • вибираємо логи з лог-стріма app="backend-api"
  • логи пишуться в JSON, тому використовуємо json парсер
  • потім з regex parser створюємо поле domain зі значенням після “https://
  • з line_format отримуємо поля path та duration
  • з unwrap “витягуємо” значення з duration
  • рахуємо середнє значення з duration за допомогою оператора avg_over_time() за останні 5 хвилин, групуючи по полям domain, path, node_name – вони потім використовуються в алертах і графіках Grafana
  • збираємо інформацію по топ-10 записів

Як ми можемо щось схоже зробити з VictoriaLogs та LogsQL?

Почнемо з фільтра по полю:

app:="backend-api"

Отримуємо всі записи з подів цієї апки.

Пам’ятаємо, що можемо використати тут регулярку, і задати фільтр як app:~"backend" – тоді будуть результати з app="backend-celery-workers", app="backend-api" і т.д.

Можна додати фільтр по стріму – тільки з продакшена:

_stream:{namespace="prod-backend-api-ns"} AND app:="backend-api"

Або просто:

namespace:="prod-backend-api-ns" AND app:="backend-api"

В наших метриках Loki неймспейс не використовується, бо фільтри в алертах і Grafana використовують ім’я домену з поля domain, але тут для приклада най буде.

Далі нам треба створити поля domain, path та duration.

Тут можна використати або unpack_json – або extract.

unpack_json розпарсить JSON, і створить поля для запису з кожного ключа в JSON:

  • в документації до unpack_json говориться, що краще використовувати extract pipe
  • якщо використовувати його, то запит був би | extract '"duration": <duration>,'

Але нам всі поля не потрібні – тому можемо дропнути всі, і з фільтром keep залишити тільки duration, _msg та _time:

Далі, нам потрібно створити поле domain. Але просто взяти key url який створив unpack_json із {"url": "http://api.app.example.co/coach/notifications?limit=0" ...} нам не підходить, бо потрібен тільки домен – без строки “/coach/notifications?limit=0“.

Можемо додати фільтр extract_regexpextract_regexp "https?://(?P<domain>([^/]+))":

Тепер, маючи всі три поля, можемо використати stats by() і avg по полю duration:

А аби прибрати з результатів {"path":"","domain":"","avg(duration)":"NaN"} – додаємо фільтр path:!"".

Тепер весь запит буде:

app:="backend-api" | unpack_json | keep path, duration, _msg, _time | extract_regexp "https?://(?P<domain>([^/]+))" | stats by(path, domain) avg(duration) | path:!""

Останнім додаємо ліміт в останні 5 хвилин – _time:5m, і виводимо тільки топ-10 результатів.

Я тут приберу domain і додам фільтр по namespace, аби простіше було порівняти з результатами в Loki.

Результат avg(duration) будемо писати в нове поле avg_duration.

Тепер весь запит буде таким:

_time:5m | app:="backend-api" AND namespace:="prod-backend-api-ns" | unpack_json | keep path, duration, _msg, _time | stats by(path) avg(duration) avg_duration | path:!"" | limit 10

Результат:

Замість limit можна використати top pipe – бо limit просто обмежує кількість запитів, а top обмежує саме по значенню поля:

_time:5m | app:="backend-api" AND namespace:="prod-backend-api-ns" | unpack_json | keep path, duration, _msg, _time | stats by(path) avg(duration) avg_duration | path:!"" | top 10 by (path, duration)

І можемо додати sort(), а умову path:!"" винести перед викликом stats(), аби швидше оброблювався запит:

_time:5m | app:="backend-api" AND namespace:="prod-backend-api-ns" | unpack_json | keep path, duration, _msg, _time | path:!"" | stats by(path) avg(duration) avg_duration | sort by (_time, avg_duration) | top 10 by (path, avg_duration)

Порівняємо його з результатом з Loki, наприклад – API-ендпоінт /sprint-planning/backlog/challenges в результатах VictoriaLogs у нас тут має значення 160.464981 мілісекунд.

Виконуємо аналогічний запит в Loki:

topk (10,
    avg_over_time (
        {app="backend-api", namespace="prod-backend-api-ns"} | __error__="" | json | line_format "{{.path}}: {{.duration}}"  | unwrap duration [5m]
    ) by (path)
)

Все сходиться.

ChatGPT, Gemini, Claude та LogsQL (але Perplexity!)

Спробував з ними переписувати запити з Loki LogQL на VictoriaMetrics LogsQL – тут все дуже пєчально.

ChatGPT взагалі прям дуже глючить, і видає оператори типу SELECT, яких взагалі нема:

Gemini трохи краще, принаймні з більш-менш реальними операторами – але все одного не той випадок, коли можна просто скопіювати і використати:

І Claude – аналогічно до ChatGPT, нічого не знає – але пропонує “щось подібне”:

А от Perplexity відповів майже вірно:

Тільки спутав порядок – by() має бути після stats().

Helm, VictoriaLogs та Grafana data source

Репозиторій та документація – victorialogs-datasource.

VictoriaLogs sub-chart installation

Давайте відразу вже сюди додамо VictoriaLogs. Нагадаю, що у нас весь стек моніторинг встановлюється з нашого власного чарту, в якому через Helm dependency додаються victoria-metrics-k8s-stack, k8s-event-logger, aws-xray і т.д.

Видаляємо встановлений вручну чарт:

$ helm -n ops-test-vmlogs-ns uninstall vlsingle

В файлі Chart.yaml описуємо ще один dependency:

apiVersion: v2
name: atlas-victoriametrics
description: A Helm chart for Atlas Victoria Metrics kubernetes monitoring stack
type: application
version: 0.1.1
appVersion: "1.17.0"
dependencies:
- name: victoria-metrics-k8s-stack
  version: ~0.25.0
  repository: https://victoriametrics.github.io/helm-charts
- name: victoria-metrics-auth
  version: ~0.6.0
  repository: https://victoriametrics.github.io/helm-charts
- name: victoria-logs-single
  version: ~0.6.0
  repository: https://victoriametrics.github.io/helm-charts  
...

Оновлюємо сабчарти:

$ helm dependency build

Оновлюємо свої values – додамо постійний сторейдж:

...
victoria-logs-single:
  server:
    persistentVolume:
      enabled: true
      storageClassName: gp2-retain
      size: 3Gi # default value, to update later
...

Деплоїмо, і перевіряємо сервіс для VictoriaLogs:

$ kk get svc | grep logs
atlas-victoriametrics-victoria-logs-single-server      ClusterIP   None             <none>        9428/TCP                     2m32s

Редагуємо конфіг Promtail – задаємо новий URL:

...
promtail:
  config:
    clients:
      - url: http://atlas-victoriametrics-loki-gateway/loki/api/v1/push
      - url: http://atlas-victoriametrics-victoria-logs-single-server:9428/insert/loki/api/v1/push?_stream_fields=namespace
...

Підключення Grafana data source

Трохи довелось повозитись з values для Grafana, але в результаті вийшло так:

...
  grafana:
    enabled: true

    env:
      GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: "victorialogs-datasource"
    ...
    plugins:
      - grafana-sentry-datasource
      - grafana-clock-panel
      - grafana-redshift-datasource
      - https://github.com/VictoriaMetrics/victorialogs-datasource/releases/download/v0.4.0/victorialogs-datasource-v0.4.0.zip;victorialogs-datasource
    additionalDataSources:
      - name: Loki
        type: loki
        access: proxy
        url: http://atlas-victoriametrics-loki-gateway:80
        jsonData:
          maxLines: 1000
          timeout: 3m
      - name: VictoriaLogs
        type: victorialogs-datasource
        access: proxy
        url: http://atlas-victoriametrics-victoria-logs-single-server:9428

Версію шукаємо на сторінці Releases, зараз остання v0.4.0.

І зверніть увагу, що версія в URL задається два рази – /releases/download/v0.4.0/victorialogs-datasource-v0.4.0.zip.

Деплоїмо, при необхідності рестартимо поди з Grafana (якщо не використовуємо щось по типу Reloader), і перевіряємо датасорси:

Пробуємо з Explore:

Все працює.

Grafana dashboards на Time series visualization

З візуалізацією в Grafana поки що не все чудово, бо потрібно додавати transformations, аби Grafana panel коректно відобразила дані.

Довелось додавати їх як мінімум три:

  • Extract fields: результат від VictoriaLogs ми отримуємо в JSON, і з цією трансформацією з нього витягуємо всі поля
  • Convert field type: поле ‘duration’ в JSON приходить в string, тому його треба змінити на Number
  • Sort by: сортуємо по полю ‘avg_duration’
  • Prepare time series: для конвертації результатів в формат, який зрозуміє Time series visualization panel

Без цього будемо мати помилки типу “Data is missing a number field“, “Data is missing a time field” або “Data outside time range“.

Налаштування трансформацій:

Запит для графіка такий:

app:="backend-api" namespace:="prod-backend-api-ns" | unpack_json | keep path, duration, _msg, _time | path:!"" | stats by(_time:1m, path) avg(duration) avg_duration

Зверніть увагу, що тут _time переміщено у виклик stats() – робити статистку по останній хвилині для кожного path.

І результат такий:

Крім того, Data source поки не дає можливості переписати Options > Legend.

Висновки

Складно робити якісь висновки отак одразу, але в цілому – система подобається, і однозначно варта того, аби її спробувати.

До LogsQL треба звикнути та навчитись з ним працювати, але можливостей дає більше.

По ресурсам CPU/Memory – тут взагалі жодних питань.

Grafana data source працює, чекаємо на його реліз.

Ну і чекаємо, коли завезуть підтримку AWS S3 та аналог Loki RecordingRules, бо на сьогодні VictoriaLogs можна використовувати виключно як систему для роботи з логами – але не для графіків чи алертів.

Біда, що всякі ChatGPT толком не можуть допомогти з запитами LogsQL, бо для Loki я ними користувався доволі часто, але згодом і вони цьому навчаться. Проте Perplexity відповідає майже без помилок.

Отже, з плюсів:

  • працює дійсно швидше, і дійсно НАБАГАТО менше споживає ресурсів
  • LogsQL приємний, багато можливостей
  • документація у VictoriaMetrics завжди досить детальна, з прикладами, добре структурована
  • підтримка у VictoriaMetrics теж чудова – і в GitHub Issues, і в Slack, і в Telegram – завжди можна поставити питання, і досить швидко отримати відповідь
  • на відміну від Grafana Loki – VictoriaLogs має власний Web UI, і як на мене – то це жирний плюс

З відносних мінусів:

  • і VictoriaLogs і Grafana data source все ще в Beta – тому можливі і якісь неочікувані проблеми, і не всі можливості поки що реалізовані
    • але знаючи команду VictoriaMetrics – вони досить швидко все роблять
  • відсутність RecordingRules та підтримки AWS S3 – це наразі те, що блокує особисто мене від того, аби повністю видалити Grafana Loki
    • але всі основні плюшки мають завезти до кінця 2024
  • ChatGPT/Gemini/Claude прям зовсім погано знають LogsQL, тому на їх допомогу очікувати не треба
    • але є допомога в Slack, і в Telegram самої VictoriaMetrics – і від комьюніті, і від команди розробників, ну і Perplexity непогано справляється