[Spring-boot] Logback으로 Log 출력

전수·2023년 1월 11일
0

Spring

목록 보기
9/13

Logging

Logging은 말 그대로 log를 남기는 것으로 시스템이 동작할 때 시스템의 상태 및 동작 정보를 시간 경과에 따라 기록하는 것을 의미한다. 이를 통해 개발자는 개발 과정 혹은 개발 후에 발생할 수 있는 예상치 못한 애플리케이션의 문제를 진달할 수 있고, 다양한 정보를 수집할 수 있다.
하지만 너무 적절한 수준의 로깅을 설정하지 않으면 너무 방대한 로그로 인해 의미있는 결과를 얻을 수 없기에 효율적인 설정이 필요하다.

📌Log-back

많이 알려진 Logging 구현체로는 log4j,log-back,log4j2가 있으며 log4j2의 등장 이후 log4j는 사용되지 않으며 이 포스트에서는 log-back의 사용법을 설명하고자 한다.

📌Log Level

  • Error : 예상하지 못한 심각한 문제가 발생하는 경우, 즉시 조취를 취해야 할 수준의 레벨

  • Warn : 로직 상 유효성 확인, 예상 가능한 문제로 인한 예외 처리, 당장 서비스 운영에는 영향이 없지만 주의해야 할 부분

  • Info : 운영에 참고할만한 사항, 중요한 비즈니스 프로세스가 완료됨

  • Debug : 개발 단계에서 사용하며, SQL 로깅을 할 수 있음

  • Trace : 모든 레벨에 대한 로깅이 추적되므로 개발 단계에서 사용함

📌직접 설정

어떤 클래스에 직접 로그를 출력하도록 설정할 수 있다.

private final Logger logger = LoggerFactory.getLogger(this.getClass());

logger.error("내용");
logger.warn("내용");
logger.info("내용");
logger.debug("내용");
logger.trace("내용");

해당 클래스에 LoggerFactory를 통해 logger를 출력할 수 있다.

또한 application.properties 설정을 통해 log-level을 설정하고 파일로 저장할 수 있다.

logging.level.root = info
logging.file.name=경로/test.log

하지만 이 경우 일자별 로그가 남지 않고, 파일 관리가 어렵기 때문에 권장되지 않는다.

📌AOP를 이용한 설정

application.properties 설정을 통해 로그에 어떤 SQL 문이 실행되었는지 출력할 수 있다.
📌application.properties

spring.jpa.properties.hibernate.format_sql=true

AOP를 생성하기 전 resource 패키지에 logback-spring.xml파일을 생성한다.

📌logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 로그의 저장 위치 -->
    <property name="LOGS" value="D:/logs" />

    <!-- appender-> 출력 위치, CONSOLE 표기 패턴-->
    <appender name="Console"
              class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %yellow(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %magenta(%C{1.}): %msg%n%throwable
            </Pattern>
        </layout>
    </appender>

    <!-- 현재 롤링파일 표기 및 아카이브 로깅 규칙 정의 -->
    <appender name="RollingFile"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOGS}/now-logFile.log</file>
        <encoder
                class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
        </encoder>

        <rollingPolicy
                class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 분당 로그 파일을 만들고, 10MB 단위로 운영 -->
            <!-- %d -> dateTime, %i -> index 둘은 필수 -->
            <fileNamePattern>${LOGS}/archive/logFile.%d{yyyy-MM-dd_HH}.%i.log
            </fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy
                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
    </appender>

    <!--전역 로깅 설정 ROOT 부터 하위로 내려감, additivity-> 상속여부-->
    <logger name="com.spring.jpa" level="trace" additivity="false">
        <appender-ref ref="RollingFile" />
        <appender-ref ref="Console" />
    </logger>


    <!--데이터 베이스 관련 로깅 설정-->

    <!--SQL 보이게 하기-->
    <logger name="org.hibernate.SQL" level="DEBUG">
        <appender-ref ref="RollingFile" />
        <appender-ref ref="Console" />
    </logger>

    <!--SQL에 들어가는 파라미터 보이게 하기-->
    <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE">
        <appender-ref ref="RollingFile" />
        <appender-ref ref="Console" />
    </logger>

    <!--DB 커넥션 표시(선택)-->
    <logger name="com.zaxxer.hikari" level="DEBUG">
        <!--<appender-ref ref="RollingFile" />-->
        <!--<appender-ref ref="Console" />-->
    </logger>

</configuration>

👀configuration 기본적인 구조

  • property :변수 역할
  • appender : 로그를 출력 할 위치, 출력 형식 등을 설정(console, file 등)
  • logger : 실제 로그 기능을 수행하는 객체로 각 Logger마다 이름을 부여하여 사용

👀appender 종류

  • ConsoleAppender : 로그를 OutputStream에 write 하여, 최종적으로 콘솔에 출력
  • FileAppender : 로그의 내용을 지정된 File에 기록
  • RollingFileAppender : FileAppender로 부터 상속받은 Appender로 날짜, 최대 용량 등을 설정하여 지정한 파일명 패턴에 따라 로그가 다른 파일에 기록

logger설정이 완료되었다면 aop.java파일을 생성한다.

📌LoggerAop.java

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect
public class LoggerAop {

    private static final Logger log = LoggerFactory.getLogger(LogAdvice.class);

    @Around("execution(* com.spring.jpa.controller..*Controller.*(..))"
            +" || execution(* com.spring.jpa.service..*Service*.*(..))"
            +" || execution(* com.spring.jpa.repository..*Repository.*(..))")
    public Object logPrint(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        //객체명
        String type = proceedingJoinPoint.getSignature().getDeclaringTypeName();

        //proceedingJoinPoint.getSignature().getName() <- 실행 메서드명
        log.info("[[START]]"+type+"."+proceedingJoinPoint.getSignature().getName()+"() <=================");
        log.info("Argument/Parameter : "+ Arrays.toString(proceedingJoinPoint.getArgs()));//<-파라미터
        log.info("================[[END : "+proceedingJoinPoint.getSignature().getName()+"()]]==================");

        return proceedingJoinPoint.proceed();
    }

}

클래스에 직접 호출할 때와 마찬가지로 LoggerFactory를 통해 logger를 생성하고 Controller,Service,Repository가 사용될 때 로그를 남기도록 설정하였다.
👀log 출력

  • proceedingJoinPoint.getSignature().getDeclaringTypeName() : 실행 위치(Controller, Service, Repository)

  • proceedingJoinPoint.getSignature().getName() : 실행 메서드

  • proceedingJoinPoint.getArgs() : 전달된 파라미터

Log를 위한 AOP까지 설정하면 프로젝트를 실행하면서 메서드의 흐름과 어떤 파라미터가 오고 가는지, 어떤 SQL문이 실행되었는지 확인할 수 있다.

마무리
Log를 사용해서 가장 좋았던 것은 프로그램의 실행 순서를 명확하게 볼 수 있다는 것과 SQL문이 올바르게 사용되었는지 확인 할 수 있다는 점이었다.
확실히 오류 지점을 빠르게 파악할 수 있다는 장점이 있지만 로그 파일을 어떻게 효율적으로 관리할 수 있을지에 대해서는 많은 경험과 고민이 필요할 것 같다.

0개의 댓글

관련 채용 정보