Статьи

Пиление через логгеры Java

Пиление через логгеры Java

Это журнал!

Я знаю, о чем ты думаешь: «Это просто лесозаготовка!» Эта небольшая, но все же распространенная часть наших приложений предоставляет разработчикам, QA и специалистам по устранению неполадок информацию, помогающую в определении последовательности выполнения кода, проверке значений данных и проблемных точек в наших приложениях. Реальность такова, что без надежных реализаций регистрации мы бы потеряли значительный инструмент для устранения неполадок.

Варианты ведения журнала Java

  1. System.out / System.err
  2. java.util.logging (JUL)
  3. Apache Commons Jogging (также известный как Jakarta Commons Logging — JCL)
  4. Log4j
  5. SLF4J
  6. 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
  • Может перехватить  System.out & System.err

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
    • Условное ведение журнала
    • Модульная конфигурация
    • Регистрация доступа
    • Фильтрация сообщений
    • Сжатие свернутых файлов журнала
    • Отбор аппендеров по атрибутам времени выполнения

Дальнейшее чтение

источники