Java專案的日誌資訊

語言: CN / TW / HK

大家好,我是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)、 LogbackLog4j2

如果你比較細心,你會發現,不同的技術框架所採用的Java日誌實現都很有可能不一樣的。

既然實現不一樣,那對應的API呼叫是不是就不一樣?(畢竟它還不像是JDBC,定義了一套介面規範,各個資料庫廠商去實現JDBC規範,程式設計師面向JDBC介面程式設計就完事了)

那這這這不是亂套呢?想到這裡,血壓就逐漸就上來了?這別慌,上面提到的Java日誌 Slf4j (Simple Logging Facade for Java)乾的就類似JDBC做的事情。

它定義了日誌的介面(門面模式),當專案使用別的日誌框架時,那就適配它!(注意:JDBC是定義介面,資料庫廠商實現。Slf4j也定義了介面,但是它適配其他的Java日誌實現,騷不騷?)

我們看Slf4j官網的一張圖,應該就挺好理解了:

扯了這麼久,我想表達的是:我們在專案中,最好是使用Slf4j提供的API,至於真實的LOG實現,都可以用 Slf4j進行橋接 (這樣一來,或許將來有一天說要從log4j改為logback,那程式程式碼也不用改動)

03、日誌有什麼用?

還沒有過生產環境的開發的同學可能認為記錄日誌就是用來 定位問題 的,其實並不完全是。

日誌一方面我們用它來定位問題,一方面我們 很多的資料也是來源於日誌

不要覺得存在資料庫裡的資料才是重要的,我們 程式執行時記錄下的日誌資料也同樣重要

在大資料領域裡,資料來源有很多:關係型資料庫、爬蟲、日誌等等

舉個例子,我以前的公司就有處理日誌的一套框架:

  1. 我們正常把日誌資訊輸出到檔案下
  2. 框架提供後臺給予我們配置(檔案的路徑以及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="logs"/>


    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化輸出:%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" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在記錄的日誌檔案的路徑及檔名 -->
        <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 class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日誌歸檔路徑以及格式 -->
            <fileNamePattern>${log.path}/logs/austin-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>1000MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日誌檔案保留天數-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日誌檔案只記錄info級別的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 時間滾動輸出 level為 ERROR 日誌 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在記錄的日誌檔案的路徑及檔名 -->
        <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 class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/austin-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>1000MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日誌檔案保留天數-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日誌檔案只記錄ERROR級別的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <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/JC51 S_bI02npm4CE5NEEow

文章大概就是美團大佬們他們用 AOP+動態模板 封裝了一套SDK,進而優雅地記錄操作日誌(說人話就是:大佬不想日誌寫在業務程式碼上,難以管理。將寫日誌這個動作抽象出來,用註解來統一記錄日誌)

文章還是很精彩的,我推薦閱讀一遍。

ZhenDong大佬看完文章後,自己實現了一套,已經差不多快要完成了。順便我跟他討論了下使用場景,感覺我的專案也可以用那一套東西( 有優雅的打日誌方式,誰不愛呢

我已經預定了,到時候他給我發源碼,我就學習下實現思路(後面專案也用他提供的SDK來打日誌,有問題就開噴 [狗頭.jpg])。等他忙完寫好文章,我也轉載下跟大家一起學習下。

像這種輪子或者說是經驗思路,自己學會了以後,就可以在面試的時候吹了。就說自己對專案系統改造了一把,從原來的破鬼樣( 介紹背景) ,變成現在如此優雅(得到的結果),並這個過程中穿插自己的實現思路以及遇到的坑(艱辛的過程),這種亮點哪個面試官又不愛呢

08、總結

日誌在一個專案裡,我認為是在一個比較重要的位置上的。我們的資料和定位問題都離不開日誌,有的專案的日誌相當混亂,那維護起來就特別特別麻煩。

其實我完全可以自己寫個 logback 配置就把這塊給忽略了,但我還是堅持梳理出來,這篇文章按照「專案」的維度從頭梳理了一遍日誌的知識,希望對大家有幫助吧。

專案原始碼 Gitee連結: https://gitee.com/austin

專案原始碼 GitHub連結: https://github.com/austin

austin專案

austin專案夢想是成為 每個Java初學者 能夠寫在簡歷上的專案。

我正在持續更新austin系列文章, 保姆級 講解搭建專案的過程(包括技術選型以及一些業務的探討)以及相關環境的搭建。

專案Gitee連結: gitee/austin

專案GitHub連結: https://github.com/austin

對線面試官

《對線面試官》是我連載了 近一年 一個 講人話 面試系列,我曾經通過這些資料去斬獲了不少的公司的offer,基本涵蓋了Java常問的知識點。

八股文不再是背誦!已有不少的同學 通過對線面試官的分享 得到BATTMD等一線大廠的的offer!

戳Gitee連結:Java3y/athena

我的原創電子書

在自學之路上,我已經把【 基礎重要的知識點 】、【 簡歷模板 】、【 思維導圖 】等等全部整理成電子書,共有 1263 頁!已經有 8756 個初學者都下載了!

我把這些 上傳到網盤 ,你們有需要直接下載就好了。做到這份上了, 不會還想白嫖吧點贊轉發 又不用錢。

連結: pan.baidu.com/s/1pQTuKBYs… 密碼:3wom

不會有人刷到這還想白嫖吧?不會吧?點贊對真的我很重要!要不加個關注?@Java3y