@Slf4j 이해하기

허준현·2023년 6월 30일
0

Spring

목록 보기
1/3
post-thumbnail

@Slf4j 에 대해서 알아보기

slf4j에 대해서 자세히 설명하는 좋은 블로그가 많이 존재하여 여기서는 loback-spring 을 보고 이해 할 수 있는 정도로만 다루고 넘어가려고 한다.
slf4j는 다양한 로깅 프레임워크에 대한 추상화(인터페이스) 역할을 하기 때문에 배포시에는 원하는 구현체를 선택해서 사용해야 한다. Spring에서는 기본적으로 logback을 사용한다.

logback 설정 요소 3가지

Logger :

실제 로깅을 구성하는 요소

Appender :

로그 이벤트를 쓰는 작업을 Appender에 위임하여 어디에 출력할지 결정하게 된다.

Layout :

Appender 에 포함되어 사용자가 지정한 형식으로 표현될 로그 메세지를 변환하는 역할을 담당한다.

아래와 같은 간단한 예시를 통해서 알아보도록 하자.

<configuration>
    <timestamp key="BY_DATE" datePattern="yyyy-MM-dd"/>
    <property name="LOG_PATTERN"
              value="[%d{yyyy-MM-dd HH:mm:ss}:%-4relative] %green([%thread]) %highlight(%-5level) %boldWhite([%C.%M:%yellow(%L)]) - %msg%n"/>

    <springProfile name="!prod">
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${LOG_PATTERN}</pattern>
            </encoder>
        </appender>

        <root level="INFO">
            <appender-ref ref="CONSOLE"/>
        </root>
    </springProfile>

</configuration>

Property는 변수를 저장하는 공간이며 Log pattern을 통해서 출력 형식을 정하고 로그 색깔 또한 지정할 수 있다.
SpringProfile은 실행시에 입력받은 Profile에 맞춰 로깅 형식을 지정해 줄 수 있다. 또 한 위에서 알아본 Layout이 로그 이벤트를 바이트 배열로 변환하고, 해당 바이트 배열을 OutputStream에 쓰는 작업을 해준다.

@slf4j 를 사용시에 일어나는 일

참고 링크를 확인해보면 Log를 다루기 위해서 @ 어노테이션을 사용했을 때 일어나는 일에 대해서 나타내고 있다. 그중에서 우리는 @Slf4j는 아래와 같이 컴파일 시에 코드가 추가 되는 것을 알 수 있다.

private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

logback에서 DB 로깅하기

쿼리 문장을 Console창에서 확인하고자 하는 경우 해당 쿼리 결과를 log를 찍는 방법과 log4jdbc를 사용해서 해당 쿼리를 logging 할 수 있다.
자세한 방법은 해당 링크를 참고하면 해당 프로젝트에서 쉽게 logging 할 수 있을 것이다. 그 중에서 아래와 같이 sql 및 sql time을 잴 수 있는 log를 쉽게 생성할 수 있다는 점만 집고 넘어가자.

<logger name="jdbc.sqlonly" level="OFF" />

<logger name="jdbc.sqltiming" level="${LOG_LEVEL}" additivity="false"/>

slf4j 를 사용하는 2가지 방법

static logger를 가지고 있는 클래스를 상속하는 것과 @Slf4j는 로깅 기능을 구현하는 두 가지 다른 방법이 있다.

static logger를 가지고 있는 클래스를 상속하는 방법:

이 방법은 일반적으로 로깅을 위해 static 필드로 구성된 로거를 사용하는 전통적인 방법이다.
자식 클래스는 상속된 로거를 통해 로그를 기록하거나 조작할 수 있지만 이 방법은 몇 가지 단점을 가지고 있다.

상속을 통해 로거를 사용하므로, 상속 계층 구조에 제약이 생긴다. 로깅 기능을 사용하려는 클래스가 이미 다른 클래스를 상속하고 있다면, 추가로 상속받을 수 없다.
로거가 static 필드로 정의되므로, 동시에 여러 인스턴스에서 로거를 사용할 수 없다.

@Slf4j를 사용하는 방법:

앞에서 알아봤듯이 @Slf4j는 Lombok 라이브러리에서 제공하는 애너테이션으로, 로깅 기능을 자동으로 추가해주는 기능이다.
클래스에 @Slf4j 어너테이션을 추가하면, 해당 클래스 내에서 로거를 사용할 수 있다. 이 방식의 장점은 다음과 같다.

상속이 필요하지 않게 된다. @Slf4j를 사용하려는 클래스는 어떤 클래스를 상속받아도 상관없다. 이는 상속 계층 구조에 제약이 없음을 의미한다.
클래스의 어느 곳에서나 로거를 사용할 수 있다. 로거는 클래스의 인스턴스에 종속되지 않으므로, 멀티스레드 환경에서도 안전하게 사용할 수 있다.

만일 상속과 @slf4j 를 둘 다 사용하게 된다면?

사실 이 부분에 대해서 기록하고자 앞에 서두를 길게 작성하였다.
간단하게 start.spring.io에서 프로젝트를 받고 별도로 lombok을 설치해 주었다.

@Slf4j
@RestController
public class LogTestController extends BaseLog{

    @RequestMapping("/log-test")
    private String logTest(){
        String name = "Spring";
        log.info(name);

        return "ok";
    }

}

위와 같이 Controller를 설정해준 다음 상속을 통한 logger 구현을 위해 다음과 같이 설정을 해준다.

// BaseLog.class
public class BaseLog {
    private final Logger Logger = LoggerFactory.getLogger(this.getClass());
    public LogFunction log = new LogFunction(Logger);
}

//LogFunction.class
@Component
@RequiredArgsConstructor
public class LogFunction {
    private Logger logger;

    public LogFunction(Logger plogger){
        logger = plogger;
    }

    public void info(String msg) {
        logger.info("Demo" + msg);
    }



}

이런 경우에 @slf4j 의 log가 찍힐 것인지 아니면 부모의 log가 찍혀 Demo + msg~ 가 나올지 확인해보면 다음과 같다.

[2023-06-28 11:22:23:10055] [http-nio-8080-exec-3] INFO  [com.example.demo.LogTestController.logTest:15] - Spring

이는 부모의 log값이 아닌 @slf4j의 log가 찍히는 것을 확인 할 수 있다. 돌아보면 당연한 것이긴 한데 자바에서 부모의 메소드, 필드를 참조할 수 있지만 만일 동일한 이름으로 자식 클래스에서 선언하게 되는 경우 자식의 필드값으로 변경이 된다.

profile
best of best

0개의 댓글