Java프로그래밍

[springboot] logback-spring.xml , Slf4jSpyLogDelegator 사용중일 때 설정 방법 예시 by ChatGpt

java springboot환경에서 logback 라이브러리를 이용하여, 백엔드 서버 로그를 파일로 남기고 있다. 로그 레벨에 따라 로그파일에 기록이 다르게 쌓임을 알고 있는데, 설정을 직접적으로 해본적은 없다. 근데 해야되는 상황에 노출되었다.

로그파일에 개인정보가 존재하면 안된다고……..그렇다라고하면, 최소한 일거리를 줄이기위해 쿼리만 노출되고 쿼리 결과는 보이지 않게 설정하기위한 삽집을 시작하였다.

그 기록을 여기에 남긴다.

👉 설정한 레벨 이상만 로그에 기록됩니다

설정 레벨실제로 기록되는 로그
TRACETRACE, DEBUG, INFO, WARN, ERROR
DEBUGDEBUG, INFO, WARN, ERROR
INFOINFO, WARN, ERROR
WARNWARN, ERROR
ERRORERROR
OFF아무것도 기록 안 됨

Spring Boot 기본 로그 레벨

Spring Boot는 기본적으로 INFO 레벨입니다.

INFO 이상만 로그 파일에 쌓임
(DEBUG, TRACE는 안 찍힘)

logback-spring.xml 기본 예제

📄 logback-spring.xml

<configuration>

    <property name="LOG_PATH" value="./logs"/>
    <property name="LOG_FILE" value="app.log"/>

    <!-- 파일 로그 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/${LOG_FILE}</file>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/app.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>

        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 전체 로그 레벨 -->
    <root level="INFO">
        <appender-ref ref="FILE"/>
    </root>

</configuration>

👉 이 경우:

  • INFO / WARN / ERROR만 파일에 저장됨
  • DEBUG / TRACE아예 기록 안 됨

패키지별 로그 레벨 다르게 설정하기 ⭐ (실무 핵심)

<logger name="com.myapp" level="DEBUG"/>
<logger name="org.springframework" level="INFO"/>
<logger name="org.hibernate.SQL" level="DEBUG"/>

📌 의미

  • com.myappDEBUG 이상 기록
  • Spring Framework → INFO 이상
  • Hibernate SQL → SQL 로그까지 찍힘

👉 결과

  • 내 코드 로그는 자세히
  • 프레임워크 로그는 최소화

application.yml / properties로 설정하는 방법

application.yml

logging:
  level:
    root: INFO
    com.myapp: DEBUG
    org.hibernate.SQL: DEBUG

application.properties

logging.level.root=INFO
logging.level.com.myapp=DEBUG
logging.level.org.hibernate.SQL=DEBUG

⚠️ 이 방식은 간단하지만,
👉 파일 롤링, 패턴, 분리 저장 같은 건 logback.xml이 필요


로그 레벨별 실제 출력 예시

log.trace("trace 로그");
log.debug("debug 로그");
log.info("info 로그");
log.warn("warn 로그");
log.error("error 로그");

root=INFO 일 때

info 로그
warn 로그
error 로그

root=DEBUG 일 때

debug 로그
info 로그
warn 로그
error 로그

실무에서 많이 쓰는 추천 설정

✅ 운영 서버

root = INFO
내 코드 = INFO
에러 원인 로그 = WARN ~ ERROR

✅ 개발 서버

root = INFO
내 코드 = DEBUG
특정 모듈만 DEBUG



mysql로그도 찍히는데, 그럼 쿼리만 로그에 남기고, 쿼리 결과는 로그에 안남기는 방법은?

1️⃣ Hibernate / JPA 사용 중인 경우 (가장 흔함)

❌ 쿼리 결과가 찍히는 원인

보통 아래 설정 때문에 결과나 파라미터까지 찍힘:

spring.jpa.show-sql: true
logging.level.org.hibernate.type: TRACE
logging.level.org.hibernate.orm.jdbc.bind: TRACE

2️⃣ SQL만 찍고, 결과/파라미터는 안 찍는 설정 ✅ (권장)

application.yml

spring:
  jpa:
    show-sql: false   # 콘솔 SQL 출력 OFF (logback으로 제어)
logging:
  level:
    org.hibernate.SQL: DEBUG
    org.hibernate.type: OFF
    org.hibernate.orm.jdbc.bind: OFF
    org.hibernate.orm.jdbc.extract: OFF

🔍 의미

로그역할결과
org.hibernate.SQL실행된 SQL✅ 찍힘
jdbc.bind바인딩 파라미터❌ 안 찍힘
jdbc.extract조회 결과(ResultSet)❌ 안 찍힘
hibernate.type타입 변환 값❌ 안 찍힘

👉 순수 SQL만 로그에 남음


