Централизованный сбор логов решает проблему, с которой сталкивается каждый системный администратор: необходимость подключаться по SSH к десяткам серверов и вручную выполнять grep по файлам. Grafana Loki меняет этот подход. Вы получаете единую точку входа для всех логов, возможность мгновенного поиска и, что важнее, автоматические оповещения о критических событиях. Эта статья проведет вас через полный цикл настройки: от запуска Loki и Promtail до создания алертов, срабатывающих при появлении конкретных ошибок в логах.
Связка Loki и Grafana дает результат, который невозможно получить при использовании разрозненных инструментов. Вы видите график падения производительности и тут же, в том же интерфейсе, находите строку лога, которая объясняет причину. Алертинг на основе LogQL-запросов замыкает цикл: система сама сообщает о проблеме до того, как её заметят пользователи. Такой подход сокращает время расследования инцидентов с часов до минут и позволяет выстроить проактивный мониторинг, где логи становятся источником данных для оповещений, а не просто архивом для post-mortem анализа.
Если вы уже используете Prometheus для метрик, Loki становится логичным продолжением вашего мониторингового стека. В отличие от ELK, Loki не индексирует содержимое логов, а работает с метаданными и лейблами. Это снижает требования к ресурсам и упрощает эксплуатацию. Подробнее о маршрутизации событий между компонентами мониторинга читайте в нашем руководстве по настройке потоков логов и метрик.
Зачем нужен централизованный сбор логов: преимущества Loki
Традиционный подход к работе с логами выглядит так: инцидент, SSH-подключение к серверу, tail -f /var/log/syslog, grep по ключевым словам. Когда серверов больше трёх, этот процесс превращается в кошмар. Добавьте сюда ротацию логов, разную скорость ответа серверов и отсутствие единого временного контекста. Централизованная система решает эти проблемы радикально.
Grafana Loki спроектирована как легковесная альтернатива Elasticsearch. Ключевое архитектурное решение: Loki индексирует только метаданные - лейблы, а содержимое логов хранит в сжатых чанках. Это даёт два практических преимущества. Первое - низкое потребление ресурсов: для небольшой инфраструктуры Loki работает на 512 МБ ОЗУ. Второе - скорость записи: агенты могут отправлять логи с минимальной задержкой, система не тратит время на построение полнотекстового индекса. Платой за это становится более медленный полнотекстовый поиск по сравнению с Elasticsearch, но на практике разница заметна только на объёмах в сотни гигабайт в день.
Архитектура Loki строится вокруг трёх компонентов. Distributor принимает входящие потоки логов, валидирует их и распределяет по инжесторам. Ingester накапливает логи в памяти и периодически сбрасывает их в долговременное хранилище - локальный диск, S3-совместимое объектное хранилище или Google Cloud Storage. Querier обрабатывает запросы от Grafana, собирая данные из инжесторов и долговременного хранилища. Promtail выступает агентом сбора: он читает файлы логов, journald или stdout Docker-контейнеров, обогащает записи лейблами и отправляет в Loki.
Лейблы - это краеугольный камень работы с Loki. В отличие от Elasticsearch, где вы можете искать по любому полю, Loki требует указывать хотя бы один лейбл в каждом запросе. Правильно спроектированная система лейблов - залог производительности. Типичный набор: host, service, environment. Избегайте создания лейблов с высокой кардинальностью, например, trace_id или user_id. Для этого есть полнотекстовый поиск. Если вы работаете с Kubernetes, посмотрите руководство по настройке Loki в Kubernetes, где разобраны тонкости работы с под-лейблами и автомасштабированием.
Установка и настройка Loki и Promtail
Начнём с подготовки окружения. Для работы связки Loki и Promtail на хосте с 2-4 ГБ ОЗУ и 2 ядрами CPU вы сможете обрабатывать до нескольких гигабайт логов в день. Точные требования зависят от количества лейблов и интенсивности запросов. Мы будем использовать Docker, так как это самый быстрый способ получить работающую систему. Если Docker не установлен, выполните стандартную установку из официального репозитория вашего дистрибутива.
Создайте директорию проекта и файлы конфигурации:
mkdir -p ~/loki-stack/config && cd ~/loki-stack
Установка Loki в Docker
Создайте конфигурационный файл Loki. Он определяет порты, настройки хранилища и политику хранения данных:
cat << 'EOF' > config/loki-config.yaml
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
instance_addr: 127.0.0.1
path_prefix: /tmp/loki
storage:
filesystem:
chunks_directory: /tmp/loki/chunks
rules_directory: /tmp/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
limits_config:
max_entries_limit_per_query: 5000
reject_old_samples: true
reject_old_samples_max_age: 168h
ruler:
alertmanager_url: http://localhost:9093
EOF
Эта конфигурация запускает Loki в однопользовательском режиме с хранением данных на локальной файловой системе. replication_factor: 1 означает отсутствие репликации - для production-среды с несколькими инстансами значение должно быть не менее 3. max_entries_limit_per_query: 5000 ограничивает количество возвращаемых записей на один запрос, защищая систему от случайных тяжёлых запросов.
Теперь создайте docker-compose.yml для запуска Loki:
cat << 'EOF' > docker-compose.yml
version: "3.8"
services:
loki:
image: grafana/loki:2.9.10
container_name: loki
ports:
- "3100:3100"
volumes:
- ./config/loki-config.yaml:/etc/loki/loki-config.yaml
- loki-data:/tmp/loki
command: -config.file=/etc/loki/loki-config.yaml
restart: unless-stopped
volumes:
loki-data:
EOF
Запустите Loki и проверьте, что он отвечает:
docker compose up -d loki
curl http://localhost:3100/ready
Ответ "Ready" означает, что Loki работает и готова принимать логи.
Конфигурация Promtail для сбора логов
Promtail - это агент, который читает логи и отправляет их в Loki. Он поддерживает несколько источников: статические файлы, journald, Docker-контейнеры через API сокета, а также Kubernetes pod logs. Создайте конфигурацию для сбора системных логов и логов Docker-контейнеров:
cat << 'EOF' > config/promtail-config.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
journal:
max_age: 12h
labels:
job: systemd
host: ${HOSTNAME}
relabel_configs:
- source_labels: ['__journal__systemd_unit']
target_label: 'unit'
- source_labels: ['__journal__hostname']
target_label: 'host'
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/(.*)'
target_label: 'container'
- source_labels: ['__meta_docker_container_label_com_docker_compose_service']
regex: '(.*)'
target_label: 'service'
pipeline_stages:
- docker: {}
- labels:
container:
service:
EOF
Разберём ключевые элементы. Секция scrape_configs определяет два задания сбора. Первое, system, читает journald и автоматически добавляет лейблы unit и host из полей journald. Второе, docker, использует механизм service discovery: Promtail подключается к Docker-сокету, обнаруживает запущенные контейнеры и собирает их stdout/stderr. pipeline_stages с директивой docker распаковывает JSON-формат логов Docker, извлекая временные метки и сообщения. Блок relabel_configs извлекает имя контейнера и сервиса Docker Compose в лейблы для последующей фильтрации.
Добавьте Promtail в docker-compose.yml:
promtail:
image: grafana/promtail:2.9.10
container_name: promtail
ports:
- "9080:9080"
volumes:
- ./config/promtail-config.yaml:/etc/promtail/promtail-config.yaml
- /var/log:/var/log:ro
- /var/run/docker.sock:/var/run/docker.sock
- /run/systemd/journal:/run/systemd/journal:ro
- /etc/machine-id:/etc/machine-id:ro
- promtail-positions:/tmp
command: -config.file=/etc/promtail/promtail-config.yaml
restart: unless-stopped
depends_on:
- loki
volumes:
loki-data:
promtail-positions:
Монтирование /var/run/docker.sock даёт Promtail доступ к API Docker для обнаружения контейнеров. Флаг :ro на системных директориях гарантирует, что агент не сможет изменять системные файлы. После запуска проверьте статус:
docker compose up -d promtail
curl http://localhost:9080/ready
curl http://localhost:3100/loki/api/v1/label
Последний запрос должен вернуть список лейблов, которые Promtail уже начал отправлять в Loki. Если список пуст, проверьте логи контейнера promtail: docker logs promtail.
Интеграция Loki с Grafana и визуализация логов
Grafana - это интерфейс, в котором метрики и логи объединяются в единую картину. Если у вас ещё нет Grafana, добавьте её в docker-compose.yml:
grafana:
image: grafana/grafana:10.4.7
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
restart: unless-stopped
depends_on:
- loki
volumes:
loki-data:
promtail-positions:
grafana-data:
После запуска откройте http://localhost:3000, войдите с логином admin и паролем admin. Перейдите в Connections → Data Sources → Add data source, найдите Loki и укажите URL http://loki:3100. Нажмите Save & test. Зелёная галочка подтверждает успешное подключение.
Основы LogQL для поиска и фильтрации
LogQL - это язык запросов Loki, построенный по образу PromQL. Запрос всегда начинается с stream selector - фильтра по лейблам в фигурных скобках, за которым опционально следует log pipeline - цепочка операторов фильтрации и преобразования содержимого.
Базовые конструкции, которые вам понадобятся с первого дня:
- Stream selector:
{job="docker", service="nginx"}- выбрать все логи контейнера с сервисом nginx. - Line filter:
{job="docker"} |= "error"- логи, содержащие строку error. Оператор != исключает строки, а |~ использует регулярное выражение:{job="docker"} |~ "(?i)error|fatal". - Label filter:
{job="docker"} | json | level = "error"- парсинг JSON и фильтрация по полю level. - Aggregation:
rate({job="docker"} |= "error" [5m])- количество ошибок в секунду за 5-минутное окно. - Count over time:
count_over_time({job="docker"} |= "error" [5m])- абсолютное количество строк с ошибкой за 5 минут.
Практический пример. У вас есть микросервис payments, и вы хотите найти все ошибки, связанные с базой данных, за исключением таймаутов соединений (потому что они обрабатываются retry-логикой):
{service="payments"} |= "error" != "connection timeout" | json | level = "error"
Этот запрос выбирает логи сервиса payments, фильтрует строки с "error", исключает упоминания таймаутов, парсит JSON и оставляет только записи с уровнем error. Результат - чистый список проблем, требующих внимания.
Создание дашборда для анализа логов
Перейдите в Dashboards → New → New Dashboard → Add visualization. Выберите источник данных Loki. Создадим три панели, которые образуют базовый дашборд для мониторинга логов.
Панель 1: Поток сырых логов. Выберите визуализацию Logs. В поле запроса введите {job="docker"}. Эта панель показывает все поступающие логи в реальном времени. Настройте отображение столбцов: Time, container, service, line. Включите опцию Enable log details, чтобы при клике на строку показывались все лейблы.
Панель 2: Частота ошибок. Выберите визуализацию Time series. Запрос: sum(rate({job="docker"} |= "error" [5m])) by (service). Эта панель показывает график количества ошибок в секунду с разбивкой по сервисам. Добавьте пороговую линию Threshold: если значение превышает 0.5 ошибок в секунду, линия становится красной.
Панель 3: Топ сервисов по количеству ошибок. Визуализация Table. Запрос: topk(5, sum(count_over_time({job="docker"} |= "error" [1h])) by (service)). Таблица показывает пять сервисов с наибольшим количеством ошибок за последний час. Настройте колонки: service (link to logs), Value. Клик по сервису должен открывать панель с сырыми логами, отфильтрованными по этому сервису.
Сохраните дашборд как "Обзор логов Docker". Теперь у вас есть готовая отправная точка для расследования инцидентов: вы видите общий поток, график аномалий и список проблемных сервисов в одном экране.
Настройка алертинга на основе логов в Grafana
Алертинг превращает логи из пассивного архива в активный инструмент мониторинга. Вместо того чтобы периодически проверять дашборды, вы получаете уведомление в момент возникновения проблемы. Grafana поддерживает создание алертов напрямую из запросов LogQL. Система периодически выполняет запрос, оценивает результат по заданным условиям и, если условие выполняется, отправляет уведомление через настроенный канал.
Перед созданием алертов настройте контактную точку - канал, куда будут приходить уведомления. Перейдите в Alerting → Contact points → New contact point. Выберите тип, например, Slack или Email. Для Slack потребуется Webhook URL, который вы получаете при создании Incoming Webhook в администрировании вашего рабочего пространства. Для Email укажите SMTP-сервер и адреса получателей. Сохраните контактную точку и отправьте тестовое уведомление кнопкой Test.
Создание правила алерта из запроса LogQL
Перейдите в Alerting → Alert rules → New alert rule. Введите имя правила, например, "Высокая частота ошибок payments". Выберите источник данных Loki. В поле запроса введите метрику, которая будет оцениваться. Рассмотрим два практических сценария.
Сценарий 1: Алерт по частоте ошибок. Сервис payments генерирует ошибки. Нормальный фоновый уровень - до 0.1 ошибок в секунду. Если частота превышает 1 ошибку в секунду в течение 5 минут, это требует немедленного вмешательства. Запрос:
sum(rate({service="payments"} |= "error" [5m]))
В секции Expressions настройте условие: IS ABOVE 1. В секции Set evaluation behavior укажите: Evaluate every 1m, Evaluate for 5m. Это означает, что запрос выполняется каждую минуту, но алерт сработает только если условие выполняется непрерывно в течение 5 минут. Такой подход защищает от ложных срабатываний при кратковременных всплесках.
Сценарий 2: Алерт по конкретному сообщению. Появление в логах строки "OutOfMemoryError" или "disk quota exceeded" должно вызывать немедленное оповещение независимо от частоты. Запрос:
count_over_time({job="system"} |~ "(?i)OutOfMemoryError|disk quota exceeded" [5m])
Условие: IS ABOVE 0. Это означает, что даже одно появление критического сообщения за 5 минут вызывает алерт.
В секции Configure labels and notifications добавьте описательные метки: severity: critical, team: backend. Они помогут маршрутизировать алерты в больших командах. В поле Summary напишите краткое описание, которое будет видно в уведомлении: "Обнаружена высокая частота ошибок в сервисе payments". В поле Description добавьте детали и ссылку на дашборд: "Частота ошибок: {{ $values.A.Value }} ошибок/сек. Дашборд: http://grafana:3000/d/logs-overview".
Настройка каналов уведомлений
Вернитесь к созданному правилу алерта и в секции Notifications выберите контактную точку, настроенную ранее. Grafana поддерживает несколько контактных точек для одного алерта - например, критичные алерты можно дублировать в Slack и на Email, а предупреждения отправлять только в Slack. Настройте Notification policies в Alerting → Notification policies, если требуется разная маршрутизация в зависимости от лейблов severity или team.
Для проверки работы алерта временно измените условие на заведомо выполняющееся, например, IS ABOVE -1. Через минуту вы должны получить тестовое уведомление. Не забудьте вернуть условие обратно. Если уведомление не пришло, проверьте логи Grafana: docker logs grafana | grep alerting.
Готовые примеры алертов для детектирования аномалий и security-инцидентов разобраны в руководстве по мониторингу на основе логов, где приведены конфигурации для Elasticsearch Watcher и Loki с интеграцией в Alertmanager.
Типичные проблемы и их решение
Promtail не видит логи Docker-контейнеров. Проверьте, что контейнер Promtail имеет доступ к Docker-сокету: docker exec promtail ls -la /var/run/docker.sock. Если файл отсутствует, проверьте монтирование в docker-compose.yml. Убедитесь, что у контейнеров, логи которых вы хотите собирать, настроен драйвер логирования json-file или journald - это драйверы по умолчанию. Контейнеры с драйвером none или syslog не будут видны через docker_sd_configs.
Loki не принимает логи. Проверьте сетевую доступность: docker exec promtail curl http://loki:3100/ready. Если соединение не устанавливается, убедитесь, что оба контейнера находятся в одной Docker-сети. docker compose по умолчанию создаёт общую сеть для сервисов, описанных в одном файле. Если вы запускали контейнеры отдельно, создайте сеть вручную: docker network create loki-net и добавьте network: loki-net в оба сервиса.
Высокое потребление ресурсов. Loki может потреблять значительный объём памяти при интенсивной записи или выполнении тяжёлых запросов. Настройте ограничения в docker-compose.yml: добавьте секцию deploy с resources limits memory: 512M для Loki. Ограничьте глубину поиска в конфигурации Loki: max_entries_limit_per_query: 1000. Для production-сред настройте retention - автоматическое удаление старых логов: добавьте в limits_config строку retention_period: 168h для хранения логов за 7 дней.
Алерты не срабатывают или срабатывают с задержкой. Проверьте состояние правила в Alerting → Alert rules. Статус Normal означает, что условие не выполняется. Pending - условие выполняется, но ещё не истёк период оценки (Evaluate for). Firing - алерт активен. Если правило в статусе Pending дольше ожидаемого, проверьте настройки Evaluation interval и Evaluate for. Учтите, что Grafana оценивает алерты на стороне сервера, а не в браузере - закрытие вкладки не влияет на работу алертов.
Дублирование логов. Если одни и те же записи появляются в Loki несколько раз, проверьте positions.yaml в томе Promtail. Этот файл хранит смещения в файлах логов, и его потеря приводит к повторной отправке всех данных. Убедитесь, что том promtail-positions смонтирован и не удаляется при перезапуске контейнера.
Заключение: единый интерфейс для метрик и логов
Вы развернули работающую систему централизованного сбора логов на базе Loki и Promtail, подключили её к Grafana и настроили алерты, срабатывающие при появлении критических событий. Теперь у вас есть единый интерфейс, где метрики из Prometheus и логи из Loki доступны в одном окне браузера. При расследовании инцидента вы видите всплеск на графике загрузки CPU, кликаете на него и тут же получаете соответствующий фрагмент логов - без переключения между инструментами и без SSH-подключений к серверам.
Дальнейшие шаги для развития системы: настройка долговременного хранения логов в S3-совместимом объектном хранилище, внедрение многотенантной архитектуры Loki для изоляции данных разных команд, добавление pipeline stages в Promtail для маскирования чувствительных данных перед отправкой. Для приложений на Python рекомендуем изучить руководство по структурированному логированию, где разобрана настройка JSON-логгеров для прямой интеграции с Loki. Если ваша инфраструктура включает сложные цепочки обработки логов, обратитесь к материалу по построению конвейера телеметрии с Fluentd и Prometheus.
Для развёртывания описанной конфигурации в production-окружении вам потребуется сервер с достаточным объёмом диска и памяти. Timeweb Cloud предоставляет облачные серверы с возможностью гибкого масштабирования ресурсов, что удобно при росте объёмов логов. Если в вашей практике встречаются задачи, требующие автоматизации анализа логов с помощью нейросетей, обратите внимание на AiTunnel - агрегатор API для доступа к GPT и Claude без VPN с оплатой в рублях.