Перейти к основному содержимому

Вход в Spring Boot

· 10 мин. чтения

Задача: Медиана двух отсортированных массивов

Даны два отсортированных массива размерами n и m. Найдите медиану слияния этих двух массивов.
Временная сложность решения должна быть O(log(m + n)) ...

ANDROMEDA

1. Обзор

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

Более подробная информация о Logback доступна в A Guide to Logback , а Log4j2 представлена в Intro to Log4j2 — Appenders, Layouts and Filters .

2. Первоначальная настройка

Давайте сначала создадим модуль Spring Boot. Рекомендуемый способ сделать это — использовать Spring Initializr , который мы рассмотрим в нашем учебном пособии по Spring Boot .

Теперь давайте создадим наш единственный файл класса, LoggingController :

@RestController
public class LoggingController {

Logger logger = LoggerFactory.getLogger(LoggingController.class);

@RequestMapping("/")
public String index() {
logger.trace("A TRACE Message");
logger.debug("A DEBUG Message");
logger.info("An INFO Message");
logger.warn("A WARN Message");
logger.error("An ERROR Message");

return "Howdy! Check out the Logs to see the output...";
}
}

Как только мы загрузим веб-приложение, мы сможем активировать эти строки журнала, просто посетив http://localhost:8080/ .

3. Регистрация нулевой конфигурации

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

В случае ведения журнала единственной обязательной зависимостью является Apache Commons Logging.

Нам нужно импортировать его только при использовании Spring 4.x ( Spring Boot 1.x ), поскольку он предоставляется модулем spring-jcl Spring Framework в Spring 5 ( Spring Boot 2.x ).

Нам вообще не следует беспокоиться об импорте spring-jcl , если мы используем Spring Boot Starter (что мы почти всегда и делаем). Это потому, что каждый starter, как и наш spring-boot-starter-web , зависит от spring-boot-starter-loging, который уже использует для нас spring-jcl .

3.1. Ведение журнала по умолчанию

При использовании стартеров Logback используется для ведения журнала по умолчанию.

Spring Boot предварительно настраивает его с помощью шаблонов и цветов ANSI, чтобы сделать стандартный вывод более читаемым.

Давайте теперь запустим приложение и посетим страницу http://localhost:8080/ и посмотрим, что происходит в консоли:

./ff508147dc450d5a11cdd7303845e264.png

Как мы видим, уровень ведения журнала Logger по умолчанию установлен на INFO, что означает, что сообщения TRACE и DEBUG не видны.

Чтобы активировать их без изменения конфигурации, мы можем передать аргументы –debug или –trace в командной строке :

java -jar target/spring-boot-logging-0.0.1-SNAPSHOT.jar --trace

3.2. Уровни журнала

Spring Boot также дает нам доступ к более детальным настройкам уровня журнала через переменные среды. Есть несколько способов сделать это.

Во-первых, мы можем установить уровень ведения журнала в наших параметрах виртуальной машины:

-Dlogging.level.org.springframework=TRACE 
-Dlogging.level.com.foreach=TRACE

В качестве альтернативы, если мы используем Maven, мы можем определить наши настройки журнала через командную строку :

mvn spring-boot:run 
-Dspring-boot.run.arguments=--logging.level.org.springframework=TRACE,--logging.level.com.foreach=TRACE

При работе с Gradle мы можем передавать настройки журнала через командную строку. Для этого потребуется установить задачу bootRun .

Как только это будет сделано, мы запускаем приложение:

./gradlew bootRun -Pargs=--logging.level.org.springframework=TRACE,--logging.level.com.foreach=TRACE

Если мы хотим навсегда изменить уровень детализации, мы можем сделать это в файле application.properties , как описано здесь :

logging.level.root=WARN
logging.level.com.foreach=TRACE

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

Мы упоминали, что Spring Boot Starter по умолчанию использует Logback. Давайте посмотрим, как определить фрагмент файла конфигурации Logback, в котором мы устанавливаем уровень для двух отдельных пакетов:

<logger name="org.springframework" level="INFO" />
<logger name="com.foreach" level="INFO" />

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

Итак, если мы установим уровни логирования с помощью Logback, Spring Boot и переменных среды одновременно, уровень логирования будет TRACE , так как он самый низкий среди запрошенных уровней.

4. Логбэк конфигурации

Несмотря на то, что конфигурация по умолчанию полезна (например, чтобы начать работу в нулевое время во время POC или быстрых экспериментов), ее, скорее всего, недостаточно для наших повседневных нужд.

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

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

