最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java常見日志框架和使用、日志記錄規(guī)范

 更新時(shí)間:2026年05月08日 15:22:06   作者:兩年半的個(gè)人練習(xí)生^_^  
文章主要介紹了Java項(xiàng)目中使用日志的重要性,推薦使用標(biāo)準(zhǔn)的日志框架,文章詳細(xì)解釋了日志門面、實(shí)現(xiàn)和歷史框架的區(qū)別,并提供了日志級(jí)別的定義及使用方法,強(qiáng)調(diào)了記錄日志時(shí)需要注意的事項(xiàng),文章總結(jié)了實(shí)際開發(fā)中常見的誤區(qū),并給出了合理使用日志的建議

日志常用于輸出到控制臺(tái)或指定文件,幫助我們記錄用戶行為以及排查bug

最早接觸的就是System.out.println將內(nèi)容輸出到控制臺(tái),也導(dǎo)致經(jīng)常在后續(xù)開發(fā)中可能順手就寫了sout來記錄。

這種方式雖然簡單,但在真實(shí)項(xiàng)目中遠(yuǎn)遠(yuǎn)不夠。正式開發(fā)里,我們更推薦使用標(biāo)準(zhǔn)的日志框架,比如 SLF4J + Logback 或 SLF4J + Log4j2。

一、為什么不能只用 System.out.println

System.out.println() 的優(yōu)點(diǎn)只有一個(gè):簡單,寫了就能看到輸出。

但它的問題也很明顯:

  • 沒有日志級(jí)別,無法區(qū)分普通信息、警告、錯(cuò)誤
  • 無法統(tǒng)一格式,排查問題時(shí)信息雜亂
  • 不方便輸出到文件、日志平臺(tái)、監(jiān)控系統(tǒng)
  • 不能按環(huán)境靈活控制輸出
  • 高并發(fā)、生產(chǎn)環(huán)境下幾乎不適合作為正式日志手段

例如:

System.out.println("用戶登錄成功:" + userId);

這句代碼只是把一行文字打印到控制臺(tái),既沒有時(shí)間、線程、類名,也無法統(tǒng)一收集。

而日志框架的寫法通常是:

log.info("用戶登錄成功, userId={}", userId);

它的價(jià)值在于:

  • 有明確的日志級(jí)別
  • 支持格式化輸出
  • 能輸出到控制臺(tái)、文件或日志系統(tǒng)
  • 可以按配置決定哪些日志要打印、哪些不打印
  • 更適合線上運(yùn)維和問題排查

所以,sout 更像臨時(shí)調(diào)試工具,log.info() 才是項(xiàng)目開發(fā)中的標(biāo)準(zhǔn)做法。

二、Java 常見日志框架

Java 日志體系里,經(jīng)常會(huì)看到好幾個(gè)名字,初學(xué)者容易混淆??梢园阉鼈兎殖扇悂砜?。

1. 日志門面

日志門面本身不負(fù)責(zé)真正輸出日志,它只負(fù)責(zé)“定義統(tǒng)一接口”,讓業(yè)務(wù)代碼不直接依賴某個(gè)具體實(shí)現(xiàn)。

常見門面:

  • SLF4J
  • JCL(Jakarta Commons Logging,較老)

目前主流項(xiàng)目中最常見的是 SLF4J。

它的好處是:代碼里統(tǒng)一寫 log.info()、log.error(),底層到底用 Logback 還是 Log4j2,可以后續(xù)替換,不影響業(yè)務(wù)代碼。

2. 日志實(shí)現(xiàn)

日志實(shí)現(xiàn)才是真正把日志打印出來、寫到文件里的組件。

常見實(shí)現(xiàn):

  • Logback
  • Log4j2
  • java.util.logging

其中:

  • Logback:Spring Boot 默認(rèn)常用實(shí)現(xiàn),配置方便,生態(tài)成熟
  • Log4j2:性能好、功能強(qiáng),企業(yè)項(xiàng)目也很常見
  • java.util.logging:JDK 自帶,但實(shí)際項(xiàng)目中使用相對(duì)少

3. 歷史框架

  • Log4j 1.x:老版本,現(xiàn)在一般不推薦新項(xiàng)目使用
  • System.out.println():只能算打印,不算真正意義上的日志框架

三、主流推薦方案

在現(xiàn)在的 Java 項(xiàng)目中,推薦組合一般是:

  • SLF4J + Logback
  • SLF4J + Log4j2

如果是 Spring Boot 項(xiàng)目,默認(rèn)通常就是 SLF4J + Logback,上手成本最低,適合大多數(shù)場景。

可以記一個(gè)簡單結(jié)論:

開發(fā)中優(yōu)先面向 SLF4J 編碼,具體實(shí)現(xiàn)選 Logback 或 Log4j2。

四、日志級(jí)別怎么理解

日志框架通常提供多個(gè)級(jí)別,用于表示信息的重要程度。常見級(jí)別從低到高如下:

  • TRACE
  • DEBUG
  • INFO
  • WARN
  • ERROR

下面逐個(gè)理解。

1. TRACE

最細(xì)粒度的跟蹤信息,一般用于非常詳細(xì)的程序執(zhí)行過程。

log.trace("進(jìn)入方法 checkPermission, userId={}", userId);

平時(shí)業(yè)務(wù)開發(fā)中很少開。

2. DEBUG

用于開發(fā)調(diào)試,記錄一些關(guān)鍵變量、執(zhí)行路徑、參數(shù)信息。

log.debug("查詢條件: userId={}, status={}", userId, status);

開發(fā)環(huán)境常用,生產(chǎn)環(huán)境通常關(guān)閉或謹(jǐn)慎開啟。

3. INFO

記錄正常業(yè)務(wù)流程中的關(guān)鍵信息,是項(xiàng)目里最常用的級(jí)別之一。

log.info("訂單創(chuàng)建成功, orderId={}, userId={}", orderId, userId);

比如:

  • 服務(wù)啟動(dòng)成功
  • 用戶登錄成功
  • 訂單創(chuàng)建成功
  • 定時(shí)任務(wù)開始/結(jié)束

4. WARN

表示程序出現(xiàn)異常情況或風(fēng)險(xiǎn),但還沒有導(dǎo)致功能徹底失敗。

log.warn("庫存不足, skuId={}, remain={}", skuId, remain);

比如:

  • 參數(shù)不規(guī)范但系統(tǒng)做了兼容
  • 某個(gè)遠(yuǎn)程調(diào)用超時(shí)后觸發(fā)重試
  • 檢測到配置缺失但系統(tǒng)使用默認(rèn)值繼續(xù)運(yùn)行

5. ERROR

表示發(fā)生了明確錯(cuò)誤,通常需要重點(diǎn)關(guān)注。

log.error("支付失敗, orderId={}", orderId, e);

比如:

  • 數(shù)據(jù)庫操作失敗
  • 接口調(diào)用異常
  • 程序捕獲到未預(yù)期異常

五、日志的基本使用方式

下面用常見的 SLF4J 風(fēng)格說明日志怎么寫。

1. 定義日志對(duì)象

傳統(tǒng)寫法:

public class UserService {
    private static final Logger log = 
            LoggerFactory.getLogger(UserService.class);
}

如果項(xiàng)目使用 Lombok,也可以簡化為:

@Slf4j
public class UserService {
}

然后直接使用:

log.info("日志打印");

2. 參數(shù)化輸出,不要字符串拼接

推薦寫法:

log.info("用戶登錄成功, userId={}", userId);

不推薦:

log.info("用戶登錄成功, userId=" + userId);

原因:

  • 代碼更整潔
  • 日志框架會(huì)更高效地處理參數(shù)
  • 可讀性更好

多個(gè)參數(shù)時(shí):

log.info("訂單創(chuàng)建成功, orderId={}, userId={}, amount={}", orderId, userId, amount);

3. 異常日志要帶堆棧

正確寫法:

@Slf4j
public class test {
    public static void main(String[] args) {
        log.info("日志打印");
        try {
            int x = 1 / 0;
        } catch (Exception e) {
            log.error("系統(tǒng)計(jì)算異常", e);
        }
    }
}

或者帶業(yè)務(wù)上下文:

 log.error("訂單支付異常, orderId={}, userId={}", orderId, userId, e);

不推薦只打印異常信息:

log.error("訂單支付異常, orderId={}, userId={}", orderId, userId);

因?yàn)檫@樣會(huì)丟失完整堆棧,不利于定位問題。

六、Spring Boot 中的日志使用

Spring Boot 默認(rèn)對(duì)日志支持比較友好,一般引入 Web 依賴后就已經(jīng)帶了日志能力。

業(yè)務(wù)代碼里通常直接這樣寫:

@Slf4j
@Service
public class OrderService {
    public void createOrder(Long userId) {
        log.info("開始創(chuàng)建訂單, userId={}", userId);
        log.info("訂單創(chuàng)建成功, userId={}", userId);
    }
}

配置日志級(jí)別也比較方便,例如在 application.yml 中:

logging:
  level:
    root: info        # 全局默認(rèn)日志級(jí)別
    com.example.demo: debug  # 你項(xiàng)目包的日志級(jí)別

表示:

  • 全局日志級(jí)別是 info
  • com.example.demo 包下允許輸出 debug 級(jí)別日志

七、日志記錄規(guī)范

下面是比較實(shí)用的一套日志規(guī)范。

1. 日志要有價(jià)值,避免“流水賬”

不要什么都記,也不要一句話完全沒有信息量。

不推薦:

log.info("進(jìn)入方法");
log.info("執(zhí)行結(jié)束");

這種日志看起來很多,但對(duì)排查問題幫助有限。

推薦:

log.info("開始處理退款申請(qǐng), refundId={}, orderId={}", refundId, orderId);
log.info("退款處理完成, refundId={}, status={}", refundId, status);

要盡量帶上業(yè)務(wù)上下文,讓日志能回答:

  • 是誰觸發(fā)的
  • 處理了什么對(duì)象
  • 結(jié)果是什么
  • 出錯(cuò)時(shí)影響了哪個(gè)業(yè)務(wù)數(shù)據(jù)

2. 關(guān)鍵業(yè)務(wù)日志必須帶唯一標(biāo)識(shí)

例如:

  • userId
  • orderId
  • requestId
  • traceId
  • taskId

示例:

log.info("訂單支付成功, orderId={}, userId={}", orderId, userId);

這樣才能通過一個(gè) ID 把整條調(diào)用鏈串起來。

3. 不要打印敏感信息

日志中嚴(yán)禁直接記錄:

  • 密碼
  • 身份證號(hào)完整信息
  • 銀行卡完整號(hào)碼
  • 手機(jī)號(hào)完整號(hào)碼
  • token、密鑰、驗(yàn)證碼
  • 用戶隱私數(shù)據(jù)

例如下面這種就不合適:

log.info("用戶登錄, username={}, password={}", username, password);

正確做法是脫敏或不打?。?/p>

log.info("用戶登錄, username={}", username);

如果必須記錄手機(jī)號(hào),也要脫敏處理。

4. INFO 記錄業(yè)務(wù)節(jié)點(diǎn),DEBUG 記錄調(diào)試細(xì)節(jié)

很多項(xiàng)目的日志問題不是“太少”,而是“太亂”。最常見錯(cuò)誤是把大量細(xì)節(jié)都打成 info,導(dǎo)致生產(chǎn)日志噪聲很大。

可以這樣理解:

  • INFO:記錄關(guān)鍵業(yè)務(wù)事件
  • DEBUG:記錄開發(fā)調(diào)試信息
  • ERROR:記錄失敗和異常

例如:

log.info("開始支付流程, orderId={}", orderId);
log.debug("支付請(qǐng)求參數(shù): {}", request);
log.info("支付完成, orderId={}, response={}, userId={}, orderId, response, userId);

5. 不要重復(fù)記錄同一個(gè)異常

一個(gè)異常如果層層捕獲、層層 log.error(),最后日志里就會(huì)出現(xiàn)多份重復(fù)堆棧,反而干擾排查。

常見原則:

  • 能處理就處理,不一定要打 error
  • 不能處理再往上拋
  • 最終由邊界層統(tǒng)一記錄一次完整異常

例如在 service 里:

catch (Exception e) { 
    throw new BusinessException("支付失敗", e); 
}

在 controller 或全局異常處理中統(tǒng)一打?。?/p>

log.error("請(qǐng)求處理失敗, requestId={}", requestId, e);

這樣更清晰。

6. 日志內(nèi)容要統(tǒng)一、可檢索

建議統(tǒng)一格式,避免同一種業(yè)務(wù)場景每個(gè)人寫法都不一樣。

例如統(tǒng)一風(fēng)格:

log.info("訂單創(chuàng)建成功, orderId={}, userId={}, amount={}", orderId, userId, amount);

統(tǒng)一風(fēng)格的好處是:

  • 搜索方便
  • 排查高效
  • 團(tuán)隊(duì)協(xié)作成本低

7. 重要操作必須記日志

下面這些場景通常建議記錄日志:

  • 用戶登錄、登出
  • 創(chuàng)建訂單、支付、退款
  • 定時(shí)任務(wù)執(zhí)行
  • 第三方接口調(diào)用結(jié)果
  • 權(quán)限校驗(yàn)失敗
  • 數(shù)據(jù)導(dǎo)入導(dǎo)出
  • 配置加載、服務(wù)啟動(dòng)與停止
  • 關(guān)鍵異常和兜底邏輯

8. 高頻循環(huán)里謹(jǐn)慎打日志

如果在循環(huán)中大量打印日志,可能導(dǎo)致:

  • 日志量暴增
  • 磁盤占用過快
  • IO 壓力變大
  • 排查時(shí)淹沒關(guān)鍵信息

例如:

for (User user : userList) {
   log.info("處理用戶: {}", user.getId());
}

如果數(shù)據(jù)量很大,這種寫法就要非常謹(jǐn)慎。

更好的方式可能是匯總記錄:

log.info("開始批量處理用戶, size={}", userList.size());

處理結(jié)束后再輸出結(jié)果摘要。

八、一個(gè)簡單的日志示例

下面給一個(gè)比較符合規(guī)范的 service 示例:

@Slf4j
@Service
public class OrderService {
    public void pay(Long orderId, Long userId) {
        log.info("開始支付訂單, orderId={}, userId={}", orderId, userId);
        try {
            // 1. 參數(shù)校驗(yàn) 
            log.debug("校驗(yàn)訂單狀態(tài), orderId={}", orderId);
            // 2. 執(zhí)行支付邏輯 
            log.debug("調(diào)用支付網(wǎng)關(guān), orderId={}", orderId);
            // 3. 支付成功 
            log.info("訂單支付成功, orderId={}, userId={}", orderId, userId);
        } catch (Exception e) {
            log.error("訂單支付失敗, orderId={}, userId={}", orderId, userId, e);
            throw e;
        }
    }
}

這個(gè)例子體現(xiàn)了幾個(gè)點(diǎn):

  • info 記錄關(guān)鍵業(yè)務(wù)節(jié)點(diǎn)
  • debug 記錄內(nèi)部處理細(xì)節(jié)
  • error 記錄失敗并保留異常堆棧
  • 日志中帶了 orderId 和 userId 這樣的關(guān)鍵上下文

九、實(shí)際開發(fā)中的常見誤區(qū)

1. 把 System.out.println() 當(dāng)正式日志用

這是最常見的初級(jí)問題。臨時(shí)調(diào)試可以,但不能作為項(xiàng)目正式方案。

2. 所有日志都打 info

這會(huì)讓生產(chǎn)日志變得非常吵,真正重要的信息反而不明顯。

3. 只打印“異常了”,不打印上下文

例如:

log.error("支付失敗");

這太模糊了。至少要帶上訂單號(hào)、用戶 ID 等關(guān)鍵信息。

4. 只打印 e.getMessage(),不打印堆棧

這樣往往無法定位代碼具體在哪一行出錯(cuò)。

5. 打印敏感數(shù)據(jù)

這是日志安全的大忌。

6. 每層都打印同一個(gè)異常

會(huì)導(dǎo)致重復(fù)日志,影響排查效率。

十、總結(jié)

Java 日志框架的核心價(jià)值,不只是“輸出內(nèi)容”,而是幫助我們?cè)陂_發(fā)、測試、上線、運(yùn)維整個(gè)生命周期里快速理解系統(tǒng)發(fā)生了什么。

從實(shí)踐角度來說,可以記住這幾個(gè)結(jié)論:

  1. 正式項(xiàng)目不要依賴 System.out.println(),而要使用日志框架。
  2. 推薦面向 SLF4J 編碼,底層常用 Logback 或 Log4j2。
  3. 合理區(qū)分 debug、info、warn、error。
  4. 日志要帶關(guān)鍵業(yè)務(wù)上下文,比如 userId、orderId、traceId。
  5. 異常日志要保留完整堆棧,不要只打印一句錯(cuò)誤信息。
  6. 嚴(yán)禁記錄密碼、密鑰、身份證號(hào)等敏感數(shù)據(jù)。
  7. 日志要服務(wù)于排查問題,而不是機(jī)械地“打印幾行字”。

到此這篇關(guān)于Java日志框架和使用、日志記錄規(guī)范的文章就介紹到這了,更多相關(guān)java日志框架使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring boot 項(xiàng)目中使用thymeleaf模板的案例分析

    spring boot 項(xiàng)目中使用thymeleaf模板的案例分析

    這篇文章主要介紹了spring boot 項(xiàng)目中使用thymeleaf模板的案例分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java實(shí)現(xiàn)導(dǎo)出ZIP壓縮包的方法

    Java實(shí)現(xiàn)導(dǎo)出ZIP壓縮包的方法

    這篇文章主要介紹了Java實(shí)現(xiàn)導(dǎo)出ZIP壓縮包的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Springboot使用Junit測試沒有插入數(shù)據(jù)的原因

    Springboot使用Junit測試沒有插入數(shù)據(jù)的原因

    這篇文章主要介紹了Springboot使用Junit測試沒有插入數(shù)據(jù)的原因,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • SpringBoot實(shí)現(xiàn)Logback輸出日志到Kafka方式

    SpringBoot實(shí)現(xiàn)Logback輸出日志到Kafka方式

    本文介紹了如何在SpringBoot應(yīng)用中通過自定義Appender實(shí)現(xiàn)Logback輸出日志到Kafka,包括配置maven依賴、Kafka工具類和logback.xml配置
    2025-02-02
  • 使用java對(duì)一副撲克牌建模

    使用java對(duì)一副撲克牌建模

    這篇文章主要為大家詳細(xì)介紹了如何使用java對(duì)一副撲克牌建模,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • java編程中字節(jié)流轉(zhuǎn)換成字符流的實(shí)現(xiàn)方法

    java編程中字節(jié)流轉(zhuǎn)換成字符流的實(shí)現(xiàn)方法

    下面小編就為大家?guī)硪黄猨ava編程中字節(jié)流轉(zhuǎn)換成字符流的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • Maven多模塊之父子關(guān)系的創(chuàng)建

    Maven多模塊之父子關(guān)系的創(chuàng)建

    這篇文章主要介紹了Maven多模塊之父子關(guān)系的創(chuàng)建,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 詳解Java修飾符

    詳解Java修飾符

    Java語言提供了很多修飾符,主要分為以下兩類:訪問修飾符;非訪問修飾符。修飾符用來定義類、方法或者變量,通常放在語句的最前端。我們通過下面的例子來說明,下面就跟小編一起來看下吧
    2016-12-12
  • RabbitMQ?Stream插件使用案例代碼

    RabbitMQ?Stream插件使用案例代碼

    這篇文章主要介紹了RabbitMQ?Stream插件使用案例代碼,2.4版為RabbitMQ流插件引入了對(duì)RabbitMQStream插件Java客戶端的初始支持,需要的朋友可以參考下
    2024-04-04
  • Java?file類中renameTo方法操作實(shí)例

    Java?file類中renameTo方法操作實(shí)例

    renameTo()方法是File類的一部分,renameTo()函數(shù)用于將文件的抽象路徑名重命名為給定的路徑名??,下面這篇文章主要給大家介紹了關(guān)于Java?file類中renameTo方法操作的相關(guān)資料,需要的朋友可以參考下
    2022-11-11

最新評(píng)論

高阳县| 蓬安县| 锡林郭勒盟| 汶上县| 深州市| 山阳县| 镇宁| 锦屏县| 汤原县| 延长县| 秦皇岛市| 广东省| 内江市| 礼泉县| 佛坪县| 蒙自县| 炉霍县| 永顺县| 安陆市| 青州市| 辽阳县| 航空| 舟曲县| 甘孜县| 宁蒗| 启东市| 黄骅市| 淳化县| 游戏| 揭阳市| 高淳县| 谢通门县| 都匀市| 雅安市| 兴和县| 新蔡县| 漾濞| 阜康市| 洪泽县| 岳西县| 宁远县|