Пиление через логгеры Java
Я знаю, о чем ты думаешь: «Это просто лесозаготовка!» Эта небольшая, но все же распространенная часть наших приложений предоставляет разработчикам, QA и специалистам по устранению неполадок информацию, помогающую в определении последовательности выполнения кода, проверке значений данных и проблемных точек в наших приложениях. Реальность такова, что без надежных реализаций регистрации мы бы потеряли значительный инструмент для устранения неполадок.
Варианты ведения журнала Java
- System.out / System.err
- java.util.logging (JUL)
- Apache Commons Jogging (также известный как Jakarta Commons Logging — JCL)
- Log4j
- SLF4J
- Logback
System.out & System.err
В первые дни (надеюсь, не сейчас) мы использовали старый System.out.println()
метод регистрации. Мы бы быстро обнаружили, что их использование не хорошо.
Причины избегать System
методов
- Мы не можем отключить в производстве, что влияет на производительность и может поставить под угрозу безопасность данных. О, у нас есть,
System.err.println()
но все еще недостаточно хорошо - Мы не можем настроить, сколько или мало информации сообщается (уровни ведения журнала)
- В кластерной среде мы не можем настроить централизованное расположение для информации
- System.out работает плохо … см. Ведение журнала против производительности System.out
- Метаданные недоступны и должны быть закодированы для каждого System.out, что неизбежно не будет выполнено или, по крайней мере, будет очень противоречивым
*** НЕ ИСПОЛЬЗУЙТЕ System.out
или System.err
где-либо еще, никогда! ***
java.util.logging (JUL)
Java предоставляет опцию регистрации, которая является шагом вперед в регистрации. Тем не менее, он не получил широкого распространения, поскольку опоздал на вечеринку. Не многие платформы с открытым исходным кодом используют JUL. Как правило , вы найдете это com.sun
или com.oracle
проектов , таких как Джерси.
Log4j
Log4j — это проект Apache, который существует уже некоторое время и широко используется в проектах с открытым исходным кодом. Log4j предоставляет гибкую структуру ведения журналов, но немного устарела на данный момент.
SLF4j — логирование API
У нас есть много вариантов ведения журнала, и в наши проекты с открытым исходным кодом мы обычно включаем проекты, которые могут реализовывать JCL и JUL.
SLF4j ( Simple Logging Facade для Java ) предоставляет общий интерфейс ведения журнала для наших проектов. Большинство респектабельных проектов с открытым исходным кодом теперь используют SLF4j для конфигурируемости и гибкости при изменении реализации ведения журнала. Думайте о SLF4j как об общем интерфейсе (API) для нашего выбора реализации ведения журнала.
Весь наш код регистрации должен использовать один и тот же API SLF4j. Например:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; … public class MyClass { private static final Logger logger = LoggerFactory.getLogger(MyClass.class); … public void someMethod() { logger.debug("something is happening"); } }
Базовые зависимости Maven SLF4j
<properties> <slf4j.version>1.7.5</slf4j.version> <logback.version>1.0.11</logback.version> </properties> <dependencies> <!-- SLF4J - logging api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <!-- Logback - logging impl --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> </dependencies>
Усовершенствованные зависимости Maven SLF4j
<properties> <slf4j.version>1.7.5</slf4j.version> <logback.version>1.0.11</logback.version> </properties> <dependencies> <!-- SLF4J - logging api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <!-- Interceptor for Commons-logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <!-- Interceptor for java.util.logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jul-to-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <!-- Logback - logging impl --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback.version}</version> </dependency> </dependencies>
Преимущества SLF4j
- Одна стратегия ведения журнала для всех
- Строковые заполнители
- logger.debug («Значение {} равно {}», myVar, myValue);
- Перехватчики
commons-logging
- Включить
jcl-over-slf4j
зависимость - Следует исключить
commons-logging
зависимости из проекта
- Включить
- Может перехватить
java.util.logging
- Включить
jul-to-slf4j
зависимость - Требуется регистрация классов в приложении
- См. Блог Best Practices Enterprise Spring
- Включить
- Может перехватить
System.out
&System.err
- Требуется в том числе зависимости
- Требуется регистрация классов в приложении
- См. Блог Best Practices Enterprise Spring
Logback — более разумное ведение журнала
Logback — это проект от создателя Log4j и SLF4j Чеки Гюльчу ( произносится как Джеки Гульджу ).
Первая статья для чтения: Logback: причины для переключения
Простой файл logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true" scan="true" scanPeriod="30 seconds"> <!-- Handle JUL --> <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> <resetJUL>true</resetJUL> </contextListener> <!-- To enable JMX Management --> <jmxConfigurator/> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%-5level %logger{0} - %msg%n</pattern> </encoder> </appender> <logger name="com.gordondickens.demo" level="debug" /> <logger name="org.springframework.beans" level="trace" /> <root level="warn"> <appender-ref ref="console" /> </root> </configuration>
File Appenders
Помимо консольного приложения есть File и RollingFile. В приложении Rolling File Appender предусмотрены параметры, основанные на времени и размере , с возможностью указания количества сохраняемых файлов и необязательного сжатия (zip).
См .: Logback Appenders
Говорит на родном SLF4j
Выше мы видели, что просто заменив Log4j на Logback, теперь у нас есть логирование через SLF4j. На самом деле, его зависимость меньше, так как мы больше не будем включать slf4j-log4j12
зависимость.
RESTful и протоколирование веб-доступа
Мы можем использовать logback-доступ для обеспечения регистрации доступа к серверу. Это может оказаться очень полезным при устранении неполадок веб-сервисов RESTful, а также для веб-приложений. В src/main/resources
каталоге нашего приложения создайте файл logback-access.xml
.
Logback-access.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" /> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${user.dir}/logs/app-access.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${user.dir}/logs/app-access.%d{yyyy-MM-dd}.log.zip</fileNamePattern> </rollingPolicy> <encoder> <pattern>combined</pattern> </encoder> </appender> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%n%n%fullRequest%n%n%fullResponse%n%n</pattern> </encoder> </appender> <appender-ref ref="FILE" /> <appender-ref ref="STDOUT" /> </configuration>
web.xml
«TeeFilter» управляет регистрацией доступа. См. Http://logback.qos.ch/access.html
Необязательный «ViewStatusMessagesServlet» позволяет нам просматривать конфигурацию возврата через URL-адрес /logbackstatus
. См. Http://logback.qos.ch/manual/configuration.html.
<filter> <filter-name>TeeFilter</filter-name> <filter-class>ch.qos.logback.access.servlet.TeeFilter</filter-class> </filter> <filter-mapping> <filter-name>TeeFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>ViewStatusMessages</servlet-name> <servlet-class>ch.qos.logback.classic.ViewStatusMessagesServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ViewStatusMessages</servlet-name> <url-pattern>/logbackStatus</url-pattern> </servlet-mapping>
Тестовая Конфигурация
В нашем проекте src/main/resources
мы определяем logback.xml
файл.
В нашем проекте src/test/resources
мы определяем logback-test.xml
файл.
Условная конфигурация
Logback использует Janino позволяя способность выполнять условную конфигурацию.
Янино Мавен Зависимость
<dependency> <groupId>org.codehaus.janino</groupId> <artifactId>janino</artifactId> <version>2.6.1</version> </dependency>
Условные операции
- boolean isDefined(String prop);
- boolean isNull(String prop);
- String p(String prop);
- String property(String prop);
Смотрите: PropertyWrapperForScripts JavaDoc
<if condition='isDefined("catalina.home")'> <then> <property name="log.dir" value="${catalina.home}"/> </then> <else> <property name="log.dir" value="${user.dir}/logs"/> </else> </if>
Круто, что мы можем использовать профили среды Spring 3 spring.profiles.active
. В приведенном ниже примере метод property()
или p()
возвращает String, поэтому мы можем использовать такие функции String, как contains()
.
<if condition='property("spring.profiles.active").contains("dev")'> <then> <property name="log.dir" value="${catalina.home}"/> </then> <else> <property name="log.dir" value="${user.dir}/logs"/> </else> </if>
Примечание. Для тестирования с Maven через подключаемые модули Jetty или Tomcat ${user.dir}
разрешается переход к исходному проекту.
Модульная конфигурация
Мы можем настроить несколько файлов конфигурации, эффективно сегментируя нашу конфигурацию. Мы могли бы использовать более подробную конфигурацию ведения журнала для тестирования и более консервативное ведение журнала для производства.
logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true" scan="true" scanPeriod="5 seconds"> <property resource="logconfig/logback.properties"/> <include resource="logconfig/headerconfig.xml"/> <if condition='property("spring.profiles.active").contains("dev")'> <then> <include resource="logconfig/springbeans.xml"/> <include resource="logconfig/hibernatefile.xml"/> </then> <else> <include resource="logconfig/productionfile.xml"/> </else> </if> <include resource="logconfig/consolelog.xml"/> <root level="warn"> <appender-ref ref="console"/> </root> </configuration>
hibernatefile.xml
Включенные файлы используют внутри include
тега.
<?xml version="1.0" encoding="UTF-8"?> <included> <appender name="hibernatefile" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.dir}/${hibernate.logfile}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>${log.dir}/${hibernate.logfile}.%i.log.zip</fileNamePattern> <minIndex>1</minIndex> <maxIndex>6</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>50MB</maxFileSize> </triggeringPolicy> <encoder> <pattern>%date %level - %msg%n</pattern> </encoder> </appender> <logger name="org.springframework.orm" level="debug"> <appender-ref ref="hibernatefile" /> </logger> <logger name="org.springframework.jdbc" level="debug"> <appender-ref ref="hibernatefile" /> </logger> <logger name="org.springframework.transaction" level="debug"> <appender-ref ref="hibernatefile" /> </logger> <logger name="org.hibernate.ejb" level="debug"> <appender-ref ref="hibernatefile" /> </logger> <logger name="org.hibernate.sql" level="debug"> <appender-ref ref="hibernatefile" /> </logger> <logger name="org.hibernate.tool.hbm2ddl" level="debug"> <appender-ref ref="hibernatefile" /> </logger> </included>
Резюме
- НЕ использовать
System.out
илиSystem.err
- Используйте заполнитель параметра SLF4j
{}
вместо конкатенации строк, это устраняет необходимостьisDebugEnabled()
обхода журнала отладки. - Всегда определяйте
Logger
какprivate static final
- Использование SLF4j и Logback обеспечивает гибкую, интеллектуальную регистрацию. У нас есть инструменты, которые предоставляют широкие возможности ведения журналов для разработки корпоративных приложений
- Logback говорит изначально с SLF4j
- Конфигурация Java и Groovy
- Условное ведение журнала
- Модульная конфигурация
- Регистрация доступа
- Фильтрация сообщений
- Сжатие свернутых файлов журнала
- Отбор аппендеров по атрибутам времени выполнения
Дальнейшее чтение
- http://logback.qos.ch
- http://www.slf4j.org
- http://logging.apache.org/log4j/1.2
- Ведение журнала против производительности System.out
- Блог Best Practices Enterprise Spring
- Janino