1. 왜 로거인가?

프로그램을 작성하거나 엔터프라이즈 프로덕션 애플리케이션을 개발하는 동안 System.out.println을 사용 하는 것이 가장 간단하고 쉬운 옵션 인 것 같습니다. 클래스 경로에 추가 할 추가 라이브러리 및 구성 할 추가 구성이 없습니다.

그러나 System.out.println을 사용하면 여러 상황에서 유용성에 영향을 미치는 몇 가지 단점이 있습니다. 이 튜토리얼에서 우리는 왜 그리고 언제 우리가 평범한 오래된 System.outSystem.err을 통해 Logger를 사용하기를 원하는지 논의 할 것 입니다. 또한 Log4J2 로깅 프레임 워크를 사용하는 몇 가지 간단한 예제를 보여줍니다.

2. 설정

시작하기 전에 필요한 Maven 의존성 및 구성을 살펴 보겠습니다.

2.1. Maven 의존성

Log4J2 의존성을 pom.xml 에 추가하여 시작하겠습니다  .

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

Maven Central 에서 최신 버전의 log4j-api 및  log4j-core찾을 수 있습니다 .

2.2. Log4J2 구성

System.out 의 사용에는 추가 구성이 필요하지 않습니다. 그러나 Log4J2를 사용하려면 log4j.xml 구성 파일이 필요 합니다.

<Configuration status="debug" name="baeldung" packages="">
    <Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %p %m%n"/>
        </Console>
    </Appenders>
    <Root level="error">
        <AppenderRef ref="STDOUT"/>
    </Root>
</Configuration>

거의 모든 로거 프레임 워크에는 프로그래밍 방식으로 또는 여기에 표시된 XML 파일과 같은 외부 구성 파일을 통해 일정 수준의 구성이 필요 합니다.

3. 로그 출력 분리

3.1. System.outSystem.err

응용 프로그램을 Tomcat과 같은 서버에 배포 할 때 서버는 자체 로거를 사용합니다. System.out 을 사용 하면 로그는 catalina.out이 됩니다. 로그가 별도의 파일에 저장되면 애플리케이션을 디버그하는 것이 훨씬 쉽습니다. Log4j2에서는 애플리케이션 로그를 별도의 파일에 저장하기 위해 구성에 파일 어 펜더를 포함해야합니다.

또한 System.out.println 을 사용하면 인쇄 할 로그를 제어하거나 필터링 할 수 없습니다. 로그를 분리하는 유일한 방법 은 정보 로그에 System.out.println  을 사용 하고 오류 로그에 System.err.println  을 사용하는 것입니다.

System.out.println("This is an informational message");
System.err.println("This is an error message");

3.2. Log4J2 로깅 수준

디버그 또는 개발 환경에서 우리는 응용 프로그램이 인쇄하는 모든 정보를보고 싶습니다. 그러나 라이브 엔터프라이즈 애플리케이션에서 로그가 많을수록 지연 시간이 늘어납니다. Log4J2와 같은 로거 프레임 워크는 여러 로그 수준 제어를 제공합니다.

  • 치명적인
  • 오류
  • 경고
  • 정보
  • 디버그
  • 자취
  • 모두

이러한 수준을 사용하면 언제 어디서 어떤 정보를 인쇄할지 쉽게 필터링 할 수 있습니다 .

logger.trace("Trace log message");
logger.debug("Debug log message");
logger.info("Info log message");
logger.error("Error log message");
logger.warn("Warn log message");
logger.fatal("Fatal log message");

각 소스 코드 패키지의 레벨을 개별적으로 구성 할 수도 있습니다. 로그 수준 구성에 대한 자세한 내용은 Java 로깅 문서를 참조하세요.

4. 파일에 로그 쓰기

4.1. System.outSystem.err 재 라우팅

System.setOut () 메서드를  사용하여 System.out.println 을 파일 로 라우팅 할 수 있습니다 .

PrintStream outStream = new PrintStream(new File("outFile.txt"));
System.setOut(outStream);
System.out.println("This is a baeldung article");

그리고 System.err의 경우 :

PrintStream errStream = new PrintStream(new File("errFile.txt"));
System.setErr(errStream);
System.err.println("This is a baeldung article error");

System.out 또는 System.err을 사용하여 출력을 파일로 리디렉션 할 때 파일 크기를 제어 할 수 없으므로 응용 프로그램이 실행되는 동안 파일이 계속 커집니다.

파일 크기가 커지면 더 큰 로그를 열거 나 분석하기 어려울 수 있습니다.

4.2. Log4J2로 파일에 로깅

Log4J2는 파일에 로그를 체계적으로 작성하고 특정 정책에 따라 파일을 롤링하는 메커니즘을 제공합니다. 예를 들어, 날짜 / 시간 패턴을 기반으로 롤오버 할 파일을 구성 할 수 있습니다 .

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <File name="fout" fileName="log4j/target/baeldung-log4j2.log"
          immediateFlush="false" append="false">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %p %m%n"/>
        </File>
    <Loggers>
        <AsyncRoot level="DEBUG">
            <AppenderRef ref="stdout"/>
            <AppenderRef ref="fout"/>
        </AsyncRoot>
    </Loggers>
</Configuration>

또는 주어진 임계 값에 도달하면 크기에 따라 파일을 롤링 할 수 있습니다 .

...
<RollingFile name="roll-by-size"
  fileName="target/log4j2/roll-by-size/app.log" filePattern="target/log4j2/roll-by-size/app.%i.log.gz"
  ignoreExceptions="false">
    <PatternLayout>
        <Pattern>%d{yyyy-MM-dd HH:mm:ss} %p %m%n</Pattern>
    </PatternLayout>
    <Policies>
        <OnStartupTriggeringPolicy/>
        <SizeBasedTriggeringPolicy size="5 KB"/>
    </Policies>
</RollingFile>

5. 외부 시스템에 로깅

이전 섹션에서 살펴본 것처럼 로거 프레임 워크를 사용하면 로그를 파일에 쓸 수 있습니다. 마찬가지로 다른 시스템 및 애플리케이션에 로그를 전송 하는 어 펜더 도 제공 합니다 . 이를 통해 System.out.println을 사용하는 대신 Log4J 어 펜더를 사용하여 Kafka Stream 또는 Elasticsearch 데이터베이스에 로그를 보낼 수 있습니다 .

우리의 참조하시기 바랍니다 의 Log4j 펜더 기사 등 펜더를 사용하는 방법에 대한 자세한 내용은.

6. 로그 출력 사용자 지정

Logger를 사용하여 실제 메시지와 함께 인쇄 할 정보를 사용자 정의 할 수 있습니다. 인쇄 할 수있는 정보에는 패키지 이름, 로그 수준, 줄 번호, 타임 스탬프, 메서드 이름 등이 포함됩니다.

System.out.println을 사용 하면 가능하지만 많은 수동 작업이 필요하지만 로깅 프레임 워크는이 기능을 즉시 제공합니다. 로거를 사용하면 로거 구성에서 패턴을 간단히 정의 할 수 있습니다 .

<Console name="ConsoleAppender" target="SYSTEM_OUT">
    <PatternLayout pattern="%style{%date{DEFAULT}}{yellow}
      %highlight{%-5level}{FATAL=bg_red, ERROR=red, WARN=yellow, INFO=green} %message"/>
</Console>

로거 프레임 워크로 Log4J2를 고려하면 선택하거나 사용자 정의 할 수있는 몇 가지 패턴이 있습니다. 이에 대한 자세한 내용은 공식 Log4J2 문서참조하십시오 .

7. 예외 출력을 대신 로깅하여 printStackTrace () 방지

코드에서 예외를 처리 할 때 종종 런타임에 실제로 발생한 예외를 알아야합니다. 이를위한 두 가지 일반적인 옵션이 있습니다 : printStackTrace () 또는 로거 호출 사용.

printStackTrace ()사용 하여 예외에 대한 세부 정보를 인쇄 하는 예외 처리를 보는 것은 매우 일반적입니다 .

try {
    // some code
} catch (Exception e) {
    e.printStackTrace();
}

여기서 문제는 printStackTrace () 가 그 정보를 System.err에 출력 한다는 것입니다. 우리는 이미 그것을 피하고 싶다고 말했습니다.

대신 로깅 프레임 워크를 사용하여 예외를 로깅하면 로그를 쉽게 검색 할 수 있습니다.

try {
    // some code
} catch (Exception e) {
    logger.log("Context message", e);
}

8. 결론

이 기사에서는 로거 프레임 워크를 사용하는 다양한 이유와 애플리케이션 로그에 대해 System.out.println 에만 의존하지 않는 이유를 설명합니다 . 소규모 테스트 프로그램에 System.out.println 을 사용하는 것이 타당하지만 엔터프라이즈 프로덕션 응용 프로그램에 대한 주요 로깅 소스로 사용하지 않는 것이 좋습니다.

항상 그렇듯이이 기사의 코드 예제는 GitHub에서 사용할 수 있습니다 .