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

Java打印高質(zhì)量日志的10條方法詳解

 更新時間:2025年06月09日 09:34:02   作者:Java技術(shù)小館  
你以為打日志是小事,也許正是這種輕視,讓你在凌晨三點被生產(chǎn)事故電話吵醒,一個優(yōu)秀的工程師和普通碼農(nóng)的區(qū)別,往往體現(xiàn)在那些看似微不足道的細節(jié)上,下面我們就來看看如何打印高質(zhì)量日志吧

一、日志的根本目的與常見誤區(qū)

1. 日志是為了"讀"

很多開發(fā)者的第一反應(yīng)就是"日志當然是為了排查問題",但問題是:誰來讀這些日志?

大多數(shù)日志的命運是:要么無人問津,要么在深夜被迫閱讀。在你敲下每一行日志代碼時,請想象凌晨三點被吵醒的自己(或者可憐的值班同事)需要從海量日志中找出線索。

// 糟糕的日志示例
log.info("處理開始");
// 大量業(yè)務(wù)邏輯...
log.info("處理結(jié)束");

// 改進后的日志
log.info("開始處理用戶支付請求 userId={}, orderId={}, amount={}", userId, orderId, amount);
// 業(yè)務(wù)邏輯...
log.info("用戶支付請求處理完成 userId={}, orderId={}, result={}", userId, orderId, result);

2. 多打日志是一個危險的建議

"多打點日志吧"是技術(shù)leader最常給的建議之一。但這句話就像"多喝點水"一樣空泛。沒有目的的狂打日志,只會讓真正有價值的信息淹沒在日志的海洋中。

我見過一個Java項目,5分鐘產(chǎn)生了50MB的日志文件,打開一看,全是:

log.debug("進入方法A");
log.debug("退出方法A");
log.debug("進入方法B");
log.debug("退出方法B");
// ...無窮無盡...

這不是日志,這是垃圾。記住,每一行日志都有成本:存儲成本、I/O成本、閱讀成本。

3. 用戶視角 vs 開發(fā)視角

日志應(yīng)該從誰的視角出發(fā)?大多數(shù)日志都是從開發(fā)者視角編寫的:

log.info("用戶數(shù)據(jù)解析完畢,開始更新緩存");

但真正有價值的日志應(yīng)該結(jié)合業(yè)務(wù)視角:

log.info("用戶{}的訂單{}狀態(tài)從{}變更為{}", userId, orderId, oldStatus, newStatus);

這樣的日志不僅技術(shù)人員看得懂,產(chǎn)品和運營同事也能大致理解,這在跨團隊溝通時非常關(guān)鍵。

二、日志的等級藝術(shù)

1. 何時使用哪種級別

  • ERROR:系統(tǒng)無法正常運行,需要立即關(guān)注
  • WARN:潛在的問題,但不影響當前功能
  • INFO:重要的業(yè)務(wù)事件,用于追蹤系統(tǒng)的工作流程
  • DEBUG:用于開發(fā)調(diào)試的詳細信息
  • TRACE:最詳盡的信息,通常只在跟蹤代碼執(zhí)行路徑時使用

2. 為什么90%的ERROR級別日志都用錯了

大多數(shù)開發(fā)者會在catch塊里機械地寫:

try {
    // 業(yè)務(wù)邏輯
} catch (Exception e) {
    log.error("處理失敗", e);
}

但這是錯的!很多異常是預(yù)期內(nèi)的業(yè)務(wù)異常,不是系統(tǒng)錯誤。例如用戶輸入了錯誤的密碼,這是業(yè)務(wù)邏輯,不是ERROR級別的系統(tǒng)故障。

try {
    authService.login(username, password);
} catch (InvalidCredentialsException e) {
    // 這是預(yù)期內(nèi)的業(yè)務(wù)場景,用INFO記錄
    log.info("用戶{}登錄失敗:密碼錯誤", username);
    return "密碼錯誤";
} catch (Exception e) {
    // 這是意外異常,用ERROR記錄
    log.error("用戶{}登錄過程發(fā)生系統(tǒng)異常", username, e);
    return "系統(tǒng)異常";
}

3. 如何正確劃分日志級別的邊界

簡單的判斷標準:

  • ERROR:需要人工介入處理的問題
  • WARN:今天不處理,明天可能變成ERROR的問題
  • INFO:標記重要業(yè)務(wù)節(jié)點,幫助理解系統(tǒng)運行狀態(tài)
  • DEBUG/TRACE:臨時排查問題用,生產(chǎn)環(huán)境通常關(guān)閉

4. 不同環(huán)境的日志級別策略

  • 開發(fā)環(huán)境:DEBUG或更詳細,幫助開發(fā)者調(diào)試
  • 測試環(huán)境:INFO,關(guān)注業(yè)務(wù)流程是否正確
  • 生產(chǎn)環(huán)境:WARN或INFO,取決于系統(tǒng)規(guī)模和性能要求

大型系統(tǒng)建議:

# 生產(chǎn)環(huán)境配置示例
logging.level.root=WARN
logging.level.com.yourcompany.core=INFO
logging.level.com.yourcompany.thirdparty=ERROR

三、日志內(nèi)容的軍規(guī)

1. 一條好日志的必備要素

一條完美的日志應(yīng)包含:

  • 時間(日志框架通常自動提供)
  • 環(huán)境/實例標識(在分布式系統(tǒng)中尤其重要)
  • 請求標識(如TraceId)
  • 操作主體(誰做了什么)
  • 關(guān)鍵業(yè)務(wù)參數(shù)
  • 操作結(jié)果
// 差的日志
log.info("支付成功");

// 好的日志
log.info("[訂單中心] 用戶{}完成訂單{}支付 金額={} 渠道={} 耗時={}ms", 
    userId, orderId, amount, channel, costTime);

2. 避免日志污染的7個實用技巧

1.避免在循環(huán)中打印日志

// 差的日志
log.info("支付成功");

// 好的日志
log.info("[訂單中心] 用戶{}完成訂單{}支付 金額={} 渠道={} 耗時={}ms", 
    userId, orderId, amount, channel, costTime);

2.使用占位符,而不是字符串拼接

// 糟糕的實踐
for (Item item : items) {
    log.info("處理商品: {}", item);  // 可能輸出成千上萬條
}

// 改進
log.info("開始處理{}個商品", items.size());
// 處理邏輯
log.info("完成處理{}個商品, 成功={}, 失敗={}", items.size(), successCount, failCount);

3.警惕大對象輸出

// 危險操作
log.debug("用戶數(shù)據(jù): {}", user);  // 可能輸出大量無用信息

// 更好的做法
log.debug("用戶基本信息: id={}, name={}, type={}", user.getId(), user.getName(), user.getType());

4.使用日志脫敏工具

5.引入SLF4J MDC機制關(guān)聯(lián)同一請求的日志

6.定期清理不再使用的日志

7.使用斷言判斷是否需要打印復(fù)雜日志

if (log.isDebugEnabled()) {
    log.debug("復(fù)雜對象詳情: {}", generateExpensiveDebugInfo(obj));
}

3. 敏感信息處理

這是最容易被忽視的問題,卻可能導(dǎo)致最嚴重的后果。請務(wù)必從日志中去除:

  • 密碼、密鑰、令牌
  • 身份證、手機號、銀行卡
  • 用戶地址等個人信息
// 危險的日志
log.info("用戶登錄: username={}, password={}", username, password);

// 安全的日志
log.info("用戶登錄: username={}, password=****", username);

// 更好的做法:使用專業(yè)的日志脫敏工具
log.info("用戶信息: {}", LogSensitiveUtils.mask(userInfo));

四、結(jié)構(gòu)化日志的威力

1. 為什么說非結(jié)構(gòu)化日志正在被淘汰

傳統(tǒng)日志是為人類閱讀設(shè)計的,但現(xiàn)代系統(tǒng)規(guī)模已經(jīng)超出人類直接閱讀的能力范圍。結(jié)構(gòu)化日志(如JSON格式)具有以下優(yōu)勢:

  • 機器可讀,便于自動化分析
  • 字段明確,不會混淆
  • 易于索引和搜索
  • 支持復(fù)雜數(shù)據(jù)結(jié)構(gòu)

2. JSON日志格式的實現(xiàn)方法

在Spring Boot項目中配置JSON日志:

# application.properties
logging.pattern.console=
logging.config=classpath:logback-spring.xml
<!-- logback-spring.xml -->
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

輸出示例:

{
  "timestamp": "2023-01-01T12:00:00.000Z",
  "level": "INFO",
  "thread": "http-nio-8080-exec-1",
  "logger": "com.example.OrderService",
  "message": "用戶支付成功",
  "userId": "12345",
  "orderId": "ORD9876",
  "amount": 99.99,
  "channel": "wechat"
}

五、日志與性能的選擇

1. 日志為何會影響性能

日志操作是典型的I/O密集型操作,主要性能瓶頸在于:

  • 磁盤I/O(寫入速度有限)
  • 文件系統(tǒng)緩存
  • 字符串處理(格式化、拼接)
  • 線程同步(在多線程環(huán)境下)

測試表明,大量日志可能導(dǎo)致應(yīng)用吞吐量下降30%-50%!

2. 異步日志的正確實現(xiàn)方式

通過異步方式將日志寫入從主線程分離:

<!-- logback異步配置 -->
<configuration>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 配置省略 -->
    </appender>
    
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE" />
        <queueSize>512</queueSize>
        <discardingThreshold>0</discardingThreshold>
        <includeCallerData>false</includeCallerData>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="ASYNC" />
    </root>
</configuration>

3. 高并發(fā)場景下的日志實現(xiàn)

采樣日志:只記錄部分請求的詳細信息

// 簡單的采樣實現(xiàn)
if (Math.random() < 0.01) {  // 1%采樣率
    log.info("詳細請求信息: request={}, headers={}", request, headers);
}

批量日志:將多條日志合并為一條寫入

異步非阻塞日志:使用Disruptor等高性能隊列

日志緩沖區(qū)調(diào)優(yōu):增加緩沖區(qū)大小,減少刷盤頻率

六、日志的運維與治理

1. 日志輪轉(zhuǎn)與歸檔策略

日志文件不能無限增長,需要設(shè)置輪轉(zhuǎn)策略:

<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>app.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <fileNamePattern>app-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <maxFileSize>100MB</maxFileSize>
        <maxHistory>30</maxHistory>
        <totalSizeCap>3GB</totalSizeCap>
    </rollingPolicy>
    <encoder>
        <pattern>%d %p %c{1} [%t] %m%n</pattern>
    </encoder>
</appender>

2. 集中式日志平臺的選擇

現(xiàn)代系統(tǒng)普遍采用ELK(Elasticsearch + Logstash + Kibana)或EFK(Elasticsearch + Fluentd + Kibana)棧來集中管理日志。

簡單架構(gòu):

應(yīng)用 -> Filebeat -> Logstash -> Elasticsearch -> Kibana

關(guān)鍵是在應(yīng)用層面保證日志格式統(tǒng)一、字段規(guī)范,才能充分利用日志平臺的能力。

3. 日志監(jiān)控告警的設(shè)計原則

基于日志的監(jiān)控策略:

  • 錯誤率監(jiān)控:ERROR日志量突增
  • 關(guān)鍵字監(jiān)控:特定異常類型或錯誤碼
  • 模式識別:異常的日志模式變化
  • 缺失檢測:預(yù)期日志未出現(xiàn)(如定時任務(wù)未執(zhí)行)

設(shè)置合理的告警閾值和降噪規(guī)則,避免"狼來了"效應(yīng)。

七、實戰(zhàn)案例解析

1. 日志缺失導(dǎo)致的災(zāi)難性后果

某電商平臺在618期間遭遇支付系統(tǒng)故障,用戶支付后無法收到訂單確認,導(dǎo)致大量重復(fù)下單。系統(tǒng)日志竟然只有:

2023-06-18 10:30:15 ERROR Process failed
2023-06-18 10:30:17 ERROR Process failed
2023-06-18 10:30:22 ERROR Process failed

沒有任何上下文信息,技術(shù)團隊不得不手動比對數(shù)據(jù)庫數(shù)據(jù)排查問題。最終發(fā)現(xiàn)是支付回調(diào)接口超時,但由于缺乏有效日志,排查過程耗時4小時,造成直接經(jīng)濟損失超過100萬。

改進后的日志:

2023-09-01 14:22:15 ERROR [PaymentService] 支付回調(diào)處理失敗 orderId=ORD123456 userId=10001 paymentId=PAY789012 channel=alipay amount=1299.00 errorCode=TIMEOUT errorMsg=第三方接口連接超時 traceId=c7d2eb9f14ce

有了詳細日志后,類似問題10分鐘內(nèi)可確定根因并采取補救措施。

2. 從日志優(yōu)化看系統(tǒng)設(shè)計的演進

某社交應(yīng)用的消息推送服務(wù)日志優(yōu)化經(jīng)歷:

第一階段:簡單文本日志

2022-01-01 12:00:00 INFO 推送消息成功

第二階段:添加基本參數(shù)

2022-03-01 12:00:00 INFO 推送消息成功 userId=123 msgId=456

第三階段:結(jié)構(gòu)化JSON日志 + 分布式追蹤

{
  "timestamp": "2022-06-01T12:00:00.000Z",
  "level": "INFO",
  "service": "push-service",
  "instance": "push-pod-3",
  "traceId": "abc123def456",
  "message": "消息推送成功",
  "data": {
    "userId": "123",
    "msgId": "456",
    "channel": "app",
    "deviceType": "iOS",
    "latency": 24
  }
}

第四階段:引入業(yè)務(wù)指標和日志聚合

