Как централизовать логи в контейнеризированных .NET приложениях с помощью FluentD и Konso
Когда приложение падает в проде, а вы не знаете почему — первое место, куда вы идёте, это логи. Но если сервисов много, всё в Docker, а развёрнуто это на локалке, в клауде или CI-сервере — быстро найти нужный лог становится настоящей головной болью.
Централизованный сбор логов решает эту проблему. В этой статье мы покажем, как настроить логирование для .NET-приложения, развернутого через docker-compose
, с помощью FluentD и платформы Konso — готового сервиса для хранения, поиска и анализа логов.
Подходы к сбору логов с приложений
Платформа Konso поддерживает два основных способа сбора логов: на уровне кода и на уровне инфраструктуры. Оба подхода можно использовать по отдельности или комбинировать, в зависимости от потребностей команды и зрелости инфраструктуры.
🔹 1. Сбор логов из самого приложения
Самый простой способ — использовать библиотеку Konso.Clients.Logging
, которая отправляет логи напрямую в хранилище Konso (через HTTP или gRPC).
✅ Преимущества:
- Не требует знаний DevOps — всё на уровне кода.
- Простая интеграция — установка пакета и конфигурация пары строк.
- Максимальный контроль — структура, уровень и контекст логов под вашим контролем.
- Хорошо подходит для frontend/backend команд, которые не взаимодействуют с инфраструктурой.
⚠️ Недостатки:
- Нужно вносить изменения в код.
- Может влиять на производительность без буферизации.
- Есть риск потери логов при сбоях сети или недоступности сервиса.
- Требуется настраивать в каждом приложении отдельно.
👉 Репозиторий клиента на GitHub
🔹 2. Сбор логов на уровне инфраструктуры (FluentD и др.)
Альтернативный подход — собирать логи на уровне платформы. Используются инструменты вроде FluentD, Fluent Bit, Logstash и т.п., которые читают stdout/stderr
контейнеров, файлы логов или данные от системных демонов.
✅ Преимущества:
- Изоляция логики логирования — приложения не "знают", как их логи обрабатываются.
- Поддержка legacy — можно собирать логи даже с устаревших приложений без изменений в коде.
- Гибкость — мощная маршрутизация, фильтрация и агрегация логов.
- Отлично подходит для DevOps-команд и production-инфраструктур.
⚠️ Недостатки:
- Сложнее конфигурировать — нужно разбираться в пайплайнах, парсинге и т.п.
- Требует понимания Docker, volume'ов, systemd и других системных нюансов.
- Сложнее добиться богатого контекста логов без хорошей стандартизации формата.
- Нужно следить за производительностью самого лог-пайплайна.
Зачем собирать логи вообще?
Логи — это взгляд внутрь системы. Без них мы в темноте. Они помогают понять, что происходило с приложением в прошлом, что происходит сейчас, и как на это реагировать.
Вот основные причины, почему стоит собирать логи:
- Диагностика и отладка — логи позволяют понять, где именно что-то пошло не так.
- Мониторинг в реальном времени — наблюдение за аномалиями, ошибками и неожиданным поведением.
- Аудит и безопасность — кто, что и когда сделал. Это особенно важно при расследовании инцидентов.
- Аналитика — использование логов для выявления закономерностей и оптимизации.
- Автоматизация — запуск действий по событиям в логах (автоскейлинг, оповещения и т.п.).
Зачем нужна централизация логов?
Централизация логов — это как единая камера наблюдения. Всё видно сразу и из одного места.
Когда у вас десятки контейнеров и микросервисов, локальные логи быстро превращаются в хаос. Централизованный подход помогает:
- Создать единый источник истины — не нужно гадать, где искать нужный лог.
- Облегчить поиск и фильтрацию — trace ID, имя сервиса, дата, уровень — всё доступно.
- Коррелировать события — отследить, как один запрос прошёл через всю систему.
- Управлять хранением — ротация, архивирование, удаление — автоматически.
- Анализировать и визуализировать — дашборды, метрики, отчёты.
- Повысить безопасность — никто не сможет тихо удалить или подменить локальный лог.
Практика: собираем логи из .NET приложения в docker-compose с помощью FluentD
Рассмотрим, как на практике собрать логи .NET-приложения, запущенного через docker-compose
, и передать их в Konso с помощью FluentD.
Шаг 1. Включаем JSON-логгинг в .NET
В .NET 8 и выше можно настроить вывод логов в формате JSON без сторонних библиотек:
builder.Logging.AddConsole(options => {
options.FormatterName = "json";
});
Шаг 2. Собираем собственный образ FluentD с нужным плагином
Для трансформации записей понадобится плагин fluent-plugin-record-modifier
. Добавим его в Dockerfile:
FROM fluent/fluentd:v1.18-1
USER root
RUN gem install fluent-plugin-record-modifier --no-document
USER fluent
Шаг 3. Конфигурация docker-compose.yaml
version: '3'
services:
fluentd:
build:
context: .
dockerfile: Dockerfile.fluentd
ports:
- "24224:24224"
- "24224:24224/udp"
volumes:
- ./fluentd/fluentd.conf:/fluentd/etc/fluentd.conf
- /var/lib/docker/containers:/var/lib/docker/containers:ro
environment:
- FLUENTD_CONF=fluentd.conf
networks:
- blog-network
web:
image: <your app image>
container_name: blog-web
environment:
ASPNETCORE_ENVIRONMENT: Production
logging:
driver: "fluentd"
options:
fluentd-address: localhost:24224
tag: blog.web
networks:
- blog-network
networks:
blog-network:
driver: bridge
Шаг 4. Конфигурация FluentD
Создайте файл fluentd.conf
:
<source>
@type forward
port 24224
bind 0.0.0.0
</source>
<filter blog.web>
@type parser
key_name log
reserve_data false
<parse>
@type json
</parse>
</filter>
<filter blog.web>
@type grep
<regexp>
key LogLevel
pattern ^(Error|Warning)$
</regexp>
</filter>
<filter blog.web>
@type record_transformer
enable_ruby true
<record>
timeStamp ${Time.now.to_i}
level ${record["LogLevel"]}
message ${record["Message"] || record["State"]["Message"]}
machineName vm
eventId ${record["EventId"]}
appName blog-web
env production
</record>
</filter>
<filter blog.web>
@type record_modifier
remove_keys EventId,Message,LogLevel,State,Category
</filter>
<match blog.web>
@type http
endpoint https://apis-spb.konso.io/logs/<бакет>
http_method post
headers {"x-api-key":"<ключ>"}
content_type application/json
format json
<buffer>
flush_interval 5s
chunk_limit_records 1
chunk_limit_size 128k
retry_max_times 5
</buffer>
</match>
Шаг 5. Запуск и проверка
docker compose up -d
docker compose logs fluentd
При необходимости можно перезапустить FluentD:
docker compose restart fluentd
Шаг 6. Просмотр логов в Konso
Перейдите в интерфейс Konso Logs > Просмотр и отфильтруйте логи по нужным критериям: имя приложения, уровень, время, окружение.
Заключение
Централизация логов — это must-have для любой современной системы. В этой статье мы показали, как собрать логи из .NET-приложения в Docker через FluentD и передать их в Konso. Такой подход облегчает мониторинг, отладку и повышает прозрачность всей системы.
Попробуйте у себя — и делитесь фидбэком!