웹사이트 검색

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 디버깅 또는 일부 다른 도구를 사용하여 애플리케이션을 디버깅할 수 있지만 프로덕션 환경에서는 충분하지 않고 실현 가능하지 않습니다. 로깅 메커니즘은 일반 디버깅에서 찾을 수 없는 몇 가지 이점을 제공합니다.

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

상위-자녀 관계를 명확히 하기 위해 위의 표를 다음과 같이 읽습니다.

  • 루트는 com의 상위입니다.
  • 루트는 com.journaldev의 조상입니다.
  • 루트는 com.journaldev.logging의 조상입니다.
  • com은 루트의 자식입니다.
  • 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 구현은 log4j2 구성 파일의 위치를 가리키는 log4j.configurationFile이라는 시스템 변수가 있다고 가정합니다.

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로 작성할 수 있습니다.
  • System.setProperties(\log4j.configurationFile\,\FILE_PATH\)를 통해 또는 아래 그림과 같이 JVM 매개변수로 전달하여 log4j.configurationFile 시스템 속성을 설정할 수 있습니다. 파일 프로토콜 접두사도 확인하십시오.

  • 시스템 속성이 정의되지 않은 경우 구성 순서가 우선 적용됩니다.
    • 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이 수행되고 기본 동작 세트로 연결됩니다.\n
      • 루트 로거가 사용됩니다.
      • 루트 로거 수준이 ERROR로 설정됩니다.
      • 루트 로거는 로깅 메시지를 콘솔에 전파합니다.
      • 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");
          }
      }
      

      • Log4j2에서 제공하는 ConfigurationFactory를 사용하거나 기본 것을 사용할 수 있습니다. ConfigurationFactory의 인스턴스를 얻기 위해 XMLConfigurationFactory를 사용했습니다.
      • Factory는 해당 구성 파일을 전달하여 필요한 구성 참조의 인스턴스를 제공합니다.
      • 구성 인스턴스는 로깅 시스템을 시작하기 위해 LoggerContext와 함께 사용됩니다.
      • 콘솔 어펜더가 구성되어 기본 레이아웃으로 구성 인스턴스에 추가되었습니다. 이 Appender는 콘솔에 메시지를 출력합니다.
      • LoggerConfig 인스턴스는 제공된 이름 LEVEL로 생성되었으며 필터는 사용되지 않았습니다. 생성된 Appender는 LoggerConfig의 이 인스턴스에 할당됩니다.
      • LoggerConfig 인스턴스가 구성 인스턴스에 추가되었습니다.
      • LoggerContext의 새 인스턴스가 정의된 이름으로 생성됩니다.
      • 구성 인스턴스가 LoggerContext 인스턴스에 전달되었으며 후자에서 시작을 호출했습니다.
      • LoggerContext에서 로거 인스턴스를 획득했습니다. 이 로거 인스턴스는 일련의 로그 이벤트를 발생시키는 데 사용됩니다.
      • Logger 인스턴스는 Log4j2 레벨 섹션에서 설명할 세 가지 이벤트를 발생시켰습니다.
      • com logger가 FATAL 수준의 메시지를 출력하도록 구성되었습니다.
      • 기본적으로 루트 로거는 수준이 ERROR인 메시지를 출력하도록 구성됩니다.
      • ERROR 메시지는 'com' 로거의 수준이 치명적이기 때문에 기록되지 않습니다.

      YAML, JSON 또는 속성 파일을 사용하여 동일한 구성을 수행할 수 있습니다. 그러나 log4j2 속성 파일 구성은 log4j 속성 파일과 다르므로 log4j2와 함께 log4j 속성 파일 구성을 사용하려고 하지 않는지 확인하십시오. 아래 오류가 발생합니다.

      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 logger에서, 두 번째 줄은 Root Logger에서 가져온 것입니다. com 로거 오류 메시지는 해당 수준이 Fatal이기 때문에 인쇄되지 않습니다.

      Log4j2 수준

      • 이전에 언급했듯이 각 로거는 LoggerConfig 인스턴스와 연결되어 있습니다. 이 loggerConfig는 구성 범위에서 정의되었습니다.
      • LoggerConfig 범위에서 로깅 수준을 결정할 수 있습니다.
      • 이름, 상위 패키지 또는 루트 로거 자체를 지정하여 로거를 얻을 수 있습니다.
      • 루트 로거는 모든 LoggerConfig 계층 구조의 최상위 노드입니다.
      • com.journaldev 로거를 가져오고 로깅을 위해 logEvent를 시작하면 loggerConfig(net.journaldev)가 메시지를 기록하고 메시지는 아무런 영향 없이 계층 구조 위로 전파됩니다. 부모 로깅 수준을 존중합니다. 따라서 로그 이벤트는 com 및 루트 로거에 전파되며 정의된 수준에 따라 각각 메시지를 기록합니다.
      • com logger를 얻고 로깅을 위해 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 ::
      

      위에 나열된 코드에 대한 자세한 설명은 다음과 같습니다.

      • 구성 파일에는 5개의 loggerConfig 인스턴스가 정의되어 있으며 이는 Root, com, com.journaldev, net 및 net.journaldev입니다. 위에 표시된 로거 계층 구조와 같습니다.
      • Root의 레벨은 ERROR로 구성되어 있으며 이것이 실제로 기본값입니다.
      • com 및 com.journaldev 수준은 TRACE로 구성됩니다.
      • net 및 net.journaldev 수준은 ERROR로 구성됩니다.
      • ComAPP 및 ComJournalDevApp 로거 메시지가 각각 2회 및 3회 표시되었음을 알 수 있습니다. 이러한 메시지는 각각 com 및 com.journalDev 패키지에 있는 ComApp 및 ComJournalDevApp의 로거 계층 구조에 따라 표시됩니다. NetApp 및 NetJournalDevApp 클래스와 유사한 사례가 있습니다.
      • 추가 지표가 기본적으로 true로 설정되어 있으므로 부모가 전파됩니다.

      Logging Space는 로거 계층 외에도 로그 이벤트의 수준과 loggerConfig의 수준을 고려합니다.

      따라서 com의 LoggerConfig를 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 로그 이벤트가 무시된 것을 알 수 있으며 이는 com 패키지에 대해 정의된 loggerConfig 수준 때문입니다. INFO(400) 수준은 여기서 TRACE(600)인 로그 이벤트 수준보다 낮습니다. 따라서 ComApp의 메시지는 더 이상 표시되지 않으며 이를 표시하려면 com에 대한 LoggerConfig의 수준을 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

      확실히 위의 표는 단어보다 훨씬 더 많은 것을 설명하며 LoggerConfig의 수준이 INFO인 동안 로그 이벤트 TRACE가 표시되지 않는 주요 원인을 제공합니다.

      로거 계층에서 로그 이벤트의 전파는 이 계산 범위를 벗어나며 수준을 무시합니다.

      그러나 구성에서 com.journaldev의 LoggerConfig를 제거하고 구성 파일을 아래와 같이 만들기 위해 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이라는 로거에 의해 로그 이벤트가 발생한 경우 해당 이름(예: com.journaldev.logging)과 연결된 LoggerConfig가 이를 처리하고 메시지를 출력하는 데 사용되었습니다.
      • com.journaldev.logging LoggerConfig의 추가 속성이 기본적으로 true로 설정되어 있으므로 로그 이벤트가 이 경우 com.journaldev를 참조하는 상위에 전파되었습니다.
      • com.journaldev LoggerConfig가 구성에 정의되어 있지 않으므로 작업이 발생하지 않으며 로그 이벤트가 com과 루트 LoggerConfig 인스턴스로 전파됩니다.
      • Com & Root는 Log 이벤트를 수신하고 전송된 레벨에 관계없이 출력합니다.

      언급된 사항에 대한 결과로 다음 출력이 표시됩니다.

      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입니다. 이전에는 세 번 있었지만 지금은 com.journaldev의 LoggerConfig가 없으므로 com.journaldev 패키지에서 로깅이 발생하지 않았을 수 있으며 이벤트가 com 및 Root에 전파됩니다.
      • com.journaldev.logging의 로그 이벤트가 세 번 표시되었습니다. 하나는 com.journaldev.logging 패키지에 대한 것이고 두 번째는 com에 대한 것이고 세 번째는 루트에 대한 것입니다. Logger Hierarchy 전파에 따르면 4번 표시되어야 하는데 com.jounraldev LoggerConfig가 없어서 3번 표시됩니다.

      레벨이 지정되지 않은 com.journaldev LoggerConfig 인스턴스를 정의한 경우 상위의 레벨을 상속합니다.

      그러나 구성 파일에서 com.journaldev LoggerConfig를 정의했고 LoggerConfig의 수준을 지정하지 않은 경우 어떻게 됩니까? 다행스럽게도 Logger Hierarchy의 개념이 여기서 당신을 구할 것이고 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 패키지는 이미 로그 수준이 TRACE인 LoggerConfig와 연결되어 있습니다.
      • com.journaldev 패키지는 로그 수준이 지정되지 않은 LoggerConfig와 이미 연결되어 있으므로 상위 로그 수준을 상속하고 com 패키지에 대한 값은 TRACE가 됩니다.
      • com 패키지는 이미 Loggerconfig와 로그 수준 TRACE로 연결되어 있습니다.
      • 기본적으로 루트는 로그 수준으로 ERROR를 갖습니다.
      • com 패키지가 선언되지 않은 경우 com.journaldev LoggerConfig는 루트의 로그 수준을 상속합니다.

      다음은 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 ::
      

      그리고 아래 결과는 com 패키지에 대한 LoggerConfig 선언을 제거한 경우입니다.

      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에 대한 메시지가 기록되지 않았음을 알 수 있습니다. 그 이유는 다음과 같습니다.

      • com 패키지와 관련된 LoggerConfig를 삭제하면 해당 패키지에서 언급된 모든 로그 이벤트가 무시됩니다.
      • 구성에서 com 패키지에 대해 정의된 LoggerConfig가 없으므로 com.journaldev와 연결된 LoggerConfig는 상위에서 로그 수준을 상속합니다. Com이 정의되지 않고 Logger Hierarchy가 Top에 도달하여 이제 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 로그 이벤트를 발생시키는 데 사용할 수 있는 직접적인 방법은 없습니다.
      • 주로 OFF/ALL 로그 이벤트를 발생시키기 위해 각각 logger.log(Level.OFF, "Msg”) 또는 logger.log(LEVEL.ALL,"Msg”)를 사용할 수 있습니다.
      • log 메서드는 언급된 방정식에 따라 로그 이벤트를 처리합니다.

      처리 방정식은 다음과 같습니다. LoggerConfig 수준이 로그 이벤트 수준보다 크거나 같으면 추가 처리를 위해 이벤트가 수락됩니다.

      추가 처리를 위해 로그 이벤트가 수락됩니다. 이는 Log4j2 필터를 사용하여 수락하더라도 일부 이벤트가 처리되지 않도록 방지할 수 있기 때문에 매우 중요합니다. 추가 속성을 false로 설정하여 상위 로거에 대한 로그 이벤트 전파를 방지할 수 있습니다. 이전에 보았던 동일한 예를 아래에서 이번에는 additivity 속성을 사용하여 수행하므로 차이점을 알 수 있습니다.

      <?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는 다양한 컨텍스트에서 값을 설정하기 위해 독립적으로 사용할 수 있는 다양한 조회 세트를 제공합니다.

      • 컨텍스트 맵 조회
      • 날짜 조회
      • 환경 조회
      • 자바 조회
      • JNDI 조회
      • JVM 입력 인수 조회(JMX)
      • 주 인수 조회
      • 지도 조회
      • 구조화된 데이터 조회
      • 시스템 속성 조회
      • 웹 조회

      모든 조회 유형에 대한 자세한 내용은 Log4j2 설명서를 참조할 수 있지만 여기에서 Log4j2 조회의 기본 사항을 다루는 몇 가지 예를 살펴보겠습니다. 환경 조회는 환경 값을 전달할 수 있는 방법을 나타냅니다(Linux etc/profile, Windows 시스템 환경 또는 응용 프로그램의 시작 스크립트 사용). 우리 대부분이 알고 있듯이 응용 프로그램에 대한 환경 값 집합을 정의할 수 있습니다. 환경 변수를 정의하는 가장 유명한 방법을 살펴보겠습니다.

      1. Windows 환경 기능을 사용하여 환경 변수를 정의합니다.\n
        • 컴퓨터 아이콘을 마우스 오른쪽 버튼으로 클릭하고 속성을 선택합니다. 제어판 홈이 표시되어야 합니다.
        • 고급 시스템 설정을 클릭한 다음 환경 변수 창을 엽니다.
        • 시스템 변수 섹션에서 JournalDev 값으로 변수 JournalDevVar를 정의합니다.
        • 새로 추가된 변수를 포함하도록 log4j2.xml 내에서 PatternLayout을 업데이트합니다.

      1. 시작 스크립트 기능을 사용하여 환경 변수를 정의합니다.\n
        • 일반적인 기본 스크립트를 사용하는 대신 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 어펜더

      구성 파일에 변수를 주입하기 위해 조회를 사용하는 방법을 이전에 확인했습니다. 그러나 메시지가 통과한 매체를 수정하고 싶을 수도 있습니다. 콘솔을 직접 사용하는 대신 메시지가 영구적으로 보존되도록 이러한 파일 또는 데이터베이스 저장소를 원할 수 있습니다. Log4j2는 많은 Appender를 제공했으며 Appender에 대한 자세한 내용은 log4j2 설명서를 참조할 수 있습니다. 간단히 말해서, 아래는 모든 Log4j2 Appenders의 목록입니다.

      1. ConsoleAppender
      2. AsyncAppender
      3. FailoverAppender
      4. FileAppender
      5. FlumeAppender
      6. JDBCAppender
      7. JMSAppender
      8. JPAAppender
      9. MemoryMappedFileAppender
      10. NoSQLAppender
      11. OutputStreamAppender
      12. RandomAccessFileAppender
      13. RewriteAppender
      14. RollingFileAppender
      15. RollingRandomAccessFileAppender
      16. RoutingAppender
      17. SMTPAppender
      18. SocketAppender
      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에 대해 잘 모른다면 Express Edition을 설치하는 것이 좋습니다.
      • 환경에 Apache Tomcat 7을 설치합니다.
      • Eclipse에 Maven WebApp 프로젝트를 만듭니다.

      • 프로젝트가 성공적으로 생성되었는지 확인하고 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 파일 내에서 서블릿을 정의하십시오.
      • 애플리케이션을 실행하고 위에 정의된 Servlet에 액세스합니다. 아래 로그가 표시됩니다.

      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 후보가 있더라도 로그 이벤트를 백엔드 Appender로 전달하는 것을 거부하도록 구성할 수 있습니다. 이는 log4j2 필터로 수행할 수 있습니다. 이 섹션은 Log4j2에서 필터를 사용하는 방법에 대해 침습적이고 방대하며 막대한 양의 자습서를 제공하기 위한 것이 아닙니다. 모든 항목을 다루는 많은 문서가 필요하기 때문입니다. 그러나 여기서는 가장 간단한 필터를 사용하여 개념을 배우는 방법을 볼 수 있습니다. 사용할 수 있는 가장 간단한 필터 중 하나는 최대 제한에 도달한 후 이벤트를 자동으로 삭제하여 LogEvents가 처리되는 속도를 제어하는 메커니즘을 제공하는 BurstFilter입니다. 지금은 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

      이제 데이터베이스 Appender 내에서 BurstFilter의 위치를 확인하십시오.

      <?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>
      

      • Database Appender는 BurstFilter를 고려하지만 Console Appender는 고려하지 않습니다.
      • 콘솔 로거를 사용하면 전체 로그 이벤트가 기록되지만 데이터베이스 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 !");
      		}
      	}
      }
      

      이러한 LoggerConfig가 거기에서 발생하는 로그 이벤트를 처리하기 위한 후보이지만 필터가 일부 이벤트를 처리한 다음 기록하지 못하도록 막았습니다. 로깅 공간 개념에 이것을 추가하여 로깅의 전체 개념을 얻을 수 있습니다.

      Log4j2 레이아웃

      로그 이벤트를 사용하는 다양한 Appender와 각 Appender의 특성으로 인해 로그 이벤트를 사용할 사람의 요구 사항을 충족하는 형식으로 LogEvent를 형성하도록 레이아웃이 만들어집니다. Log4j 1.x 및 Logback API에서 Log Events의 레이아웃 변환은 문자열로 된 반면 Log4j2 레이아웃은 다른 변환 방법을 고려했습니다. 이는 LogEvent를 바이트 배열로 변환하는 것입니다. 이 새로운 유형의 변환은 바이트 배열에 올바른 값이 포함되도록 Charset을 구성하도록 강제합니다. Apache Log4j2 공식 사이트로 돌아가서 Log4j2가 제공하는 레이아웃 및 다양한 유형에 대해 자세히 알아보는 것이 좋습니다. 이 섹션에서는 대부분의 개발자가 항상 사용하는 가장 유명한 레이아웃을 고려할 것입니다. 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 IDE는 maven이 활성화되어 있습니다.
      • Apache Tomcat에는 Apache Home lib 폴더 내에 mysql-connector JAR이 있습니다.
      • Maven 사용법을 알고 있습니다.

      Apache Log4j 2 예제 프로젝트 다운로드

      이것이 log4j2 튜토리얼의 전부입니다. 애플리케이션에서 Log4j2를 사용하는 데 필요한 대부분의 중요한 사항을 다루었기를 바랍니다.