Loki не читает файлы и journald сам: логи попадают в него через агент. Агент находит источники, читает новые строки, добавляет labels и отправляет батчи в HTTP API по пути /loki/api/v1/push. От его конфигурации зависят скорость поиска и стоимость хранения.
Короткий ответ для 2026 года. Для новых развертываний выбирайте Grafana Alloy. Promtail переведен в deprecated и не получает обновлений, Alloy занял его место как рекомендованный агент Grafana Labs. Vector подключайте там, где нужны сложные трансформации и отправка логов сразу в несколько систем.
Дальше: архитектура Loki, сравнение трех агентов, готовые конфигурации, работа с labels и парсингом, запросы LogQL, настройка retention и разбор типичных ошибок.
Зачем нужен агент сбора логов и как он работает с Loki
Loki хранит логи потоками. Поток - уникальная комбинация labels плюс временное окно. Distributor принимает записи, хеширует поток по labels и передает ingester, который собирает строки в чанки и складывает их в объектное хранилище. В индексе остаются только labels: содержимое строк не индексируется.
Архитектура Loki: почему labels важнее содержимого
Elasticsearch строит полнотекстовый индекс по каждому слову. Loki индексирует только labels, поэтому индекс в десятки раз меньше, а хранение дешевле. Плата за это - дисциплина в labels: чем их больше и чем выше кардинальность, тем больше потоков и памяти потребляют ingesters.
Пример. Метки app (20 значений), env (3), host (100) дают до 6000 потоков. Добавьте level с пятью значениями, и потолок вырастет до 30 000 потоков. Каждый поток ingester держит в памяти, а индекс получает отдельную запись. Если положить в метку request_id или user_id, число потоков улетит в миллионы, Loki начнет отклонять запись с ошибкой о превышении лимита потоков.
Высококардинальные поля не нужно превращать в labels. В Loki 3.x есть structured metadata: поля вроде trace_id или request_id прикрепляются к записи, не попадают в индекс и не создают новый поток. Фильтровать по ним можно в LogQL так: {app="api"} | trace_id="4f8c". Экспериментальные bloom filters в Loki 3.x ускоряют поиск по содержимому, но требуют отдельного включения и сборки индекса.
Базовый запрос всегда начинается с селектора потока: {app="api", env="prod"} |= "timeout" | json | status >= 500. Селектор обязан содержать хотя бы один непустой matcher: конструкция {job=~".+"} формально допустима, но заставляет Loki сканировать все чанки и часто упирается в лимиты.
Promtail, Alloy, Vector: краткий обзор и статус в 2026 году
Promtail - классический агент Grafana Labs. Простой YAML, pipeline stages для парсинга, поддержка файлов, journald (systemd), Docker и Kubernetes. 2 марта 2025 года Promtail достиг конца жизненного цикла: новых функций и исправлений нет, но существующие конфигурации продолжают работать.
Grafana Alloy - преемник Promtail и Grafana Agent. Конфигурация на HCL, компонентная модель, одна установка для метрик, логов, трейсов и профилей. В комплекте идет конвертер promtail-конфигов.
Vector - агент от Datadog на Rust. Конфигурация TOML, язык трансформаций VRL, источники и приемники десятков типов. Отправляет логи в Loki, Elasticsearch, ClickHouse, Kafka, S3 и другие системы.
Сравнение Promtail, Grafana Alloy и Vector: что выбрать
| Параметр | Promtail | Grafana Alloy | Vector |
|---|---|---|---|
| Статус | EOL с марта 2025 | Активно развивается Grafana Labs | Активно развивается Datadog |
| Формат конфига | YAML | HCL | TOML |
| Трансформации | pipeline_stages | компоненты и стадии stage.* | VRL |
| Источники | файлы, journald, Docker, Kubernetes, syslog | файлы, journald, Docker, Kubernetes, syslog, Windows Events | файлы, journald, Docker, Kubernetes, syslog, HTTP, Kafka |
| Приемники | только Loki | Loki, Prometheus, OTLP | Loki, Elasticsearch, ClickHouse, Kafka, S3 и другие |
| Буферизация | файл позиций и повторы | WAL и очередь | дисковая очередь, backpressure |
| Порог входа | низкий | средний | средний и высокий |
Практические сценарии. Сервер с десятком сервисов и одна Loki: хватит Alloy. Уже работает Promtail: не ломайте конвейер, но добавьте миграцию в план. Логи нужно фильтровать, обогащать, маскировать и раздавать в Loki, S3 и Elasticsearch одновременно: выбирайте Vector.
Если решение принимается на уровне платформы, а не агента, сравните Loki с Elasticsearch, OpenSearch и Graylog по стоимости и сложности: архитектура централизованного сбора логов в 2026 году.
Promtail: простота и deprecated-статус
Promtail остается самым простым входом в Loki. Минимальный конфиг занимает 15 строк, позиции чтения хранятся в файле positions.yaml, pipeline stages знакомы большинству администраторов. Слабые места: нет одного бинарника для метрик и трейсов, ограниченная маршрутизация (только Loki), отсутствие обновлений безопасности.
Кому подходит в 2026: тем, у кого Promtail уже работает и не требует изменений; для экспериментов и небольших стендов. Новые production-контуры лучше строить на Alloy.
Grafana Alloy: рекомендованный преемник
Alloy собирает логи, метрики, трейсы и профили в одном процессе. Конфигурация описывается блоками: источник (loki.source.file), обработчик (loki.process), приемник (loki.write). Конвертация promtail-конфига выполняется командой:
alloy convert --source-format=promtail --output=/etc/alloy/config.alloy /etc/promtail/config.yml
Конвертер покрывает типовые scrape_configs и pipeline_stages, но проверять результат нужно вручную: часть stage-ов и relabel-правил переносится не дословно.
Vector: мощь и гибкость для сложных сценариев
Vector обрабатывает сотни тысяч событий в секунду на одном узле, поддерживает дисковые буферы и подтверждения доставки. VRL позволяет парсить, обогащать, маскировать и маршрутизировать записи без внешних скриптов.
Типичные сценарии: несколько приемников, разная судьба для разных типов логов, высокая нагрузка, требования к аудиту. Схемы маршрутизации под высокие нагрузки разобраны в руководстве маршрутизация событий и логов под высокие нагрузки.
Настройка Promtail: установка и конфигурация
Установка Promtail на сервер
Promtail ставится из репозитория Grafana пакетом deb или rpm, либо распаковывается как бинарник. Пакетная установка создает systemd-юнит promtail.service и каталог /etc/promtail.
sudo apt-get update sudo apt-get install -y promtail sudo systemctl enable --now promtail sudo systemctl status promtail
Для бинарной установки скачайте архив promtail-linux-amd64.zip со страницы релизов Loki, распакуйте в /usr/local/bin и создайте юнит с параметром -config.file=/etc/promtail/config.yml. Позиции чтения храните на диске: /var/lib/promtail/positions.yaml.
Конфигурация scrape_configs и labels
Минимальный конфиг для сбора системных логов и Nginx:
server:
http_listen_port: 9080
positions:
filename: /var/lib/promtail/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets: [localhost]
labels:
job: syslog
host: web-01
__path__: /var/log/*.log
- job_name: nginx
static_configs:
- targets: [localhost]
labels:
job: nginx
host: web-01
__path__: /var/log/nginx/*.log
pipeline_stages:
- json:
expressions:
level: level
status: status
- labels:
level:
Метка __path__ служебная: Promtail использует ее для поиска файлов и не отправляет в Loki. Метки job и host попадают в поток. Для Docker применяйте docker_sd_configs, для Kubernetes - kubernetes_sd_configs с relabel-правилами по namespace, pod и container.
Не добавляйте в labels request_id, IP-адреса клиентов и другие значения с тысячью вариантов. Подробный разбор парсинга access.log и error.log с готовыми запросами LogQL и дашбордами есть в статье мониторинг логов Nginx с Loki и Promtail.
Настройка Grafana Alloy: конфигурация для Loki
Установка и базовый конфиг Alloy
Alloy ставится пакетом из репозитория Grafana или запускается в Docker. Конфиг лежит в /etc/alloy/config.alloy, веб-интерфейс доступен на порту 12345.
sudo apt-get install -y alloy sudo systemctl enable --now alloy sudo systemctl status alloy
Минимальная конфигурация отправки файловых логов в Loki:
loki.source.file "system" {
targets = [
{__path__ = "/var/log/*.log", job = "syslog", host = "web-01"},
]
forward_to = [loki.write.local.receiver]
}
loki.write "local" {
endpoint {
url = "http://loki:3100/loki/api/v1/push"
}
}
Если у вас уже есть promtail-конфиг, начните с конвертера:
alloy convert --source-format=promtail --output=/etc/alloy/alloy.alloy /etc/promtail/config.yml
После конвертации проверьте блоки loki.source.file, loki.process и loki.write: часть настроек требует ручной правки. Миграция без простоя: запустите Alloy рядом с Promtail, убедитесь, что записи идут в те же потоки, и только потом остановите старый агент.
Сбор логов из файлов и Kubernetes
Парсинг и добавление меток на стороне Alloy выполняет компонент loki.process:
loki.source.file "nginx" {
targets = [
{__path__ = "/var/log/nginx/access.log", job = "nginx", host = "web-01"},
]
forward_to = [loki.process.nginx.receiver]
}
loki.process "nginx" {
stage.json {
expressions = {status = "status", request_time = "request_time"}
}
stage.labels {
values = {status = "status"}
}
forward_to = [loki.write.local.receiver]
}
Для Kubernetes используются компоненты discovery.kubernetes, discovery.relabel и loki.source.kubernetes:
discovery.kubernetes "pods" {
role = "pod"
}
discovery.relabel "pod_logs" {
targets = discovery.kubernetes.pods.targets
rule {
source_labels = ["__meta_kubernetes_namespace"]
target_label = "namespace"
}
rule {
source_labels = ["__meta_kubernetes_pod_name"]
target_label = "pod"
}
rule {
source_labels = ["__meta_kubernetes_pod_container_name"]
target_label = "container"
}
}
loki.source.kubernetes "pods" {
targets = discovery.relabel.pod_logs.output
forward_to = [loki.write.local.receiver]
}
Логи systemd собирает компонент loki.source.journal, он читает journald напрямую и не требует доступа к файлам. Полный сценарий для кластера, включая Helm, S3-хранилище и алерты, разобран в статье Grafana Loki в Kubernetes.
Настройка Vector: конфигурация для Loki
Установка и базовый конфиг Vector
Vector поставляется пакетами deb и rpm, Docker-образом и Helm-чартом. Конфигурация хранится в /etc/vector/vector.toml, проверка синтаксиса: vector validate /etc/vector/vector.toml.
sudo systemctl enable --now vector sudo systemctl status vector vector validate /etc/vector/vector.toml
Конвейер для сбора файлов и отправки в Loki:
[sources.syslog_files]
type = "file"
include = ["/var/log/*.log"]
read_from = "beginning"
[transforms.parse]
type = "remap"
inputs = ["syslog_files"]
source = '''
parsed, err = parse_json(.message)
if err == null {
.level = parsed.level
}
if !exists(.level) {
.level = "info"
}
'''
[sinks.loki]
type = "loki"
inputs = ["parse"]
endpoint = "http://loki:3100"
encoding.codec = "text"
tenant_id = "team-a"
out_of_order_action = "accept"
labels = {job = "syslog", host = "web-01", level = "{{ level }}"}
Приемник loki принимает базовый URL, путь /loki/api/v1/push Vector добавляет сам. Поле labels формирует поток, tenant_id задает тенанта в multi-tenant Loki, out_of_order_action управляет поведением при устаревшей метке времени (accept или drop).
Трансформации и фильтрация в Vector
Фильтр отсекает лишние записи до отправки в Loki:
[transforms.only_errors] type = "filter" inputs = ["parse"] condition = '.level == "error" or .level == "warn"'
Маршрутизация разводит логи по разным приемникам:
[transforms.routing] type = "route" inputs = ["parse"] [transforms.routing.route.errors] condition = '.level == "error"' [transforms.routing.route.other] condition = 'true'
Маскирование секретов выполняется VRL-функцией replace:
source = 'replace(.message, r"(?i)api_key=[^ ]+", "api_key=***")'
Для защиты от потери данных при недоступности Loki включите дисковый буфер:
[sinks.loki.buffer] type = "disk" max_size = 268435456 when_full = "block"
Буфер на 256 МБ переживает перезапуск Vector и сетевые сбои. Как встроить Vector в общий конвейер телеметрии вместе с Fluentd и Prometheus, показано в руководстве маршрутизация логов и метрик в DevOps.
Labels, парсинг и фильтрация: практические примеры
Управление кардинальностью labels
Правило простое: в labels попадают только поля с конечным и небольшим набором значений. Подходят app, env, job, namespace, container, host, level. Не подходят user_id, request_id, session_id, trace_id, IP-адреса, полные URL с параметрами.
Считайте потоки заранее: произведение числа значений всех меток дает верхнюю границу. 50 приложений, 4 окружения, 200 хостов и 4 уровня логирования дают до 160 000 потоков. Ingester держит состояние каждого активного потока в памяти, поэтому такие числа приводят к OOM и ошибкам maximum active stream limit exceeded.
Динамические поля передавайте через structured metadata: Promtail и Alloy прикрепляют их к записи без создания потока. В Promtail это стадия structured_metadata, в Alloy - stage.structured_metadata. Поля остаются доступны для фильтрации: {app="api"} | request_id="a1b2c3".
Второй прием - отбрасывать мусор на агенте. Health-check, GET /health, kube-probe, debug-строки не несут пользы и занимают место. Promtail: стадии match и drop; Alloy: stage.drop; Vector: трансформ filter.
Парсинг логов: JSON, logfmt, regex
Promtail разбирает форматы стадиями pipeline:
pipeline_stages:
- json:
expressions:
level: level
trace_id: trace_id
- logfmt:
mapping:
level: level
msg: message
- regex:
expression: '^(?P<ip>[^ ]+) [^ ]+ [^ ]+ (?P<method>[A-Z]+)'
- labels:
level:
- structured_metadata:
trace_id:
В Alloy те же операции выполняют стадии stage.json, stage.logfmt, stage.regex, stage.labels, stage.structured_metadata внутри loki.process. В Vector используются функции VRL:
parsed, err = parse_logfmt(.message)
if err == null {
.level = parsed.level
.msg = parsed.msg
}
Метки извлекайте из стабильных полей, остальное оставляйте в теле записи. Парсинг на агенте снижает нагрузку на Loki: отфильтрованные и обогащенные записи приходят уже готовыми к поиску.
Поиск и фильтрация логов в Grafana
Основы LogQL: запросы и фильтры
Запрос строится из селектора потока и цепочки операций:
- {job="nginx"} |= "error" - строки с подстрокой error.
- {job="nginx"} != "health" - исключить проверки.
- {job="nginx"} |~ " 5[0-9]{2} " - регулярное выражение для кодов 5xx.
- {app="api"} | json | level="error" - разбор JSON и фильтр по полю.
- {app="api"} | logfmt | duration > 2s - разбор logfmt и числовое сравнение.
- sum by (level) (count_over_time({app="api"} | json [5m])) - количество записей по уровням за 5 минут.
- topk(5, sum by (path) (count_over_time({job="nginx"} |= "error" [1h]))) - топ-5 путей с ошибками.
Порядок операций влияет на скорость. Сначала сужайте поток селектором и строковыми фильтрами, потом подключайте парсеры: {job="nginx"} |= "error" | json работает быстрее, чем {job="nginx"} | json |= "error".
Создание дашбордов для логов
В Grafana соберите панель Logs с запросом {namespace="$namespace", app=~"$app"}, переменные $namespace и $app задайте через label_values. Рядом поставьте график с rate({job="nginx"} |= "error" [5m]) и панель топ-ошибок.
Алерт на всплеск ошибок: sum(rate({job="nginx"} |= "error" [5m])) > 10 с удержанием for: 5m. Перед сохранением проверьте запрос в Explore на коротком интервале: так вы поймете реальную стоимость сканирования чанков.
Срок хранения и ограничения Loki
Настройка retention и хранения
Retention задается глобально и по потокам. Глобальный срок на 90 дней и удаление старых чанков включаются так:
limits_config:
retention_period: 2160h
max_query_series: 1000
compactor:
working_directory: /var/loki/compactor
retention_enabled: true
delete_request_store: s3
common:
storage:
s3:
bucketnames: loki-data
region: eu-central-1
access_key_id: ${S3_ACCESS_KEY}
secret_access_key: ${S3_SECRET_KEY}
Без включенного compactor и delete_request_store удаление не работает: файлы остаются в бакете. Для разных потоков задайте отдельные сроки:
limits_config:
retention_stream:
- selector: '{namespace="prod"}'
priority: 1
period: 4320h
- selector: '{namespace="dev"}'
priority: 2
period: 360h
Чанки и индекс складывайте в S3-совместимое объектное хранилище: локальный диск подходит только для тестов. Для продакшена подойдет облачное хранилище, например Timeweb Cloud: объектное хранилище и управляемый Kubernetes позволяют держать Loki и агентов рядом с источником логов.
Сжатие дает 5-10 крат на текстовых логах: гигабайты сырых записей превращаются в сотни мегабайт в бакете. Проверяйте фактический коэффициент на своих логах, он зависит от формата и повторов.
Ограничения Loki и как их обойти
Loki не индексирует содержимое строк. Поиск по подстроке выполняется сканированием чанков выбранных потоков, поэтому широкие селекторы вроде {job=~".+"} работают медленно. Стандартные лимиты: max_query_series 500, max_entries_limit_per_query 5000 строк на запрос, скорость приема ingestion_rate_mb 4 МБ/с на тенанта. После превышения Loki отвечает ошибкой 429.
Что помогает: сужайте селектор и временной диапазон; включайте structured metadata вместо новых меток; используйте bloom filters для частых строковых фильтров; контролируйте кардинальность по метрике loki_ingester_memory_streams. Число потоков растет вместе с числом уникальных комбинаций меток, поэтому новые метки добавляйте после расчета худшего случая.
Типичные ошибки и их решение
Логи не отправляются в Loki
Проверяйте по порядку: агент, доступность Loki, права, лимиты.
sudo systemctl status promtail sudo journalctl -u promtail -n 50 curl http://loki:3100/ready
- Агент запущен, но читает не те файлы: проверьте путь в __path__ и права пользователя promtail, добавьте его в группу adm.
- Ошибка 401 или 403: включена аутентификация, в clients.url нужен заголовок Authorization или корректный tenant.
- Ошибка 429: превышен лимит приема, поднимите ingestion_rate_mb или сократите поток фильтрацией на агенте.
- Out of order: записи с меткой времени старее последней в потоке. В Vector помогает параметр out_of_order_action, в Promtail проверьте ротацию файлов и порядок чтения.
- Файл positions.yaml поврежден: удалите его и перезапустите агент, логи перечитаются.
Проблемы с производительностью Loki
Рост памяти ingesters обычно связан с числом потоков. Смотрите loki_ingester_memory_streams, loki_distributor_bytes_received_total и loki_ingester_chunks_created_total. Если метрика потоков растет без остановки, ищите метку с высокой кардинальностью: чаще всего это pod, request_id или путь с ID.
Практические шаги: сократите число меток до 5-7 на поток; отбрасывайте мусор на агенте; настройте retention; добавьте ресурсы ingester или шардируйте потоки; для тяжелых запросов используйте отдельный read path. Ускорение поиска дают bloom filters и structured metadata, но оба механизма требуют аккуратной настройки.
Чек-лист перед продакшеном: labels без динамических значений; structured metadata для trace_id и request_id; фильтрация health-check на агенте; retention и compactor включены; бакет S3 проверен на запись и удаление; алерты на 429 и рост loki_ingester_memory_streams.