Рубрики
Без рубрики

Настройка обратного входа с помощью Spring Boot

Вход в систему предоставляется из коробки с пружинной загрузкой, когда вы используете один из стартеров пружинной загрузки… С тегами java, вход в систему, ведение журнала, весна.

Обратный вход в систему предоставляется из коробки с Spring Boot, когда вы используете одну из зависимостей Spring Boot starter, поскольку они включают spring-boot-starter-logging , обеспечивающую ведение журнала без какой-либо конфигурации, и при необходимости могут быть изменены для работы по-другому. Существует два способа предоставления вашей собственной конфигурации, если вам нужны только более простые изменения, их можно добавить в файл свойств, такой как application.properties , или для более сложных нужд вы можете использовать XML или Groovy для указания своих настроек. В этом руководстве мы сосредоточимся на использовании XML для определения пользовательской конфигурации ведения журнала и рассмотрим некоторые основы этого, а также кратко рассмотрим использование файлов свойств для указания простых изменений в стандартной настройке, предоставляемой Spring Boot.

В этом посте я использовал зависимость spring-boot-starter для подключения spring-boot-starter-logging , которую можно найти ниже.


  org.springframework.boot
  spring-boot-starter

Это позволит использовать spring-boot-starter-logging , от которого, в свою очередь, зависят.


  
    ch.qos.logback
    logback-classic
    1.2.3
    compile
  
  
    org.apache.logging.log4j
    log4j-to-slf4j
    2.11.1
    compile
  
  
    org.slf4j
    jul-to-slf4j
    1.7.25
    compile
  

logback-classic содержит зависимость logback-core , и между ними они содержат все, что нам нужно для начала. Версии библиотек, показанные выше, предназначены для версии 2.1.1. ОСВОБОЖДЕНИЕ пружинного ботинка. Эти зависимости остаются неизменными между версиями Spring Boot, но их собственные версии могут немного отличаться.

Прежде чем мы начнем рассматривать настройку обратного входа, стоит быстро просмотреть, как отправить сообщение в журнал из класса.

@Service
public class MyServiceImpl implements MyService {

  private static final Logger LOGGER = LoggerFactory.getLogger(MyServiceImpl.class);

  @Override
  public void doStuff(final String value) {
    LOGGER.trace("doStuff needed more information - {}", value);
    LOGGER.debug("doStuff needed to debug - {}", value);
    LOGGER.info("doStuff took input - {}", value);
    LOGGER.warn("doStuff needed to warn - {}", value);
    LOGGER.error("doStuff encountered an error with value - {}", value);
  }
}

РЕГИСТРАТОР позволяет записывать сообщения в журнал, используя методы, которые представляют каждый уровень ведения журнала, трассировка , отладка , информация , предупреждение , ошибка за этим следует сообщение. Фигурные скобки/фигурные скобки будут заменены значением, переданным в качестве параметра метода.

Теперь мы можем приступить к настройке самого входа в систему, начав с относительно простого примера. Ниже приведен logback.xml файл, который является одним из файлов, которые Logback будет искать для настройки его параметров.




  
    
      
        %d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n
      
    
  

  
    
  


Он создает приложение класса ConsoleAppender , который будет выводить сообщения журнала на консоль, как System.out.print обычно. Устанавливается шаблон, которому будут соответствовать сообщения журнала, снабженные некоторыми обозначениями, которые заменяются сгенерированными значениями в зависимости от сообщения, отправленного регистратору. Некоторые обозначения были включены в пример, и ниже приведены объяснения того, что каждый из них делает.

  • %d – выводит время, в течение которого произошло сообщение журнала, в форматах, которые позволяет SimpleDateFormat .
  • %поток – выводит имя потока, в котором произошло сообщение журнала.
  • $-$-уровень – выводит уровень ведения журнала сообщения журнала.
  • %регистратор{36} – выводит пакет + имя класса, в котором произошло сообщение журнала. Число внутри скобок представляет максимальную длину пакета + имя класса. Если выходные данные длиннее указанной длины, они будут принимать подстроку первого символа каждого отдельного пакета, начиная с корневого пакета, пока выходные данные не станут меньше максимальной длины. Имя класса никогда не будет уменьшено. Хорошую диаграмму этого можно найти в документах Conversion word/|. %M
  • – выводит имя метода, в котором произошло сообщение журнала (по-видимому, это довольно медленно в использовании и не рекомендуется, если вы не беспокоитесь о производительности или имя метода особенно важно для вас). %msg
  • – выводит фактическое сообщение журнала. %n
  • – разрыв строки. % пурпурный ()
  • – устанавливает цвет вывода, содержащегося в скобках, в пурпурный (доступны другие цвета). выделить()
  • – устанавливает цвет выходных данных, содержащихся в скобках, в зависимости от уровня ведения журнала (например).

На созданное приложение затем ссылаются в корневом регистраторе. В приведенном выше примере уровень ведения журнала был установлен на INFO (можно использовать нижний или верхний регистр). В результате он выводит только сообщения, определенные на уровне информации журнала или выше (ИНФОРМАЦИЯ, ПРЕДУПРЕЖДЕНИЕ, ОШИБКА).

Доступные уровни ведения журнала в Logback следующие:

  • ВЫКЛ. (вывод без журналов)
  • ошибка
  • предупреждать
  • информация
  • отлаживать
  • след

Возвращаясь к фрагменту, показанному выше, с уровнем регистрации ИНФОРМАЦИИ, в журнал выводятся только сообщения об уровне информации или выше (ПРЕДУПРЕЖДЕНИЕ и ОШИБКА). Так что, если бы мы позвонили MyService.doStuff ("значение") он сгенерирует следующее (журналы, связанные с spring, были удалены из этого и всех следующих примеров вывода).

28-08-2017 13:32:18.549 [main] INFO  com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - value
28-08-2017 13:32:18.549 [main] WARN  com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - value
28-08-2017 13:32:18.549 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value

Обратите внимание, что, хотя сообщения уровня ТРАССИРОВКИ и отладки были отправлены в регистратор, они не отображались, поскольку они находятся ниже уровня INFO.

Если вы хотите написать эквивалент предыдущего примера кода из application.properties вы могли бы сделать это следующим образом.

logging.level.root=info
logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n

Когда это делается в такой форме, logback.xml файл не требуется, и, как вы можете видеть, конфигурация немного короче и полезна для более простых настроек.

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


Дополнительную информацию об этом см. в разделе Документы по загрузке Spring – Настройка обратного входа для ведения журнала .

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


  

Если вы затем продолжите запускать этот фрагмент кода, с все еще определенным корневым регистратором, он будет генерировать выходные данные.

27-08-2017 17:02:10.248 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - value
27-08-2017 17:02:10.248 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - value
27-08-2017 17:02:10.248 [main] INFO  com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - value
27-08-2017 17:02:10.248 [main] INFO  com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - value
27-08-2017 17:02:10.248 [main] WARN  com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - value
27-08-2017 17:02:10.248 [main] WARN  com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - value
27-08-2017 17:02:10.248 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value
27-08-2017 17:02:10.248 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value

Как вы можете видеть, каждое сообщение журнала было сгенерировано дважды, что, вероятно, не то, что вам нужно. Чтобы исправить это, необходимо использовать аддитивность="ложь" . Неиспользование аддитивности="false" приведет к тому, что сообщение будет распечатано дважды из-за добавления корневого журнала и добавления уровня класса, которые записываются в журнал. Даже если корневой уровень равен ОШИБКА , установив уровень класса в отлаживать он перезаписывает его глобально и приведет к тому, что корневое приложение также выполнит запись на уровень DEBUG для класса MyServiceImpl . Ниже показано, как должен выглядеть код с включенным этим свойством.


  

Другое возможное решение – установить уровень журнала только для класса без записи в журнал (из-за отсутствия определенного приложения), это эквивалентно версии выше, но предполагает, что другое приложение журнала (в данном случае корневое приложение) записывает в журнал, чтобы он работал


Если используется любое из этих решений, результат возвращается к ожидаемому.

27-08-2017 16:30:47.818 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - value
27-08-2017 16:30:47.834 [main] INFO  com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - value
27-08-2017 16:30:47.834 [main] WARN  com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - value
27-08-2017 16:30:47.834 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value

Ведение журнала на уровне класса можно записать в application.properties , добавив следующее.

logging.level.com.lankydan.service.MyServiceImpl=debug

Ведение журнала на уровне пакета также можно определить, просто используя имя пакета вместо имени класса в теге регистратора.


  

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


  

по сравнению с


  

