티스토리 뷰

springboot 3.0 이상 p6spy 설정 (로깅이 안될 경우)

springboot가 업데이트되면서 p6spy의 쿼리 로깅이 잘 안되는 문제가 있습니다.

아래 추가 설정을 통해서 순서와 상관없이 진행을 하시면 해결이 됩니다.

단, 개발 환경에만 적용하기!

 

1. build.gradle 의존성 추가

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

 

2. [project]/src/main/resources/META-INF/spring 경로에 파일 추가

* 파일 경로 : /src/main/resources/META-INF/spring/

* 파일명 : org.springframework.boot.autoconfigure.AutoConfiguration.imports

* 파일 내용

com.github.gavlyukovskiy.boot.jdbc.decorator.DataSourceDecoratorAutoConfiguration

 

3. [project]/src/main/resources 경로에 파일 추가

* 파일 경로 : /src/main/resources/

* 파일명 : spy.properties

* 파일 내용

appender=com.p6spy.engine.spy.appender.Slf4JLogger

 

4. application.yml 에서 다른 쿼리 로그는 헷갈리지 않도록 안보이게 설정

 

5. p6spy 로그를 줄바꿈 formatting하여 가독성 높이기

* config 패키지에 P6spyLogMessageFormatConfiguration.java 생성

파일명은 상관없습니다. 파일 내용이 중요합니다.

 

@Configuration
public class P6spyLogMessageFormatConfiguration {

    @PostConstruct
    public void setLogMessageFormat() {
        P6SpyOptions.getActiveInstance().setLogMessageFormat(P6spySqlFormatConfiguration.class.getName());
    }

    static public class P6spySqlFormatConfiguration implements MessageFormattingStrategy {

        // 표기에 허용되는 filter
        private static final String ALLOW_FILTER = "com.creed";

        @Override
        public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {

            sql = formatSql(category, sql);
            if (sql.trim().isEmpty()) { // sql 이 없다면 출력하지 않아도 됨
                return "";
            }

            // stack 을 구성하는 Format을 만든다
            return sql + createStack(connectionId, elapsed);
        }

        private String formatSql(String category, String sql) {

            if (sql == null || sql.trim().equals("")) {
                return sql;
            }

            // Only format Statement, distinguish DDL And DML
            if (Category.STATEMENT.getName().equals(category)) {
                String tmpsql = sql.trim().toLowerCase(Locale.ROOT);
                if (tmpsql.startsWith("create") || tmpsql.startsWith("alter") || tmpsql.startsWith("comment")) {
                    sql = FormatStyle.DDL.getFormatter().format(sql);
                } else {
                    sql = FormatStyle.BASIC.getFormatter().format(sql);
                }
                sql = "|\nFormatSql(P6Spy sql, Hibernate format):" + sql;
            }

            return sql;
        }

        // stack 콘솔 표기
        private String createStack(int connectionId, long elapsed) {
            Stack<String> callStack = new Stack<>();
            StackTraceElement[] stackTrace = new Throwable().getStackTrace();

            for (StackTraceElement stackTraceElement : stackTrace) {
                String trace = stackTraceElement.toString();

                // trace 항목을 보고 내게 맞는 것만 필터
                if (trace.startsWith(ALLOW_FILTER)) {
                    callStack.push(trace);
                }
            }

            StringBuilder sb = new StringBuilder();
            int order = 1;
            while (callStack.size() != 0) {
                sb.append("\n\t\t").append(order++).append(".").append(callStack.pop());
            }

            return new StringBuffer().append("\n\n\tConnection ID: ").append(connectionId)
                    .append("\n\tExcution Time: ").append(elapsed).append("ms")
                    .append("\n\tCall Stack:").append(sb)
                    .append("\n--------------------------------------")
                    .toString();
        }
    }
}

 

 

 

댓글
Total
최근에 올라온 글