[Spring] Log 정리, Log 예쁘게 찍기

장성준·2024년 1월 26일
1

Spring

목록 보기
2/5
post-thumbnail

Slf4j

로그 관련 인터페이스
스프링 부트에서는 기본적으로 LogBack을 구현체로 제공합니다.

적용

build.gradle

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok' // 테스트 코드에서 사용하려면 추가
testAnnotationProcessor 'org.projectlombok:lombok' // 테스트 코드에서 사용하려면 추가

사용

코드로 불러와 사용할 수 있지만 대부분 Lombok의 어노테이션인 @Slf4j를 선언하여 사용합니다.

// Lombok의 어노테이션으로 사용하는 방법(클래스 위에 선언해줍니다.)
@Slf4j 

// 코드로 불러와 사용하는 방법(잘 사용하지 않습니다.)
private Logger log = LoggerFactory.getLogger(getClass());
private static final Logger log = LoggerFactory.getLogger(Xxx.class)

// 로그 출력(+로 문자열 연산을 하면 쓸데없는 연산이 추가되어 추천하지 않습니다.)
log.trace("trace log={}", name);
log.debug("debug log={}", name);
log.info("info log={}", name);
log.warn("warn log={}", name);
log.error("error log={}", name);

로깅 레벨

TRACE > DEBUG > INFO > WARN > ERROR 순으로 로깅 출력 레벨을 지정할 수 있습니다.

예를들어 로깅 출력 레벨을 INFO로 설정하면 INFO, WARN, ERROR이 출력되고
TRACE로 설정하면 모든 로깅이 출력됩니다.

application.properties

// 전체 로그 레벨 설정
logging.level.root=info

// 특정 패키지 로그 레벨 설정
logging.level.[패키지 명]=info

로그 예쁘게 찍기

기존의 로그를 찍으면 로그가 한 줄로 출력되고 있습니다.
하지만 여기에서 필자는 객체의 내용을 빠르게 확인하기 어려워 불편함을 느꼈습니다.

따라서 필자는 json string으로 변환 후에 포맷팅하는 방식으로 커스텀 로그를 만들어 보았습니다.

적용

build.gradle

implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'

DateTime을 json string으로 변환하기 위해 추가

Log.java

@Slf4j
public class Log {

    private static final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
    private static final ObjectWriter prettyPrinter = objectMapper.writerWithDefaultPrettyPrinter();

    private Log() {
        // 유틸리티 클래스이므로 인스턴스 생성을 막기 위해 private 생성자 사용
    }

    public static <T> void info(T object) {
        try {
            String jsonString = prettyPrinter.writeValueAsString(object);
            log.info("{} as json\n{}", object.getClass().getSimpleName(), jsonString);
        } catch (JsonProcessingException e) {
            log.error("Error converting object to json", e);
        }
    }
}

util 패키지 밑에 다음과 같이 추가해 주었습니다.
다른 레벨의 로그 함수도 같은 방식으로 추가하시면 됩니다.

사용

Log.info(xxx);

결과

다음과 같이 로그가 포맷팅되어 찍히는 것을 확인할 수 있습니다.


p6spy

SQL 쿼리 로그 관련 라이브러리
기존에도 show_sql 과 format_sql 설정으로 쿼리 로그를 확인할 수 있었지만
파라미터가 보이지 않아 불편했던 부분을 해당 라이브러리로 해결할 수 있습니다.

적용

build.gradle

implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'

스프링 부트 3.0 이상을 사용하면 라이브러리 버전을 1.9.0 이상으로 사용.

application.properties

decorator.datasource.p6spy.enable-logging=true

여기까지하고 테스트해보면 쿼리가 한줄로 나오며 파라미터가 보이는 것을 확인할 수 있습니다.

예쁘게 찍기

여기에서도 필자는 한줄로 나오는 것에 불편함을 느꼈습니다.
따라서 해당 로그를 포맷팅하여 출력하도록 설정을 추가해 주었습니다.

P6SpyFormatter.java

@Configuration
public class P6SpyFormatter implements MessageFormattingStrategy {

    @PostConstruct
    public void setLogMessageFormat() {
        P6SpyOptions.getActiveInstance().setLogMessageFormat(this.getClass().getName());
    }

    @Override
    public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
        sql = formatSql(category, sql);
        return String.format("[%s] | %d ms | %s", category, elapsed, formatSql(category, sql));
    }

    private String formatSql(String category, String sql) {
        if (sql != null && !sql.trim().isEmpty() && Category.STATEMENT.getName().equals(category)) {
            String trimmedSQL = sql.trim().toLowerCase(Locale.ROOT);
            if (trimmedSQL.startsWith("create") || trimmedSQL.startsWith("alter") || trimmedSQL.startsWith("comment")) {
                sql = FormatStyle.DDL.getFormatter().format(sql);
            } else {
                sql = FormatStyle.BASIC.getFormatter().format(sql);
            }
            return sql;
        }
        return sql;
    }
}

결과

이후에 실행해보면 SQL 쿼리가 포맷팅되어 찍히는 것을 확인할 수 있습니다.

profile
Backend Engineer

0개의 댓글