Выводит совершенно другое количество строк журнала. Может быть, сотни против одной или двух строк, с приложением Spring журналы содержатся внутри org.springframework.загрузка журналы.

Вход на уровне пакета в application.properties выполняется в том же формате, в котором используется пакет вместо имени класса.

logging.level.com.lankydan.service=debug

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


Это свойство с именем LOG_PATH используется в дальнейших примерах и будет использовать каталог DEV_HOME/журналы где ДОМ_ДЕВУШКИ – это корневой каталог вашего проекта (по крайней мере, так было в моем случае…). Вероятно, это не лучшее место для сохранения журналов в реальности, но для нужд этого руководства оно подходит. LOG_PATH – это свойство, которое имеет значение для настройки ведения журнала загрузки Spring по умолчанию, но может быть создано свойство с любым именем. Значение ПУТЬ К ЖУРНАЛУ затем можно получить доступ ко всей остальной конфигурации, добавив ${LOG_PATH} .

Эта конфигурация может быть достигнута с помощью application.properties как LOG_PATH имеет важное значение в Spring Boot.

logging.path=logs

Это также работает, когда вы определяете свое собственное свойство/переменную, позволяя ссылаться на нее из остальной части вашего кода. Например.

propertyA=value
propertyB=${propertyA} # extra configuration if required

