大家好,我是3y,在正文之前,先給各位股東匯報下austin專案進度:
總的來說,我感覺這次的反響是不錯的,雖然閱讀量不高,但留言的人多了很多,也有很多人都擔心我會不會鴿掉(更新一半中途就斷了)
我只能說:別慌,絕對不鴿,你只管追更就好,
我已經決定每個周末都扛著電腦回家,有空就往附近的圖書館里跑(圖書館是學習的YYDS,在家的效率就是要比圖書館要低不少)
不多BB了,今天繼續聊個話題:日志
01、什么是日志
所謂日志,在我理解下就是:記錄程式運行時的資訊
在Java最初期又或是我們初學階段,列印日志全憑System.out.println();
這好用嗎?有待商榷,
對于大部分初學者來說,好用!我想看的資訊,直接在console就能看到了,這是多么地方便阿,學習Java的第一個運行結果都是由System.out.println();出來的,不需要有任何的學習成本,
對于大部分作業者來說,本地除錯可以,但如果程式部署到服務器以后,那就算了,
生產環境跟本地環境是有區別的:
- 生產環境需要記錄的日志會更多(畢竟是作為一個系統/專案在線上運行,不可能只列印一點點內容)
- 生產環境的日志內容需要保留至檔案(作為留存,線上不會說第一時間發現問題,很多需要查找歷史日志資料)
- 生產環境的日志內容需要有一定的規范格式(至少日志記錄的時間需要有吧)
- …
上面這些要求,System.out.println();都是不具備的,
所以,我們可以看到在公司里寫的專案,是沒有用System.out.println();記錄日志的
02、Java日志體系
作業了以后,你會發現每次引入一個框架,這個框架下幾乎都有對應的日志包,
我之前在公司里曾經整合過幾個專案(將原有的幾個工程合并到一個專案內),
系統分久必合合久必分,當時是認為以前的同事把專案拆得過于細,造成一定的資源浪費(畢竟每個工程跑在線上至少都會部署兩臺線上機器),所以有段時間公司就希望我們把一些細小的專案進行合并,
至于這做得對與錯,這塊我就不談了,
在合并的程序中,最最最麻煩的就是解決依賴沖突的問題(都是Maven專案,會有Maven仲裁的問題),而這里邊,最明顯的就是Java日志包的問題,
如果你有那么一丟丟了解Java日志,你就應該多多少少聽說過以下的名字:Log4j(log for java)、JUL(Java Util Logging)、JCL(Jakarta Commons Logging)、Slf4j(Simple Logging Facade for Java)、Logback、Log4j2
如果你比較細心,你會發現,不同的技術框架所采用的Java日志實作都很有可能不一樣的,
既然實作不一樣,那對應的API呼叫是不是就不一樣?(畢竟它還不像是JDBC,定義了一套介面規范,各個資料庫廠商去實作JDBC規范,程式員面向JDBC介面編程就完事了)
那這這這不是亂套呢?想到這里,血壓就逐漸就上來了?這別慌,上面提到的Java日志Slf4j(Simple Logging Facade for Java)干的就類似JDBC做的事情,
它定義了日志的介面(門面模式),當專案使用別的日志框架時,那就適配它!(注意:JDBC是定義介面,資料庫廠商實作,Slf4j也定義了介面,但是它適配其他的Java日志實作,騷不騷?)
我們看Slf4j官網的一張圖,應該就挺好理解了:
扯了這么久,我想表達的是:我們在專案中,最好是使用Slf4j提供的API,至于真實的LOG實作,都可以用Slf4j進行橋接(這樣一來,或許將來有一天說要從log4j改為logback,那程式代碼也不用改動)
03、日志有什么用?
還沒有過生產環境的開發的同學可能認為記錄日志就是用來定位問題的,其實并不完全是,
日志一方面我們用它來定位問題,一方面我們很多的資料也是來源于日志
不要覺得存在資料庫里的資料才是重要的,我們程式運行時記錄下的日志資料也同樣重要,
在大資料領域里,資料來源有很多:關系型資料庫、爬蟲、日志等等
舉個例子,我以前的公司就有處理日志的一套框架:
- 我們正常把日志資訊輸出到檔案下
- 框架提供后臺給予我們配置(檔案的路徑以及Kafka Topic Name)
該框架做的事情說白了就是:把我們的日志檔案內容轉成Kafka訊息(如果使用方需要將哪個日志檔案的內容轉為MQ訊息,那在平臺上配置下就完事了)
有了Kafka訊息,那配合流式處理平臺(Storm/Spark/Flink)再對日志進行清洗,是不是就能產生有價值的資料
04、Austin 日志
扯了這么久的日志基礎,只是想讓還不了解日志的同學有個認知,
不扯別的了,還是回到我們還在「新建檔案夾」階段的austin專案吧,
austin專案的搭建技術框架使用的是SpringBoot,SpringBoot默認的日志組合是:Slf4j + logback
我在公司接觸到的專案幾乎都是這個組合,所以我就不打算動了,就直接用logback作為austin的日志實作框架了(要是真有那么一天要改成別的日志實作,理論上只要引入對應的橋接包就完事了),
05、logback日志初體驗
在無任何配置的前提下,只要我們引入了SpringBoot的包,就能直接使用日志的功能了,具體效果入下圖
SpringBoot是約定大于配置的一個框架
SpringBoot會默認去加載resources下名為**logback.xml **或者 logback-spring.xml的組態檔( xml 格式也可以改為 groovy 格式)
如果都不存在,那么 logback 默認地會呼叫BasicConfigurator ,創建一個最小化配置,
最小化配置由一個關聯到根 logger 的ConsoleAppender 組成,輸出用模式為%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 的 PatternLayoutEncoder 進行格式化
06、logback配置
從上面可以發現的是,默認的logback配置是不符合我們的要求的(它是列印在console的),我們是希望把日志記錄在檔案下的,
所以,我們會在resources下新建一個logback配置,常見的配置內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<contextName>austin</contextName>
<!-- 設定日志輸出路徑 可以使“${}”來使用變數,TODO 這里后面是需要讀配置的 -->
<property name="log.path" value="https://www.cnblogs.com/Java3y/p/logs"/>
<appender name="CONSOLE" >
<encoder >
<!--格式化輸出:%d表示日期,%thread表示執行緒名,%-5level:級別從左顯示5個字符寬度%msg:日志訊息,%n是換行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<!-- 設定字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 時間滾動輸出 level為 INFO 日志 -->
<appender name="INFO_FILE" >
<!-- 正在記錄的日志檔案的路徑及檔案名 -->
<file>${log.path}/austin-info.log</file>
<!--日志檔案輸出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<!-- 日志記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy >
<!-- 每天日志歸檔路徑以及格式 -->
<fileNamePattern>${log.path}/logs/austin-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy >
<maxFileSize>1000MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志檔案只記錄info級別的 -->
<filter >
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 時間滾動輸出 level為 ERROR 日志 -->
<appender name="ERROR_FILE" >
<!-- 正在記錄的日志檔案的路徑及檔案名 -->
<file>${log.path}/austin-error.log</file>
<!--日志檔案輸出格式-->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此處設定字符集 -->
</encoder>
<!-- 日志記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy >
<fileNamePattern>${log.path}/austin-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy >
<maxFileSize>1000MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志檔案保留天數-->
<maxHistory>15</maxHistory>
</rollingPolicy>
<!-- 此日志檔案只記錄ERROR級別的 -->
<filter >
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<root level="info">
<!-- TODO console列印后面可以只針對dev環境的 -->
<appender-ref ref="CONSOLE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</configuration>
日志的配置不會是一成不變的,現在專案剛搭建出來,就怎么簡單怎么來,
07、彩蛋
這篇文章發布的前一個晚上,ZhenDong突然問我現在用的什么MQ比較多,我隨口一答:Kafka吧,我接觸MQ基本都是Kafka
他說在寫一個好東西,到時候發出來,我這一聽,就肯定感興趣了啊,
ZhenDong發的文章鏈接:https://mp.weixin.qq.com/s/JC51S_bI02npm4CE5NEEow
文章大概就是美團大佬們他們用AOP+動態模板封裝了一套SDK,進而優雅地記錄操作日志(說人話就是:大佬不想日志寫在業務代碼上,難以管理,將寫日志這個動作抽象出來,用注解來統一記錄日志)
文章還是很精彩的,我推薦閱讀一遍,
ZhenDong大佬看完文章后,自己實作了一套,已經差不多快要完成了,順便我跟他討論了下使用場景,感覺我的專案也可以用那一套東西(有優雅的打日志方式,誰不愛呢)
我已經預定了,到時候他給我發原始碼,我就學習下實作思路(后面專案也用他提供的SDK來打日志,有問題就開噴??[狗頭.jpg]),等他忙完寫好文章,我也轉載下跟大家一起學習下,
像這種輪子或者說是經驗思路,自己學會了以后,就可以在面試的時候吹了,就說自己對專案系統改造了一把,從原來的破鬼樣(介紹背景) *,變成現在如此優雅(**得到的結果**),并這個程序中穿插自己的實作思路以及遇到的坑(**艱辛的程序**),這種亮點*哪個面試官又不愛呢?
08、總結
日志在一個專案里,我認為是在一個比較重要的位置上的,我們的資料和定位問題都離不開日志,有的專案的日志相當混亂,那維護起來就特別特別麻煩,
其實我完全可以自己寫個logback配置就把這塊給忽略了,但我還是堅持梳理出來,這篇文章按照「專案」的維度從頭梳理了一遍日志的知識,希望對大家有幫助吧,
專案原始碼Gitee鏈接:https://gitee.com/austin
專案原始碼GitHub鏈接:https://github.com/austin

關注我的微信公眾號【Java3y】來聊點不一樣的!

【對線面試官+從零撰寫Java專案】 持續高強度更新中!求star
原創不易!!求三連!!
更多的文章可往:文章的目錄導航轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/378088.html
標籤:Java
上一篇:【計題01組001號】LeetCode刷題筆記001
下一篇:flowable 啟動流程