Когда файл в пути к классам имеет одно из следующих имен, Spring Boot автоматически загрузит его поверх конфигурации по умолчанию:

  • logback-spring.xml
  • logback.xml
  • logback-spring.groovy
  • logback.groovy

Spring рекомендует по возможности использовать вариант -spring вместо простых, как описано здесь .

Напишем простой logback-spring.xml :

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<property name="LOGS" value="./logs" />

<appender name="Console"
class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
</Pattern>
</layout>
</appender>

<appender name="RollingFile"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS}/spring-boot-logger.log</file>
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
</encoder>

<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- rollover daily and when the file reaches 10 MegaBytes -->
<fileNamePattern>${LOGS}/archived/spring-boot-logger-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>

<!-- LOG everything at INFO level -->
<root level="info">
<appender-ref ref="RollingFile" />
<appender-ref ref="Console" />
</root>

<!-- LOG "com.foreach*" at TRACE level -->
<logger name="com.foreach" level="trace" additivity="false">
<appender-ref ref="RollingFile" />
<appender-ref ref="Console" />
</logger>

</configuration>

И когда мы запускаем приложение, вот результат:

./db56b054c9685a770825aac9e4ef49e8.png

Как мы видим, теперь он регистрирует сообщения TRACE и DEBUG , а общий шаблон консоли как в текстовом, так и в хроматическом плане отличается от прежнего.

Теперь он также регистрирует файл в папке /logs , созданный по текущему пути, и архивирует его с помощью скользящей политики.

5. Ведение журнала конфигурации Log4j2

В то время как Apache Commons Logging является ядром, а Logback является предоставленной эталонной реализацией, все маршруты к другим библиотекам ведения журналов уже включены, чтобы упростить переключение на них.

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

Для каждого такого стартера (в нашем примере он единственный, но их может быть много):

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

нам нужно превратить его в тощую версию, и (только один раз) добавить нашу альтернативную библиотеку, здесь через сам стартер:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

На этом этапе нам нужно поместить в путь к классам файл с одним из следующих имен:

  • log4j2-spring.xml
  • log4j2.xml

Мы будем печатать через Log4j2 (через SLF4J) без дальнейших модификаций.

Напишем простой log4j2-spring.xml :

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%style{%d{ISO8601}}{black} %highlight{%-5level }[%style{%t}{bright,blue}] %style{%C{1.}}{bright,yellow}: %msg%n%throwable" />
</Console>

<RollingFile name="RollingFile"
fileName="./logs/spring-boot-logger-log4j2.log"
filePattern="./logs/$${date:yyyy-MM}/spring-boot-logger-log4j2-%d{-dd-MMMM-yyyy}-%i.log.gz">
<PatternLayout>
<pattern>%d %p %C{1.} [%t] %m%n</pattern>
</PatternLayout>
<Policies>
<!-- rollover on startup, daily and when the file reaches
10 MegaBytes -->
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy
size="10 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
</Appenders>

<Loggers>
<!-- LOG everything at INFO level -->
<Root level="info">
<AppenderRef ref="Console" />
<AppenderRef ref="RollingFile" />
</Root>

<!-- LOG "com.foreach*" at TRACE level -->
<Logger name="com.foreach" level="trace"></Logger>
</Loggers>

</Configuration>

И когда мы запускаем приложение, вот результат:

./abc1d81fb39861ee8b4c145c3b5504e4.png

Как мы видим, вывод сильно отличается от Logback — доказательство того, что мы сейчас полностью используем Log4j2.

Помимо конфигурации XML, Log4j2 позволяет нам использовать также конфигурацию YAML или JSON, описанную здесь .

6. Log4j2 без SLF4J

Мы также можем использовать Log4j2 изначально, без прохождения через SLF4J.

Для этого мы просто используем нативные классы:

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
// [...]
Logger logger = LogManager.getLogger(LoggingController.class);

Нам не нужно вносить какие-либо другие изменения в стандартную конфигурацию Log4j2 Spring Boot.

Теперь мы можем использовать совершенно новые функции Log4j2, не зацикливаясь на старом интерфейсе SLF4J. Но мы также привязаны к этой реализации, и нам нужно будет переписать наш код при переходе на другой фреймворк ведения журналов.

7. Регистрация с помощью Ломбока

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

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

Сначала нам нужно добавить зависимость Lombok в наш скрипт сборки, чтобы работать с ним:

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>

7.1. @Slf4j и @CommonsLog

API-интерфейсы SLF4J и Apache Commons Logging позволяют нам гибко изменять нашу структуру ведения журналов, не влияя на наш код.

И мы можем использовать аннотации Lombok @ Slf4j и @CommonsLog , чтобы добавить нужный экземпляр регистратора в наш класс: org.slf4j.Logger для SLF4J и org.apache.commons.logging.Log для Apache Commons Logging.

