Spring Boot Series (4): подробная динамическая конфигурация журнала

Spring Boot

Самый быстрый путь в мире — быть приземленным, эта статья включенаКолонка архитектурных технологийПодпишитесь на лайки, чтобы поделиться.

Проект с открытым исходным кодом:

**Весенняя коллекция ботинок**

Spring Boot Series (1): Начало работы с SpringApplication

Серия Spring Boot (2) Анализ особенностей конфигурации

Серия Spring Boot (3): подробное объяснение последней версии элегантного завершения работы.

Spring Boot Series (4): подробная динамическая конфигурация журнала

1. Введение

Версия Spring Boot: 2.3.4.RELEASE

Я не знаю, нужны ли вам когда-нибудь какие-либо журналы DEBUG, когда возникает проблема в сети, но в настоящее время я использую INFO.

Если вы хотите включить DEBUG, вам нужно переупаковать релизную версию, но в некоторых сценариях перезапуск может не воспроизвести проблему, что на самом деле является головной болью.

Сегодня мы поговорим о динамической настройке конфигурации журнала под Spring Boot, чтобы ваш уровень журнала мог перемещаться как вам угодно.

Журналы весенней загрузки

Commons Logging на самом деле используется внутри Spring Boot, а механизм загрузки конфигурации, основанный на Spring Boot, предоставляет нам несколько методов журналирования Java Util Logging, Log4j2 и Logback.

Logback является его фреймворком по умолчанию, и заменять его без особой необходимости не рекомендуется. (не говоря уже о производительности)

формат журнала

Не стоит недооценивать формат, это важная вещь в практическом применении.

Я не знаю, есть ли в вашей компании базовый компонент единого журнала, конечно, нет файла конфигурации единого журнала.

Подумайте о том, если ваш формат журнала неоднороден, если каждый проект имеет свой собственный стиль, как вы попросите своего партнера по эксплуатации и обслуживанию помочь вам сегментировать журнал? Вызвать полицию для вас? Это действительно обычное письмо до смерти, полностью полагающееся на любовь, чтобы генерировать электричество. (Например, Loghub, который мы используем, не унифицирован и будет убит эксплуатацией и обслуживанием)

Давайте посмотрим на нашу конфигурацию формата журнала, здесь только PATTERN

-|%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{tid}|%thread|%logger{36}.%M:%L-%msg%n

Сначала объясните каждое место:

  • %d{yyyy-MM-dd HH:mm:ss.SSS} :время
  • %-5level: уровень журнала
  • %X{tid} : наш собственный идентификатор распределенной трассировки
  • %thread : нить
  • %logger{36}.%M:%L: Полное имя класса (36 — самый длинный символ).Информация Номер строки
  • %msg%n: вывод информации о новой строке

Я не знаю, можете ли вы понять, что есть предыдущий-|за что? На самом деле, это облегчает различение журналов новой строки, таких как информация о стеке исключений, во время обычной сегментации.

несколько очков знаний

Давайте поговорим о нескольких других моментах, используемых Spring Boot, давайте перейдем к сути

  • Здесь Logback не имеет уровня FATAL и классифицируется как ERROR.

  • допустимыйapplication.properties внутренняя конфигурацияdebug=trueЧтобы включить режим отладки, вы также можете настроитьtrace=trueВключить режим трассировки

  • может сноваapplication.propertiesиспользуется вlogging.level.<logger-name>=<level>Этот формат используется для настройки различных уровней журнала, таких какorg.hibernateуровень установлен на ОШИБКАlogging.level.org.hibernate=error

  • Концепция группы журналов, если такая конфигурация раздражает, вы можете установить группу, чтобы настроить ее как единое целое. Такие как:logging.group.tomcat=org.apache.catalina, org.apache.coyoteУровень конфигурации TRACElogging.level.tomcat=TRACE

  • Если вы используете файл конфигурации Logback, официально рекомендуется использоватьlogback-spring.xmlтакое имя, если вы используетеlogback.xmlТаким образом, должна возникнуть проблема с инициализацией журнала Spring.

  • Если вы управляете конфигурацией ведения журнала, но не хотите использовать logback.xml в качестве имени конфигурации Logback, вы можете указать пользовательское имя в файле конфигурации application.properties через свойство logging.config:logging.config=classpath:xxx-log.xml

2. Динамически изменять уровень журнала

Поговорим о том, как приложение Spring Boot в рабочем состоянии изменяет уровень динамического логирования

Spring Boot Actuator

Привод должен знать название Spring Boot, информацию о мониторинге, аудите, измерениях и так далее. Грамотное завершение работы, проверка работоспособности и информация журнала, которую мы используем, реализуются с помощью этой штуки.

