老闆下了死命令,要把日誌系統切換到Logback

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/AXgNnJe8djD901EmhFkWUg","title":""},"content":[{"type":"text","text":"Log4j"}]},{"type":"text","text":" 介紹過了,"},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/EhKf1rHWL-QII0f6eo0uVA","title":""},"content":[{"type":"text","text":"SLF4J"}]},{"type":"text","text":" 也介紹過了,那接下來,你懂的,"},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/mm0OYM-raVBi2KwK_QK21g","title":""},"content":[{"type":"text","text":"Logback"}]},{"type":"text","text":" 就要隆重地登場了,畢竟它哥仨有一個爹,那就是巨佬 Ceki Gulcu。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"就在昨天,老闆聽我說完 Logback 有多牛逼之後,徹底動心了,對我下了死命令,“這麼好的日誌系統,你還不趕緊點,把它切換到咱的項目當中!”"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們項目之前用的 Log4j,在我看來,已經足夠用了,畢竟是小公司,性能上的要求沒那麼苛刻。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/76/76dacfb2d4b049b0be4cd2a3dfceef32.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"01、Logback 強在哪"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1)非常自然地實現了 SLF4J,不需要像 Log4j 和 JUL 那樣加一個適配層。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b9/b98eee035cb097300368ea5c3f8267fa.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2)Spring Boot 的默認日誌框架使用的是 Logback。一旦某款工具庫成爲了默認選項,那就說明這款工具已經超過了其他競品。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/aa/aaf1ea39effcb810250bb5d7d4ac0fe5.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意看下圖(證據找到了,來自 "},{"type":"link","attrs":{"href":"https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-logging","title":""},"content":[{"type":"text","text":"Spring Boot 官網"}]},{"type":"text","text":"):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0e/0e8fe17c3139d6abab47e5d527d98c96.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也可以通過源碼的形式看得到:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c3/c3d9b033a5cd6d95824748474fdc363f.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3)支持自動重新加載配置文件,不需要另外創建掃描線程來監視。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4)既然是巨佬的新作,那必然在性能上有了很大的提升,不然呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"02、Logback 使用示例"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"第一步"},{"type":"text","text":",在 pom.xml 文件中添加 Logback 的依賴:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"xml"},"content":[{"type":"text","text":"\n ch.qos.logback\n logback-classic\n 1.2.3\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Maven 會自動導入另外兩個依賴:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c3/c3c5f8cd64aafe7cc1d6b7398b461daa.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"logback-core 是 Logback 的核心,logback-classic 是 SLF4J 的實現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"第二步"},{"type":"text","text":",來個最簡單的測試用例:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"import org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author 微信搜「沉默王二」,回覆關鍵字 PDF\n */\npublic class Test {\n static Logger logger = LoggerFactory.getLogger(Test.class);\n public static void main(String[] args) {\n logger.debug(\"logback\");\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Logger 和 LoggerFactory 都來自 SLF4J,所以如果項目是從 Log4j + SLF4J 切換到 Logback 的話,此時的代碼是零改動的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行 Test 類,可以在控制檯看到以下信息:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"12:04:20.149 [main] DEBUG com.itwanger.Test - logback"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在沒有配置文件的情況下,一切都是默認的,Logback 的日誌信息會輸出到控制檯。可以通過 StatusPrinter 來打印 Logback 的內部信息:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();\nStatusPrinter.print(lc);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 main 方法中添加以上代碼後,再次運行 Test 類,可以在控制檯看到以下信息:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"12:59:22.314 [main] DEBUG com.itwanger.Test - logback\n12:59:22,261 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]\n12:59:22,262 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]\n12:59:22,262 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]\n12:59:22,268 |-INFO in ch.qos.logback.classic.BasicConfigurator@5e853265 - Setting up default configuration."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也就是說,Logback 會在 classpath 路徑下先尋找 logback-test.xml 文件,沒有找到的話,尋找 logback.groovy 文件,還沒有的話,尋找 logback.xml 文件,都找不到的話,就輸出到控制檯。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一般來說,我們會在本地環境中配置 logback-test.xml,在生產環境下配置 logback.xml。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"第三步"},{"type":"text","text":",在 resource 目錄下增加 logback-test.xml 文件,內容如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"xml"},"content":[{"type":"text","text":"\n \n \n %d{HH:mm:ss.SSS} %relative [%thread] %-5level %logger{36} - %msg%n\n \n \n\n \n \n \n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Logback 的配置文件非常靈活,最基本的結構爲 "},{"type":"codeinline","content":[{"type":"text","text":""}]},{"type":"text","text":" 元素,包含 0 或多個 "},{"type":"codeinline","content":[{"type":"text","text":""}]},{"type":"text","text":" 元素,其後跟 0 或多個 "},{"type":"codeinline","content":[{"type":"text","text":""}]},{"type":"text","text":" 元素,其後再跟最多隻能存在一個的 "},{"type":"codeinline","content":[{"type":"text","text":""}]},{"type":"text","text":" 元素。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/52/5207ab729603a455e113413df0390652.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"1)配置 appender"},{"type":"text","text":",也就是配置日誌的輸出目的地,通過 name 屬性指定名字,通過 class 屬性指定目的地:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ch.qos.logback.core.ConsoleAppender:輸出到控制檯。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ch.qos.logback.core.FileAppender:輸出到文件。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ch.qos.logback.core.rolling.RollingFileAppender:文件大小超過閾值時產生一個新文件。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了輸出到本地,還可以通過 SocketAppender 和 SSLSocketAppender 輸出到遠程設備,通過 SMTPAppender 輸出到郵件。甚至可以通過 DBAppender 輸出到數據庫中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"encoder 負責把日誌信息轉換成字節數組,並且把字節數組寫到輸出流。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"pattern 用來指定日誌的輸出格式:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"%d"}]},{"type":"text","text":":輸出的時間格式。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"%thread"}]},{"type":"text","text":":日誌的線程名。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"%-5level"}]},{"type":"text","text":":日誌的輸出級別,填充到 5 個字符。比如說 info 只有 4 個字符,就填充一個空格,這樣日誌信息就對齊了。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"反例(沒有指定 -5 的情況):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/11/11bd9a05444be07af75316f357bcf3d5.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"%logger{length}"}]},{"type":"text","text":":logger 的名稱,length 用來縮短名稱。沒有指定表示完整輸出;0 表示只輸出 logger 最右邊點號之後的字符串;其他數字表示輸出小數點最後邊點號之前的字符數量。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"%msg"}]},{"type":"text","text":":日誌的具體信息。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"%n"}]},{"type":"text","text":":換行符。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"%relative"}]},{"type":"text","text":":輸出從程序啓動到創建日誌記錄的時間,單位爲毫秒。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"2)配置 root"},{"type":"text","text":",它只支持一個屬性——level,值可以爲:TRACE、DEBUG、INFO、WARN、ERROR、ALL、OFF。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"appender-ref 用來指定具體的 appender。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"3)查看內部狀態信息"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以在代碼中通過 StatusPrinter 來打印 Logback 內部狀態信息,也可以通過在 configuration 上開啓 debug 來打印內部狀態信息。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"重新運行 Test 類,可以在控制檯看到以下信息:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"13:54:54,718 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml] at [file:/Users/maweiqing/Documents/GitHub/JavaPointNew/codes/logbackDemo/target/classes/logback-test.xml]\n13:54:54,826 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]\n13:54:54,828 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]\n13:54:54,833 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property\n13:54:54,850 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to DEBUG\n13:54:54,850 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]\n13:54:54,850 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.\n13:54:54,851 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@f8c1ddd - Registering current configuration as safe fallback point\n13:54:54.853 [main] DEBUG com.itwanger.Test - logback"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"4)自動重載配置"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之前提到 Logback 很強的一個功能就是支持自動重載配置,那想要啓用這個功能也非常簡單,只需要在 configuration 元素上添加 "},{"type":"codeinline","content":[{"type":"text","text":"scan=true"}]},{"type":"text","text":" 即可。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"\n ...\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"默認情況下,掃描的時間間隔是一分鐘一次。如果想要調整時間間隔,可以通過 scanPeriod 屬性進行調整,單位可以是毫秒(milliseconds)、秒(seconds)、分鐘(minutes)或者小時(hours)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面這個示例指定的時間間隔是 30 秒:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":""}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意:如果指定了時間間隔,沒有指定時間單位,默認的時間單位爲毫秒。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當設置 "},{"type":"codeinline","content":[{"type":"text","text":"scan=true"}]},{"type":"text","text":" 後,Logback 會起一個 ReconfigureOnChangeTask 的任務來監視配置文件的變化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"03、把 log4j.properties 轉成 logback-test.xml"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你的項目以前用的 Log4j,那麼可以通過下面這個網址把 log4j.properties 轉成 logback-test.xml:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":">http://logback.qos.ch/translator/"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"把之前 log4j.properties 的內容拷貝一份:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"### 設置###\nlog4j.rootLogger = debug,stdout,D,E\n\n### 輸出信息到控制檯 ###\nlog4j.appender.stdout = org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target = System.out\nlog4j.appender.stdout.layout = org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n\n\n### 輸出DEBUG 級別以上的日誌到=debug.log ###\nlog4j.appender.D = org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.D.File = debug.log\nlog4j.appender.D.Append = true\nlog4j.appender.D.Threshold = DEBUG \nlog4j.appender.D.layout = org.apache.log4j.PatternLayout\nlog4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n\n\n### 輸出ERROR 級別以上的日誌到=error.log ###\nlog4j.appender.E = org.apache.log4j.DailyRollingFileAppender\nlog4j.appender.E.File =error.log \nlog4j.appender.E.Append = true\nlog4j.appender.E.Threshold = ERROR \nlog4j.appender.E.layout = org.apache.log4j.PatternLayout\nlog4j.appender.E.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"粘貼到該網址的文本域:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b4/b4e852334fa758ed7099bde26cb4a653.png","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"點擊「Translate」,可以得到以下內容:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"\n\n\n\n\n\n\n\n\n\n \n System.out\n \n [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n\n \n \n \n \n \n \n true\n debug.log\n \n %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n\n \n \n DEBUG\n \n \n \n \n \n \n error.log\n true\n \n %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n\n \n \n ERROR\n \n \n \n \n \n \n \n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以確認一下內容,發現三個 appender 都在。 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/53/534096cda10b51c49d9383c890d2ddc0.png","alt":null,"title":"","style":[{"key":"width","value":"25%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是呢,轉換後的文件並不能直接使用,需要稍微做一些調整,因爲:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一,日誌的格式化有細微的不同,Logback 中沒有 "},{"type":"codeinline","content":[{"type":"text","text":"%l"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第二,RollingFileAppender 需要指定 RollingPolicy 和 TriggeringPolicy,前者負責日誌的滾動功能,後者負責日誌滾動的時機。如果 RollingPolicy 也實現了 TriggeringPolicy 接口,那麼只需要設置 RollingPolicy 就好了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TimeBasedRollingPolicy 和 SizeAndTimeBasedRollingPolicy 是兩種最常用的滾動策略。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TimeBasedRollingPolicy 同時實現了 RollingPolicy 與 TriggeringPolicy 接口,因此使用 TimeBasedRollingPolicy 的時候就可以不指定 TriggeringPolicy。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"TimeBasedRollingPolicy 可以指定以下屬性:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"fileNamePattern,用來定義文件的名字(必選項)。它的值應該由文件名加上一個 "},{"type":"codeinline","content":[{"type":"text","text":"%d"}]},{"type":"text","text":" 的佔位符。"},{"type":"codeinline","content":[{"type":"text","text":"%d"}]},{"type":"text","text":" 應該包含 "},{"type":"codeinline","content":[{"type":"text","text":"java.text.SimpleDateFormat"}]},{"type":"text","text":" 中規定的日期格式,缺省是 "},{"type":"codeinline","content":[{"type":"text","text":"yyyy-MM-dd"}]},{"type":"text","text":"。滾動週期是通過 fileNamePattern 推斷出來的。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"maxHistory,最多保留多少數量的日誌文件(可選項),將會通過異步的方式刪除舊的文件。比如,你指定按月滾動,指定 "},{"type":"codeinline","content":[{"type":"text","text":"maxHistory = 6"}]},{"type":"text","text":",那麼 6 個月內的日誌文件將會保留,超過 6 個月的將會被刪除。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"totalSizeCap,所有日誌文件的大小(可選項)。超出這個大小時,舊的日誌文件將會被異步刪除。需要配合 maxHistory 屬性一起使用,並且是第二條件。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"來看下面這個 RollingFileAppender 配置:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"\n debug.log\n \n \n debug.%d{yyyy-MM-dd}.log\n \n 30\n 3GB\n \n \n %relative [%thread] %level %logger{35} - %msg%n\n \n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於按天滾動的文件策略,最多保留 30 天,最大大小爲 30G。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SizeAndTimeBasedRollingPolicy 比 TimeBasedRollingPolicy 多了一個日誌文件大小設定的屬性:maxFileSize,其他完全一樣。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於我們對 RollingPolicy 的瞭解,可以把 logback-test.xml 的內容調整爲以下內容:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"\n \n System.out\n \n %d{HH:mm:ss.SSS} [%thread] %level %logger{36} - %msg%n\n \n \n\n true\n debug.log\n \n \n debug.%d{yyyy-MM-dd}.log\n \n 30\n 3GB\n \n \n %relative [%thread] %-5level %logger{35} - %msg%n\n \n\n \n error.log\n \n \n error.%d{yyyy-MM-dd}.log\n \n 30\n 3GB\n \n \n %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n\n \n \n ERROR\n \n \n \n \n \n \n \n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"修改 Test 類的內容:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class Test {\n static Logger logger = LoggerFactory.getLogger(Test.class);\n public static void main(String[] args) {\n logger.debug(\"logback\");\n logger.error(\"logback\");\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行後,可以在 target 目錄下看到兩個文件:debug.log 和 errror.log。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3d/3d36d3d71a640f634cc3c0d7e5011708.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"到此爲止,項目已經從 Log4j 切換到 Logback 了,過程非常的絲滑順暢,嘿嘿。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"04、Logback 手冊"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Logback 的官網上是有一份手冊的,非常詳細,足足 200 多頁,只不過是英文版的。小夥伴們可以看完我這篇文章入門實操的 Logback 教程後,到下面的地址看官方手冊。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"http://logback.qos.ch/manual/index.html"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果英文閱讀能力有限的話,可以到 GitHub 上查看雷鋒翻譯的中文版:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"https://github.com/itwanger/logback-chinese-manual"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然了,還有一部分小夥伴喜歡看離線版的 PDF,我已經整理好了:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"鏈接:"},{"type":"link","attrs":{"href":"https://pan.baidu.com/s/16FrbwycYUUIfKknlLhRKYA","title":""},"content":[{"type":"text","text":"https://pan.baidu.com/s/16FrbwycYUUIfKknlLhRKYA"}]},{"type":"text","text":" 密碼:bptl"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實話實話吧,"},{"type":"text","marks":[{"type":"strong"}],"text":"白嫖的感覺就是舒服"},{"type":"text","text":",趕緊去下載吧!日常求個三連,謝謝你勤勞的手指,嘿嘿。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章