Сбор логов в Grafana Loki: Promtail, Alloy и Vector - сравнение и настройка (2026) | AdminWiki

Сбор логов в Grafana Loki: Promtail, Alloy и Vector - сравнение и настройка (2026)

11 сентября 2026 13 мин. чтения
Содержание статьи

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: что выбрать

ПараметрPromtailGrafana AlloyVector
СтатусEOL с марта 2025Активно развивается Grafana LabsАктивно развивается Datadog
Формат конфигаYAMLHCLTOML
Трансформацииpipeline_stagesкомпоненты и стадии stage.*VRL
Источникифайлы, journald, Docker, Kubernetes, syslogфайлы, journald, Docker, Kubernetes, syslog, Windows Eventsфайлы, journald, Docker, Kubernetes, syslog, HTTP, Kafka
Приемникитолько LokiLoki, Prometheus, OTLPLoki, 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.
Поделиться:
Сохранить гайд? В закладки браузера