Логирование
Kora использует slf4j-api как общий фасад логирования во всем фреймворке.
SLF4J отделяет код приложения от конкретной реализации логирования, а в качестве основной реализации Kora предполагает использование Logback.
Модуль логирования отвечает за получение Logger через стандартную фабрику SLF4J, управление уровнями логирования через конфигурацию Kora и передачу структурированных данных в записи логов.
Структурированные данные можно добавлять через StructuredArgument, Marker и MDC, чтобы они выводились вместе с обычным текстовым сообщением.
Пошаговый разбор перед справочным описанием смотрите в разделе Наблюдаемость.
Использование¶
Logger создается через фабрику SLF4J:
Конфигурация¶
Уровни логирования описываются классом LoggingConfig.
Конфигурация задает уровень для ROOT, пакета или конкретного класса:
Ключ секции можно записать как levels или как level — оба варианта принимаются как псевдонимы.
Имена логгеров можно перечислять плоскими строками с точками (как выше) или как вложенный объект; Kora разворачивает вложенные объекты в имена логгеров с точками.
Имя логгера ROOT сопоставляется без учета регистра, поэтому ROOT и root эквивалентны.
Например, в поставляемых примерах используется псевдоним level в единственном числе с вложенным root в нижнем регистре:
Note
Когда секция logging отсутствует, Kora не применяет собственную карту уровней.
Однако реализация Logback сбрасывает все логгеры при каждом (повторном) применении: ROOT нормализуется к INFO, а уровень каждого остального логгера очищается, чтобы он наследовался от родителя, после чего сверху применяются настроенные уровни.
В результате значение <root level="..."> из logback.xml при запуске фактически заменяется на INFO, если только уровень ROOT не задан в конфигурации.
Обновление уровней во время работы¶
Настроенные уровни применяются компонентом LoggingLevelRefresher — корневым компонентом, который при запуске сбрасывает все логгеры и заново применяет уровни из секции logging через LoggingLevelApplier.
Он повторно запускается при каждом обновлении конфигурации, поэтому когда активен наблюдатель конфигурации, изменение уровня в файле конфигурации вступает в силу во время работы без перезапуска приложения.
Параметры логирования конкретных модулей описываются в документации этих модулей, например HTTP сервер, HTTP клиент, gRPC-клиент.
Модули¶
Включение и выключение логирования конкретных модулей задается в конфигурации самих модулей через telemetry.logging.enabled.
По умолчанию логирование выключено для всех модулей, поэтому ниже приведена конфигурация для включения логирования большинства модулей:
db.telemetry.logging.enabled = true //(1)!
cassandra.telemetry.logging.enabled = true //(2)!
grpcServer.telemetry.logging.enabled = true //(3)!
httpServer.telemetry.logging.enabled = true //(4)!
scheduling.telemetry.logging.enabled = true //(5)!
grpcClient.SomeGrpcServiceName.telemetry.logging.enabled = true //(6)!
soapClient.SomeSoapServiceName.telemetry.logging.enabled = true //(7)!
SomePathToConfigHttpClient.telemetry.logging.enabled = true //(8)!
SomePathToConfigKafkaConsumer.telemetry.logging.enabled = true //(9)!
SomePathToConfigKafkaProducer.telemetry.logging.enabled = true //(10)!
- Логирование запросов к базе данных JDBC,
R2DBCилиVertx(по умолчанию:false). - Логирование запросов к базе данных Cassandra (по умолчанию:
false). - Логирование запросов gRPC-сервера (по умолчанию:
false). - Логирование запросов HTTP-сервера (по умолчанию:
false). - Логирование запусков планировщика (по умолчанию:
false). - Логирование запросов gRPC-клиента, указывается для конкретного сервиса (по умолчанию:
false). - Логирование запросов SOAP-клиента, указывается для конкретного сервиса (по умолчанию:
false). - Логирование запросов HTTP-клиента, указывается для конкретного клиента (по умолчанию:
false). - Логирование Kafka-потребителя, указывается для конкретного потребителя (по умолчанию:
false). - Логирование Kafka-производителя, указывается для конкретного производителя (по умолчанию:
false).
db.telemetry.logging.enabled: true #(1)!
cassandra.telemetry.logging.enabled: true #(2)!
grpcServer.telemetry.logging.enabled: true #(3)!
httpServer.telemetry.logging.enabled: true #(4)!
scheduling.telemetry.logging.enabled: true #(5)!
grpcClient.SomeGrpcServiceName.telemetry.logging.enabled: true #(6)!
soapClient.SomeSoapServiceName.telemetry.logging.enabled: true #(7)!
SomePathToConfigHttpClient.telemetry.logging.enabled: true #(8)!
SomePathToConfigKafkaConsumer.telemetry.logging.enabled: true #(9)!
SomePathToConfigKafkaProducer.telemetry.logging.enabled: true #(10)!
- Логирование запросов к базе данных JDBC,
R2DBCилиVertx(по умолчанию:false). - Логирование запросов к базе данных Cassandra (по умолчанию:
false). - Логирование запросов gRPC-сервера (по умолчанию:
false). - Логирование запросов HTTP-сервера (по умолчанию:
false). - Логирование запусков планировщика (по умолчанию:
false). - Логирование запросов gRPC-клиента, указывается для конкретного сервиса (по умолчанию:
false). - Логирование запросов SOAP-клиента, указывается для конкретного сервиса (по умолчанию:
false). - Логирование запросов HTTP-клиента, указывается для конкретного клиента (по умолчанию:
false). - Логирование Kafka-потребителя, указывается для конкретного потребителя (по умолчанию:
false). - Логирование Kafka-производителя, указывается для конкретного производителя (по умолчанию:
false).
Logback¶
Модуль предоставляет реализацию логирования на основе Logback, добавляет поддержку структурированных логов и позволяет управлять уровнями логирования через файл конфигурации.
Подключение¶
Зависимость build.gradle:
Модуль:
Зависимость build.gradle.kts:
Модуль:
Конфигурация¶
Logback настраивается через logback.xml, а в конфигурации Kora обычно указываются только уровни логирования.
Пример logback.xml:
<configuration debug="false">
<statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ru.tinkoff.kora.logging.logback.ConsoleTextRecordEncoder"/>
</appender>
<appender name="ASYNC" class="ru.tinkoff.kora.logging.logback.KoraAsyncAppender">
<appender-ref ref="STDOUT"/>
</appender>
<root level="WARN">
<appender-ref ref="ASYNC"/>
</root>
</configuration>
ConsoleTextRecordEncoder выводит текстовую запись лога и добавляет к ней структурированные данные из StructuredArgument, Marker, пар ключ-значение SLF4J и MDC.
Это единственный энкодер, поставляемый модулем: он формирует текст с добавленными структурированными полями, а не единый JSON-документ.
Запись выводится как обычная текстовая строка — timestamp level [thread] logger - <mdc prefixes>message — за которой, при наличии структурированных полей, следуют строки fieldName={json} с отступом табуляцией:
2026-07-02 10:15:30.123 INFO [main] r.t.k.example.SomeService - userId=42 user logged in
role="admin"
KoraAsyncAppender используется для асинхронной записи логов: он сохраняет значения MDC из текущего контекста в KoraLoggingEvent, чтобы они не терялись при передаче записи в другой поток.
Собственный шаблон¶
Вместо ConsoleTextRecordEncoder можно использовать стандартный PatternLayoutEncoder вместе с конвертерами, которые отображают структурированные данные Kora.
KoraMdcConverter отображает MDC контекста Kora, а KoraLoggingMarkerConverter отображает маркер StructuredArgument; зарегистрируйте их как слова преобразования и сошлитесь на них в шаблоне:
<configuration>
<conversionRule conversionWord="koraMdc" converterClass="ru.tinkoff.kora.logging.logback.KoraMdcConverter"/>
<conversionRule conversionWord="koraMarker" converterClass="ru.tinkoff.kora.logging.logback.KoraLoggingMarkerConverter"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger - %koraMdc%msg %koraMarker%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
Другая реализация¶
Kora использует slf4j-api как фасад логирования, поэтому можно подключить любую совместимую реализацию.
Базовый модуль добавляет общие компоненты для структурированных логов и управления уровнями логирования через файл конфигурации.
Подключение¶
Требуется подключить общий модуль логирования:
Зависимость build.gradle:
Модуль:
Зависимость build.gradle.kts:
Модуль:
Использование¶
При использовании собственной реализации предоставьте компонент LoggingLevelApplier, который умеет применять уровень логирования для указанного Logger и сбрасывать уровни к их исходному состоянию.
Если приложение использует структурированные данные, собственная реализация также должна поддерживать запись StructuredArgument, StructuredArgumentWriter и MDC.
Структурированные логи¶
Структурированные логи позволяют передавать в запись лога не только текст, но и именованные поля. Такие поля удобны для средств сбора логов и могут использоваться для поиска, фильтрации и построения представлений.
Передать структурированные данные в запись лога можно двумя способами:
- через
Marker; - через параметр сообщения.
Методы marker и arg также принимают значения Long, Integer, String, Boolean и Map<String, String>.
Для более сложных объектов передайте свой StructuredArgumentWriter или JsonWriter.
Marker¶
Marker добавляет структурированное поле к записи лога и не занимает место параметра в текстовом сообщении:
Параметр¶
Параметр сообщения добавляет структурированное поле через обычный массив аргументов SLF4J:
Сложный объект¶
Для значений, которые не являются String, числом, Boolean или Map<String, String>, передайте JsonWriter<T> (тот же генерируемый для типа писатель @Json) или необработанную лямбду StructuredArgumentWriter, которая пишет значение поля напрямую в JsonGenerator.
Обе перегрузки предоставляют и arg, и marker:
MDC¶
Структурированные данные можно прикрепить ко всем записям в рамках текущего контекста с помощью класса ru.tinkoff.kora.logging.common.MDC.
Значение будет добавляться в каждую запись лога, пока оно не будет удалено из MDC:
Импорт
Используйте ru.tinkoff.kora.logging.common.MDC, а не org.slf4j.MDC. Kora хранит свой MDC внутри контекста Kora, а не в thread-local, поэтому значения, помещенные в org.slf4j.MDC, не отображаются энкодерами Kora и не распространяются через асинхронные границы. Декларативную альтернативу смотрите в @Mdc.
put принимает значения String, Integer, Long и Boolean, а также необработанный StructuredArgumentWriter для произвольного JSON; типизированные значения отображаются как их JSON-тип, а не как текст.
Также есть перегрузка put(Context, key, value) для записи в явно переданный контекст вместо текущего:
Поскольку MDC находится в контексте Kora, он распространяется через асинхронные и реактивные границы вместе с контекстом.
Если используется AsyncAppender, для корректной передачи параметров MDC используйте ru.tinkoff.kora.logging.logback.KoraAsyncAppender.
Он делает снимок MDC текущего контекста в момент добавления и передает делегату ru.tinkoff.kora.logging.logback.KoraLoggingEvent, поэтому структурированный MDC сохраняется при передаче записи в асинхронный рабочий поток.