Логотип Индевлабс

Как централизовать логи в контейнеризированных .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 и других системных нюансов.
  • Сложнее добиться богатого контекста логов без хорошей стандартизации формата.
  • Нужно следить за производительностью самого лог-пайплайна.

Зачем собирать логи вообще?

Логи — это взгляд внутрь системы. Без них мы в темноте. Они помогают понять, что происходило с приложением в прошлом, что происходит сейчас, и как на это реагировать.

Вот основные причины, почему стоит собирать логи:

  1. Диагностика и отладка — логи позволяют понять, где именно что-то пошло не так.
  2. Мониторинг в реальном времени — наблюдение за аномалиями, ошибками и неожиданным поведением.
  3. Аудит и безопасность — кто, что и когда сделал. Это особенно важно при расследовании инцидентов.
  4. Аналитика — использование логов для выявления закономерностей и оптимизации.
  5. Автоматизация — запуск действий по событиям в логах (автоскейлинг, оповещения и т.п.).

Зачем нужна централизация логов?

Централизация логов — это как единая камера наблюдения. Всё видно сразу и из одного места.

Когда у вас десятки контейнеров и микросервисов, локальные логи быстро превращаются в хаос. Централизованный подход помогает:

  1. Создать единый источник истины — не нужно гадать, где искать нужный лог.
  2. Облегчить поиск и фильтрацию — trace ID, имя сервиса, дата, уровень — всё доступно.
  3. Коррелировать события — отследить, как один запрос прошёл через всю систему.
  4. Управлять хранением — ротация, архивирование, удаление — автоматически.
  5. Анализировать и визуализировать — дашборды, метрики, отчёты.
  6. Повысить безопасность — никто не сможет тихо удалить или подменить локальный лог.

Практика: собираем логи из .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. Такой подход облегчает мониторинг, отладку и повышает прозрачность всей системы.

Попробуйте у себя — и делитесь фидбэком!