3️⃣ logback-spring.xml로 제어 (더 정확)

<logger name="org.hibernate.SQL" level="DEBUG"/>

<logger name="org.hibernate.orm.jdbc.bind" level="OFF"/>
<logger name="org.hibernate.orm.jdbc.extract" level="OFF"/>
<logger name="org.hibernate.type" level="OFF"/>

📌 이 방법이 운영 환경에서 가장 안전합니다.


4️⃣ MySQL 서버 로그와는 다른 개념 ⚠️

구분설명
MySQL general logDB 서버에서 모든 쿼리 기록
slow query log느린 쿼리만 기록
Hibernate SQL log애플리케이션에서 실행한 SQL

👉 질문하신 건 애플리케이션 로그 기준
(MySQL 서버 general log를 켜면 결과 제어 불가)


5️⃣ JDBC Driver 레벨 로그 (비추천)

아래는 절대 운영에서 켜지 마세요

logging.level.com.mysql.cj.jdbc: TRACE

📛 이유

  • SQL + 파라미터 + 결과까지 다 찍힘
  • 로그 폭발
  • 개인정보 유출 위험

6️⃣ 실무 추천 조합 (BEST PRACTICE)

🔧 개발 서버

logging.level.org.hibernate.SQL: DEBUG
logging.level.org.hibernate.orm.jdbc.bind: OFF

🚀 운영 서버

logging.level.org.hibernate.SQL: INFO
logging.level.org.hibernate.orm.jdbc.bind: OFF
logging.level.org.hibernate.orm.jdbc.extract: OFF

hibernate.orm 사용하지않아.!! org.springframework 사용해



1️⃣ Spring JDBC에서 SQL 로그가 찍히는 원인

Spring 쪽에서 SQL이 찍히는 대표 로그는 이거예요:

로거설명
org.springframework.jdbc.core.JdbcTemplate실행 SQL
org.springframework.jdbc.core.StatementCreatorUtils바인딩 파라미터
org.springframework.jdbc.datasource.DataSourceUtils커넥션 관련
org.springframework.jdbc.supportResultSet 처리

👉 결과/파라미터는 TRACE / DEBUG에서만 노출됨


2️⃣ SQL만 남기는 최소 설정 ⭐⭐⭐

✅ application.yml

logging:
  level:
    root: INFO

    # SQL 문장만
    org.springframework.jdbc.core.JdbcTemplate: DEBUG

    # ❌ 파라미터, 결과 제거
    org.springframework.jdbc.core.StatementCreatorUtils: OFF
    org.springframework.jdbc.support: OFF
    org.springframework.jdbc.datasource: OFF

    # ❌ MySQL Driver 로그 완전 차단
    com.mysql.cj.jdbc: OFF

📌 결과

  • SELECT / INSERT / UPDATE / DELETE SQL만 찍힘
  • ? 바인딩 값 안 찍힘
  • ❌ ResultSet 값 안 찍힘

3️⃣ logback-spring.xml 기준 (운영 권장)

<!-- SQL만 -->
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG"/>

<!-- 파라미터 / 결과 -->
<logger name="org.springframework.jdbc.core.StatementCreatorUtils" level="OFF"/>
<logger name="org.springframework.jdbc.support" level="OFF"/>

<!-- 커넥션, 드라이버 -->
<logger name="org.springframework.jdbc.datasource" level="OFF"/>
<logger name="com.mysql.cj.jdbc" level="OFF"/>

4️⃣ MyBatis 쓰는 경우라면 (추가 정리)

MyBatis는 로그 구현체에 따라 다릅니다.

❌ 이렇게 설정하면 결과까지 다 나옴

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

✅ SQL만 찍고 싶을 때 (권장)

logging:
  level:
    org.mybatis.spring.SqlSessionTemplate: DEBUG
    org.apache.ibatis.executor: DEBUG
    org.apache.ibatis.type: OFF

👉 이러면 SQL은 나오고, ResultSet은 안 나옴


5️⃣ MySQL 서버 로그랑 혼동하면 안 되는 부분

로그 위치제어 가능 여부
Spring Boot 로그✅ 가능
MySQL general log❌ 결과 제어 불가
slow query log결과 없음 (SQL만)

👉 general log 켜면 무조건 다 찍힘 → 운영에서 ❌


6️⃣ 실무 BEST 설정 (Spring JDBC + MySQL)

🧪 개발

org.springframework.jdbc.core.JdbcTemplate: DEBUG

🚀 운영

org.springframework.jdbc.core.JdbcTemplate: INFO

(필요 시 특정 패키지만 DEBUG)


7️⃣ 한 줄 요약

Spring JDBC 환경에서는
JdbcTemplate만 DEBUG로 두고
StatementCreatorUtils, jdbc.support, mysql driver를 OFF 하면
SQL만 로그에 남고 결과/파라미터는 절대 안 남는다.


다음으로 이어서 알려줄 수 있어요 👇

  • SQL 로그를 **별도 파일(sql.log)**로 분리
  • 실행 시간(ms) 포함 SQL 로그
  • P6Spy 없이 Spring 로그만으로 SQL 추적하는 법

(필요 시 특정 패키지만 DEBUG) 하는 방법은?

좋은 포인트 짚으셨어요 👍
“필요한 패키지만 DEBUG” 는 운영/개발 로그 관리의 핵심입니다.

아래를 보시면 3분 안에 바로 적용할 수 있어요.


1️⃣ 가장 간단한 방법 (application.yml / properties)

✅ application.yml

logging:
  level:
    root: INFO

    # 내 서비스 패키지
    com.myapp: DEBUG

    # 특정 하위 패키지만
    com.myapp.user: DEBUG
    com.myapp.order.service: DEBUG

    # Spring JDBC SQL만
    org.springframework.jdbc.core.JdbcTemplate: DEBUG

📌 규칙

  • 패키지 단위로 전부 적용
  • 하위 패키지는 자동 상속

✅ application.properties

logging.level.root=INFO
logging.level.com.myapp=DEBUG
logging.level.com.myapp.order.service=DEBUG
logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG

2️⃣ logback-spring.xml 방식 (운영에서 가장 권장 ⭐⭐⭐)

📄 logback-spring.xml

<configuration>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/app.log</file>
        <!-- encoder, rolling 설정 생략 -->
    </appender>

    <!-- 전체 기본 -->
    <root level="INFO">
        <appender-ref ref="FILE"/>
    </root>

    <!-- 내 프로젝트 전체 -->
    <logger name="com.myapp" level="DEBUG"/>

    <!-- 특정 패키지 -->
    <logger name="com.myapp.order.service" level="DEBUG"/>

    <!-- SQL만 -->
    <logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG"/>

    <!-- 불필요한 로그 차단 -->
    <logger name="org.springframework.jdbc.support" level="OFF"/>
    <logger name="com.mysql.cj.jdbc" level="OFF"/>

</configuration>

📌 특징

  • root=INFO 유지
  • 필요한 부분만 DEBUG
  • 운영 환경에서 가장 안전

3️⃣ 클래스 단위로 DEBUG 설정 (가능은 하지만 비추천)

<logger name="com.myapp.order.service.OrderService" level="DEBUG"/>

⚠️ 단점

  • 클래스명 변경 시 설정 깨짐
  • 유지보수 어려움

👉 패키지 단위 권장


4️⃣ 런타임에 로그 레벨 변경 (운영에서 유용)

actuator 사용 시

management:
  endpoints:
    web:
      exposure:
        include: loggers
# 현재 로그 레벨 조회
GET /actuator/loggers/com.myapp.order.service

# DEBUG로 변경
POST /actuator/loggers/com.myapp.order.service
{
  "configuredLevel": "DEBUG"
}

📌 서버 재기동 없이 변경 가능 🔥


5️⃣ 실무에서 자주 쓰는 패턴

🔹 패키지 구조 예시

com.myapp
 ├─ controller
 ├─ service
 ├─ repository

🔹 추천 설정

<logger name="com.myapp.service" level="DEBUG"/>
<logger name="com.myapp.controller" level="INFO"/>
<logger name="com.myapp.repository" level="WARN"/>

👉 Service 로직만 상세 로그


6️⃣ 주의사항

  • DEBUG 남발 ❌ → 로그 용량 폭증
  • SQL DEBUG는 꼭 기간 한정
  • 개인정보 포함 로그는 마스킹 필수


흠… 잘 안되네… [DEBUG] [MybatisLoggingInterceptro.java] : 쿼리 로그를 찍고, [INFO] [Slf4jSpyLOgDelegator.java] 가 쿼리 결과를 찍네.. Slf4jSpyLOgDelegator를 못남기해 해야돼

아, 이제 원인이 딱 보입니다 👍
지금 상황은 Spring / MyBatis 문제가 아니라 P6Spy예요.

로그를 보면 이미 답이 나와 있어요 👇

[DEBUG] MybatisLoggingInterceptor.java   -> SQL 로그
[INFO ] Slf4jSpyLogDelegator.java        -> 쿼리 결과 로그

👉 Slf4jSpyLogDelegator = P6Spy 로그 클래스
즉,

❗ 쿼리 결과를 찍는 주범은 P6Spy 입니다


해결 핵심 요약

P6Spy 로그(Slf4jSpyLogDelegator)를 끄면
쿼리 결과 로그는 완전히 사라집니다

방법은 3가지가 있고, 1번 또는 2번이면 충분합니다.


1️⃣ logback에서 P6Spy 로그 완전 차단 ⭐⭐⭐ (가장 확실)

📄 logback-spring.xml

<!-- P6Spy 로그 완전 차단 -->
<logger name="p6spy" level="OFF"/>
<logger name="com.p6spy" level="OFF"/>
<logger name="com.p6spy.engine.spy" level="OFF"/>
<logger name="com.p6spy.engine.common" level="OFF"/>

📌 이러면

  • Slf4jSpyLogDelegator 로그 ❌
  • ResultSet 로그 ❌
  • 파라미터 로그 ❌

👉 MybatisLoggingInterceptor 로그는 그대로 유지


2️⃣ p6spy.properties에서 로그 자체를 비활성화 (추천 ⭐⭐⭐)

📄 p6spy.properties

# SLF4J 로깅 사용 중지
appender=com.p6spy.engine.spy.appender.NoopAppender

📌 효과

  • P6Spy가 아예 로그를 안 남김
  • 성능 가장 좋음
  • 운영 서버에 강력 추천

3️⃣ 결과(ResultSet)만 선택적으로 끄기 (부분 차단)

⚠️ 이건 P6Spy를 계속 쓰고 싶을 때만

excludecategories=result,resultset,commit,rollback

또는

excludecategories=info,debug,result,resultset

📌 하지만

  • 버전별로 동작 다를 수 있음
  • 완전 차단은 아님

👉 그래서 실무에선 1번 or 2번만 씁니다.


4️⃣ 왜 MyBatis 인터셉터 로그는 괜찮은가?

MybatisLoggingInterceptor
→ SQL만 직접 찍는 사용자 코드
→ ResultSet 접근 안 함

반면

Slf4jSpyLogDelegator (P6Spy)
→ JDBC Driver 레벨
→ ResultSet까지 후킹
→ 조회 결과 전부 로그

5️⃣ 실무 BEST 조합 (지금 상황에 딱 맞음)

✅ SQL은 MyBatis 인터셉터로만 관리

❌ P6Spy 로그는 완전 차단

MybatisLoggingInterceptor → DEBUG
P6Spy → OFF


Slf4jSpyLogDelegator 로그남기는거만 끄고 싶어 전부 끄면 안돼

이건 logback + p6spy.properties 조합으로 해결해야 합니다.


현재 구조 정리 (중요)

MybatisLoggingInterceptor (DEBUG)
 └─ SQL만 출력 (OK)

P6Spy
 └─ Slf4jSpyLogDelegator (INFO)
     └─ ResultSet / 결과 로그 출력 (❌ 이걸 끄고 싶음)

👉 Slf4jSpyLogDelegator 자체를 OFF 하면
P6Spy 전체가 죽어버릴 수 있음 → ❌
그래서 “결과 카테고리만 제외” 해야 함


정답: P6Spy에서 result / resultset 카테고리만 제외

1️⃣ p6spy.properties 설정 ⭐⭐⭐ (정석)

# SLF4J 사용 (유지)
appender=com.p6spy.engine.spy.appender.Slf4JLogger

# 결과 관련 로그만 제외
excludecategories=result,resultset

📌 이 설정의 효과

항목결과
SQL (statement)✅ 남음
바인딩 값⚠️ 설정에 따라
ResultSet / 조회 결과❌ 안 남음
P6Spy 자체✅ 유지

2️⃣ (선택) 바인딩 값도 같이 끄고 싶다면

excludecategories=result,resultset,debug

또는 더 명확하게:

excludecategories=result,resultset,bind

(버전에 따라 bind / debug 동작 차이 있음)


3️⃣ logback에서 클래스 단위로만 제어 (보조 수단)

Slf4jSpyLogDelegator는 보통 이 패키지에서 로그를 찍어요:

com.p6spy.engine.spy.appender.Slf4JLogger

❌ 이렇게 하면 전체 P6Spy 로그가 죽을 수 있음 (비추천)

<logger name="com.p6spy.engine.spy.appender.Slf4JLogger" level="OFF"/>

✅ 대신 INFO → WARN으로 낮추는 건 가능

<logger name="com.p6spy.engine.spy.appender.Slf4JLogger" level="WARN"/>

👉 INFO로 찍히는 결과 로그만 차단
👉 ERROR 수준 로그는 유지

⚠️ 하지만 카테고리 차단이 더 정확


4️⃣ P6Spy 로그 카테고리 한눈에 정리

카테고리내용
statementSQL 문
result결과 요약
resultsetResultSet 상세
commit커밋
rollback롤백
debug바인딩 / 내부
info일반 정보

👉 지금 상황에 필요한 건 딱 이것 👇

excludecategories=result,resultset

5️⃣ 최종 추천 조합 (지금 구조 기준)

✅ MyBatis 인터셉터

MybatisLoggingInterceptor → DEBUG (SQL)

✅ P6Spy

appender=com.p6spy.engine.spy.appender.Slf4JLogger
excludecategories=result,resultset

✅ logback

<logger name="com.p6spy" level="INFO"/>


log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator 설정파일에 이렇게 되어있어. 이거 기준으로 알려줘

아, 좋습니다.
지금 쓰시는 건 **P6Spy가 아니라 log4jdbc**이고,
Slf4jSpyLogDelegatorlog4jdbc의 SLF4J 델리게이터네요 👍
(아까 P6Spy랑 헷갈릴 수 있는 포인트였어요)

log4jdbc.spylogdelegator.name=
net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

👉 이 설정 기준으로 “쿼리는 남기고, 쿼리 결과(ResultSet)만 안 남기기” 방법을 정확히 정리할게요.


log4jdbc 로그 구조 이해 (중요)

log4jdbc는 로그를 카테고리(로거 이름)별로 분리해서 찍습니다.

로거 이름의미
jdbc.sqlonlySQL만
jdbc.sqltimingSQL + 실행시간
jdbc.auditJDBC 호출 흐름
jdbc.resultsetResultSet 내용 ❌
jdbc.resultsettableResultSet 테이블 형태 ❌
jdbc.connection커넥션

👉 쿼리 결과는 jdbc.resultset* 계열에서 찍힘


정답: resultset 계열 로거만 OFF 하면 된다 ⭐⭐⭐

1️⃣ logback-spring.xml 설정 (가장 정확)

<!-- SQL 로그 (유지) -->
<logger name="jdbc.sqlonly" level="DEBUG"/>
<!-- 또는 -->
<logger name="jdbc.sqltiming" level="DEBUG"/>

<!-- ❌ 쿼리 결과 로그 차단 -->
<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>

<!-- (선택) 불필요한 것들 -->
<logger name="jdbc.audit" level="OFF"/>
<logger name="jdbc.connection" level="OFF"/>

📌 이게 log4jdbc 정석 설정입니다.


2️⃣ application.yml / properties 로도 가능

application.yml

logging:
  level:
    jdbc.sqlonly: DEBUG
    jdbc.sqltiming: DEBUG

    jdbc.resultset: OFF
    jdbc.resultsettable: OFF

application.properties

logging.level.jdbc.sqlonly=DEBUG
logging.level.jdbc.sqltiming=DEBUG
logging.level.jdbc.resultset=OFF
logging.level.jdbc.resultsettable=OFF

3️⃣ 왜 Slf4jSpyLogDelegator만 OFF 하면 안 되나?

<logger name="net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator" level="OFF"/>

❌ 이렇게 하면

  • SQL 로그까지 같이 사라질 수 있음
  • log4jdbc 전체 로깅 경로가 끊김

👉 델리게이터는 유지 + 카테고리만 제어가 정답


4️⃣ 실무에서 가장 많이 쓰는 조합 (추천)

<logger name="jdbc.sqlonly" level="DEBUG"/>
<logger name="jdbc.sqltiming" level="DEBUG"/>

<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>

📌 결과

[DEBUG] jdbc.sqlonly        -> SELECT ... FROM ...
[DEBUG] jdbc.sqltiming     -> 실행시간 포함 SQL
(❌ ResultSet 로그 없음)



logeback-spring.xml 을 ChatGpt에 전달함.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />

	<springProfile name="local">
		<property resource="config/application-local.properties"/>
	</springProfile>
	<springProfile name="dev">
		<property resource="config/application-dev.properties"/>
	</springProfile>
	<springProfile name="real">
		<property resource="config/application-real.properties"/>
	</springProfile>
    </springProfile>

    <!-- 변수 지정 -->
    <property name="LOG_DIR" value="/logs" />
    <property name="LOG_PATH_NAME" value="${log.dir}" />

    <!-- FILE Appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH_NAME}/test-api-${spring.profiles.active}.log</file>
        <encoder>
            <charset>UTF-8</charset>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5p] [%F]%M\(%L\) : %m%n</pattern>
        </encoder>
        <!-- 일자별로 로그파일 적용하기 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH_NAME}/test-api-${spring.profiles.active}.log.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- 파일당 최고 용량 10MB -->
                <maxFileSize>30MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <maxHistory>60</maxHistory> <!-- 일자별 백업파일의 보관기간 -->
        </rollingPolicy>
    </appender>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
      <layout class="ch.qos.logback.classic.PatternLayout">
        <pattern>%d{yyyy-MM-dd HH:mm:ss} [%-5p] [%F]%M\(%L\) : %m%n</pattern>
      </layout>
    </appender>

    <logger name="org.springframework" level="WARN" />
    <logger name="org.springframework.web" level="DEBUG"/>
    <logger name="org.springframework.jdbc" level="DEBUG" />
    <logger name="org.springframework.transaction" level="DEBUG" />

    <logger name="mybatis" level="info"/>

    <logger name="jdbc.sqltiming" level="ERROR"/>
    <logger name="jdbc.audit" level="ERROR"/>
    <logger name="jdbc.connection" level="ERROR"/>
    <logger name="jdbc.sqlonly" level="ERROR"/>
    <logger name="jdbc.resultset" level="ERROR"/>
    <logger name="jdbc.resultsettable" level="DEBUG"/>
    <logger name="log4jdbc.debug" level="ERROR"/>

    <logger name="com.test.package" level="DEBUG"/>

    <!-- TRACE > DEBUG > INFO > WARN > ERROR, 대소문자 구분 안함 -->
    <!-- profile 을 읽어서 appender 을 설정할수 있다.(phase별 파일을 안만들어도 되는 좋은 기능) -->
    <springProfile name="local">
      <root level="DEBUG">
        <appender-ref ref="FILE" />
        <appender-ref ref="console" />
      </root>
    </springProfile>
    <springProfile name="dev">
      <root level="DEBUG">
        <appender-ref ref="FILE" />
        <!-- <appender-ref ref="console" /> -->
      </root>
    </springProfile>
    <springProfile name="stage">
      <root level="DEBUG">
        <appender-ref ref="FILE" />
        <!-- <appender-ref ref="console" /> -->
      </root>
    </springProfile>
    <springProfile name="real">
      <root level="DEBUG">
        <appender-ref ref="FILE" />
      </root>
    </springProfile>
</configuration>

문제의 핵심 원인 (딱 이 한 줄)

<logger name="jdbc.resultsettable" level="DEBUG"/>

👉 이 설정 때문에 쿼리 결과가 찍히는 겁니다.

log4jdbc에서:

로거역할
jdbc.resultsetResultSet row 단위 출력
jdbc.resultsettableResultSet을 테이블 형태로 출력 ❌ (가장 시끄러움)

지금 설정은 👇

  • jdbc.resultset → ERROR (거의 안 찍힘)
  • jdbc.resultsettableDEBUG (결과 전부 출력)

그래서 로그에 이렇게 보이는 거예요:

[INFO ] Slf4jSpyLogDelegator : ResultSet ...

Slf4jSpyLogDelegator출력 통로일 뿐이고,
실제 트리거는 jdbc.resultsettable=DEBUG 입니다.


해결 방법 (의도 그대로, 최소 수정)

🔧 수정 전

<logger name="jdbc.resultset" level="ERROR"/>
<logger name="jdbc.resultsettable" level="DEBUG"/>

🔧 수정 후 (정답)

<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>

또는 (OFF 대신 ERROR 써도 됨)

<logger name="jdbc.resultset" level="ERROR"/>
<logger name="jdbc.resultsettable" level="ERROR"/>

👉 이렇게만 바꾸면

  • ✅ SQL 로그 유지
  • ❌ 쿼리 결과 로그 완전 제거
  • Slf4jSpyLogDelegator 결과 로그 사라짐

그럼 SQL은 어떻게 남기나?

현재 SQL도 ERROR로 막혀 있는 상태라,
원래 의도대로라면 아래 중 하나만 DEBUG로 두는 게 일반적이에요.

✅ SQL + 실행시간

<logger name="jdbc.sqltiming" level="DEBUG"/>

✅ SQL만

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

📌 추천 조합 (실무에서 가장 많이 씀)

<logger name="jdbc.sqltiming" level="DEBUG"/>

<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>

왜 Slf4jSpyLogDelegator를 끄면 안 되나?

<logger name="net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator" level="OFF"/>

❌ 이건 log4jdbc 전체 로깅 경로 차단
→ SQL까지 같이 안 찍힐 수 있음

👉 log4jdbc는 “로거 이름(jdbc.*)”으로 제어하는 게 정석


최종 정리 (지금 설정 기준)

❌ 문제 원인

jdbc.resultsettable = DEBUG

✅ 해결

jdbc.resultset / jdbc.resultsettable → OFF (또는 ERROR)

✅ 유지

Slf4jSpyLogDelegator → 그대로 둠


너가 하라는데로 해결은 되었어.. 근데 동일 쿼리가 2개씩 찍히네.. 이유가?

좋은 질문이고, 이건 거의 다들 한 번씩 겪는 케이스예요 👍
결론부터 말하면 지금은 “같은 SQL을 찍는 주체가 2개”라서 2번 찍히는 상태입니다.


왜 동일 쿼리가 2번 찍히나? (원인 3가지 중 하나)

지금 구성 기준으로 보면 ①번이 거의 확실합니다.


✅ 원인 ① (가장 유력)

MyBatis 인터셉터 + log4jdbc가 동시에 SQL을 찍음

현재 로그 흐름 👇

MybatisLoggingInterceptor.java   → SQL 출력 (1번)
log4jdbc (jdbc.sqltiming)        → SQL 출력 (1번)
------------------------------------------------
총 2번