Чтобы увидеть эти аннотации в действии, давайте создадим класс, похожий на LoggingController, но без экземпляра регистратора. Мы назовем его LombokLoggingController и аннотируем @Slf4j :

@RestController
@Slf4j
public class LombokLoggingController {

@RequestMapping("/lombok")
public String index() {
log.trace("A TRACE Message");
log.debug("A DEBUG Message");
log.info("An INFO Message");
log.warn("A WARN Message");
log.error("An ERROR Message");

return "Howdy! Check out the Logs to see the output...";
}
}

Обратите внимание, что мы немного изменили фрагмент, используя log в качестве экземпляра регистратора. Это связано с тем, что при добавлении аннотации @Slf4j автоматически добавляется поле с именем log .

С ведением журнала с нулевой конфигурацией приложение будет использовать базовую реализацию ведения журнала Logback для ведения журнала. Точно так же реализация Log4j2 используется для ведения журнала с Log4j2-Configuration Logging.

Мы получаем такое же поведение, когда заменяем аннотацию @Slf4j на @CommonsLog.

7.2. @Log4j2

Мы можем использовать аннотацию @Log4j2 для прямого использования Log4j2. Итак, мы делаем простое изменение в LombokLoggingController , чтобы использовать @Log4j2 вместо @Slf4j или @CommonsLog :

@RestController
@Log4j2
public class LombokLoggingController {

@RequestMapping("/lombok")
public String index() {
log.trace("A TRACE Message");
log.debug("A DEBUG Message");
log.info("An INFO Message");
log.warn("A WARN Message");
log.error("An ERROR Message");

return "Howdy! Check out the Logs to see the output...";
}
}

Помимо ведения журнала, есть и другие аннотации от Lombok, которые помогают поддерживать чистоту и порядок в нашем коде. Более подробная информация о них доступна в разделе Introduction to Project Lombok , а также у нас есть учебник по настройке Lombok с Eclipse и IntelliJ .

8. Остерегайтесь Java Util Logging

Spring Boot также поддерживает ведение журнала JDK через файл конфигурации logging.properties .

Однако бывают случаи, когда использовать его нецелесообразно. Из документации :

Существуют известные проблемы с загрузкой классов в Java Util Logging, которые вызывают проблемы при запуске из «исполняемого jar». Мы рекомендуем вам избегать этого при запуске из «исполняемого jar», если это вообще возможно.

Также хорошей практикой при использовании Spring 4 является ручное исключение регистрации общих ресурсов в pom.xml, чтобы избежать возможных конфликтов между библиотеками регистрации. Вместо этого Spring 5 обрабатывает это автоматически, поэтому нам не нужно ничего делать при использовании Spring Boot 2.

9. ДЖАНСИ в Windows

В то время как операционные системы на основе Unix, такие как Linux и Mac OS X, по умолчанию поддерживают цветовые коды ANSI, на консоли Windows все будет, к сожалению, монохромным.

Windows может получать цвета ANSI через библиотеку JANSI.

Однако мы должны обратить внимание на возможные недостатки загрузки классов.

Мы должны импортировать и явно активировать его в конфигурации следующим образом:

Логбэк :

<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<encoder>
<pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<!-- more stuff -->
</configuration>

Лог4j2 :

Управляющие последовательности ANSI изначально поддерживаются на многих платформах, но не по умолчанию в Windows. Чтобы включить поддержку ANSI, добавьте jar Jansi в наше приложение и установите для свойства log4j.skipJansi значение false . Это позволяет Log4j использовать Jansi для добавления escape-кодов ANSI при записи в консоль. Примечание. До Log4j 2.10 Jansi был включен по умолчанию. Тот факт, что для Jansi требуется собственный код, означает, что Jansi может быть загружен только одним загрузчиком классов . Для веб-приложений это означает, что jar Jansi должен находиться в пути к классам веб-контейнера. Чтобы избежать проблем с веб-приложениями, Log4j больше не пытается автоматически загружать Jansi без явной настройки, начиная с Log4j 2.10.

Также стоит отметить:

  • Страница документации макета содержит полезную информацию Log4j2 JANSI в разделе highlight{pattern}{style} .
  • В то время как JANSI может раскрасить вывод, баннер Spring Boot (собственный или настроенный с помощью файла banner.txt ) останется монохромным.

10. Заключение

Мы рассмотрели основные способы взаимодействия с основными платформами ведения журналов из проекта Spring Boot.

Мы также изучили основные преимущества и недостатки каждого решения.

Как всегда, полный исходный код доступен на GitHub .