2018年4月24日 星期二

Logback 的 Log 篩選設定

平常比較容易遇到的有幾種案例:

  1. 我想要 logback 輸出所有的 log,但特定某些 package 想要隱藏 DEBUG 和 TRACE
  2. 我想要 logback 只輸出 INFO 以上的 log,但特定某些 package 想要輸出所有 log
  3. 我想要 logback 只輸出 INFO 以上的 log,但特定某些 package 想要輸出所有 log,而且某個 package 的 INFO 以上 log 要輸出到別的 appender

之前開發時,大多用到的是第一種,但偶而想要第二和第三種時,花了不少時間才調整出來
最後發現一開始對設定的認知其實有點不太正確。

Logback 設定的 Logger

Logger 的設定可以參考官方的文件 [1]。

整個 Logger 的概念,應該要以樹狀結構去思考,其中樹狀結構的組成是 package。
例如我的程式碼中有 com.example 和 org.example 兩個 package
這意味著樹狀結構中,ROOT 有兩個子節點 com 和 org,然後 com 和 org 節點各自都有一個叫做 example 的子節點。

ROOT 是樹狀結構當中的根節點,在 <ROOT> 上做的設定,預設會套用到樹狀結構中的每個節點
但這並不表示 ROOT 的設定是所有東西的預設值(這是我自己原先觀念上的錯誤)。

例如下述的官方範例來說

<logger name="chapters.configuration" level="INFO" />

<!-- turn OFF all logging (children can override) -->
<root level="OFF">
  <appender-ref ref="STDOUT" />
</root>

如果 ROOT 設定當作是預設值,這個設定應該要認為除了 chapters.configuration 以外的所有 package 都不會輸出 log
但正確的解釋是,chapters.configuration 以及它的所有子節點,都是設為 INFO 等級,除此之外的所有 package 都是 OFF。

Logger name Assigned Level Effective Level
root OFF OFF
chapters.configuration INFO INFO
chapters.configuration.MyApp3 null INFO
chapters.configuration.Foo null INFO

如官網的表格,表格的意思如下:

  • root 在設定檔中被設定為 OFF,實際執行時輸出效果為 OFF
  • chapters.configuration 在設定檔中被設定為 INFO,實際輸出效果為 INFO
  • chapters.configuration.MyApp3 在設定檔中沒有被設定,實際輸出效果為 INFO(因為繼承了由上層節點 chapters.configuration 的設定)
  • chapters.configuration.Foo 在設定檔中沒有被設定,實際輸出效果為 INFO(因為繼承了由上層節點 chapters.configuration 的設定)
隱藏特定 Package 的 log

其實這種案例已經在上面的範例中展示了 XD

<logger name="chapters.configuration" level="INFO" />

<root level="ALL">
  <appender-ref ref="STDOUT" />
</root>

例如像上述這樣小做調整的結果,就是所有 LOG 都會輸出,只有 chapters.configuration 以及其下的 package 是只輸出 INFO 以上。

只有特定 Package 的 log 輸出全部;其他 Package 都輸出 INFO 以上

這個其實概念也跟上面一樣。

<logger name="chapters.configuration" level="ALL" />

<root level="INFO">
  <appender-ref ref="STDOUT" />
</root>
特定 Package 的 INFO 以上 log 輸出到資料庫;我寫的程式的 log 全部輸出到 console;剩下的 log 只輸出 INFO 以上到 console

這個就是這次主要要紀錄的狀況,子標題有點長 XD
具體來說有像是以下的需求:

  1. com.example 以下的所有 log 都要輸出到 console
  2. com.example.aaa.bbb 的 log,INFO 以上的要輸出到資料庫,同時 com.example.aaa.bbb 所有的 log 都要輸出到 console
  3. 除了 com.example 以外的所有函式庫的 log,只輸出 INFO 以上

首先,我本來嘗試的作法是在 com.example.aaa.bbb 上設定 level = INFO

<logger name="com.example.aaa.bbb" level="INFO" additivity="true">
  <appender-ref ref="MSSQL" />
</logger>

<logger name="com.example" level="ALL" additivity="false">
  <appender-ref ref="STDOUT" />
</logger>

<root level="INFO">
  <appender-ref ref="STDOUT" />
</root>

但結果是 com.example.aaa.bbb 的 DEBUG 和 TRACE 的 log 都沒有印在 console。
實際上這也是正常的,因為 com.example.aaa.bbb 設定為 level = INFO 的話
表示自它以下的 package,DEBUG 和 TRACE 都會被過濾掉。

因為實際上我希望 com.example 的所有 log 都要出現在 console
因此我並不能對 com.example 以下的任何 package 設定 level,而是應該把 level 的篩選設定在 appender 上。
也就是 logger 本身會輸出所有 log 到 appender,但是 appender 負責篩選 level。

最後,設定檔就寫成這樣:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  ......
</appender>

<appender name="MSSQL" class="ch.qos.logback.classic.db.DBAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> ...... </appender> <logger name="com.example.aaa.bbb" level="ALL" additivity="true"> <appender-ref ref="MSSQL" /> </logger> <logger name="com.example" level="ALL" additivity="false"> <appender-ref ref="STDOUT" /> </logger> <root level="INFO"> <appender-ref ref="STDOUT" /> </root>

Logger 的等級關係如下表

Logger nameAssigned LevelEffective Level
rootINFOINFO
com.exampleALLALL
com.example.aaanullALL
com.example.aaa.bbbALLALL


參考資料
  1. Chapter 3: Logback configuration

沒有留言: