Elasticsearch индексирует полный текст каждой строки лога — мощно, но дорого по диску и CPU при больших объёмах. Loki поступает наоборот: индексирует только лейблы (как Prometheus индексирует метрики), а сам текст лежит сжатыми блоками без полнотекстового индекса.
Запрос на LogQL всегда начинается с селектора стрима — тех же лейблов, что у метрик:
{container="query-frontend", namespace="loki-dev"}
Дальше через | навешивается пайплайн обработки — фильтрация по тексту, парсинг структурированных полей, фильтрация по извлечённым полям:
{container="query-frontend", namespace="loki-dev"} |= "metrics.go" | logfmt | duration > 10s
|= "metrics.go" — построчный фильтр по подстроке (дешёвый, работает до парсинга), | logfmt — распарсить строку в поля вида key=value, duration > 10s — фильтр уже по значению распарсенного поля, применяется после парсинга.
Ровно поэтому важно, какие лейблы выбраны при сборе логов (Promtail или Alloy их проставляют): {container=...} сужает поиск до конкретного набора файлов/стримов, а сам текстовый поиск (|= "error") внутри уже выбранных стримов — это построчный скан без индекса. Слишком общий селектор ({} или один лейбл на миллион строк) означает полный скан всего объёма логов за период — на больших инсталляциях это буквально разница между секундами и минутами ответа.
Практическое следствие: лейблы стоит выбирать по тому, как реально будут фильтровать логи (app, namespace, pod), а не по всему, что можно вытащить из строки — высококардинальные поля (user_id, request_id) вообще не должны становиться лейблами, для них есть парсинг внутри пайплайна (logfmt/json + фильтр), а не отдельный лейбл на каждое уникальное значение.
#prometheus #grafana #lgtm
