Поиск по сайту:

Учебное пособие по примерам Log4j2 - конфигурация, уровни, приложения


Добро пожаловать в учебник по примерам Apache Log4j2. Если вы спросите опытного разработчика о том, что больше всего раздражает в приложении, ответ может быть связан с ведением журнала. Если в приложении нет подходящей регистрации, обслуживание станет кошмаром. Большинство приложений проходят тестирование разработки, модульное тестирование, интеграционное тестирование. Но когда дело доходит до производства, вы всегда будете сталкиваться с уникальными сценариями и исключениями. Так что единственный способ выяснить, что произошло в конкретном случае, — отладить по логам. Многие фреймворки предоставляют какой-либо способ ведения журнала по умолчанию, но всегда лучше использовать стандартный для отрасли механизм ведения журнала. Apache Log4j — одна из наиболее широко используемых сред ведения журналов. Apache Log4j 2 — это следующая версия, которая намного лучше, чем Log4j.

Учебник по примерам Log4j

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

  1. Обзор Log4j2
  2. Архитектура Log4j2
  3. Конфигурация Log4j2
  4. Уровни Log4j2
  5. Поиски Log4j2
  6. Добавления Log4j2
  7. Фильтры Log4j2
  8. Макеты Log4j2
  9. Какой уровень Log4j2 следует использовать
  10. Краткий обзор руководства по Log4j2

Обзор Log4j2

Использование Logging API в приложении — это не роскошь, а необходимость. Log4j – это библиотека с открытым исходным кодом, опубликованная и лицензированная в рамках Apache Software. Вы можете отлаживать приложение с помощью Eclipse Debugging или некоторых других инструментов, но этого недостаточно и невозможно в производственной среде. Механизм ведения журнала предоставит вам несколько преимуществ, которых вы не найдете при обычной отладке.

Category / Operation (Debugging, Logging) Debugging Logging
Human Intervention There’s a need for human intervention No need for human intervention
Persistent Medium Can’t be integrated with persistent storage Can be integrated with persistent storage (Files, Database, NoSQL database, etc.)
May used for Auditing Can’t be used for achieving auditing Can be used for achieving auditing if it’s used efficiently
Sufficient for complicated structure and flow Not sufficient; you may get lost with flow. Sufficient
Productivity Less productive More productive

Как вы можете видеть выше, использование механизма ведения журнала будет более эффективным с меньшими затратами на обслуживание. Apache Log4j — передовой инструмент для ведения журналов в приложениях Java, поэтому вам следует использовать его.

Архитектура Log4j2

  • Applications will ask LogManager for a Logger with a specific name.

  • LogManager will locate the appropriate LoggerContext and then obtain Logger from it.

  • If the Logger isn’t created yet, it will be created and associated with LoggerConfig according to three choices below:

    1. Logger instance will be created and associated with the LoggerConfig that have the same name. For example App.class in getLogger(App.class) will be evaluated to be a String com.journaldev.App. LoggerConfig name is identical to fully qualified class name (Software component).
    2. Logger instance will be created and associated with the LoggerConfig that have the same Loggers parent package. For example com.journaldev in getLogger("com.journaldev")
    3. Logger instance will be created and associated with the Root LoggerConfig. Root LoggerConfig will be used when there is no configuration file or when you’re obtaining a logger with name not defined in the logger declarations.
  • LoggerConfig objects are created from Logger declaration in the configuration file. LoggerConfig is also used to handle LogEvents and delegate them for their defined Log4j2 Appenders.

  • Root logger is an exceptional case, in terms of its existence. It always exists and at the top of any logger hierarchy.

  • You may obtain the root logger by using the below statements:

    Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    Logger logger = LogManager.getRootLogger();
    
  • The name of log4j2 loggers are case sensitive.

  • Except root logger, all loggers can be obtained through passing their name into LogManager.getLogger().

  • LoggerContext is a vocal point for Logging system as you may have multiple LoggerContexts inside your application. Per each LoggerContext an active configuration should be set.

  • Log4j2 configuration contains all Logging system assets; LoggerConfig(s), Appender(s), Filter(s) and many others.

  • Calling of LogManager.getLogger() by passing the same name will always return the reference for the exact same logger instance.

  • Configuration of Logging system is typically done with the application initialization. This can take different forms; programmatically or by reading a log4j2 configuration file.

LoggerConfig (Is A) Root com com.journaldev com.journaldev.logging
Root X Child descendant descendant
com Parent X Child descendant
com.journaldev Ancestor Parent X Child
com.journaldev.logging Ancestor Ancestor Parent X

Чтобы прояснить отношения Родитель-Ребенок, приведенную выше таблицу следует читать следующим образом:

  • Root является родительским для com.
  • Root является предком com.journaldev.
  • Root является предком com.journaldev.logging.
  • com – это дочернее имя Root.
  • com является родителем для com.journaldev.
  • com является предком com.journaldev.logging.
  • com.journaldev.logging является дочерним для com.journaldev и так далее.

Экземпляр LoggerConfig считается предком другого LoggerConfig; если его имя, за которым следует точка, является префиксом имени потомка. Экземпляр LoggerConfig считается родительским для другого LoggerConfig; если между ними нет чередующихся имен.

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

Существует множество способов использования конфигурации Log4j2 в вашем приложении.

  1. Используя файл конфигурации, написанный в формате XML, JSON, YAML, или файл свойств.
  2. Программно, путем создания фабрики конфигураций и реализации конфигурации.
  3. Программно, вызывая API, представленные в интерфейсе конфигурации.
  4. Программно, вызывая методы внутреннего класса регистратора.

Мы сосредоточимся в основном на файле конфигурации. Тем не менее, полезно также знать подход к программированию, если вы хотите настроить определенную стратегию ведения журнала для определенного регистратора. Прежде всего, давайте рассмотрим случай, когда вы не предоставили файл конфигурации. Реализация Log4j2 предполагает, что существует системная переменная с именем log4j.configurationFile, указывающая расположение файла конфигурации log4j2.

package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App
{
    public static void main( String[] args ) {
    	Logger logger = LogManager.getRootLogger();
    	logger.trace("Configuration File Defined To Be :: "+System.getProperty("log4j.configurationFile"));
    }
}

Простой файл конфигурации log4j2 будет выглядеть следующим образом. конфигурация.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

А вот подробное объяснение приведенного выше кода:

  • Приложение обратилось к корневому регистратору, вызвав метод LogManager getRootLogger.
  • Ссылка на регистратор из LogManager запустила систему Log4j.
  • Log4j проверит системное свойство log4j.configurationFile, чтобы определить файл конфигурации log4j2. Конфигурация Log4j может быть записана в JSON, YAML и XML.
  • Мы можем установить системное свойство log4j.configurationFile через System.setProperties(log4j.configurationFile,FILE_PATH) или передав его как параметр JVM, как показано на рисунке ниже. Обратите также внимание на префикс протокола файла.

  • Если системное свойство не определено, порядок конфигурации имеет следующий приоритет:
    • Property ConfigurationFactory будет искать log4j2-test.properties в пути к классам.
    • YAML ConfigurationFactory будет искать log4j2-test.yaml или log4j2-test.yml в пути к классам.
    • JSON ConfigurationFactory будет искать log4j2-test.jsn или log4j2-test.json в пути к классам.
    • XML ConfigurationFactory будет искать log4j2-test.xml в пути к классам.
    • Property ConfigurationFactory будет искать log4j2.properties в пути к классам
    • YAML ConfigurationFactory будет искать log4j2.yml или log4j2.yaml в пути к классам.
    • JSON ConfigurationFactory будет искать log4j2.jsn или log4j2.json в пути к классам.
    • XML ConfigurationFactory будет искать log4j2.xml в пути к классам.
    • Если файл конфигурации не был предоставлен, имеет место DefaultConfiguration , и это приведет вас к набору поведения по умолчанию:
      • Будет использоваться корневой регистратор.
      • Уровень корневого регистратора будет установлен на ОШИБКА.
      • Корневой регистратор будет передавать сообщения журнала в консоль.
      • PatternLayout имеет значение %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n

      Использование файла конфигурации log4j2 делает настройку log4j2 такой простой, но давайте посмотрим, как мы можем настроить ее программно. Это все об использовании ConfigurationFactory.

      package com.journaldev;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileNotFoundException;
      import java.io.IOException;
      import org.apache.logging.log4j.Level;
      import org.apache.logging.log4j.core.Logger;
      import org.apache.logging.log4j.core.LoggerContext;
      import org.apache.logging.log4j.core.appender.ConsoleAppender;
      import org.apache.logging.log4j.core.config.Configuration;
      import org.apache.logging.log4j.core.config.ConfigurationFactory;
      import org.apache.logging.log4j.core.config.ConfigurationSource;
      import org.apache.logging.log4j.core.config.LoggerConfig;
      import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
      import org.apache.logging.log4j.core.layout.PatternLayout;
      public class App
      {
          public static void main( String[] args ) throws FileNotFoundException, IOException {
       
          	// Get instance of configuration factory; your options are default ConfigurationFactory, XMLConfigurationFactory,
          	// 	YamlConfigurationFactory & JsonConfigurationFactory
          	ConfigurationFactory factory =  XmlConfigurationFactory.getInstance();
       
          	// Locate the source of this configuration, this located file is dummy file contains just an empty configuration Tag
          	ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File("C:/dummyConfiguration.xml")));
       
          	// Get a reference from configuration
          	Configuration configuration = factory.getConfiguration(configurationSource);
       
          	// Create default console appender
          	ConsoleAppender appender = ConsoleAppender.createDefaultAppenderForLayout(PatternLayout.createDefaultLayout());
       
          	// Add console appender into configuration
          	configuration.addAppender(appender);
       
          	// Create loggerConfig
          	LoggerConfig loggerConfig = new LoggerConfig("com",Level.FATAL,false);
       
          	// Add appender
          	loggerConfig.addAppender(appender,null,null);
       
          	// Add logger and associate it with loggerConfig instance
          	configuration.addLogger("com", loggerConfig);
       
          	// Get context instance
          	LoggerContext context = new LoggerContext("JournalDevLoggerContext");
       
          	// Start logging system
          	context.start(configuration);
       
          	// Get a reference for logger
          	Logger logger = context.getLogger("com");
       
          	// LogEvent of DEBUG message
          	logger.log(Level.FATAL, "Logger Name :: "+logger.getName()+" :: Passed Message ::");
       
          	// LogEvent of Error message for Logger configured as FATAL
          	logger.log(Level.ERROR, "Logger Name :: "+logger.getName()+" :: Not Passed Message ::");
       
          	// LogEvent of ERROR message that would be handled by Root
          	logger.getParent().log(Level.ERROR, "Root Logger :: Passed Message As Root Is Configured For ERROR Level messages");
          }
      }
      

      • Вы можете использовать любую фабрику ConfigurationFactory, предоставленную Log4j2, или использовать фабрику по умолчанию. Мы использовали XMLConfigurationFactory, чтобы получить экземпляр ConfigurationFactory.
      • Factory предоставит вам экземпляр требуемой ссылки на конфигурацию, передав соответствующий файл конфигурации.
      • Экземпляр конфигурации будет использоваться вместе с LoggerContext для запуска системы ведения журнала.
      • Добавление консоли настроено и добавлено в экземпляр конфигурации с макетом по умолчанию. Этот Appender будет распечатывать сообщения в вашу консоль.
      • Экземпляр LoggerConfig создан с указанным именем, УРОВНЕМ и без использования фильтра. Созданный Appender будет назначен этому экземпляру LoggerConfig.
      • Экземпляр LoggerConfig добавлен в экземпляр конфигурации.
      • Создается новый экземпляр LoggerContext с определенным именем.
      • Экземпляр конфигурации был передан для экземпляра LoggerContext, и для последнего был запущен start.
      • Экземпляр средства ведения журнала был получен из LoggerContext. Этот экземпляр регистратора будет использоваться для запуска набора событий журнала.
      • Экземпляр Logger запустил три события, которые будут описаны в разделе «Уровни Log4j2».
      • com logger настроен на печать сообщений, уровень которых является FATAL.
      • По умолчанию корневой регистратор настроен на печать сообщений с уровнем ERROR.
      • Сообщения об ОШИБКЕ не будут регистрироваться регистратором com, поскольку его уровень FATAL.

      Ту же конфигурацию можно выполнить с помощью YAML, JSON или файла свойств. Однако конфигурация файла свойств log4j2 отличается от файла свойств log4j, поэтому убедитесь, что вы не пытаетесь использовать конфигурацию файла свойств log4j с log4j2. Это выдаст ошибку ниже;

      ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.
      

      При обработке приведенного выше кода вы получите следующий вывод:

      Logger Name :: com :: Passed Message ::
      00:01:27.705 [main] ERROR - Root Logger:: Passed Message As Root Is Configured For ERROR Level messages
      

      Первая строка журналов принадлежит регистратору com, а вторая — корневому регистратору. сообщение об ошибке com logger не печатается, потому что его уровень фатальный.

      Уровни Log4j2

      • Как мы уже говорили ранее, каждый регистратор связан с экземпляром LoggerConfig. Этот loggerConfig был определен в области конфигурации.
      • Уровень ведения журнала можно определить в области LoggerConfig.
      • Вы можете получить регистратор по его имени, родительскому пакету или указав корневой регистратор.
      • Root Logger — это узел верхнего уровня для каждой иерархии LoggerConfig.
      • После того как вы получите регистратор com.journaldev и инициируете logEvent для ведения журнала, loggerConfig (net.journaldev) зарегистрирует сообщение, и оно будет распространено вверх по иерархии без каких-либо уважение к уровням регистрации родителей. Таким образом, событие журнала будет распространяться на регистраторы com и Root, и они также будут регистрировать сообщение соответственно в соответствии с определенными уровнями.
      • После того, как вы получите регистратор com и инициируете logEvent для ведения журнала, loggerConfig(com) зарегистрирует сообщение, и сообщение будет также распространено вверх по иерархии без какого-либо учета родительских уровней ведения журнала. То есть корневой регистратор будет распространять событие журнала, а также регистрировать сообщение.
      • То же самое для иерархии net.journaldev.
      • Следующие разделы добавят дополнительные пояснения к аддитивной концепции.
      • Родитель может проигнорировать сообщение, используя концепцию фильтра или установив для дополнительного индикатора значение false, чтобы события журнала не передавались родителям.
      • У регистратора есть шанс проигнорировать сообщение, если соответствующий уровень loggerConfig БОЛЬШЕ, ЧЕМ уровень событий журнала.

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

      import net.NetApp;
      import net.journaldev.NetJournalDevApp;
      import com.ComApp;
      import com.journaldev.ComJournalDevApp;
      public class Main {
      	public static void main(String [] args){
      		new ComApp();
      		new ComJournalDevApp();
      		new NetApp();
      		new NetJournalDevApp();
      	}
      }
      
      package com.journaldev;
      import org.apache.logging.log4j.LogManager;
      import org.apache.logging.log4j.Logger;
      public class ComJournalDevApp {
      	public ComJournalDevApp(){
      		Logger logger = LogManager.getLogger(ComJournalDevApp.class);
      		logger.trace("COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::");
      	}
      }
      
      package net;
      import org.apache.logging.log4j.LogManager;
      import org.apache.logging.log4j.Logger;
      public class NetApp {
      	public NetApp(){
      		Logger logger = LogManager.getLogger(NetApp.class);
      		logger.error("NET :: LEVEL :: NetApp ERROR Message ::");
      	}
      }
      
      package net.journaldev;
      import org.apache.logging.log4j.LogManager;
      import org.apache.logging.log4j.Logger;
      public class NetJournalDevApp {
      	public NetJournalDevApp(){
      		Logger logger = LogManager.getLogger(NetJournalDevApp.class);
      		logger.error("NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::");
      	}
      }
      

      Принимая во внимание, что файл конфигурации log4j2 выглядит следующим образом:

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration>
        <Appenders>
          <Console name="Console">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
          </Console>
        </Appenders>
        <Loggers>
          <Root level="ERROR">
            <AppenderRef ref="Console"/>
          </Root>
        	<logger name="com" level="TRACE">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="com.journaldev" level="TRACE">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net" level="ERROR">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net.journaldev" level="ERROR">
        		<AppenderRef ref="Console"/>
        	</logger>
        </Loggers>
      </Configuration>
      

      Если вы запустите класс Main, вы увидите следующие результаты:

      10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
      10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
      10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      

      Вот подробное объяснение приведенного выше кода:

      • Файл конфигурации содержит пять определенных экземпляров loggerConfig: Root, com, com.journaldev, net и net.journaldev. Так же, как иерархия регистратора, показанная выше.
      • Корневой уровень настроен как ERROR, и фактически это значение по умолчанию.
      • Уровни com и com.journaldev настроены на TRACE.
      • уровни net и net.journaldev настроены как ERROR.
      • Вы могли заметить, что сообщения регистраторов ComAPP и ComJournalDevApp отображались два и три раза соответственно. Эти сообщения отображаются в соответствии с иерархией регистратора для ComApp и ComJournalDevApp, где они находятся в пакетах com и com.journalDev соответственно. Аналогичный случай с классами NetApp и NetJournalDevApp.
      • Родители распространяются, поскольку по умолчанию для индикатора добавления установлено значение true.

      Logging Space учитывает уровни событий журнала и уровень loggerConfig в дополнение к Logger Hierarchy.

      Так что, если мы изменим LoggerConfig для com на INFO и оставим всю программу как есть:

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration>
        <Appenders>
          <Console name="Console">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
          </Console>
        </Appenders>
        <Loggers>
          <Root level="ERROR">
            <AppenderRef ref="Console"/>
          </Root>
        	<logger name="com" level="INFO">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="com.journaldev" level="TRACE">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net" level="ERROR">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net.journaldev" level="ERROR">
        		<AppenderRef ref="Console"/>
        	</logger>
        </Loggers>
      </Configuration>
      

      Тогда результат будет таким, как показано ниже:

      11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      

      • Конечно, вы можете заметить, что событие журнала ComAPP было проигнорировано из-за определенного уровня loggerConfig для пакета com. Уровень INFO (400) меньше, чем уровень события журнала, который здесь TRACE(600). Таким образом, сообщение ComApp больше не будет отображаться, и чтобы оно отображалось, вам нужно изменить уровень LoggerConfig для com, чтобы он был TRACE(600) или ALL(Integer.MAX_VALUE).

      Чтобы убедиться, что события журнала отображаются, уровень LoggerConfig должен быть больше или равен уровню события журнала.

      В таблице ниже показаны уровни log4j2 и вес каждого из них:

      LEVEL Weight
      OFF 0
      FATAL 100
      ERROR 200
      WARN 300
      INFO 400
      DEBUG 500
      TRACE 600
      ALL Integer.MAX_VALUE

      Наверняка приведенная выше таблица разъясняет гораздо больше, чем просто слова, и дает вам основную причину того, что событие журнала TRACE не отображается, когда уровень LoggerConfig равен INFO.

      Обратите внимание, что распространение событий журнала вверх по иерархии регистратора выходит за рамки этих вычислений и игнорирует уровни.

      Но что произойдет, если мы удалим LoggerConfig для com.journaldev из конфигурации и добавим новый для com.journaldev.logging, чтобы файл конфигурации выглядел следующим образом:

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration>
        <Appenders>
          <Console name="Console">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
          </Console>
        </Appenders>
        <Loggers>
          <Root level="ERROR">
            <AppenderRef ref="Console"/>
          </Root>
        	<logger name="com" level="TRACE">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="com.journaldev.logging" level="TRACE">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net" level="ERROR">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net.journaldev" level="ERROR">
        		<AppenderRef ref="Console"/>
        	</logger>
        </Loggers>
      </Configuration>
      

      • Когда события журнала создаются регистратором с именем com.journaldev.logging, LoggerConfig, связанный с этим именем (например, com.journaldev.logging), используется для обработки и вывода сообщения.
      • Поскольку для дополнительного атрибута com.journaldev.logging LoggerConfig по умолчанию установлено значение true, событие журнала было распространено для родителя, который в данном случае относится к com.journaldev.
      • Поскольку com.journaldev LoggerConfig не определен в конфигурации, никаких действий не происходит, а событие журнала распространяется на com, а затем на корневые экземпляры LoggerConfig.
      • Com & Root получит событие журнала и распечатает его независимо от уровня, с которым оно было отправлено.

      В результате для упомянутых точек вы увидите следующие результаты:

      14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
      14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
      14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      

      И вы можете заметить следующее:

      • Событие журнала в пакете com было показано дважды. Один для com, а второй для Root.
      • Событие журнала на com.journaldev показано дважды. Один для com и второй для Root. Несмотря на то, что это было три раза раньше, но на данный момент LoggerConfig для com.journaldev отсутствует, поэтому в пакете com.journaldev может не происходить логирование, и событие будет распространяться на com и Root.
      • Событие журнала на com.journaldev.logging было показано три раза: один раз для пакета com.journaldev.logging, второй для com и третий для Root. Согласно распространению Logger Hierarchy, он должен отображаться четыре раза, но из-за отсутствия com.jounraldev LoggerConfig он отображается три раза.

      Если вы определили экземпляр com.journaldev LoggerConfig без указания уровня, он унаследует уровень своего родителя.

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

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration>
        <Appenders>
          <Console name="Console">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
          </Console>
        </Appenders>
        <Loggers>
          <Root level="ERROR">
            <AppenderRef ref="Console"/>
          </Root>
        	<logger name="com" level="TRACE">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="com.journaldev">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="com.journaldev.logging" level="TRACE">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net" level="ERROR">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net.journaldev" level="ERROR">
        		<AppenderRef ref="Console"/>
        	</logger>
        </Loggers>
      </Configuration>
      
      Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
      Root Root ERROR ERROR
      com com TRACE TRACE
      com.journaldev com TRACE TRACE
      com.journaldev.logging com.journaldev.logging TRACE TRACE

      • Пакет com.journaldev.logging уже связан с LoggerConfig с уровнем журнала TRACE.
      • Пакет com.journaldev уже связан с LoggerConfig без указания уровня журнала, поэтому он унаследует свой родительский уровень журнала, и для пакета com значение наверняка будет TRACE.
      • пакет com уже связан с Loggerconfig с уровнем журнала TRACE.
      • По умолчанию корневой уровень имеет уровень журнала ERROR.
      • Если пакет com не объявлен, com.journaldev LoggerConfig унаследует уровень журнала Root.

      Ниже приведен результат выполнения, когда com.journaldev наследует уровень журнала com:

      14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
      14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
      14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      

      И ниже результат будет, если вы удалите объявление LoggerConfig для пакета com:

      14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      

      Вы можете заметить, что для com и com.journaldev не регистрируются сообщения. Ниже приведены причины.

      • Удаление LoggerConfig, связанного с пакетом com, приведет к игнорированию всех событий журнала, упомянутых в этом пакете.
      • Поскольку в конфигурации не определен LoggerConfig для пакета com, LoggerConfig, связанный с com.journaldev, унаследует уровень журнала от своего родителя. Com не определен, а иерархия Logger достигла вершины и теперь относится к Root. Корневой уровень журнала — ERROR (200), а уровень события журнала в com.journaldev — TRACE (600) — см. ComJournalDevApp — и, согласно предыдущему уравнению, уровень LoggerConfig должен быть больше или равен событию журнала, и это ложно, поэтому нет здесь будут отображаться сообщения для com.journaldev.

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

      X (N/A) LoggerConfig Level OFF(0) FATAL(100) ERROR(200) WARN(300) INFO(400) DEBUG(500) TRACE(600) ALL(MAX)
      Event Level X X X X X X X X X
      OFF(0) X YES NO NO NO NO NO NO NO
      FATAL(100) X NO YES YES YES YES YES YES YES
      ERROR(200) X NO NO YES YES YES YES YES YES
      WARN(300) X NO NO NO YES YES YES YES YES
      INFO(400) X NO NO NO NO YES YES YES YES
      DEBUG(500) X NO NO NO NO NO YES YES YES
      TRACE(600) X NO NO NO NO NO NO YES YES
      ALL(MAX) X NO NO NO NO NO NO NO YES

      • Не существует прямого метода, который можно использовать для создания событий журнала ВЫКЛ/ВСЕ.
      • В основном, для создания событий журнала OFF/ALL вы можете использовать logger.log(Level.OFF, \Msg) или logger.log(LEVEL.ALL,\Msg) соответственно.
      • Метод журнала отвечает за обработку события журнала в соответствии с упомянутым уравнением.

      Уравнение обработки гласит: если уровень LoggerConfig больше или равен уровню события журнала, событие будет принято для дальнейшей обработки.

      Событие журнала будет принято для дальнейшей обработки — это очень важно, потому что у вас есть возможность предотвратить обработку некоторого события, даже если оно принято с помощью фильтров Log4j2. Вы можете установить для дополнительного свойства значение false, чтобы избежать распространения событий журнала на родительские регистраторы. Следуя ниже тому же примеру, который вы видели раньше, но на этот раз с атрибутом аддитивности, вы можете заметить разницу.

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration>
        <Appenders>
          <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
          </Console>
        </Appenders>
        <Loggers>
          <Root level="ERROR">
            <AppenderRef ref="Console"/>
          </Root>
        	<logger name="com" level="TRACE" additivity="false">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="com.journaldev" additivity="false">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="com.journaldev.logging" level="TRACE" additivity="false">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net" level="ERROR" additivity="false">
        		<AppenderRef ref="Console"/>
        	</logger>
        	<logger name="net.journaldev" level="ERROR" additivity="false">
        		<AppenderRef ref="Console"/>
        	</logger>
        </Loggers>
      </Configuration>
      

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

      17:55:30.558 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
      17:55:30.560 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      17:55:30.561 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      17:55:30.561 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      17:55:30.562 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      

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

      Поиск Log4j2

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

      • Поиск контекстной карты
      • Поиск даты
      • Поиск среды
      • Поиск Java
      • Поиск JNDI
      • Поиск входного аргумента JVM (JMX)
      • Поиск основных аргументов
      • Поиск на карте
      • Поиск структурированных данных
      • Поиск свойств системы
      • Поиск в Интернете

      Вы можете обратиться к документации Log4j2 для получения дополнительной информации о каждом типе поиска, но давайте рассмотрим здесь несколько примеров, чтобы охватить основы поиска Log4j2. Поиск среды представляет собой способ, которым вы можете передать значение среды (либо Linux и т.д./профиль, системную среду Windows или сценарии запуска для приложения. Как известно большинству из нас, у нас есть возможность определить набор значений среды для приложения Давайте рассмотрим наиболее известные способы определения переменных окружения.

      1. Определите переменную среды с помощью средства среды Windows:
        • Щелкните правой кнопкой мыши значок своего компьютера и выберите свойства. Должен отобразиться главный экран панели управления.
        • Нажмите «Дополнительные параметры системы», а затем откройте окно «Переменные среды».
        • В разделе Системные переменные определите переменную JournalDevVar со значением JournalDev.
        • Обновление PatternLayout внутри вашего файла log4j2.xml, чтобы он содержал вашу новую добавленную переменную.

      <старт=\2\>

    • Определите переменные среды с помощью средства сценария запуска.
      • Вместо использования обычного сценария по умолчанию вы можете использовать средство запуска сценария Eclipse IDE, щелкнуть меню «Выполнить» и выбрать «Выполнить конфигурацию».
      • Перейдите на вкладку Среда и определите в ней свою переменную.
    • <Console name="Console" target="SYSTEM_OUT">
          <PatternLayout pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n"/>
      </Console>
      

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

      23:57:02.511 JournalDev www.journaldev.com [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
      23:57:02.517 JournalDev www.journaldev.com [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
      23:57:02.520 JournalDev www.journaldev.com [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
      23:57:02.523 JournalDev www.journaldev.com [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
      23:57:02.527 JournalDev www.journaldev.com [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
      
      EnvironmentLookup lookup = new EnvironmentLookup();
      LogManager.getRootLogger().error(lookup.lookup("JournalDevSecondVar"));
      

      Приложения Log4j2

      Ранее вы видели, как можно использовать Lookups для ввода переменных в ваш файл конфигурации. Тем не менее, вы можете изменить среду, через которую проходили ваши сообщения. Вместо того, чтобы использовать консоль напрямую, вам может понадобиться такой репозиторий файлов или баз данных, чтобы ваши сообщения сохранялись постоянно. Log4j2 предоставил множество приложений Appender, и вы можете обратиться к документации log4j2, чтобы получить дополнительные сведения об Appender. Вкратце ниже приведен список всех приложений Log4j2.

      1. Консольное приложение
      2. Асинхронное приложение
      3. Отказоустойчивое приложение
      4. FileAppender
      5. FlumeAppender
      6. JDBCAppender
      7. JMSAppender
      8. JPAAppender
      9. MemoryMappedFileAppender
      10. NoSQLAppender
      11. OutputStreamAppender
      12. RandomAccessFileAppender
      13. Перезаписать приложение
      14. RollingFileAppender
      15. RollingRandomAccessFileAppender
      16. РутингAppender
      17. SMTPAppender
      18. СокетАппендер
      19. SyslogAppender

      Наиболее известными средствами, используемыми для регистрации событий , являются консоль, файл и база данных. Поскольку файл будет сохранять ваши сообщения, база данных может использоваться для их аудита. С этой целью в этом разделе основное внимание будет уделено тому, как можно эффективно использовать JDBCAppender.

      JDBCAppender

      Основная цель JDBCAppender — записывать события журнала в реляционную таблицу через соединения JDBC. Мы не будем тратить много времени на объяснение того, как вы можете оптимизировать свои пулы соединений, поскольку это руководство не предназначено для этой цели. Но вы наверняка получите полнофункциональный пример, который поможет записывать ваши события журнала в базу данных. Прежде чем мы сможем продолжить, давайте посмотрим на все необходимые параметры и описание для каждого из них, чтобы правильно настроить JDBCAppender.

      Parameter Name Type Description
      Name String Required, The name of the Appender
      ignoreExceptions boolean Default value is set to true, making exceptions thrown to be logged also and then ignored. False value means the exception will be propagated for the caller.
      filter Filter The filter that should be used to make a decision whether the log events are going to be handled by this Appender or not.
      bufferSize int Default value is zero, indicating there’s no buffering have been done upon log events. Value greater than 0 would lead the Appender to buffer log events and then flush them once the buffer reaches the limit specified.
      connectionSource ConnectionSource Required, the connections source from which the database connections should be retrieved.
      tableName String Required, the name of the Table on which your log events should be persisted.
      columnConfigs ColumnConfig[] Required, additional information may be set upon those used columns and how the data should be persisted on each of them. This can be handled with multiple <Column> elements.
      Parameter Name Type Description
      jndiName String Required, full prefixed JNDI name that the javax.sql.Datasource is bound to.
      Parameter Name Type Description
      class String Requird, The fully qualified name for a class containg a static factory method for obtaining JDBC connections.
      method boolean Required, The name of the static factory method for obtaining JDBC connections.
      Parameter Name Type Description
      name String Required, the name of the database column
      pattern String Ability to specify any legal pattern that Log event would be formatted with
      literal String Ability to specify literal value in this column (i.e. SEQ.NEXTVAL)
      isEventTimestamp boolean Indicating whether the event would consider Timestamp
      isUnicode boolean For unicode purpose as you may refer for Log4j2 documentation for further details
      isClob boolean For storing character large object, you may refer for Log4j2 documentation for further details.

      Поскольку вы вынуждены использовать JNDI, в нашем примере будет настроен источник данных подключения для базы данных Oracle и Apache Tomcat 7.

      • Если вы не установили базу данных Oracle в свою среду, будем признательны, если сможете это сделать. Если вы мало знаете об Oracle, я рекомендую вам установить его экспресс-версию.
      • Установите Apache Tomcat 7 в своей среде.
      • Создайте проект Maven WebApp в Eclipse.

      • Убедитесь, что ваш проект успешно создан, и если вы заметите какие-либо ошибки в pom, убедитесь, что вы их исправили.
      • Добавить зависимости Log4j2.

      <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-api</artifactId>
         <version>2.2</version>
      </dependency>
      <dependency>
         <groupId>org.apache.logging.log4j</groupId>
         <artifactId>log4j-core</artifactId>
         <version>2.2</version>
      </dependency>
      

      • Настройте свой контекст, чтобы включить объявление источника данных MySQL. Согласно документации Apache, этот файл должен находиться в папке META-INF вашего веб-приложения.

      <Context path="/JournalDevWebLogging"
      	privileged="true" antiResourceLocking="false" antiJARLocking="false">
      	<Resource name="jdbc/JournalDevDB" auth="Container"
      			factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
      			type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
      			username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
      			url="jdbc:mysql://localhost:3306/journaldev" />
      </Context>
      

      • Настройте свою базу данных и создайте таблицу регистрации,

      CREATE TABLE `logging` (
        `EVENT_ID` int(11) NOT NULL AUTO_INCREMENT,
        `EVENT_DATE` datetime DEFAULT NULL,
        `LEVEL` varchar(45) DEFAULT NULL,
        `LOGGER` varchar(45) DEFAULT NULL,
        `MSG` varchar(45) DEFAULT NULL,
        `THROWABLE` varchar(45) DEFAULT NULL,
        PRIMARY KEY (`EVENT_ID`)
      ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
      

      • Настройте файл log4j2.xml, как показано ниже:

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration>
      	<Appenders>
      		<Console name="Console" target="SYSTEM_OUT">
      			<PatternLayout
      				pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n" />
      		</Console>
      		<JDBC name="databaseAppender" tableName="journaldev.logging">
      			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
      			<Column name="EVENT_DATE" isEventTimestamp="true" />
      			<Column name="LEVEL" pattern="%level" />
      			<Column name="LOGGER" pattern="%logger" />
      			<Column name="MSG" pattern="%message" />
      			<Column name="THROWABLE" pattern="%ex{full}" />
      		</JDBC>
      	</Appenders>
      	<Loggers>
      		<Root level="ERROR">
      			<AppenderRef ref="Console" />
      		</Root>
      		<logger name="com" level="TRACE" additivity="false">
      			<AppenderRef ref="databaseAppender" />
      		</logger>
      		<logger name="com.journaldev" additivity="false">
      			<AppenderRef ref="databaseAppender" />
      		</logger>
      	</Loggers>
      </Configuration>
      

      • Создайте любой веб-ресурс, который позволит вам получить ссылку на регистратор, а затем зарегистрировать событие.

      package com.journaldev;
      import java.io.IOException;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import org.apache.logging.log4j.LogManager;
      import org.apache.logging.log4j.Logger;
      public class JournalDevServlet extends HttpServlet{
      	private static final long serialVersionUID = 1L;
      	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
      			Logger logger = LogManager.getLogger(JournalDevServlet.class);
      			logger.trace("JournalDev Database Logging Message !");
      	}
      }
      

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

      package com.journaldev;
      import javax.naming.Context;
      import javax.naming.InitialContext;
      import javax.naming.NamingException;
      import javax.servlet.ServletContextEvent;
      import javax.servlet.ServletContextListener;
      import org.apache.logging.log4j.LogManager;
      public class JournalDevServletContextListener implements ServletContextListener{
      	private InitialContext context = null;
      	public void contextDestroyed(ServletContextEvent event) {
      	}
      	public void contextInitialized(ServletContextEvent event) {
      		try {
      			// Get initial context
      			context = new InitialContext();
      			// Get a reference for sub context env
      			Context envContext = (Context)context.lookup("java:comp/env");
      			// Get a reference for sub context jdbc and then locating the data source defined
      			LogManager.getRootLogger().error(((Context)envContext.lookup("jdbc")).lookup("JournalDevDB"));
      		} catch (NamingException e) {
      			LogManager.getRootLogger().error(e);
      		}
      	}
      }
      

      • Определите свой сервлет в файле web.xml.
      • Запустите приложение и получите доступ к указанному выше сервлету. Ниже вы увидите журналы.

      Mar 15, 2015 2:31:41 PM org.apache.catalina.core.AprLifecycleListener init
      INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jdk1.6.0_26\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.6.0_26\jre\bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin/server;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/lib/amd64;D:\OracleWebCenter\OracleWC\Oracle11g\app\oracle\product\11.2.0\server\bin;;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;D:\OracleDB\app\product\11.2.0\dbhome_1\bin;org.C:\Program Files (x86)\Common Files\NetSarang;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;D:\SpringRoo\spring-roo-1.2.5.RELEASE\bin;D:\Ant\apache-ant-1.9.2\bin;C:\Python27;C:\Program Files\Java\jdk1.6.0_26\bin;D:\Maven\apache-maven-3.2.1/bin;D:\bower-master\bin;C:\Program Files (x86)\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\Microsoft Windows Performance Toolkit\;D:\Grails\grails-2.4.0\bin;D:\Gradle\gradle-2.0\bin;C:\Program Files (x86)\Windows Live\Shared;C:\Program Files\TortoiseSVN\bin;D:\Strawberry\perl\bin;D:\Strawberry\perl\site\bin;D:\Strawberry\c\bin;C:\Users\mohammad.amr\AppData\Roaming\npm;D:\JournalDev\eclipse;;.
      Mar 15, 2015 2:31:41 PM org.apache.tomcat.util.digester.SetPropertiesRule begin
      WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:JournalDevWebLogging' did not find a matching property.
      Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
      INFO: Initializing ProtocolHandler ["http-bio-8080"]
      Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
      INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
      Mar 15, 2015 2:31:41 PM org.apache.catalina.startup.Catalina load
      INFO: Initialization processed in 1020 ms
      Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardService startInternal
      INFO: Starting service Catalina
      Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardEngine startInternal
      INFO: Starting Servlet Engine: Apache Tomcat/7.0.35
      14:31:43.847 [localhost-startStop-1] ERROR  - org.apache.tomcat.jdbc.pool.DataSource@10fd0a62{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=30; minIdle=10; initialSize=10; maxWait=10000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=root; url=jdbc:mysql://localhost:3306/journaldev; username=root; validationQuery=null; validatorClassName=null; validationInterval=30000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; }
      Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
      INFO: Starting ProtocolHandler ["http-bio-8080"]
      Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
      INFO: Starting ProtocolHandler ["ajp-bio-8009"]
      Mar 15, 2015 2:31:43 PM org.apache.catalina.startup.Catalina start
      INFO: Server startup in 1909 ms
      

      Фильтры Log4j2

      Даже если есть кандидат LoggerConfig для обработки событий журнала, вы можете настроить его так, чтобы он запрещал передачу событий журнала внутренним приложениям. Это можно сделать с помощью фильтра log4j2. Этот раздел не предназначен для предоставления вам инвазивного, массивного и огромного количества руководств по использованию фильтров в Log4j2, так как им нужно много статей, охватывающих каждый из них. Но здесь вы увидите, как использовать самый простой фильтр для изучения концепции. Одним из самых простых фильтров, которые вы можете использовать, является BurstFilter, который предоставляет вам механизм управления скоростью, с которой обрабатываются LogEvents, автоматически отбрасывая события после достижения максимального предела. На данный момент вы можете увидеть ниже всю информацию, необходимую для использования BurstFilter.

      Parameter Name Type Description
      level String Level of messages to be filtered
      rate float The average number of events per second to allow
      maxBurst integer The maximum number of events that can occur before events are filtered for exceeding the average rate. The default is 10 times the rate.
      onMatch String Action to take when filter matches. May be Accept, DENY or NEUTRAL. The default is NEUTRAL
      onMismatch String Action to tale when filter doesn’t match. May be Accept, DENY or NEUTRAL. The default is NEUTRAL

      Теперь посмотрите на расположение BurstFilter внутри вашей базы данных Appender.

      <?xml version="1.0" encoding="UTF-8"?>
      <Configuration>
      	<Appenders>
      		<Console name="Console" target="SYSTEM_OUT">
      			<PatternLayout
      				pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
      		</Console>
      		<JDBC name="databaseAppender" tableName="journaldev.logging">
      			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
      			<BurstFilter level="TRACE" rate="20" maxBurst="2"/>
      			<Column name="EVENT_DATE" isEventTimestamp="true" />
      			<Column name="LEVEL" pattern="%level" />
      			<Column name="LOGGER" pattern="%logger" />
      			<Column name="MSG" pattern="%message" />
      			<Column name="THROWABLE" pattern="%ex{full}" />
      		</JDBC>
      	</Appenders>
      	<Loggers>
      		<Root level="ERROR">
      			<AppenderRef ref="Console" />
      		</Root>
      		<logger name="com" level="TRACE" additivity="false">
      			<AppenderRef ref="databaseAppender" />
      		</logger>
      		<logger name="com.journaldev" additivity="false">
      			<AppenderRef ref="databaseAppender" />
      		</logger>
      	</Loggers>
      </Configuration>
      

      • Приложение базы данных учитывает BurstFilter, а приложение консоли — нет.
      • Хотя использование консольного логгера приведет к тому, что вы будете регистрировать полные события журнала, Appender базы данных не будет этого делать, поскольку BurstFilter запретит некоторые из них продолжать.
      • Этот отказ от LogEvents достигается даже в том случае, если используемые регистраторы являются кандидатами для обработки LogEvents. Это настолько разумно, как показано в JournalDevServlet ниже.

      package com.journaldev;
      import java.io.IOException;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import org.apache.logging.log4j.LogManager;
      import org.apache.logging.log4j.Logger;
      public class JournalDevServlet extends HttpServlet{
      	private static final long serialVersionUID = 1L;
      	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
      		Logger logger = LogManager.getLogger(JournalDevServlet.class);
      		for(int i = 0 ; i < 1000 ; i++){
      			logger.trace("Index :: "+i+" :: JournalDev Database Logging Message !");
      			LogManager.getRootLogger().error("Index :: "+i+" :: JournalDev Database Logging Message !");
      		}
      	}
      }
      

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

      Макеты Log4j2

      Из-за различных приложений, которые используют события журнала, и характера каждого приложения, макеты созданы для формирования события журнала в формате, который соответствует потребностям того, кто будет использовать событие журнала. В API Log4j 1.x и Logback преобразование макета событий журнала было в строку, в то время как макеты Log4j2 рассматривали другой способ преобразования; и это путем преобразования LogEvent в массив байтов. Этот новый тип преобразования заставит вас настроить набор символов, чтобы убедиться, что массив байтов содержит правильные значения. Настоятельно рекомендуется вернуться на официальный сайт Apache Log4j2 и узнать больше о Layout и различных типах, которые предоставляет Log4j2. В этом разделе мы рассмотрим самый известный Layout, который всегда используется большинством наших разработчиков и наверняка вы о нем слышали; это PatternLayout.

      Log4j2 PatternLayout

      Какой уровень Log4j2 следует использовать

      Самый большой вопрос, который вы можете задать себе, — это когда следует использовать определенный уровень событий журнала. В области разработки нормально использовать событие журнала DEBUG, тогда как в производстве мы должны использовать уровень INFO или WARN. Эта таблица ниже должна указать вам, какой уровень log4j2 следует использовать в каком случае.

      Log Event Level When It Should Be Used
      OFF When no events will be logged
      FATAL When a severe error will prevent the application from continuing
      ERROR When an error in the application, possibly recoverable
      WARN When an event that might possible lead to an error
      INFO When an event for informational purposes
      DEBUG When a general debugging event required
      TRACE When a fine grained debug message, typically capturing the flow through the application
      ALL When all events should be logged

      Краткое изложение руководства по Log4j2

      Log4j2 — это обновленная версия платформы Apache Logging. Log4j2 предоставил набор новых функций и улучшений производительности по сравнению с Log4j1.x. Этот учебник по log4j2 призван помочь вам получить все это в одном месте. Поскольку некоторые из этих концепций не так просто охватить их все сразу, мы решили приложить наши усилия к объяснению концепции и использованию некоторых примеров для большего пояснения. Это правило распространяется на добавления, фильтры, макеты и поиск. Некоторые важные моменты Чтобы убедиться, что вы можете запустить приведенное ниже приложение и избежать каких-либо препятствий, проверьте следующее:

      • В вашей среде разработки Eclipse включен maven.
      • У вашего Apache Tomcat есть JAR-файл mysql-connector внутри вашей домашней папки Apache Home lib.
      • Вы знаете, как использовать Maven.

      Скачать пример проекта Apache Log4j 2

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