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

API ведения журнала платформы Java 9

Изучите недавно введенный API ведения журнала в Java 9 вместе с примерами, которые охватывают наиболее распространенные случаи.

Автор оригинала: Marcos Lopez Gonzalez.

1. введение

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

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

2. Создание пользовательской реализации

В этом разделе мы покажем основные классы API ведения журнала, которые мы должны реализовать для создания нового регистратора. Мы сделаем это, реализовав простой регистратор, который печатает все журналы на консоль.

В этом разделе мы покажем основные классы API ведения журнала, которые мы должны реализовать для создания нового регистратора. Мы сделаем это, реализовав простой регистратор, который печатает все журналы на консоль.

Основной класс, который мы должны создать, – это Logger . Этот класс должен реализовать систему .Интерфейс Logger и эти четыре метода, по крайней мере:

  • getName() : возвращает имя регистратора. Он будет использоваться JDK для создания регистраторов по имени
  • isLoggable() : указывает, для каких уровней включен регистратор
  • log() : это метод, который выводит журнал в любую базовую систему, используемую приложением, – в нашем случае в консоль. Существует 2 метода log() для реализации, каждый из которых получает разные параметры

Давайте посмотрим, как будет выглядеть наша реализация:

public class ConsoleLogger implements System.Logger {

    @Override
    public String getName() {
        return "ConsoleLogger";
    }

    @Override
    public boolean isLoggable(Level level) {
        return true;
    }

    @Override
    public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) {
        System.out.printf("ConsoleLogger [%s]: %s - %s%n", level, msg, thrown);
    }

    @Override
    public void log(Level level, ResourceBundle bundle, String format, Object... params) {
        System.out.printf("ConsoleLogger [%s]: %s%n", level, 
          MessageFormat.format(format, params));
    }
}

Наш класс ConsoleLogger переопределяет четыре упомянутых метода. Метод getName() возвращает строку, в то время как метод isLoggable() возвращает true во всех случаях. Наконец, у нас есть метод 2 log () , который выводится на консоль.

2.2. Создание регистратора

Как только мы создадим наш регистратор, нам нужно реализовать LoggerFinder , который создает экземпляры нашего ConsoleLogger .

Для этого мы должны расширить абстрактный класс System.LoggerFinder и реализовать метод getLogger() :

public class CustomLoggerFinder extends System.LoggerFinder {

    @Override
    public System.Logger getLogger(String name, Module module) {
        return new ConsoleLogger();
    }
}

В этом случае мы всегда возвращаем наш ConsoleLogger .

Наконец, нам нужно зарегистрировать наш LoggerFinder как сервис, чтобы он мог быть обнаружен JDK . Если мы не предоставим реализацию, по умолчанию будет использоваться SimpleConsoleLogger .

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

Поскольку мы используем Java 9, мы упакуем ваш класс в модуль и зарегистрируем нашу службу в module-info.java файл:

module com.baeldung.logging {
    provides java.lang.System.LoggerFinder
      with com.baeldung.logging.CustomLoggerFinder;
    exports com.baeldung.logging;
}

Для получения дополнительной информации о модулях Java ознакомьтесь с этим другим учебником .

2.3. Тестирование Нашего Примера

Чтобы проверить наш пример, давайте создадим еще один модуль, который будет действовать как приложение. Это будет содержать только класс Main , который использует нашу реализацию сервиса.

Этот класс получит экземпляр нашего ConsoleLogger , вызвав метод System.getLogger() :

public class MainApp {

    private static System.Logger LOGGER = System.getLogger("MainApp");

    public static void main(String[] args) {
        LOGGER.log(Level.ERROR, "error test");
        LOGGER.log(Level.INFO, "info test");
    }
}

Внутренне JDK будет принимать наши Пользовательский поиск регистратора внедрение и создание экземпляра нашего КонсольЛоггер.

После этого давайте создадим файл module-info для этого модуля:

module com.baeldung.logging.app {
}

На данный момент структура нашего проекта будет выглядеть следующим образом:

├── src
│   ├── modules
│   │   ├── com.baeldung.logging
│   │   │   ├── com
│   │   │   │   └── baeldung
│   │   │   │       └── logging
│   │   │   │           ├── ConsoleLogger.java
│   │   │   │           └── CustomLoggerFinder.java
│   │   │   └── module-info.java
│   │   ├── com.baeldung.logging.app
│   │   │   ├── com
│   │   │   │   └── baeldung
│   │   │   │       └── logging
│   │   │   │           └── app
│   │   │   │               └── MainApp.java
│   │   │   └── module-info.java
└──

Наконец, мы скомпилируем наши два модуля и поместим их в каталог mods :

javac --module-path mods -d mods/com.baeldung.logging \
  src/modules/com.baeldung.logging/module-info.java \
  src/modules/com.baeldung.logging/com/baeldung/logging/*.java

javac --module-path mods -d mods/com.baeldung.logging.app \
  src/modules/com.baeldung.logging.app/module-info.java \
  src/modules/com.baeldung.logging.app/com/baeldung/logging/app/*.java

Наконец, давайте запустим класс Main модуля app :

java --module-path mods \
  -m com.baeldung.logging.app/com.baeldung.logging.app.MainApp

Если мы посмотрим на вывод консоли, то увидим, что наши журналы печатаются с помощью нашего ConsoleLogger :

ConsoleLogger [ERROR]: error test
ConsoleLogger [INFO]: info test

3. Добавление внешней структуры ведения журнала

В нашем предыдущем примере мы записывали все наши сообщения в консоль, что аналогично тому, что делает регистратор по умолчанию. Одно из наиболее полезных применений API ведения журнала в Java 9 заключается в том , чтобы позволить приложениям направлять журналы JDK в ту же структуру ведения журнала, которую использует приложение , и именно это мы собираемся сделать в этом разделе.

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

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

3.1. Пользовательские Реализации С использованием SLF4J

Во-первых, мы реализуем другой Logger , который создаст новый регистратор SLF4J для каждого экземпляра:

public class Slf4jLogger implements System.Logger {

    private final String name;
    private final Logger logger;

    public Slf4jLogger(String name) {
        this.name = name;
        logger = LoggerFactory.getLogger(name);
    }

    @Override
    public String getName() {
        return name;
    }
    
    //...
}

Обратите внимание, что это Лесоруб является является .

Для остальных методов мы будем полагаться на реализацию в экземпляре регистратора SLF4J . Таким образом, наш Регистратор будет включен, если включен регистратор SLF4J:

@Override
public boolean isLoggable(Level level) {
    switch (level) {
        case OFF:
            return false;
        case TRACE:
            return logger.isTraceEnabled();
        case DEBUG:
            return logger.isDebugEnabled();
        case INFO:
            return logger.isInfoEnabled();
        case WARNING:
            return logger.isWarnEnabled();
        case ERROR:
            return logger.isErrorEnabled();
        case ALL:
        default:
            return true;
    }
}

И методы журнала вызовут соответствующий метод регистратора SLF4J в зависимости от используемого уровня журнала:

@Override
public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) {
    if (!isLoggable(level)) {
        return;
    }

    switch (level) {
        case TRACE:
            logger.trace(msg, thrown);
            break;
        case DEBUG:
            logger.debug(msg, thrown);
            break;
        case INFO:
            logger.info(msg, thrown);
            break;
        case WARNING:
            logger.warn(msg, thrown);
            break;
        case ERROR:
            logger.error(msg, thrown);
            break;
        case ALL:
        default:
            logger.info(msg, thrown);
    }
}

@Override
public void log(Level level, ResourceBundle bundle, String format, Object... params) {
    if (!isLoggable(level)) {
        return;
    }
    String message = MessageFormat.format(format, params);

    switch (level) {
        case TRACE:
            logger.trace(message);
            break;
        // ...
        // same as the previous switch
    }
}

Наконец, давайте создадим новый LoggerFinder , который использует наш Slf4jLogger :

public class Slf4jLoggerFinder extends System.LoggerFinder {
    @Override
    public System.Logger getLogger(String name, Module module) {
        return new Slf4jLogger(name);
    }
}

3.2. Конфигурация модуля

Как только мы реализуем все наши классы, давайте зарегистрируем наш сервис в нашем модуле и добавим зависимость модуля SLF4J:

module com.baeldung.logging.slf4j {
    requires org.slf4j;
    provides java.lang.System.LoggerFinder
      with com.baeldung.logging.slf4j.Slf4jLoggerFinder;
    exports com.baeldung.logging.slf4j;
}

Этот модуль будет иметь следующую структуру:

├── src
│   ├── modules
│   │   ├── com.baeldung.logging.slf4j
│   │   │   ├── com
│   │   │   │   └── baeldung
│   │   │   │       └── logging
│   │   │   │           └── slf4j
│   │   │   │               ├── Slf4jLoggerFinder.java
│   │   │   │               └── Slf4jLogger.java
│   │   │   └── module-info.java
└──

Теперь мы можем скомпилировать этот модуль в каталог mods , как мы делали в предыдущем разделе.

Обратите внимание, что для компиляции этого модуля мы должны поместить jar slf4j-api в каталог mods. Кроме того, имейте в виду использовать модульную версию библиотеки. Последнюю версию можно найти в Maven Central .

3.3. Добавление Логбэка

Мы почти закончили, но нам все еще нужно добавить зависимости и конфигурацию обратной связи. Для этого поместите файлы logback-classic и logback-core в каталог mods .

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

Наконец, давайте создадим файл конфигурации логбэка и поместим его в каталог mods :


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

    
        
    

3.4. Запуск Нашего Приложения

На этом этапе мы можем запустить наше приложение с помощью нашего модуля SLF4J.

В этом случае нам также необходимо указать наш файл конфигурации логбэка :

java --module-path mods \
  -Dlogback.configurationFile=mods/logback.xml \
  -m com.baeldung.logging.app/com.baeldung.logging.app.MainApp

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

2018-08-25 14:02:40 [main] ERROR MainApp -- error test
2018-08-25 14:02:40 [main] INFO  MainApp -- info test

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

В этой статье мы показали, как создать пользовательский регистратор в Java 9 с помощью нового API регистрации платформы. Кроме того, мы реализовали пример с использованием внешней среды ведения журнала, которая является одним из наиболее полезных вариантов использования этого нового API.

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