После того, как мы используем Actuator, мы можем использовать его REST-интерфейс Logger для работы с нашими журналами, есть следующие три

  • GET http://127.0.0.1:6080/actuator/loggersВозвращает всю информацию об уровне журнала текущего приложения (независимо от того, что вы хотите)
  • GET http://127.0.0.1:6080/actuator/loggers/{name}Возвращает уровень журнала {name}
  • POST http://127.0.0.1:6080/actuator/loggers/{name}Параметры конфигурации{"configuredLevel":"INFO","effectiveLevel":"INFO"}Изменить уровень журнала

Динамически изменять уровни с помощью механизма актуатора

1), полагаться на необходимую конфигурацию Spring Boot Actuator (при наследовании родительской версии не требуется)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.3.4.RELEASE</version>
</dependency>

2), файл конфигурации

#注意,这里我只开启了loggers,health两个Actuator
management.endpoints.web.exposure.include=loggers,health
management.endpoint.loggers.enabled=true

3), создайте контроллер

@RestController
@RequestMapping("/log")
public class TestLogController {

    private Logger log = LoggerFactory.getLogger(TestLogController.class);

    @GetMapping
    public String log() {
        log.trace("This is a TRACE level message");
        log.debug("This is a DEBUG level message");
        log.info("This is an INFO level message");
        log.warn("This is a WARN level message");
        log.error("This is an ERROR level message");
        return "See the log for details";
    }
}

4), запустить приложение

На данный момент, после запуска приложения, если вы используете IDEA, вы можете увидеть следующее сопоставление, есть три интерфейса REST для регистратора.

5), тест

В этот момент я сначала выполняюGET http://127.0.0.1:6080/log, консоль выводит следующую информацию

2020-10-15 23:14:51.204  INFO 52628 --- [nio-6080-exec-7] c.q.chapter1.failure.TestLogController   : This is an INFO level message
2020-10-15 23:14:51.220  WARN 52628 --- [nio-6080-exec-7] c.q.chapter1.failure.TestLogController   : This is a WARN level message
2020-10-15 23:14:51.221 ERROR 52628 --- [nio-6080-exec-7] c.q.chapter1.failure.TestLogController   : This is an ERROR level message

В этот момент мы выполняемGET http://127.0.0.1:6080/actuator/loggers/ROOTвернуть{"configuredLevel":"INFO","effectiveLevel":"INFO"}, что означает, что уровень журнала нашего приложения в это время — INFO, а ROOT представляет собой корневой узел.

6), изменить уровень

На данный момент мы не хотим больше смотреть на информацию INFO, и если мы хотим изменить уровень журнала всего приложения на WARN, давайте выполнимPOST http://127.0.0.1:6080/actuator/loggers/ROOTПараметры{"configuredLevel":"TRACE","effectiveLevel":"TRACE"}

В этот момент мы выполнимGET http://127.0.0.1:6080/log, консоль выводит следующую информацию

2020-10-15 23:24:11.481 TRACE 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController   : This is a TRACE level message
2020-10-15 23:24:11.481 DEBUG 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController   : This is a DEBUG level message
2020-10-15 23:24:11.481  INFO 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController   : This is an INFO level message
2020-10-15 23:24:11.481  WARN 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController   : This is a WARN level message
2020-10-15 23:24:11.481 ERROR 53552 --- [nio-6080-exec-3] c.q.chapter1.failure.TestLogController   : This is an ERROR level message

другие методы

  • Сканирование файла конфигурации: это уровень модификации функции автоматического сканирования журнала.logback-spring.xmlвключи<configuration scan="true" scanPeriod="15 seconds">динамическая модификацияlogback-spring.xmlНазначение внутреннего уровня журнала, если вам интересно, можете попробовать сами.

  • Артас Динамическая модификация

  • Привязка конфигурации удаленного центра, например Apollo, для достижения уровня динамической модификации

3. Принцип реализации

Здесь мы в основном используемSpring Boot Actuator Log, поэтому мы также говорим о его принципе.

Загрузка конечных точек

Сначала начнем с зависимостиspring-boot-actuatorнайти нашLoggersEndpoint(Все актуаторы имеют этот номер), как показано на рисунке:

Друзья, знакомые с механизмом загрузки Spring Boot, знают, что за каждой конечной точкой привода должен стоять еще одинxxxEndpointAutoConfigurationДавайте загрузим Endpoint для нас.

И эти механизмы загрузки хранятся вspring-boot-actuator-autoconfigure, в котором находимLoggersEndpointAutoConfigurationдля погрузкиLoggersEndpointкласс конфигурации.

Давайте взглянем на его ядро:

@Bean
	@ConditionalOnBean(LoggingSystem.class)
	@Conditional(OnEnabledLoggingSystemCondition.class)
	@ConditionalOnMissingBean
	public LoggersEndpoint loggersEndpoint(LoggingSystem loggingSystem,
			ObjectProvider<LoggerGroups> springBootLoggerGroups) {
		return new LoggersEndpoint(loggingSystem, springBootLoggerGroups.getIfAvailable(LoggerGroups::new));
	}

Можно увидеть два важных параметра:

  • LoggingSystem: абстрактный класс верхнего уровня.
  • springBootLoggerGroups: сохраняет текущие данные группы журналов.

Обобщить:

1. Мы зависим отspring-boot-starter-actuator После пакета, это зависит отspring-boot-actuator-autoconfigure

2. Запустите сканированиеspring-boot-actuator-autoconfigureвнизMETA-INF/spring.factoriesчас,LoggersEndpointAutoConfigurationбудет загружен в

3.LoggersEndpointAutoConfigurationобъявил сноваLoggersEndpoinи назначитьLoggingSystemа такжеspringBootLoggerGroupsкак его параметр

4. После старта проекта проходимLoggersEndpointИнтерфейс для доступа к данным журнала

LoggingSystem

Отношение наследования LoggingSystem

Из вышесказанного можно понятьLoggingSystemЭто ядро ​​управления операциями с журналами, поэтому давайте сначала взглянем на его диаграммы.

Вы можете сразу увидеть отношения наследования,LogbackLoggingSystemЭто наш мастер, хотя мастер нам известен, как именно загружается наша LoggingSystem?

Загрузка LoggingSystem

Основные классы участия следующие:

  • LoggingApplicationListener
  • ApplicationStartingEvent
  • LogbackLoggingSystem
  • LoggingSystem

Нечего сказать, первое фото

1. Использование приложенияSpringApplication.run(Chapter1Application.class, args);запускать

2. Отправить стартовое событиеApplicationStartingEvent,ApplicationEnvironmentPreparedEventЖдать

3.LoggingApplicationListenerПолучение событий для распространения событий

4.LoggingApplicationListenerполучать событияApplicationStartingEvent

5.LoggingApplicationListenerпозвони внутрьonApplicationStartingEvent(ApplicationStartingEvent event) метод, используйте LoggingSystem.get(classloader) для инициализации LoggingSystem.

6. Затем позвонитеLogbackLoggingSystem.beforeInitialize()(потому что здесь мы используем logback)

7.LoggingApplicationListenerполучать событияApplicationEnvironmentPreparedEvent

8,LoggingApplicationListenerпозвони внутрьonApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) метод

9,onApplicationEnvironmentPreparedEventперечислитьinitialize(ConfigurableEnvironment environment, ClassLoader classLoader)метод, инициализирует систему ведения журнала в соответствии с конфигурацией переменной среды.

LoggersEndpoint

Наконец, давайте взглянем на LoggersEndpoint.Для удобства толкования я не буду копировать все это здесь.Где вам нужно выбрать?

Сначала взгляните на наши три интерфейса для операций с журналами:

  • GET /actuator/loggersвести перепискуpublic Map<String, Object> loggers() метод

  • GET /actuator/loggers/{name} вести перепискуpublic LoggerLevels loggerLevels(@Selector String name) метод

  • POST /actuator/loggers/{name}вести перепискуpublic void configureLogLevel(@Selector String name, @Nullable LogLevel configuredLevel) метод

возьми один здесьpublic Map<String, Object> loggers() Способ примерный, остальные почти такие же

@ReadOperation
	public LoggerLevels loggerLevels(@Selector String name) {
		Assert.notNull(name, "Name must not be null");
		LoggerGroup group = this.loggerGroups.get(name);
		if (group != null) {
			return new GroupLoggerLevels(group.getConfiguredLevel(), group.getMembers());
		}
		LoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(name);
		return (configuration != null) ? new SingleLoggerLevels(configuration) : null;
	}

Код на самом деле очень простой, поэтому нет необходимости его слишком много интерпретировать.

В-четвертых, болтовня

Фактически, журналы очень важны для наших системных приложений, а также являются важными учетными данными для устранения неполадок. Согласно нашему опыту, журнал нашей системы может лучше всего достигать нескольких пунктов:

  • Унификация формата журнала

  • Лучше всего предоставить единый компонент журнала, например, мы используем общедоступный компонент logback-spring.xml. Если нам нужно изменить некоторые функции журнала, такие как добавление журналов APM и т. Д., Нам нужно изменить только одну точку, и все состояния журнала нашей системы изменятся.

  • Лучше всего использовать динамическую настройку и настроить конфигурацию журнала, например Apollo

Самый быстрый путь в мире — быть приземленным, эта статья включенаКолонка архитектурных технологийПодпишитесь на лайки, чтобы поделиться.

Проект с открытым исходным кодом: