SQL 日誌不打印:先定段落,再進分支
SQL 日誌要經過四道關才能到你眼前:設定活進 Environment、logger 級別放行、持久層框架把 SQL 交給日誌系統、appender 和採集鏈路送到你的觀察口。任何一道關卡住,現象都是「不打印」。先確認持久層是 JPA 還是 MyBatis、跑的是 Boot 2 還是 3,再按現象對號進分支。

按首個可操作的例外分流
SQL 日誌不是開了就有:設定要先活進 Environment,級別要放行,框架要把 SQL 交給日誌系統,最後 appender 和採集鏈路要把日誌送到你眼前。先確認兩件事:持久層是 JPA 還是 MyBatis、跑的是 Boot 2 還是 3。再按現象對號進分支。
當前環境
先記錄設定寫在哪個文件、哪一層縮進,以及打包產物裡到底有沒有這份設定。設定寫錯位置是最常見的啞火原因。
- 列出項目裡所有設定文件:application.yml / application.properties / 各 profile 文件
- 確認構建產物(target/classes 或 jar 內 BOOT-INF/classes)裡實際打包了哪幾份
報錯識別
控制台与日志文件里都没有 Hibernate: select ...
也没有 DEBUG org.hibernate.SQL 行# 错:show-sql 写进了 datasource 命名空间
spring:
datasource:
show-sql: true
# 错:yml 缩进错位,show-sql 挂到了 logging 下
logging:
level:
org.hibernate.SQL: DEBUG
show-sql: true/actuator/env 里查不到 spring.jpa.show-sql→ 設定根本沒綁定,查鍵的位置、拼寫和文件是否被打包env 里值是 false→ 設定綁上了但被別的設定源蓋掉,走 A3 分支键值都对、就是没输出→ 不是設定問題,去 C1 看輸出是不是走到了 stdout
spring.jpa.show_sql(下劃線)靠 relaxed binding 也能綁上,別把它當反例;真正坑的是命名空間和縮進。
快速解法
按序執行三條判據命令,用輸出定位是「沒綁上」還是「被打包漏了」。需要暴露 actuator 的 env 端點:management.endpoints.web.exposure.include=env。
判據一:查生效值與來源。property 不存在 → 設定沒綁上;value=false → 被覆蓋(去 A3)
curl -s localhost:8080/actuator/env/spring.jpa.show-sql | jq判據二:查打包產物。grep 無輸出 → 文件沒被打包,查 resources 目錄與多模塊結構
unzip -p target/app.jar BOOT-INF/classes/application.yml | grep -n "show-sql"修復:把鍵放回 spring.jpa 命名空間
spring:
jpa:
show-sql: true驗證
- 重啟後 /actuator/env/spring.jpa.show-sql 返回 true,origin 指向預期設定文件
- 執行一次查詢,控制台出現 Hibernate: select ... 輸出
解法無效時
- 沒有 actuator:用命令行參數 --spring.jpa.show-sql=true 啟動一次,能打印就說明開關有效、問題在設定文件
- 仍無輸出:確認用的是 JPA/Hibernate 而不是 MyBatis,MyBatis 不認這個鍵,去 A4
相關
- A2:設定寫在不激活的 profile 文件裡,同樣查不到生效值
- A3:值被設定中心或環境變數覆蓋
- C1:show-sql 生效了但輸出在 stdout,日誌文件裡照樣沒有
當前環境
記錄啟動時實際激活的 profile,以及每個 profile 文件裡分別寫了什麼。本地 dev 能打印、服務器不能打印,八成是這個分支。
- 確認啟動命令、腳本、Dockerfile / K8s 清單裡的 SPRING_PROFILES_ACTIVE
- 列出 application-{profile}.yml 與主 application.yml 的分工
報錯識別
The following 1 profile is active: "prod"
# 或
No active profile set, falling back to 1 default profile: "default"激活的 profile 与配置文件后缀对不上→ application-dev.yml 整份沒加載,裡面的開關全是白寫spring.profiles.active 出现在多个地方→ 高優先級的定義說了算,低優先級的被忽略
檢索方式:在啟動日誌裡搜 profile is active。
快速解法
先確認激活的是誰,再決定是切 profile 還是挪設定。
判據:查激活的 profile,與設定文件後綴比對
grep -i "profile is active" logs/app.log
# 容器环境
kubectl logs deploy/<app-name> | grep -i "profile is active"修法一:激活對應 profile 啟動
java -jar app.jar --spring.profiles.active=dev
# 或环境变量
SPRING_PROFILES_ACTIVE=dev修法二:把 SQL 日誌開關挪進主 application.yml,用 profile 只留差異項
logging:
level:
org.hibernate.SQL: DEBUG驗證
- 啟動日誌裡的 active profile 與目標設定文件後綴一致
- /actuator/env 複核開關值已生效
解法無效時
- profile 是 CI/CD 或部署清單注入的:去 Dockerfile、K8s env、systemd unit 裡找 SPRING_PROFILES_ACTIVE
- 用了 Spring Cloud:bootstrap 上下文另有 profile 來源,查 spring.cloud.config 或 Nacos 的 profile 設定
相關
- A1:profile 對了但鍵寫錯位置,同樣查不到生效值
- A3:profile 文件加載了,值卻被更高優先級的設定源蓋掉
當前環境
記錄項目接了哪些設定源:本地 yml、設定中心(Nacos / Spring Cloud Config)、K8s ConfigMap、環境變數、啟動參數。源越多,越要先問「誰說了算」。
- 確認部署環境裡有沒有環境變數:LOGGING_LEVEL_ROOT、SPRING_JPA_SHOWSQL 這類
- 確認是否接了設定中心且有動態刷新
報錯識別
GET /actuator/env/spring.jpa.show-sql
{
"property": { "value": "false",
"origin": "systemEnvironment property \"SPRING_JPA_SHOWSQL\"" }
}origin 指向 systemEnvironment / commandLineArgs→ 環境變數或啟動參數蓋掉了 yml,去部署清單裡找origin 指向配置中心(nacos / config server)→ 遠端設定優先,改本地沒用origin 就是本地 application.yml 且值为 true→ 不是覆蓋問題,去 C1 看輸出落點
快速解法
先用 env 端點定位來源,再動對應的源。
判據:查值的來源,origin 字段就是答案
curl -s localhost:8080/actuator/env/spring.jpa.show-sql | jq '.propertySources[] | {name, value: .property.value}'環境變數來源:在部署清單裡查並改掉
kubectl get deploy <app-name> -o yaml | grep -iE "SHOWSQL|LOGGING_LEVEL"確需本環境打開:在高優先級源裡顯式設為 true(改設定中心,或加啟動參數)
java -jar app.jar --spring.jpa.show-sql=true驗證
- /actuator/env 返回的值與來源都符合預期
- 改設定中心時確認客戶端已刷新(或重啟後再查一次)
解法無效時
- 改完設定中心又被刷回去:確認 @RefreshScope 與設定中心的優先級,客戶端本地設定頂不過遠端
- 找不到來源:Spring Boot 設定優先級官方文檔對照排查(命令行 > 環境變數 > 設定中心 > 本地文件)
相關
- 官方外部化設定優先級:https://docs.spring.io/spring-boot/reference/features/external-config.html
- A2:profile 沒激活時,連被覆蓋的資格都沒有
當前環境
記錄持久層用的是原生 MyBatis 還是 MyBatis-Plus,兩套設定前綴互不兼容,是這類啞火的高發區。
- 確認依賴是 mybatis-spring-boot-starter 還是 mybatis-plus-boot-starter
- 確認有沒有自定義 SqlSessionFactory Bean
報錯識別
日志里没有任何 ==> Preparing: 行
# 项目里同时存在两种写法:
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl依赖是 mybatis-plus-boot-starter→ 只有 mybatis-plus.* 前綴生效,mybatis.* 一律不讀前缀对了、log-impl 也是 Slf4jImpl,仍无输出→ 不是這個分支,去 B3 查 mapper 包的 logger 級別
檢索方式:依賴樹裡搜 mybatis,看是哪個 starter。
快速解法
先定身份(哪個 starter),再對齊前綴。
判據:確認用的是哪個 starter
mvn dependency:tree | grep -Ei "mybatis"
# Gradle: ./gradlew dependencies --configuration runtimeClasspath | grep -i mybatisMyBatis-Plus:用 mybatis-plus 前綴
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl別忘了給 mapper 包開 DEBUG(Slf4jImpl 按 mapper namespace 輸出)
logging:
level:
com.example.mapper: DEBUG驗證
- 執行一次查詢,日誌出現 ==> Preparing: 與 <== Total: 輸出
解法無效時
- 項目裡自定義了 SqlSessionFactory Bean:yml 裡的 mybatis.* / mybatis-plus.* 整體失效,要在 Bean 裡 setConfiguration / setLogImpl
- 多數據源場景:每個 SqlSessionFactory 獨立設定,只配了一個就只看到一個庫的 SQL
相關
- C3:log-impl 的選型(Slf4jImpl 與 StdOutImpl 的差別)
- B3:logger 名對了但級別沒放行
當前環境
記錄 classpath 上有哪些日誌實現:預設 spring-boot-starter 帶 Logback,換 Log4j2 需要顯式排除。綁定錯了一個,你改的那份設定文件就永遠沒人讀。
- 確認項目想用 Logback 還是 Log4j2
- 確認有沒有 starters 排除不徹底留下的傳遞依賴
報錯識別
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/.../logback-classic-1.2.13.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/.../log4j-slf4j-impl-2.20.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]SLF4J(W): Class path contains multiple SLF4J providers.
SLF4J(W): Found provider [ch.qos.logback.classic.spi.LogbackServiceProvider]
SLF4J(W): Found provider [org.apache.logging.slf4j.SLF4JServiceProvider]Actual binding is of type [...Logback...]→ slf4j 綁到了 Logback,你改的 log4j2.xml 完全不會被讀没有多绑定警告,但配置文件改了没反应→ 不是綁定衝突,去 B2 查設定文件有沒有被加載
啟動日誌最前面幾行,搜 SLF4J 就能看到。
快速解法
目標只有一個:classpath 上只剩一個 slf4j 實現。
判據:列出所有日誌相關依賴,找出多餘的實現是誰帶進來的
mvn dependency:tree | grep -Ei "logback|log4j|slf4j|jul-to-slf4j"用 Log4j2:先排除預設 Logback,再引 log4j2 starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>保留 Logback:把傳遞進來的 log4j-slf4j2-impl / log4j-to-slf4j 排掉
mvn dependency:tree -Dincludes=org.apache.logging.log4j驗證
- 啟動日誌不再出現 multiple bindings / multiple providers 警告
- 修改目標日誌框架的設定文件,輸出行為隨之變化
解法無效時
- 排除後仍有多個實現:是某個業務依賴傳遞帶進來的,用 dependency:tree -Dincludes 定位到具體 GAV 再排
- WebFlux 項目注意 spring-boot-starter-webflux 同樣內置 logging starter,每個 starter 都要排
相關
- Spring Boot 官方 Logging 文檔:https://docs.spring.io/spring-boot/reference/features/logging.html
- B2:綁定對了但設定文件沒被加載
當前環境
記錄設定文件的確切文件名、所在模塊、是否打進了最終產物。多模塊項目裡設定文件躺在沒被打包的模塊裡,是最典型的翻車方式。
- 核對文件名逐字符:logback-spring.xml 不是 logback-sprint.xml
- 確認是否用 logging.config 顯式指定了別的路徑
報錯識別
自定义的日志格式、appender、级别全部没出现
启动输出仍是 Spring Boot 默认格式unzip -l target/app.jar | grep -Ei "logback|log4j2"
# 无输出 → 文件根本没打进 jarjar 里 BOOT-INF/classes 下找不到配置文件→ 沒打包進去,查模塊的 resources 目錄與構建設定文件在 jar 里但行为没变化→ 文件名不符合約定,或 logging.config 指向了別處用了 Log4j2 却只提供 logback-spring.xml→ 綁定的框架跟設定文件對不上,回 B1
快速解法
兩條判據:文件在不在產物裡、名字對不對。
判據一:查打包產物裡有沒有設定文件
unzip -l target/app.jar | grep -Ei "logback|log4j2"判據二:核對命名約定,Boot 識別帶 -spring 的版本優先
# Logback 识别顺序:logback-spring.xml 优先于 logback.xml
# Log4j2 识别顺序:log4j2-spring.xml 优先于 log4j2.xml
ls src/main/resources/ | grep -Ei "logback|log4j2"臨時驗證:顯式指定設定路徑,能生效就坐實是命名或位置問題
java -jar app.jar --logging.config=classpath:logback-spring.xml驗證
- 啟動後日誌輸出變成自定義 pattern / 級別 / 文件落點
- 產物裡能 unzip 出設定文件
解法無效時
- Logback:加 JVM 參數 -Dlogback.statusListenerClass=ch.qos.logback.core.status.OnConsoleStatusListener,看設定加載全過程
- Log4j2:加 JVM 參數 -Dlog4j2.debug,打印內部狀態日誌,看實際讀了哪份設定
相關
- B1:綁定錯了,文件名再對也沒人讀
- log4j2-spring.xml 裡才能用 Spring Boot 的 springProperty / springProfile 擴展
當前環境
記錄 root 級別、相關類目的顯式級別,以及 xml 裡有沒有寫死級別或 additivity。logger 級別是第一道閘,閘不開後面全白搭。
- 確認 logging.level.root 的值
- 確認 xml 裡有沒有 <logger name="org.hibernate" level="INFO" additivity="false"> 這類硬編碼
報錯識別
GET /actuator/loggers/org.hibernate.SQL
{ "configuredLevel": null, "effectiveLevel": "WARN" }<logger name="org.hibernate" level="INFO" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>configuredLevel 为 null、effectiveLevel 是 WARN/INFO→ 類目沒顯式配,繼承了 root 的低級別,顯式開類目即可configuredLevel=DEBUG 但输出仍没有→ logger 級別已放行,問題在下一道閘,去 D2 查 appender 過濾xml 里 additivity="false"→ 日誌被截在自己的 appender,root 掛的文件 appender 收不到
快速解法
先查生效級別,再決定臨時改還是永久改。查和改都用 actuator 的 loggers 端點(需暴露:management.endpoints.web.exposure.include=loggers)。
判據:查生效級別,effectiveLevel 高於 DEBUG 就是沒放行
curl -s localhost:8080/actuator/loggers/org.hibernate.SQL | jq臨時開(不重啟,診斷完記得關)
curl -X POST localhost:8080/actuator/loggers/org.hibernate.SQL \
-H 'Content-Type: application/json' \
-d '{"configuredLevel": "DEBUG"}'永久開:yml 顯式聲明,並刪掉 xml 裡寫死的級別與 additivity="false"
logging:
level:
org.hibernate.SQL: DEBUG驗證
- /actuator/loggers 複核 effectiveLevel 已變成 DEBUG
- 執行一次查詢,目標輸出位置出現對應日誌行
解法無效時
- 沒有 actuator:Logback 加 -Dlogback.statusListenerClass 看加載時的級別;或用 Arthas 的 logger 命令在線改
- 改了 yml 沒生效:確認 yml 本身被加載(回 A1/A2 的判據),且沒有 xml 硬編碼級別壓過它
相關
- D2:logger 級別放行後,appender 的過濾器是第二道閘
- A3:logging.level.* 同樣會被環境變數(如 LOGGING_LEVEL_ROOT=WARN)覆蓋
當前環境
記錄你平時在哪看日誌:IDE 控制台、SSH 終端、日誌文件還是日誌平臺。show-sql 只寫 System.out,哪個觀察口收集 stdout,哪個就能看到,日誌文件永遠看不到。
- 確認 hibernate.show_sql 的來源(spring.jpa.show-sql 或 spring.jpa.properties.hibernate.show_sql)
- 確認應用日誌文件的採集方式
報錯識別
Hibernate: select u1_0.id,u1_0.email from user u1_0 where u1_0.id=?2026-09-27 10:15:32.118 DEBUG 23456 --- [nio-8080-exec-1] org.hibernate.SQL : select u1_0.id,u1_0.email from user u1_0 where u1_0.id=?行首是裸 Hibernate:,没时间戳、级别、logger 名→ 這是 show_sql 直接寫 System.out,不經 Logback,日誌文件自然沒有行带 DEBUG org.hibernate.SQL→ 走的是日誌框架,文件裡沒有就去 D2 查 appender
Hibernate 官方對 show_sql 的定義就是 Write all SQL statements to console,是控制台,不是日誌。
快速解法
根治方案:棄用 show-sql,改用 logger 輸出,讓 SQL 進日誌體系。
關掉 show-sql
spring:
jpa:
show-sql: false改用 logger 輸出 SQL(參數綁定日誌見 C2)
spring:
jpa:
properties:
hibernate.format_sql: true
logging:
level:
org.hibernate.SQL: DEBUG驗證
- 日誌文件裡出現帶級別與 logger 名的 SQL 行
- stdout 裡的裸 Hibernate: 行消失
解法無效時
- 歷史包袱必須保留 show-sql:把 stdout 納入採集:容器場景 kubectl logs 本來就有;物理機用 nohup 重定向或 systemd journal 兜底
- 改用 logger 後級別不生效:去 B3 查級別
相關
- C3:MyBatis 的 StdOutImpl 是同一個病
- D1:stdout 與日誌文件是兩個觀察口,採集鏈路要對上
當前環境
記錄 Hibernate 版本。Boot 2 帶 Hibernate 5,Boot 3 帶 Hibernate 6,參數綁定的 logger 名在 6 裡換了,老設定原樣帶過來就是白配。
- 確認 hibernate-core 的版本號
- 確認現有設定裡寫的是哪個 logger 名
報錯識別
logging:
level:
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE # Hibernate 5 的类目,6 里已改名
# 输出只有:
# select ... where u1_0.id=?依赖里 hibernate-core 是 6.x→ BasicBinder 類目在 Hibernate 6 已廢棄,設定打在空處hibernate-core 是 5.x 且 BasicBinder 已开→ 級別沒放行或 appender 擋了,去 B3 / D2只想看 SQL 不想看参数→ 不是這個分支,org.hibernate.SQL=DEBUG 就夠了
檢索方式:依賴樹裡搜 hibernate-core 看版本。
快速解法
先定 Hibernate 版本,再選對應的 logger 名。
判據:確認 Hibernate 主版本,5 還是 6
mvn dependency:tree | grep hibernate-coreHibernate 6(Boot 3):參數綁定走新類目,結果集提取另有一個
logging:
level:
org.hibernate.SQL: DEBUG
org.hibernate.orm.jdbc.bind: TRACE
# 需要看结果集提取时再加:
# org.hibernate.orm.jdbc.extract: TRACEHibernate 5(Boot 2):保留老類目
logging:
level:
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE驗證
- 日誌出現 binding parameter 字樣且參數值可見,不再是滿屏問號
解法無效時
- 類目對了仍無參數輸出:查 effectiveLevel(B3 的判據),TRACE 比 DEBUG 更容易被壓
- 升級後 SQL 本身也沒了:去 B1,Boot 3 升級常常伴隨日誌依賴變動
相關
- Hibernate 官方文檔的日誌類目表:https://docs.hibernate.org/orm/6.2/introduction/html_single/Hibernate_Introduction.html
- C1:順手把 show-sql 換成 org.hibernate.SQL
當前環境
記錄 log-impl 的當前取值。沒配時 MyBatis 按 slf4j → commons-logging → log4j2 → log4j → jdk 的順序自動探測,有 slf4j 就走 slf4j,這時 SQL 打不打全看 mapper 包的級別。
- 確認 mybatis.configuration.log-impl(或 mybatis-plus 前綴)當前值
- 確認 mapper 接口所在包名
報錯識別
DEBUG c.e.mapper.UserMapper.selectById - ==> Preparing: SELECT id,name FROM user WHERE id=?
DEBUG c.e.mapper.UserMapper.selectById - ==> Parameters: 1(Long)
DEBUG c.e.mapper.UserMapper.selectById - <== Total: 1==> Preparing: SELECT id,name FROM user WHERE id=?
==> Parameters: 1(Long)
# 裸输出在控制台,日志文件里没有log-impl 配成 StdOutImpl→ 直接寫 stdout,與 C1 的 show-sql 同病,日誌文件永遠看不到log-impl 是 Slf4jImpl 但 mapper 包是 INFO→ slf4j 收到了但被級別擋住,給 mapper 包開 DEBUG什么 log-impl 都没配且没有 slf4j 绑定→ 探測落到了 jdk logging 等實現,回 B1 先把日誌後端理順
快速解法
推薦組合:Slf4jImpl 加 mapper 包 DEBUG,SQL 就進了統一日誌體系。
判據:確認 log-impl 現狀,注意 MyBatis-Plus 是另一個前綴
grep -rn "log-impl" src/main/resources/推薦:走 slf4j,按 mapper namespace 輸出
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
logging:
level:
com.example.mapper: DEBUG只想在控制台看:可以用 StdOutImpl,但先想清楚它不進文件、不進採集
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl驗證
- 執行一次查詢,看到 Preparing / Parameters / Total 三段輸出
- Slf4jImpl 方案下,日誌文件裡同樣能搜到這三段
解法無效時
- mapper 包開了 DEBUG 還是沒有:確認包名寫對(是接口所在包,不是 xml 所在目錄),再去 B3 查 effectiveLevel
- 只想給單個 mapper 開:logging.level.com.example.mapper.UserMapper=DEBUG,精確到類
相關
- A4:前綴寫錯時 log-impl 根本不生效
- MyBatis 官方日誌文檔:http://mybatis.org/mybatis-3/zh/logging.html
當前環境
記錄持久層寫法和連接池類型。JDBC 規範本身沒有 SQL 日誌這一說,JdbcTemplate 的 DEBUG 日誌也不展開完整帶參 SQL;想在 JDBC 層抓全量 SQL,得給 DataSource 包一層代理。
- 確認連接池:Druid、HikariCP 還是預設池
- 確認有沒有自定義 DataSource Bean
報錯識別
logging.level.org.springframework.jdbc=DEBUG 只见到模板动作日志
看不到完整的、带参数的 SQL 文本项目用 Druid 连接池→ 開 Druid 自帶的 slf4j filter 即可,別再引入第二套代理HikariCP 或默认池→ 池子沒有日誌 filter,需要 p6spy / datasource-proxy 這類 JDBC 代理项目混用 JPA 和 JdbcTemplate→ JPA 的 SQL 走 Hibernate(C1/C2),JdbcTemplate 的走這裡,兩邊都要配
快速解法
按連接池選型走對應路徑。Druid 方案改設定即可,代理方案要動依賴。
Druid:啟用 slf4j filter 並開對應 logger
spring:
datasource:
druid:
filters: stat,slf4j
filter:
slf4j:
enabled: true
statement-executable-sql-log-enable: true
logging:
level:
druid.sql.Statement: DEBUG非 Druid:引 p6spy,依賴加 spy.properties 裡指定 slf4j 輸出,p6spy 這個 logger 開 INFO 即可
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.9.1</version>
</dependency>
# spy.properties
appender=com.p6spy.engine.spy.appender.Slf4JLogger非 Druid 備選:datasource-proxy 的 SLF4JQueryLoggingListener,對應 logger 開 DEBUG
logging:
level:
net.ttddyy.dsproxy.listener.logging.SLF4JQueryLoggingListener: DEBUG驗證
- 執行一次查詢,日誌出現帶真實參數值的 SQL(代理輸出通常直接展開參數)
- 確認原有 JPA/MyBatis 的 SQL 輸出沒有被代理方案重複打印或打斷
解法無效時
- 代理裝了仍無輸出:確認 DataSource 是不是自定義 Bean 直接 new 出來的,代理根本沒包上
- Druid filter 開了沒輸出:確認 filters 裡確實包含 slf4j,且 druid.sql.Statement 的 effectiveLevel 已放行(B3 判據)
相關
- C1/C3 是框架層方案,代理是 JDBC 層兜底,能抓到所有走 DataSource 的 SQL
- 慢 SQL 監控是另一條線:Druid 的 stat filter 或 p6spy 的 outage 檢測
當前環境
記錄應用的運行方式和日誌採集鏈路:誰採集 stdout、誰採集文件。到這個階段,設定和級別都已確認沒問題,查的是「日誌去了哪、你在哪看」對不對得上。
- 確認運行方式:IDE、nohup、systemd、Docker、K8s
- 確認日誌平臺採集的是容器 stdout 還是應用日誌文件
報錯識別
kubectl logs deploy/<app-name> | grep -i "select"
# 或物理机:
journalctl -u myapp -n 500 | grep -i hibernate
# 能搜到,但应用日志文件里搜不到同一条stdout 有、文件没有→ 輸出落點問題,別再回頭改 yml,要麼把 SQL 挪進日誌框架,要麼把 stdout 納入採集stdout 也没有→ 不是落點問題,回 01–03 階段按順序查
快速解法
兩個方向:根治(SQL 進日誌框架)或補短板(採集 stdout)。
判據:確認落點差異,stdout 與文件各查一遍
kubectl logs deploy/<app-name> | grep -i "select"
grep -i "select" logs/app.log根治:SQL 改走日誌框架,讓文件 appender 接住(JPA 見 C1,MyBatis 見 C3)
logging:
level:
org.hibernate.SQL: DEBUG補短板:把 stdout 納入採集,容器 stdout 接 filebeat / fluent-bit;物理機 nohup 重定向到文件
nohup java -jar app.jar >> logs/stdout.log 2>&1 &驗證
- 同一條 SQL 能在你日常使用的觀察口(文件或日誌平臺)搜到
- 臨時驗證用 actuator 動態開級別(B3),確認整條鏈路通了再固化設定
解法無效時
- 日誌平臺有延遲:先確認不是採集延遲造成的誤判,等一個採集週期再搜
- 多副本部署:確認你查的副本就是處理請求的那個,負載均衡會把請求分到別的實例
相關
- C1:show-sql 是 stdout 派的頭號來源
- 容器十二要素主張日誌走 stdout,約定本身沒錯,關鍵是採集鏈路要知道去哪撈
當前環境
記錄 logback-spring.xml / log4j2 設定裡每個 appender 的過濾器。logger 級別放行後,appender 的過濾器是第二道閘:控制台放行了,文件沒放行,就會出現一半有一半沒有。
- 確認控制台與文件 appender 各自的 filter 設定
- 確認有沒有用 AsyncAppender 包文件 appender
報錯識別
同一个 logger 的 DEBUG SQL 行:控制台有,文件 appender 没有<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
...
</appender>文件 appender 带 ThresholdFilter=INFO→ DEBUG/TRACE 在 appender 處被過濾,logger 開得再低也沒用低峰期文件里有、高峰期丢→ AsyncAppender 隊列滿後按 discardingThreshold 丟棄 DEBUG,不是過濾是丟棄控制台和文件都没有→ 不是 appender 問題,回 B3 查 logger 級別
快速解法
先找到過濾器,再決定放行還是給 SQL 開專用 appender。
判據:定位 appender 上的過濾器設定
grep -n -B2 -A4 "filter" src/main/resources/logback-spring.xml修法一:文件 appender 放行 DEBUG
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>修法二:給 SQL 日誌開專用 appender,與業務日誌分開滾
<logger name="org.hibernate.SQL" level="DEBUG" additivity="false">
<appender-ref ref="SQL_FILE"/>
</logger>驗證
- 執行一次查詢,文件 appender 裡出現與控制台相同的 DEBUG SQL 行
- 高峰時段複核一次,確認不是異步丟棄
解法無效時
- Log4j2 同理:查 appender 上的 ThresholdFilter 與 RegexFilter
- 放行後文件仍沒有:確認 logger 的 appender-ref 指向的是不是你盯著的那個文件
相關
- B3:logger 級別是第一道閘,先過那關再來這
- logback Filter 官方文檔:https://logback.qos.ch/manual/filters.html