✔ 이미 말씀하신 로그:

[DEBUG] [MybatisLoggingInterceptor.java]
[DEBUG] jdbc.sqltiming

👉 의도대로 동작 중이지만,
👉 “같은 SQL을 서로 다른 계층에서 찍고 있는 것”

🔧 해결 방법 (택1)

✅ 방법 A (권장 ⭐⭐⭐)

👉 MyBatis 인터셉터는 유지, log4jdbc는 SQL 로그 끔

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

(결과 로그는 이미 OFF 했으니 그대로)

➡ SQL 로그는 MyBatis 쪽에서만 1번


✅ 방법 B

👉 log4jdbc만 사용, MyBatis 인터셉터 로그 제거

<!-- MyBatis 인터셉터 logger -->
<logger name="com.test.패키지.MybatisLoggingInterceptor" level="OFF"/>

또는 코드에서 SQL 로그 제거

➡ SQL 로그는 jdbc.sqltiming에서만 1번


✅ 원인 ②

FILE + CONSOLE Appender 둘 다 보고 있는 경우 (착각 케이스)

local profile 기준 👇

<appender-ref ref="FILE" />
<appender-ref ref="console" />

📌 이 경우

  • 콘솔 1번
  • 파일 1번

👉 파일만 보면 1번
👉 콘솔 + 파일 같이 보면 2번처럼 보임

✔ 확인법

  • 로그 파일만 열어보기
  • 콘솔 로그 끄고 테스트
<!-- local에서도 console 잠시 주석 -->
<!-- <appender-ref ref="console" /> -->

✅ 원인 ③ (빈도는 낮음)

org.springframework.jdbc DEBUG 로그와 겹침

지금 설정에 이게 있어요 👇

<logger name="org.springframework.jdbc" level="DEBUG" />

Spring JDBC도 SQL을 찍을 수 있어서
log4jdbc랑 겹칠 수 있음

🔧 해결

<logger name="org.springframework.jdbc" level="WARN" />

또는 아예 OFF


지금 상황 기준 “정답 조합” (실무 추천)

👉 MyBatis 인터셉터 기준으로 SQL 관리

<!-- log4jdbc -->
<logger name="jdbc.sqltiming" level="OFF"/>
<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>

<!-- MyBatis SQL 로그 -->
<logger name="com.test.package" level="DEBUG"/>

✔ SQL 1번
✔ 결과 로그 없음
✔ 제어 쉬움


👉 log4jdbc 기준으로 SQL 관리

<logger name="jdbc.sqltiming" level="DEBUG"/>
<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>

<!-- MyBatis 인터셉터 로그 제거 -->

✔ 실행시간 포함
✔ SQL 1번


✅ 한 줄 결론

동일 쿼리가 2번 찍히는 이유는
MyBatis 인터셉터와 log4jdbc가
같은 SQL을 각각 한 번씩 찍고 있기 때문이다.
둘 중 하나만 남기면 바로 해결된다.


지금 선택은 딱 하나만 물어볼게요 👇
👉 “SQL 로그의 기준을 MyBatis로 할지, log4jdbc로 할지”
정해주면 거기에 맞춰 최종 설정안 딱 정리해줄게요.

log4jdbc로 결정

좋아요 👍
그럼 SQL 로그의 단일 기준을 log4jdbc로 확정하고,
👉 **중복 로그 원인을 깔끔하게 제거하는 “최종 설정안”**을 정리해 드릴게요.


✅ 목표 (log4jdbc 기준)

  • ✔ SQL 1번만 출력
  • ✔ 실행시간 포함
  • ❌ ResultSet / 결과 로그 없음
  • ❌ MyBatis / Spring JDBC 중복 로그 없음
  • ✔ 운영에서도 안전

1️⃣ MyBatis 쪽 SQL 로그 완전 제거 (중복 원인 제거)

🔧 MyBatis 인터셉터 로그 OFF

<logger name="MybatisLoggingInterceptor" level="OFF"/>

패키지명이 정확하면 더 좋음:

<logger name="com.test.package" level="INFO"/>

(이미 test.package을 DEBUG로 두셨다면,
인터셉터 클래스만 INFO/OFF로 낮추는 게 베스트)

예:

<logger name="com.test.package.common.interceptor.MybatisLoggingInterceptor" level="OFF"/>

2️⃣ Spring JDBC SQL 로그 제거

현재 설정 👇

<logger name="org.springframework.jdbc" level="DEBUG" />

❌ 이건 중복 원인

✅ 수정

<logger name="org.springframework.jdbc" level="WARN"/>

3️⃣ log4jdbc 최종 권장 설정 ⭐⭐⭐

<!-- SQL + 실행시간 -->
<logger name="jdbc.sqltiming" level="DEBUG"/>

<!-- 결과 로그 제거 -->
<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>

<!-- 불필요한 것들 -->
<logger name="jdbc.audit" level="OFF"/>
<logger name="jdbc.connection" level="OFF"/>

4️⃣ 콘솔 + 파일 중복 착각 방지 (확인 포인트)

local profile에서:

<appender-ref ref="FILE" />
<appender-ref ref="console" />

👉 콘솔 + 파일을 동시에 보고 있으면 2번처럼 보일 수 있음

✔ 실제 확인은 로그 파일만 기준으로 판단


5️⃣ 최종 “정리된 logback 핵심 부분”

<!-- Spring / MyBatis -->
<logger name="org.springframework" level="WARN"/>
<logger name="org.springframework.jdbc" level="WARN"/>
<logger name="mybatis" level="INFO"/>

<!-- log4jdbc -->
<logger name="jdbc.sqltiming" level="DEBUG"/>
<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>
<logger name="jdbc.audit" level="OFF"/>
<logger name="jdbc.connection" level="OFF"/>

로그 예시 (정상 상태)

[DEBUG] jdbc.sqltiming - 25 ms | SELECT * FROM TB_USER WHERE ID = ?

✔ 딱 1줄
✔ 결과 없음
✔ 중복 없음


최종 한 줄 결론

log4jdbc를 기준으로 쓰려면
MyBatis 인터셉터 + Spring JDBC SQL 로그를 끄고
jdbc.sqltiming만 DEBUG로 두면
SQL은 정확히 1번만 찍힌다.



SQL 로그의 기준을 MyBatis로 하려면?

좋아요 👍
그럼 이번엔 SQL 로그의 “단일 기준을 MyBatis”로 가져가는 최종 정리를 해드릴게요.
(지금까지 설정을 되돌리지 않고, 최소 변경 기준입니다)


목표 (MyBatis 기준)

  • ✔ SQL 1번만 출력
  • ✔ log4jdbc 완전 배제 (SQL 출력 안 함)
  • ✔ ResultSet / 쿼리 결과 로그 없음
  • ✔ Spring JDBC 중복 로그 없음
  • ✔ 유지보수 쉬움

1️⃣ log4jdbc SQL 로그 완전 차단 (가장 중요)

log4jdbc는 데이터소스 레벨이라
켜져 있으면 무조건 SQL을 가로챕니다.

🔧 logback-spring.xml

<!-- log4jdbc 전부 OFF -->
<logger name="jdbc.sqlonly" level="OFF"/>
<logger name="jdbc.sqltiming" level="OFF"/>
<logger name="jdbc.audit" level="OFF"/>
<logger name="jdbc.connection" level="OFF"/>
<logger name="jdbc.resultset" level="OFF"/>
<logger name="jdbc.resultsettable" level="OFF"/>

📌 이걸로 **log4jdbc는 존재하지만 “조용한 상태”**가 됩니다.


2️⃣ MyBatis 인터셉터에서 SQL 로그 찍기 (기준)

이미 쓰고 계신 걸로 보이는 👇

MybatisLoggingInterceptor.java

✅ 로그 레벨

<logger name="com.test.package.common.interceptor.MybatisLoggingInterceptor"
        level="DEBUG"/>

또는 패키지 기준

<logger name="com.test.package" level="DEBUG"/>

3️⃣ Spring JDBC / MyBatis 내부 로그 중복 제거

🔧 Spring JDBC

<logger name="org.springframework.jdbc" level="WARN"/>

🔧 MyBatis 내부

<logger name="org.mybatis" level="WARN"/>
<logger name="mybatis" level="WARN"/>

4️⃣ (선택) MyBatis 기본 로그 구현체 쓰는 경우 확인

❌ 이런 설정이 있으면 제거

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

또는

mybatis.configuration.log-impl=STDOUT_LOGGING

👉 이건 System.out 으로 SQL 찍어서 logback이랑 겹침


5️⃣정상 상태 로그 예시

[DEBUG] MybatisLoggingInterceptor - SELECT * FROM TB_USER WHERE ID = ?

✔ SQL 1번
✔ 실행 주체 명확
✔ log4jdbc 출력 없음


6️⃣ MyBatis 기준의 장단점 (현실 정리)

👍 장점

  • 로그 제어 쉬움
  • SQL 출력 위치 명확
  • 인터셉터에서 마스킹/포맷 자유

👎 단점

  • 실행시간 측정 직접 구현 필요
  • JDBC 레벨 이슈는 안 보임

✅ 최종 한 줄 결론

SQL 로그를 MyBatis 기준으로 쓰려면
log4jdbc의 jdbc.* 로그를 전부 OFF 하고
MyBatis 인터셉터 로그만 DEBUG로 유지하면 된다.

Hi, I’m 똘켓