Language/Java

p6spy 로그 설정 방법

건담아빠 2024. 9. 27. 14:53



스프링부트 설정

P6spyConfig

이 클래스는 스프링 애플리케이션이 시작될 때 자동으로 실행되며, P6Spy의 로그 포맷을 P6spyPrettySqlFormatter라는 사용자 정의 포맷터로 설정하는 역할을 한다. 이로 인해, P6Spy가 데이터베이스 쿼리를 로그할 때 P6spyPrettySqlFormatter에 정의된 형식대로 로그를 출력하게 된다.

import com.p6spy.engine.spy.P6SpyOptions;
import jakarta.annotation.PostConstruct;
import org.springframework.context.annotation.Configuration;

@Configuration
public class P6spyConfig {

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

 

P6spyPrettySqlFormatter

간단하게 아래처럼 사용할 수 있다.

public class P6spyPrettySqlFormatter implements MessageFormattingStrategy {
    @Override
    public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
        return String.format("%s | took %dms | SQL: %s", now, elapsed, sql);
    }
}

 

저는 블로그와 지피티의 도움으로 아래처럼 설정하였다.

import com.p6spy.engine.logging.Category;
import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import org.hibernate.engine.jdbc.internal.FormatStyle;

public class P6spyPrettySqlFormatter implements MessageFormattingStrategy {
  private String getServiceNameFromStackTrace() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

    for (StackTraceElement element : stackTrace) {
      // 예: "com.example.service" 패키지의 클래스를 서비스로 가정
      if (element.getClassName().contains("service")) {
        return element.getClassName() + "." + element.getMethodName();
      }
    }
    return "UnknownService";
  }

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

    sql = formatSql(category, sql);
//    Date currentDate = new Date();
//    SimpleDateFormat format1 = new SimpleDateFormat("yy.MM.dd HH:mm:ss");
//    return now + "|" + elapsed + "ms|" + category + "|connection " + connectionId + "|" + P6Util.singleLine(prepared) + sql;
//    return format1.format(currentDate) + " | " + "OperationTime : " + elapsed + "ms" + sql;
    return String.format("%s | took %dms | category: %s | connection: %d | %s | SQL: %s",
        serviceInfo, elapsed, category, connectionId, now, sql);
  }

  private String formatSql(String category, String sql) {
    if (sql == null || sql.trim().isEmpty()) {
      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 = "|\nHeFormatSql(P6Spy sql,Hibernate format):" + sql;
    }

    return sql;
  }
}

 

application.yml

#p6spy 로그설정 (운영환경은 반드시 false)
decorator:
  datasource:
    p6spy:
      enable-logging: true

# 운영환경
#decorator:
#  datasource:
#    enabled: false

 

결과

주요설정

  if (tmpsql.startsWith("create") || tmpsql.startsWith("alter") || tmpsql.startsWith("comment")) {
    sql = FormatStyle.DDL.getFormatter().format(sql);
  } else {
    sql = FormatStyle.BASIC.getFormatter().format(sql);
  }


결과

 

끝!

 

참고)
https://backtony.tistory.com/34