{
  "timestamp": "2022-10-01T12:00:00.000Z",
  "level": "INFO",
  "service": "push-service",
  "instance": "push-pod-3",
  "traceId": "abc123def456",
  "message": "批量消息推送完成",
  "data": {
    "batchId": "batch789",
    "totalMessages": 1000,
    "successCount": 950,
    "failCount": 50,
    "avgLatency": 28,
    "p95Latency": 42,
    "errorBreakdown": {
      "TIMEOUT": 30,
      "DEVICE_OFFLINE": 15,
      "PERMISSION_DENIED": 5
    }
  }
}

這種演進不僅改進了日志本身,還反過來優(yōu)化了系統(tǒng)的可觀測性設(shè)計,最終使整個系統(tǒng)更加健壯和可維護。

以上就是Java打印高質(zhì)量日志的10條方法詳解的詳細內(nèi)容,更多關(guān)于Java打印日志的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java字符串中有多個分隔符的處理方式

    Java字符串中有多個分隔符的處理方式

    這篇文章主要介紹了Java字符串中有多個分隔符的處理方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • 使用Java實現(xiàn)價格加密與優(yōu)化功能

    使用Java實現(xiàn)價格加密與優(yōu)化功能

    在現(xiàn)代軟件開發(fā)中,數(shù)據(jù)加密是一個非常重要的環(huán)節(jié),尤其是在處理敏感信息(如價格、用戶數(shù)據(jù)等)時,本文將詳細介紹如何使用?Java?實現(xiàn)價格加密,并對代碼進行優(yōu)化,需要的朋友可以參考下
    2025-01-01
  • 關(guān)于JAVA11中圖片與BASE64相互轉(zhuǎn)換的實現(xiàn)

    關(guān)于JAVA11中圖片與BASE64相互轉(zhuǎn)換的實現(xiàn)

    這篇文章主要介紹了關(guān)于JAVA11中圖片與BASE64相互轉(zhuǎn)換的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • spring boot 實現(xiàn)阿里云視頻點播功能(刪除視頻)

    spring boot 實現(xiàn)阿里云視頻點播功能(刪除視頻)

    這篇文章主要介紹了spring boot 實現(xiàn)阿里云視頻點播(刪除視頻功能),本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Maven本地jar引用的實現(xiàn)方法

    Maven本地jar引用的實現(xiàn)方法

    這篇文章主要介紹了Maven本地jar引用的實現(xiàn)方法的相關(guān)資料,希望通過本文能幫助到大家,實現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • ssm框架上傳圖片保存到本地和數(shù)據(jù)庫示例

    ssm框架上傳圖片保存到本地和數(shù)據(jù)庫示例

    本篇文章主要介紹了ssm框架上傳圖片保存到本地和數(shù)據(jù)庫示例,主要使用了Spring+SpringMVC+MyBatis框架集合,有興趣的可以了解一下。
    2017-03-03
  • Java最簡單的DES加密算法實現(xiàn)案例

    Java最簡單的DES加密算法實現(xiàn)案例

    下面小編就為大家?guī)硪黄狫ava最簡單的DES加密算法實現(xiàn)案例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • jackson 如何將實體轉(zhuǎn)json json字符串轉(zhuǎn)實體

    jackson 如何將實體轉(zhuǎn)json json字符串轉(zhuǎn)實體

    這篇文章主要介紹了jackson 實現(xiàn)將實體轉(zhuǎn)json json字符串轉(zhuǎn)實體,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SpringBoot項目整合OpenFeign啟動失敗及運行時常見錯誤解決方案

    SpringBoot項目整合OpenFeign啟動失敗及運行時常見錯誤解決方案

    文章總結(jié)了在使用Feign進行服務(wù)調(diào)用時可能遇到的常見問題及其解決方案,涵蓋了依賴配置、接口定義、運行時錯誤和其它常見問題的解決方法,建議使用兼容的版本、統(tǒng)一的包名結(jié)構(gòu),并為接口方法添加HTTP注解,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • Maven配置倉庫的方法步驟

    Maven配置倉庫的方法步驟

    本文主要介紹了Maven配置倉庫的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06

最新評論

克山县| 出国| 乌拉特中旗| 会同县| 龙州县| 延津县| 济南市| 宁远县| 七台河市| 万年县| 沅江市| 比如县| 清原| 云林县| 科尔| 象州县| 城口县| 岱山县| 青铜峡市| 侯马市| 昌宁县| 甘谷县| 鄂温| 常德市| 奉新县| 永昌县| 龙里县| 宁德市| 大化| 徐汇区| 楚雄市| 胶南市| 西畴县| 阳谷县| 和林格尔县| 怀宁县| 托克逊县| 化州市| 河东区| 赣州市| 汤阴县|