Kai Chen
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 六角鼠年鐵人賽 Week 12 - Spring Boot - 一次搞懂 LOG 設定 ==大家好,我是 "為了拿到金角獎盃而努力著" 的文毅青年 - Kai== ## 史詩名句 荷馬 :::info 決定問題,需要智慧,貫徹執行時則需要耐心 ::: ## 主題 今天來跟大家分享處理 LOG 這部分,尤其介紹 SpringBoot 有哪些方式或套件可以使用的~ 在上一篇文章中使用 Lombok 有短暫出現關於 LOG 的處理,但實際上還是有很多眉眉角角要設定,才能幫助各位開發者們在 Log 的處理上更順心~ ## What is Log? Why we need Log? 讓我們先來認識 Log,Log 是一種類似寫日記或寫工作日誌的動作,只是我們把這動作交給了系統本身去執行,讓程式在執行特定功能時,會自動寫下 "預設" 應該留下的訊息,可能是日期、執行過程、錯誤、進度條或是回報等等。 :::info 透過這些訊息,開發者們可以得到下述的這些幫助: 1. 開發時,檢視單元測試狀況 2. 開發後,檢視完整流程狀況 3. 產品上線後,供日後發生的問題作追溯 4. ~~撇清責任~~ 釐清責任 ::: 工程師們請不要鐵齒保證系統沒問題,請相信世界上沒有完美的程式。現在留下的Log,是為了日後的Bug布局 。 :::warning 來看看如果沒有 Log,你可能會遇到什麼狀況? 1. 系統出包,追 Bug 得在 Local 從頭錯一次,假設 IDE 也沒有顯示錯誤,只能憑經驗驗錯 2. 修正 Bug 時間拖長,無法在短時間處理完畢,產品在短時間內流失顧客的風險提高 3. 權責無法釐清,無法及時確定問題是出自於系統 or 網路 or 資料庫 4. 權責無法釐清,產品與顧客之間的角力更容易失去立場 ::: 綜觀上述後會發現到,留下 Log 本身是小事,但後續卻像蝴蝶效應一樣,要馬產生莫大效應;要馬產生莫大風險。 工程師們出外工作也要明哲保身,千萬記得什麼模塊都可以不用加,但是 Log 的部分一定要做好處理。 ## Log Level 在簡單介紹完 Log 後,來介紹紀錄 Log 的時候,一般的分級處理,畢竟 - 有些 Log 是用於測試,不需要跟產品一起上線給客戶看; - 有些地方僅是沒有資料的問題,並非影響系統的大錯; - 有些錯誤可以在紀錄後,繼續維持系統運作,不讓其停止; - 有些錯誤會讓系統運作停止,必須加以防範 有這麼多種不同程度的問題,當然在 Log 的處理上也會有分級的方式去幫助工程師們選定適當的級別進行設定,且不同的分級可以幫助產品在不同階段時,顯示各階段需要印出的 Log 級別,不須再為了測試與上線的不同又從頭把 Log 設定作調整。 此外,不同的 Log 套件又會有不同的分級方式,開發者可以選定自己熟悉的套件,或是 Kai 後續推薦的套件,再對自己的系統進行級別的詳細設置即可。 舉例: java.util.logging 階級: |Log 分級|說明|應用| |---|---|---| |SEVERE|嚴重訊息|設置在可能會導致系統無法運作的系統模組中,不論是**測試時期**還是**LIVE**,都要保留的訊息| |WARNING|警示訊息|設置在雖然有問題,但不影響系統運作的功能模組中,同 SEVERE 在任何時期都建議保留| |INFO|一般訊息|通常用作紀錄執行流程,測試時期一定要寫,確保每個動作都OK,LIVE 是建議保留最低限度的流程訊息即可,避免紀錄文件太快吃滿空間| |CONFIG|設定方面的訊息|通常用於紀錄連網、DB連線,或是註冊功能套件等動作時,建議任何時期都要保留,此類訊息不單給開發師,還可以給 MIS、DBA、Deploy 團隊作參考用| |FINE|會印出包含 FINE 以上級別的 Log|詳細資訊設置| |FINER|次低階級,會印出包含 FINEST 以上級別的 Log|更詳細的資訊設置| |FINEST|最低階級,會印出所有級別的 Log|超級無敵詳細的資訊設置| > 依照設定文件的階級,將會只印出 **包含該級別與以上級別** 的 Log 訊息,級別高到低為由上往下。例如設定了 INFO 等級後,將無法看到 CONFIG、FINE、FINER、FINEST 的訊息 舉例: Log4j 階級: |Log 分級|說明|應用| |---|---|---| |OFF |關閉記錄功能|intLevel = 0,將讓所有 Log 記錄功能關閉| |FATAL |嚴重訊息|intLevel = 100,用於會導致系統停止運作的模組中| |ERROR |錯誤訊息|intLevel = 200,用於雖然會出錯,但不至於影響系統運作的功能模組中| |WARN |警示訊息|intLevel = 300,用於警示訊息,如: 沒有資料、格式異常等| |INFO |一般訊息|intLevel = 400,一般訊息| |DEBUG |除錯訊息|intLevel = 500,除錯用的訊息| |TRACE |追蹤訊息|intLevel = 600,追蹤流程的訊息,建議只用於測試時期| |ALL |紀錄全部等級的訊息|intLevel = Integer.MAX_VALUE,不建議開的階級,容易讓Log文件塞滿一大堆無用的資訊| > - intLevel 是 Log4j 用來處理 Log 分級的參數 > - 在文件中設定的級別,會使系統印出 **包含該級別與以上級別** 的所有訊息,級別是用 intLevel 來計算,值越小的排行越高 > - 因此當設定 INFO 的時候,將會印出 INFO、WARN、ERROR、FATAL 四個級別的 LOG 訊息 > - 當然 Log4j 還可以做到只輸出單獨一種階級或不輸出某種階級的設計,後續會提到 ## Log 套件種類 在這裡簡單的介紹 Spring Boot 可以使用的幾個 Log 套件 ### Log (JUL) 套件包: java.util.logging.Logger 簡單易懂,直呼其名,這是在 Log4j 問世後,Java API 決定自行打造的處理 Log 的套件,但因其階級的分設不同於 Log4j 來的易懂,且僅能輸出於 Console 和 文件,在其他部分的功能並沒有達到 Log4j 的強大,加上 Log4j 已取得市場的信任與穩定使用率,因此並沒有太多的開發者會選擇使用 JUL,若只是開發小功能、求快速結束的專案來說,不失為一個選擇。 (~~然而,套入 Log4j 並不會花太多時間,因此Log的使用率上還是非常非常少~~) ### commonsLog 套件包: org.apache.commons.logging.Log 主要用於處理 JUL 與 Log4j 整合的套件,可以讓開發師同時使用 JUL 和 Log4j 的功能,減少了需要同時配置 JUL 和 Log4j 的設定文檔,然而要注意的是,在 commonsLog 中使用的 function,其底層大多還是會使用 Log4j 的 function。 > - Spring 4.X 的話需要設置套件管理工具進行下載與import,但在 Spring 5.X 版本開始便會直接封裝在 spring-jcl 的套件內,可以直接使用。 > - 使用 SpringBoot 框架的開發師不用擔心需要設置套件管理工具進行處理,因為 SpringBoot 的框架原先就有包含 spring-jcl 的套件。 ### Log4j / Log4j2 套件: - Log4j: org.apache.log4j.Logger - Log4j2: org.apache.logging.log4j.Logger Java 史上第一個功能最多的 Log 套件,建立了 Log Level、Loggers、Appenders 等重要觀念,也影響日後其他套件產出許多類似的設計。 以下是四個 Log4j 改變了 Log 處理方式的創新: 1. 透過 Log Level 進行分級處理 2. 透過 Loggers 建立使用 lib 的函式庫的實體 3. 透過 Appenders 建立每個 Loggers 實體的詳細處理,並不限於輸出 Console 和 文件,可以和其他方式整合處理,例如寄信、連網傳輸等 4. 透過 異步寫入方式,不影響程式本身運作的效能,大大提升了寫入日誌的效率與安全性 在 2014 年,Log4j2 釋出了第一個版本,2 繼承了 1 的所有設計,最大的新功能是使用 Java 8 新增的 Lambda 功能去做到 lazy evaluation。 ### SLF4J 套件: org.slf4j.Logger 與其說 SLF4J 是 Log 套件,倒不如說它是在處理 Log 套件與程式之間解耦合的一個套件,其用來記錄 Log 的實體還是得依靠其他 Log 套件,如: Log4j、JUL、commonsLog 等。 因為在 Log4j 開發完成後,Log4j V2 的構思就是要做到 Log 套件與程式解耦合,而 SLF4J 的出現則解決了這個問題。 SLF4J也是目前大多專案使用的套件。 ### Flogger 套件: com.google.common.flogger.FluentLogger 是 Google 近年為 Java 打造的一款開源日誌框架,號稱提供比 **現有 Java Log API** 更多更完善的功能詳細可參考 [Flogger 官方文件](https://google.github.io/flogger/) 整體而言,Flogger 提供了更強可讀性的結構語句,以及將 Logger 實體與 Level 實體分開處理的方式,減少不必要的 Class 產生。 Flogger 也有增加處理 lazy evaluation 的部分,但 SLF4J 已經搶先設計完成這部分的功能,因此這無法成為讓大家捨棄 SLF4J 去使用 Flogger 的亮點。 ## 整合 Lombok [可參考官方設計文件](https://projectlombok.org/features/log) 類同於 Kai 在 Lombok 一文中提到的方式作即可。 [六角鼠年鐵人賽 Week 11 - Spring Boot - Clean Clear - Lombok](/uWHqezBxQ9CPqr5iUOfNFQ) ## 範例 **build.gradle** ```xml= configurations.all { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging' } dependencies { implementation 'org.springframework.boot:spring-boot-starter-log4j2' } ``` **log4j2.properties** 放置在 resources 資料夾底下 ```xml= appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n rootLogger.level = DEBUG rootLogger.appenderRefs = stdout rootLogger.appenderRef.stdout.ref = STDOUT ``` **test.java** ```java= import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class test { private final static Logger logger = LoggerFactory.getLogger(test.class); } ``` ※ Logger 的寫法強烈建議使用 **private final static** 的方式。 不管該CLASS本身是否有實現 Serilaizable,這樣的寫法比較安全,特別在有使用 CACHE 套件的部分要更加注意。 Kai 經歷的專案曾經有同仁沒有正確將 Logger 物件設置為 static,而被包進了 CACHE 中,每一次動作就包了將近 80MB 的東西,不到一小時,200G的記憶體空間完全吃滿 -- 炸 Server。 一般對於這種情況我們可以透過將包入 CACHE 中的物件序列化,減少占用空間,畢竟有些資料本身就需要被 CACHE,但 Logger 一定要設為 static 才能夠避免被包入,CACHE 在執行的過程中是不會去主動包入 static 的物件,除非強制改動判別方式。 以上這部分就當老人碎念了... ## 結語 :::danger 以上內容差不多介紹完 LOG 的部分,下一篇將繼續介紹 **LogBack**,是一個幫助設定 Log 細節的套件,大大的減低開發者在處理不同 Log 套件整合的難度。 [六角鼠年鐵人賽 Week 13 - Spring Boot - 一次搞懂 LogBack 設定](/uXSkOMESTE6QGvRkqwwAaw) ::: 首頁 [Kai 個人技術 Hackmd](/2G-RoB0QTrKzkftH2uLueA) ###### tags: `Spring Boot`,`w3HexSchool`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully