Logging

Logging

Problem

  • Как узнать что все модули приложения запустились корректно?

  • Как узнать что в приложении, которое используется клиентами произошла ошибка?

  • Как узнать при каких обстоятельствах произошла ошибка?

  • Как локализировать ошибки?

Solution

  • Logging

Logging (Логирование/Журналирование)

Logging

  • Без логов найти проблему на продакшене очень сложно (не возможно)

  • Принцип «Чем больше логов, тем лучше» – не работает.

  • Вывод логов требует процессорного времени

Frameworks

  • Log4j

  • java.util.logging

  • Apache Commons logging

  • Logback

  • Log4j 2

  • Simple Logging Facade for Java (SLF4J)

Log4j

Log4j

  • Появился первым

  • Очень широко используется

  • Большой ассортимент возможностей

java.util.logging

java.util.logging

  • С версии JavaSE 1.4

  • Не требует дополнительных библиотек

  • Уступает Log4j по возможностям и по популярности

Apache Commons Logging

Apache Commons Logging

  • Прослойка между разработчиком и конкретным фреймворком логирования

  • «Унифицированный» интерфейс

  • Абстрагирует Log4j, java.util.Logging, Avalon LogKit, Lumberjack

  • Не занимается инициализацией и конфигурация конкретных фреймворков

SLF4J

SLF4J

  • Абстрагирующий фреймворк логирования

  • Поддерживает намного шире набор возможностей

  • Структура:

    • Общая часть библиотеки - API

    • Дополнительно подключаются нужные библиотеки

Logback

Logback

  • Вырос из Log4j (один автор у Logback, Log4j и SLF4J)

  • Взял самое лучшее у своего прародителя

Log4j

Использование Log4j

В основе лежат понятия:

  • Logger (Логгер)

  • Appender (Аппендер )

  • Layout (Компоновка )

Logger

Logger

  • org.apache.log4j.Logger

  • Установка уровня означает – сообщения, выводимые с этим уровнем или более высоким попадут в лог.

  • Все Loggers иерархичны

Levels

  • TRACE

  • DEBUG

  • INFO

  • WARN

  • ERROR

  • FATAL

  • OFF

Examples

ИмяНазначенный уровеньЭффективный уровень

by

INFO

INFO

by.rakovets

WARN

WARN

by.rakovets.logger

DEBUG

DEBUG

by.rakovets.logger.test

ERROR

ERROR

Examples

ИмяНазначенный уровеньЭффективный уровень

by

INFO

INFO

by.rakovets

нет

INFO

by.rakovets.logger

DEBUG

DEBUG

by.rakovets.logger.test

нет

DEBUG

Examples

ИмяНазначенный уровеньЭффективный уровень

root

INFO

INFO

by

нет

INFO

by.rakovets

нет

INFO

by.rakovets.logger

DEBUG

DEBUG

by.rakovets.logger.test

нет

DEBUG

Appender

Appender

  • Logger – это та точка, куда уходят сообщения в коде.

  • Appender – то та точка, куда они приходят в конечном итоге

  • Интерфейс org.apache.log4j.Appender

  • Appender наследуется от родительских логгеров

Реализации

  • Console

  • File

  • JDBC

  • JMS Topic

  • java.io.Writer

  • java.io.OutputStream

Loggers

ИмяНазначенный уровеньЭффективный уровень

root

INFO

INFO

by

нет

INFO

by.rakovets

нет

INFO

by.rakovets.logger

DEBUG

DEBUG

by.rakovets.logger.test

нет

DEBUG

additivity

Имя loggerНазначенные appendersЗначение additivityЭффективные appendersКомментарии

root

A1

A1

Родительских appenders нет, additivity значения не имеет

by

A2,A3

true

A1,A2,A3

appenders родительского (корневого) logger плюс собственные

by.rakovets

-

true

A1,A2,A3

Все appenders родительского logger (включая унаследованные), собственных нет

by.rakovets.logger

A4

true

A1,A2,A3,A4

Все appenders родительского logger (включая унаследованные) плюс собственные

info

A5

false

A5

Только собственные appenders – родительские не наследуются

info.rakovets

-

true

A5

Только родительские appenders – от ближайшего родителя, собственных нет

org.apache.log4j.ConsoleAppender

  • Ввод данных в консоль (STDOUT)

  • Удобно при отладке

  • Как правило, бессмысленно на продакшене (часто вывод в консоль глушится — перехватывается и никуда не пишется)

File Appenders

  • org.apache.log4j.FileAppender

    • Добавляет данные в конец файла до бесконечности

  • org.apache.log4j.RollingFileAppender

    • По достижению файлом заданного размера, текущему файлу добавляется расширение .0 и создается новый файл. Предыдущей с расширением .0 меняется расширение на .1. В конфигурации задается максимальный размер файла и максимальный индекс, по достижению которого файлы будут удаляться

File Appender

  • org.apache.log4j.varia.ExternallyRolledFileAppender

    • Делает то же самое что и org.apache.log4j.RollingFileAppender

    • Слушает определенный порт. Если туда послать сообщение RollOver, то он сделает внеочередную смену индекса

  • org.apache.log4j.DailyRollingFileAppender

    • Ротирует файл с определенной частотой, а не по размеру файла. Например: '.'yyyy-MM – файл ротируется раз в месяц

    • К имени лога будет добавляться соответствующая дата. Благодаря этому логи уникальны и удобны в поиске

Layout

Layout

  • Конфигурация формата вывода

  • Наследуют org.apache.log4j.Layout

    • org.apache.log4j.SimpleLayout - самый простой, на выходе уровень лога и само сообщение

    • org.apache.log4j.HTMLLayout

    • org.apache.log4j.xml.XMLLayout

    • org.apache.log4j.TTCCLayout - Time-Thread-Category-Context

    • org.apache.log4j.PatternLayout - самый популярный и мощный

    • org.apache.log4j.EnhancedPatternLayout с версии 1.2.16

Конфигурация

Конфигурация

  • Через

    • properties файл (log4j.properties)

    • xml файл(log4j.xml)

  • Оба варианта равнозначны

  • При инициализации classpath ищется сначала log4j.xml потом log4j.properties.

log4j.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration debug="false" xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="Cp866"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                    value="%d{ISO8601} [%-5p][%-16.16t][%32.32c] - %m%n"/>
        </layout>
    </appender>

    <root>
        <priority value="ERROR"/>
        <appender-ref ref="ConsoleAppender"/>
    </root>
</log4j:configuration>

log4j.properties

log4j.debug=false

log4j.rootLogger=ERROR, ConsoleAppender

log4j.appender.ConsoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.ConsoleAppender.encoding=Cp866
log4j.appender.ConsoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.ConsoleAppender.layout.ConversionPattern=%d{ISO8601} [%-5p][%-16.16t][%32.32c] - %m%n

Использование

Использование

  • Инициализация Log4j: автоматически ищется в classpath конфигурация

  • Использование Logger:

public class Program {
    private static final Logger logger=Logger.getLogger(MyClass.class);

    void someMethod() {
        logger.info("Info level message");
        try {
            // код, вызывающий исключение
        } catch(RateCalculationException ex) {
            logger.error("Error while calculating rate change!", ex);
        }
    }
}

Вывод в Debug/Trace

  • Так делать не стоит:

logger.debug("Starting rate charge calculation for account " + accountNum
        + " with parameters: rest=" + rest
        + ", percent=" + percent
        + " period=" + period);
  • Выводить в DEBUG/TRACE с дополнительно проверкой:

if (logger.isDebugEnabled()) {
    logger.debug("Starting rate charge calculation for account " + accountNum
            + " with parameters: rest=" + rest
            + ", percent=" + percent
            + " period=" + period);
}

Diagnostic context

Diagnostic context

  • Используется для вывода дополнительной информации (например id, name пользователя, который совершает действия)

  • Реализации

    • Nested Diagnostic Context

    • Mapped Diagnostic Context

  • Привязывает к потоку с помощью ThreadLocal (обеспечивает доступность в любой точке)

NDC - Nested Diagnostic Context

  • Класс org.apache.log4j.NDC

  • Добавление информации NDC.push(String)

  • Удаление информации NDC.pop(). Метод push() и pop() должны быть парными

  • При завершении работы NDC.remove().

  • Для вывода используется опция %x

NDC examples

public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    NDC.push(getUserName());
    // тут выполняем какие-то действия
    doWork(); // вызываем метод
    // тут выполняем какие-то действия
    NDC.pop();
    NDC.remove();
}

private void doWork() {
    NDC.push(getPermissions());
    // тут выполняем какие-то действия
    NDC.pop();
}

MDC - Mapped Diagnostic Context

  • Класс org.apache.log4j.MDC

  • Методы

    • put(String,Object) - помещает в контекст объект

    • remove(String) - удаляет из контекста объект

    • get(String) - получает из контекста

    • clear() - очищает контекст

  • Для вывода используется опция %X