${${свойство} будет заменено значением свойство , позволяющим свойство использовать его.

Для сохранения в логи можно использовать файл FileAppender . Это простое приложение для файлов, которое сохранит все журналы в отдельный файл, который может стать очень большим, поэтому вы с большей вероятностью будете использовать RollingFileAppender , который мы рассмотрим позже.



  ${LOG_PATH}/log.log

  
    
      %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
    
  


В этом нет ничего особенного, он имеет ту же структуру, что и ConsoleAppender , с добавлением имени файла, в который сохраняются сообщения журнала. Стоит отметить, что я удалил цвета, которые были добавлены к шаблону кодировщика при сохранении в файл, так как он будет содержать символы, которые не предназначены для отображения и будут загромождать файл журнала. Затем на это приложение можно ссылаться так же, как на стандартный вывод приложение, показанное ранее, что позволяет его фактически использовать. Это будет показано ниже, и в следующих фрагментах кода будет использоваться тот же код.


  

Следуя из предыдущего application.properties фрагмента, где ведение журнала.был задан путь , что фактически приводит к тому, что журналы выводятся в файл (а также в консоль), если другие настройки не были сильно изменены. Поэтому вы могли бы остановиться на этом, но шаблон, записанный в файл, и имя файла не находятся под вашим контролем, если это сделано таким образом. В приведенном ниже примере будет продемонстрирована конфигурация, аналогичная приведенному выше приложению СОХРАНИТЬ В ФАЙЛ .

logging.pattern.console=
logging.path=logs
logging.file=${logging.path}/log.log
logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

Где это отличается от конфигурации XML, так это то, что в примере показано приложение, на которое ссылается регистратор для MyServiceImpl но приведенный выше фрагмент application.properties также будет включать корневой регистратор и, следовательно, выводить все сообщения журнала в файл. logging.pattern.console был добавлен, чтобы остановить его вывод на консоль, чтобы он соответствовал приведенному выше XML-коду (это не кажется хорошим способом сделать это но я не видел другого решения).

RollingFileAppender сохранит журналы в разные файлы в зависимости от их политики переноса. Это удобно, так как позволяет разделить вывод журнала на различные формы, которые вы можете контролировать. Например, вы можете разделить файлы журналов по дате, чтобы вы могли просматривать ошибки, которые произошли в прошлом в определенные даты, отдельно по размеру файла, чтобы вам не нужно было искать в огромном бесконечном файле или делать и то, и другое, и разделять по дате и размеру. Ниже приведены некоторые фрагменты кода, демонстрирующие политику, о которой мы только что говорили.

Timebasedrolling Policy создаст новый файл на основе даты. Приведенный ниже код будет создавать новый файл каждый день и добавлять данные к имени файла журнала с помощью обозначения %d . Формат обозначения %d важен, так как из него выводится период времени переноса. Приведенный ниже пример будет опрокидываться каждый день, но для опрокидывания ежемесячно вместо этого может использоваться другой шаблон %d{ММ-гггг} , который исключает дневную часть даты. Различные периоды опрокидывания могут использоваться не только ежедневно или ежемесячно из-за предполагаемого периода, если формат внутри обозначения %d соответствует тому, что позволяет SimpleDateFormat .



  ${LOG_PATH}/log.log

  
    
      %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
    
  

  
    
      ${LOG_PATH}/archived/log_%d{dd-MM-yyyy}.log
    
    10
    100MB
  


Я включил некоторые свойства, доступные для timebasedrolling Policy в приведенном выше примере. максимальная история указывает, как долго будут храниться архивированные файлы журнала, прежде чем они будут автоматически удалены. Время, в течение которого они хранятся, зависит от периода времени переноса, указанного в имени файла, поэтому в приведенном выше примере период переноса составляет ежедневно, что позволяет хранить архивированные журналы максимум за 10 дней до их удаления. ограничение общего размера ограничивает максимальный размер всех архивированных файлов журналов, для этого требуется, чтобы свойство maxHistory было установлено с maxHistory , имеющим приоритет над

Эта конфигурация выходит за рамки того, что можно сделать внутри файла application.properties , то же самое можно сказать и о следующих примерах. Хотя конфигурация по умолчанию позволяет переносить файл журнала, когда он достигает 10 МБ, и позволяет хранить до 7 архивированных файлов журнала.

Для переноса только на размер файла политика переноса Необходимо использовать политику Fixedwindowrolling и политику запуска SizeBasedTriggeringPolicy . В предыдущем примере журналы были сохранены в папке архива при переносе, но для этой политики я не сохранил их как таковые, поскольку разделение журналов в основном предназначено для облегчения их просмотра из-за меньших размеров файлов.



  ${LOG_PATH}/log.log

  
    
      %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
    
  

  
    
      ${LOG_PATH}/log_%i.log
    
    2
    3
  

  
    1KB
  


Необязательные свойства minIndex и maxIndex найдено в fixedwindowrollingполитике укажите минимальное и максимальное значение, которое %i может принимать имена файлов журнала. Поэтому в приведенном выше примере, когда журналы переворачиваются, они могут принимать имя Поэтому в приведенном выше примере, когда журналы переворачиваются, они могут принимать имя и log_3.log (хотя начинать с 2 странно и включено только для ясности, обычно это начинается с 1). Процесс создания файлов журнала выглядит следующим образом (используя приведенный выше фрагмент кода в качестве примера); файл log.log будет принимать все новые входные данные журнала и при достижении максимального размера файла /log.log переименовывается в архивированный файл log_2.log и создается новый log.log файл, когда log_2.log также достигнет максимального размера, все файлы журналов переименовываются и сдвигаются вместе с новым log.log файлом, который создается снова. Этот процесс будет продолжаться, если maxIndex не задан, но когда это файл журнала с указанным максимальным индексом удаляется (он содержит самые старые сообщения) в момент, когда должен быть создан другой архивный файл. Следуя тому же примеру выше, это означает, что log_4.log должен быть создан log_3.log вместо этого удаляется, а все остальные журналы соответственно переименовываются.

Если вас смущает то, что я написал выше о том, как переносятся файлы, не волнуйтесь, так как даже я думаю, что после написания этого объяснения это можно было бы сделать лучше. Поэтому ниже я предпринял вторую попытку проиллюстрировать, как это работает (что, надеюсь, легче понять).

  • log.log достигнут максимальный размер файла -> log.log переименован в log_2.log и новый журнал.журнал создается
  • log_2.log достигнут максимальный размер файла -> log_2.log переименован в log_3.log , log.log назван в log_2.log и новый журнал.журнал создается
  • log_3.log достигнут максимальный размер файла -> log_3.log достигнут максимальный размер файла -> удаляется, log_2.log переименован в log_3.log , log.log переименован в log_2.log и новый

Если я все еще плохо справился с объяснением вам этого процесса, то посмотрите Документы FixedWindowRollingPolicy , которые, надеюсь, помогут вам в этом, если я потерпел неудачу…

Политика изменения размера и времени использует части обоих приведенных выше примеров, позволяя ей изменять размер и время. Обратите внимание, что он использует как %d и % i обозначение для включения данных и номера журнала соответственно в имя файла.



    ${LOG_PATH}/log.log

    
      
        %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
      
    

    
      
        ${LOG_PATH}/archived/log_%d{dd-MM-yyyy}_%i.log
      
      10MB
      10
      100MB
    


Как вы можете видеть, он содержит Максимальный размер файла , Максимальная история и ограничение общего размера обеспечение ИТ-контроля над размером отдельных файлов, а также над коллекцией файлов. Поэтому в приведенном выше примере 10-дневная история будет разделена на файлы размером 10 МБ, и когда общий размер всех файлов достигнет 100 МБ, самые старые файлы будут удалены.

Теперь, когда мы рассмотрели, как определить несколько приложений, которые могут выводиться в консоль или файл, мы можем объединить их для вывода в обе формы одновременно. Просто путем ссылки на несколько приложений в регистраторе.


  
  

Итак, теперь этот регистратор будет выводить данные на консоль благодаря STDOUT , а также в файл с помощью приложения СОХРАНИТЬ В ФАЙЛ .

Аналогичная конфигурация может быть достигнута с помощью application.properties . Если вы вернетесь на страницу, вы, возможно, сможете понять, как это сделать самостоятельно, так как в предыдущем примере была добавлена одна дополнительная строка, чтобы предотвратить ее печать на консоль и в файл. Опять же, это будет содержать сообщения журнала от корневого регистратора, а не только MyServiceImpl , как в приведенном выше фрагменте.

logging.path=logs
logging.file=${logging.path}/log.log
logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n

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




  

  
    
      
      
    
    
      
      
    
  

  
    
      
    
    
      
    
  


Первый шаг, чтобы заставить это работать, – переименовать logback.xml файл в logback-spring.xml разрешение использования тега Профиль пружины . В этом теге может быть указано имя, которое можно задать с помощью свойств, переменных среды или параметров виртуальной машины. Ниже показано, как вы можете установить для профиля spring имя dev , которое использовалось для представления среды разработки.

Для установки в application.properties или в качестве переменной среды

spring.profiles.active=dev

Или в качестве опции виртуальной машины

-Dspring.profiles.active=dev

Теперь при запуске приложения будет использоваться профиль spring для dev , в результате чего журналы будут выводиться на консоль и в файл. Если это было затем запущено в производство, для свойства необходимо установить значение prod , которое изменит конфигурацию на то, что считается подходящим, например, только запись журналов в файл и, возможно, изменение уровня ведения журнала всех или определенных классов/пакетов.

Аналогичная конфигурация также может быть предоставлена через application.properties . Ну, на самом деле нет application.properties но вместо этого из application-dev.свойства и приложение-prod.свойства которые являются отдельными файлами свойств для каждой среды. В соответствии с соглашением об именовании приложения-{среда}.свойства где {среда} заменяется именем среды. В зависимости от параметров вашей виртуальной машины или переменных среды один из них может быть выбран точно так же, как при использовании springProfile в logback-spring.xml . Ниже приведены эквивалентные конфигурации для приведенного выше фрагмента кода.

Ниже приведены эквивалентные конфигурации для приведенного выше фрагмента кода.

logging.level.root=info
logging.level.com.lankydan.service=debug
logging.path=logs
logging.file=${logging.path}/log.log
logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n

Ниже приведены эквивалентные конфигурации для приведенного выше фрагмента кода.

logging.level.root=info
logging.level.com.lankydan.service=error
logging.path=logs
logging.file=${logging.path}/log.log
logging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
logging.pattern.console=

Я думаю, что мне следует завершить этот пост на этом этапе, так как он был намного длиннее, чем я первоначально ожидал. При этом, как говорится, с помощью Logback и Spring Boot можно сделать гораздо больше, о чем я здесь не рассказывал. В заключение этого урока вы должны были понять, как использовать обратную связь с Spring Boot, в том числе как использовать файлы свойств для изменения настроек по умолчанию, предоставляемых Spring Boot, и как пойти еще дальше и создать свои собственные конфигурации с помощью обратной связи через logback.xml и logback-spring.xml . А также иметь представление об ограничениях, которые может предоставить конфигурация внутри файлов свойств, чтобы вы знали, когда пришло время переключиться на прямое использование Logback, чтобы добраться до финиша.

Код, используемый в этих примерах, можно найти на моем GitHub .

Чтобы быть в курсе моих новых постов, вы можете следить за мной по адресу @Lankydandev .

Первоначально опубликовано 31 августа 2017 года и обновлено 9 января 2019 года.

Оригинал: “https://dev.to/lankydandev/configuring-logback-with-spring-boot-4lnk”