В одном предложении: после того, как logback реализует базовую функцию вывода журнала в файл, в практике предприятия будут другие дополнительные требования.В этой статье описывается расширенное использование logback.
1. Введение
Предыдущая статья《Корпоративная практика вывода журнала Springboot + logback (включена)"Описывает использование и настройку логбэка, а также реализует функцию вывода в независимые файлы по уровню лога. Однако в корпоративной практике будут другие требования, такие как необходимость использования разных уровней журналов в нескольких средах, как справиться с низкой производительностью вывода журналов, как отслеживать журналы запросов в распределенных системах и т. д. Для этих требований logback предоставляет соответствующие функции, в этой статье объясняется реализация этих требований. В частности, он включает в себя следующее:
- Повышение производительности с помощью асинхронного ведения журнала выходных данных
- Logback выбирает конфигурацию уровня журнала в нескольких средах.
- Отслеживание запросов в распределенной системе с помощью MDC
Чтобы увидеть исходный код, эта статьяПример адреса проекта:https://github.com/mianshenglee/my-example/tree/master/springboot-logback-demo
2. Вывод данных о состоянии журнала
logback официальная документацияОбратите внимание, что настоятельно рекомендуется включить вывод данных о состоянии журнала, что в значительной степени поможет нам в диагностике проблем, связанных с журналом. С помощью этих данных о состоянии вы можете узнать состояние загрузки файла конфигурации журнала, соответствующего приложения в конфигурации и состояние загрузки регистратора. Есть два способа включить вывод данных о состоянии:
- Задайте свойства в корневом элементе (конфигурация)
debug="true"
- Добавить элемент ( statusListener ), использование класса
OnConsoleStatusListener
. следующим образом:
<!-- 输出logback的本身状态数据 -->
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
Обратите внимание, что вы можете выбрать один из двух.Отладка здесь не имеет ничего общего с уровнем журнала в файле конфигурации и используется только для указания выходных данных о состоянии.
В этом примере, используя второй метод (добавлениеstatusListener
элемент), после добавления вывод выглядит следующим образом:
3. журнал асинхронного вывода
3.1 Конфигурация асинхронного выхода
В соответствии с предыдущей конфигурацией журнала, вывод журнала в файл выводится синхронно, то есть каждый вывод будет напрямую записывать операции ввода-вывода в файл на диске, что приводит к блокировке и ненужной потере производительности. Конечно, для общих приложений влияние невелико, но для приложений с высокой степенью параллелизма по-прежнему необходимо оптимизировать производительность. logback предоставляет AsyncAppender для асинхронного вывода журнала. Способ асинхронного вывода логов очень прост, добавьте лог на основе асинхронной записиappender
, и укажите на ранее настроенныйappender
Вот и все. См. следующую конфигурацию:
<!-- 异步输出 -->
<appender name="ASYNCDEBUG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 默认如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志,若要保留全部日志,设置为0 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1024</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="DEBUGFILE"/>
<includeCallerData>true</includeCallerData>
</appender>
//INFO 结构同上,略
//WARN 结构同上,略
//ERROR 结构同上,略
<!-- 异步输出关联到root -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="ASYNCDEBUG" />
...//略
</root>
Параметры, которые необходимо установить в соответствии с AsyncAppender:
Имя свойства | Типы | описывать |
---|---|---|
queueSize | int |
Максимальная емкость очереди, по умолчанию 256 |
discardingThreshold | int |
По умолчанию, когда в очереди осталось 20% емкости, журналы с уровнями TRACE, DEBUG и INFO будут удалены, и останутся только журналы с уровнями WARN и ERROR. Чтобы сохранить все события, установите 0 |
includeCallerData | boolean |
Извлечение данных вызывающего абонента является относительно дорогостоящим. Для повышения производительности информация о вызывающем абоненте по умолчанию не собирается. По умолчанию только такие вещи, как имя потока илиMDCЭти «дешевые» данные реплицируются. Если установлено значение true, приложение будет содержать информацию о вызывающем абоненте. |
maxFlushTime | int |
В зависимости от глубины и задержки указанной очереди добавления,AsyncAppender Очистка очереди может занять много времени. когдаLoggerContext при остановке,AsyncAppender stop Метод ожидает завершения времени, указанного рабочим потоком. Используйте maxFlushTime, чтобы указать максимальное время сброса в миллисекундах. События, не обработанные в течение указанного времени, будут отброшены. Смысл значения этого свойства такой же, как иThread.join(long)такой же |
neverBlock | boolean |
По умолчанию false, приложение будет блокироваться, а не отбрасывать сообщения, когда очередь заполнена. Установите значение true, приложение не будет блокировать ваше приложение и отклонит сообщение. |
3.2 Принцип асинхронного вывода
AsyncAppender реализуется путем блокировки очереди (BlockingQueue
), чтобы избежать прямого вывода лога в файл, а выводить события лога вBlockingQueue
, а затем запустить новый рабочий поток. Основной поток не блокируется. Рабочий поток получает журнал для записи из очереди и асинхронно выводит его в соответствующее место.
4. Конфигурация журнала в мультисреде springboot
Используйте Springboot для разработки приложений, поддерживайте поддержку конфигурации для нескольких сред, просто нажмитеapplication-*.properties
format для добавления файла конфигурации, затем используйтеspring.profiles.active
Просто укажите среду. Точно так же вывод журнала, как правило, в среде разработки, использует уровень DEBUG для проверки наличия проблем, в то время как в производственной среде выводятся только журналы уровня ERROR. Как показано ниже, профиль определяет среду разработки как dev, а производственную среду как prod:
<!-- 开发环境:debug级别-->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
...//略
</root>
</springProfile>
<!-- 生产环境:error级别-->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="STDOUT"/>
...//略
</root>
</springProfile>
Вышеупомянутая конфигурация предназначена для установки root (конечно, можно использовать и другие элементы). После этой настройкиspring.profiles.active
Вместо этого решите использовать указанный вывод уровня журнала.
Фактически, logback также поддерживает использование элементов if в форме if-then-else в сочетании с атрибутом условия для достижения условной обработки. Заинтересованные читатели могут ознакомиться с официальной документацией "Условная обработка конфигурационных файлов"
5. Запрос на отслеживание распределенного приложения MDC
При использовании Springboot для разработки распределенных приложений многие из них являются микросервисами.Когда приходит запрос, может потребоваться вызов нескольких сервисов для выполнения действия запроса. При запросе логов, особенно в случае большого количества запросов, логов много, и трудно найти логи, соответствующие запросам, что затрудняет поиск и отслеживание логов. Для таких проблем logback предоставляет MDC (отображение диагностического контекста Mapped Diagnostic Contexts), MDC позволяет разработчикамДиагностический контекстЭти сообщения используются внутри ThreadLocal для обеспечения изоляции данных между потоками и управления контекстной информацией каждого потока. И в выводе лога можно передать идентификатор%X{key}
для вывода содержимого настроек в MDC. Поэтому, когда распределенное приложение отслеживает запросы, идеи реализации следующие:
- В веб-приложении добавьте перехватчик, а при поступлении запроса добавьте уникальный идентификатор как
request-id
, чтобы идентифицировать этот запрос. - Добавь это
request-id
в MDC - Если вам нужно вызвать другие службы, поставьте это
request-id
как параметр заголовка - В вывод журнала добавьте это
request-id
вывод как идентификатор - После завершения запроса очистите это
request-id
5.1 Добавить перехватчик
5.1.1 Реализация перехватчика
Через перехватчик добавить перед запросомrequest-id
и поместите его в MDC; действие очищается после завершения запроса. добавить пакетinterceptor
Сохраните класс перехватчика, определение класса выглядит следующим образом:
@Slf4j
@Component
public class RequestIdTraceInterceptor implements HandlerInterceptor {
public static final String REQUEST_ID_KEY = "request-id";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
MDC.put(REQUEST_ID_KEY, getRequestId(request));
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//把requestId添加到响应头,以便其它应用使用
response.addHeader(REQUEST_ID_KEY, MDC.get(REQUEST_ID_KEY));
//请求完成,从MDC中移除requestId
MDC.remove(REQUEST_ID_KEY);
}
public static String getRequestId(HttpServletRequest request) {...// 后面给出}
}
Этот перехватчик в основном охватываетpreHandle
а такжеafterCompletion
метод, который обрабатывает предварительную и послезапросную обработку соответственно. использоватьMDC.put()
а такжеMDC.remove()
Реализуйте операции записи и очистки в MDC.
в полученииrequest-id
, метод использованияgetRequestId()
,Следующее:
public static String getRequestId(HttpServletRequest request) {
String requestId;
String parameterRequestId = request.getParameter(REQUEST_ID_KEY);
String headerRequestId = request.getHeader(REQUEST_ID_KEY);
// 根据请求参数或请求头判断是否有“request-id”,有则使用,无则创建
if (parameterRequestId == null && headerRequestId == null) {
log.debug("no request-id in request parameter or header");
requestId = IdUtil.simpleUUID();
} else {
requestId = parameterRequestId != null ? parameterRequestId : headerRequestId;
}
return requestId;
}
Определить есть ли "request-id" по параметрам запроса или заголовку запроса, если есть - использовать, если нет - создать.request-id
Это простой UUID, который используется как уникальный идентификатор.
5.1.2 Зарегистрируйте перехватчик в веб-конфигурации
Добавить кconfig
Пакеты используются для хранения файлов конфигурации. наследоватьWebMvcConfigurer
выполнитьaddInterceptors
Чтобы добавить перехватчик в веб-конфигурацию:
@Configuration
public class WebAppConfig implements WebMvcConfigurer {
@Autowired
RequestIdTraceInterceptor requestIdTraceInterceptor;
/**
* 添加拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加requestId
registry.addInterceptor(requestIdTraceInterceptor);
}
}
5.2 Настройка вывода журнала MDC
вывод logback's MDC%X{key}
для вывода в качестве идентификатора, следовательно, изменитьlogback-spring.xml
файл, добавить в выходной формат%X{request-id}
Результат выглядит следующим образом:
<property name="log.pattern"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5level [%10thread] [%X{request-id}] %40.40logger{40} [%10method,%line] : %msg%n"/>
На этом обработка MDC завершена, запустите приложение, получите доступ к одному из интерфейсов, и вывод будет следующим (где8e955ff61fa7494788f52891a4fdbc6a
Только чтоrequest-id
):
Обратите внимание, код примера не дает обработки при вызове других сервисов, при вызове он получается из MDC
request-id
, а затем передать его как параметр заголовка, реализовавrequest-id
коробка передач. Таким образом, при запросе журнала вы можете отслеживать его по этому идентификатору.
6. Резюме
В этой статье основное внимание уделяется тому, как лучше использовать logback для решения проблем, связанных с выводом журнала при разработке приложений Springboot, в основном включая вывод данных о состоянии loback, использование асинхронного режима для решения проблем с производительностью вывода журнала, настройку вывода журнала в нескольких средах и использование MDC для решения проблемы с распространением, запрос на отслеживание приложений. Надеюсь быть полезным для всех вас.
Пример кода, использованный в этой статье, помещен вмой гитхаб:https://github.com/mianshenglee/my-example/tree/master/springboot-logback-demo
, Заинтересованные студенты могут получить код и учиться вместе с примерами.
использованная литература
-
официальный сайт:
http://logback.qos.ch
-
logback китайское руководство:
http://www.logback.cn/
-
logback github:
https://github.com/qos-ch/logback
-
Используйте requestId для отслеживания запросов в распределенных системах:
https://juejin.cn/post/6844903641535479821
Прошлые статьи
- Корпоративная практика вывода журнала Springboot + logback (включена)
- Интерфейс Springboot + swagger документирует корпоративную практику (ниже)
- Интерфейс Springboot + swagger документирует корпоративную практику (включено)
- Изучив более дюжины учебных ресурсов, я подытожил этот путь обучения ИИ.
- Мониторинг приложений Java (8) - диагностический инструмент Ali arthas
- мониторинг java-приложений (7) — онлайн-артефакт динамической диагностики BTrace
Подпишитесь на мой официальный аккаунт (поискMason技术记录
) для более технических записей: