2023-10-25,   조평연

본 포스팅은 로그 종류와 개념을 알아보고 Log4j2의 사용법을 알아보는 내용입니다.

로그란?

로그 (Log)란 소프트웨어의 이벤트를 기록하는 것이다.
소프트웨어의 동작 상태를 파악하고 문제가 발생하면 찾아내서 해결하기 위해 디자인 되었다.

기존에 Debugger, Println 같은 방법들과 비교해서 로그는 아래와 같은 장점이 있다.

  • 상황별 Level을 지정하여 Level별 메세지를 선택 가능하다

  • 응용 프로그램의 실행에 대한 흐름과 에러 확인이 가능하다

  • 프레임워크를 이용하여 간단하고 쉬운 사용환경 조성이 가능하다

  • 모듈 별로 유연하게 메세지 출력이 가능하다

  • 자유로운 출력 위치 및 다양한 출력 형식이 지원된다

Java에는 로그에 대한 프레임워크가 여러개 존재한다.
아래에서 알아보도록 하자.

SLF4J

Simple Logging Facade For Java의 약자로써 자체적인 로깅 프레임워크가 아니라
logger 추상체로 다른 로깅 프레임워크가 접근할 수 있게 도와주는 추상화 계층이라고 보면된다.
로깅에 대한 추상 레이어를 제공하는 인터페이스의 모음이다. (로깅 Facade)
즉 logback 이나 log4j2 같은 로깅 프레임워크의 인터페이스 역할을 한다고 볼 수 있다.
인터페이스를 사용하여 로깅을 구현하게 되면 좋은 점은 추후에 필요로 의해 로깅 라이브러리를 변경할 때 코드의 변경 없이 가능하다는 점이다.
즉 slf4j를 이용하면 코드를 일정하게 유지하면서 구현체의 전환을 통해 다른 로깅 프레임워크로 전환이 쉽다.

그림
출처 : https://www.slf4j.org/manual.html

Log4J

log4j는 가장 오래된 로깅 프레임워크로써 Apache의 Java기반 로깅 프레임워크이다.
콘솔 및 파일 출력의 형태로 로깅을 도와주며 xml, properties로 환경을 구성할 수 있다.
현재는 2015년 기준으로 개발이 중단되었다.

1) log4j 구성

  • Logger : 출력할 메시지를 Appender에게 전달

  • Appender : 전달된 로그를 어디에 출력할 것인지 결정 (Console, File, JDBC 등)
  • Layout : 로그를 어떤 형식으로 출력할 것인지 결정

2) log4j 로그 레벨

  • FATAL : 아주 심각한 에러가 발생한 상태
  • ERROR : 요청을 처리하는 중 문제가 발생한 상태
  • WARN : 실행에는 문제가 없지만 향후 에러의 원인이 될 수 있는 경고 메세지
  • INFO : 상태변경과 같은 정보성 메세지
  • DEBUG :개발시 디버그 용도로 사용하는 메세지
  • TRACE : 디버그 레벨 보다 상세한 이벤트를 나타내는 메세지

FATAL > ERROR > WARN > INFO > DEBUG > TRANCE

Logback

logback이란 log4j 이후에 출시된 보다 향상되고 가장 널리 사용되고 있는 Java 로깅 프레임워크중 하나이다.
slf4j의 구현체로써 동작하는 logback은 Springboot 환경의 경우는 spring-boot-starter-web안에 spring-boot-starter-logging에 logback이 기본적으로 포함되어 있어서 별다른 dependency 추가 없이 사용할 수 있다.
logback은 log4j에 비해 향상된 필터링 정책 및 기능(ex. 로그인 한 경우 logging 등등)과 로그 레벨 변경등에 대해 서버 재시작 없는 자동 리로딩을 지원해 준다.

Log4j2

가장 최신에 나온 로깅 프레임워크로써 Apache의 log4j의 다음 버전이다.
logback처럼 필터링 기능과 자동 리로딩을 지원한다.
logback과의 가장 큰 차이는 Multi Thread 환경에서 비동기 로거(Async Logger)의 경우 다른 로깅 프레임워크보다 처리량이 훨씬 많고, 대기 시간이 훨씬 짧다.
또한 Java8부터 도입된 람다식을 지원하고 Lazy Evalutaion을 지원한다.

그림
출처 : https://logging.apache.org/log4j/2.x/performance.html

Log4j2 사용법

Springboot는 기본 Java 로깅 프레임워크로 spring-boot-starter-web안에 spring-boot-starter-loggig의 logback이 포함되어 있지만
가장 최신에 나오고 성능이 좋은 log4j2를 Springboot 프로젝트에 설정을 해보았다.
다음과 같은 과정을 거쳐 설정을 진행했다.

1) log4j2 Dependency 추가

log4j2의 dependency를 추가해주기 위해 maven환경에서의 pom.xml에서 작업을 해주었다.
우선적으로 Springboot의 기본적으로 주어져있는 logback 라이브러리를 제외 시켜주고 log4j2를 추가시켜주었다.

<!-- springboot -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- log4j2 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

2) log4j2.xml 추가

application.properties가 존재하는 main/resources에 다음과 같은 log4j2.xml 설정파일을 작성해주었다.
application.properties에서 xml 경로 설정도 해주어야 한다.
아래 경로에 log4j2.xml 파일을 만들어주면 된다.

logging.config=src/main/resources/log4j2.xml


Java 로깅 프레임워크의 설정파일(여기선 log4j2.xml)은 부분적으로는 다르지만 거의 대부분이 크게 아래와 같은 3가지 부분으로 구성되어있다.
Logger : 출력할 메시지를 Appender에게 전달
Appender : 전달된 로그를 어디에 출력할 것인지 결정 (Console, File, JDBC 등)
Layout : 로그를 어떤 형식으로 출력할 것인지 결정

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info" monitorInterval="30">
    <Properties>
        <Property name="BASE_DIR">./logs</Property>
        <Property name="LOG_FORMAT">[%date{yyyy-MM-dd HH:mm:ss}] %level %logger{36}(%file:%line) - %msg%n</Property>
    </Properties>
 
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT" follow="true">
            <PatternLayout pattern="${LOG_FORMAT}"/>
        </Console>
 
         <RollingFile name="File"
                     fileName="${BASE_DIR}/logfile.log"
                     filePattern="${BASE_DIR}/logfile.%d{yyyyMMdd}.log">
            <PatternLayout pattern="${LOG_FORMAT}"/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
            </Policies>
            <DefaultRolloverStrategy>
                <Delete basePath="${BASE_DIR}">
                    <IfFileName glob="*.log"/>
                    <IfLastModified age="30d"/>
                </Delete>
            </DefaultRolloverStrategy>
        </RollingFile>
    </Appenders>
 
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="File"/>
        </Root>
 
        <Logger name="com.pacakge.controller" level="DEBUG" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="File"/>
        </Logger>
    </Loggers>
</Configuration>

3) Java 에서 log 작성

@RestController
@RequestMapping("/api")
public class ApiController {
    private static final Logger LOGGER = LogManager.getLogger(ApiController.class);
 
    @GetMapping
    public ResponseEntity<String> hello() {
        LOGGER.debug("Hello World");
        LOGGER.info("Hello World");
        LOGGER.warn("Hello World");
        return new ResponseEntity<String>("Hello World", HttpStatus.OK);
    }
}


참고 문헌

Log4j2 공식문서

https://logging.apache.org/log4j/2.x/

업데이트: