應用程式日誌最佳實踐 - 從設計到生產

  1. 為什麼日誌策略很重要
  2. 設計時的日誌策略
  3. 記錄什麼
  4. 日誌監控模式
  5. 結構化與非結構化日誌
  6. 日誌監控工具
  7. 日誌記錄最佳實踐
  8. 應用程式日誌保留策略
  9. 常見的日誌記錄錯誤
  10. 建立日誌文化
  11. 做出選擇

大多數團隊將日誌視為事後才考慮的事情。他們在程式碼中到處添加 console.log()print() 陳述式,希望在出現問題時能夠捕獲足夠的資訊。然後在凌晨 3 點生產環境崩潰時,他們才意識到日誌毫無用處——格式不一致、缺少上下文、沒有結構。

有效的日誌記錄不是從部署時開始的,而是從應用程式設計時開始的。在編寫程式碼之前做出的決策決定了日誌是能為你節省數小時的除錯時間,還是用雜訊浪費你的時間。

這不是關於日誌框架或工具的討論——而是關於策略。是關於設計能夠回答問題而不是製造更多困惑的日誌。

為什麼日誌策略很重要

凌晨 3 點測試:當你的應用程式在凌晨 3 點崩潰時,你能僅憑日誌診斷問題嗎?還是需要添加更多日誌、重新部署,然後等待問題再次發生?

糟糕日誌的成本

  • 延長的停機時間:因為日誌沒有顯示失敗原因而花費數小時除錯
  • 重複的事故:因為日誌沒有捕獲根本原因,同樣的問題再次發生
  • 告警疲勞:太多雜訊,找不到訊號
  • 儲存成本:記錄所有內容每月花費數千美元卻沒有價值

良好日誌的價值

  • 快速除錯:在幾分鐘而不是幾小時內找到根本原因
  • 主動檢測:在使用者投訴之前發現問題
  • 稽核軌跡:知道誰在何時做了什麼
  • 業務洞察:追蹤交易、使用者行為、系統健康狀況

⚠️ 事後無法添加日誌

當生產環境當機時,你無法添加日誌並重新部署。你只能使用現有的日誌。從一開始就正確設計日誌。

設計時的日誌策略

有效的日誌記錄需要在編寫程式碼之前制定標準、結構和計畫。

儘早定義日誌標準

日誌層級標準:記錄整個組織何時使用每個層級。沒有標準,一個開發人員的 ERROR 就是另一個開發人員的 WARNING。

DEBUG: 變數值、函式進入/退出(僅開發環境)
INFO: 使用者操作、業務事件(「使用者 123 登入」)
WARNING: 可恢復的問題(「API 慢,正在重試」、「快取未命中」)
ERROR: 操作失敗但應用程式繼續執行(「支付失敗」、「郵件未發送」)
CRITICAL: 服務降級或當機(「資料庫無法存取」、「記憶體不足」)

何時使用每個層級

DEBUG:詳細的診斷資訊。在生產環境中停用。用於開發期間的故障排除。

INFO:正常的應用程式行為。使用者登入、訂單建立、批次處理作業啟動。幫助理解應用程式流程。

WARNING:意外但已處理的情況。API 逾時並重試、快取未命中並使用備用方案、使用已棄用的功能。需要調查但不緊急。

ERROR:操作失敗但應用程式繼續執行。支付被拒絕、郵件發送失敗、檔案未找到。需要關注。

CRITICAL:應用程式無法繼續執行。資料庫無法存取、記憶體不足、設定缺失。需要立即採取行動。

錯誤分類

定義與監控和告警需求一致的錯誤類別。

# 基礎設施錯誤
ERROR [INFRA.DATABASE]: 連線池耗盡
ERROR [INFRA.NETWORK]: 連線 payment-service 逾時
ERROR [INFRA.STORAGE]: 磁碟寫入失敗

# 應用程式錯誤
ERROR [APP.VALIDATION]: 無效的電子郵件格式
ERROR [APP.BUSINESS]: 訂單庫存不足
ERROR [APP.INTEGRATION]: 第三方 API 回傳 500

# 安全事件
WARNING [SECURITY.AUTH]: 登入嘗試失敗
CRITICAL [SECURITY.ACCESS]: 未授權的管理員存取嘗試
ALERT [SECURITY.INJECTION]: 偵測到 SQL 注入

為什麼要分類

  • 路由告警[SECURITY.*] 發送給安全團隊,[INFRA.DATABASE] 發送給資料庫團隊
  • 過濾日誌:搜尋所有服務的基礎設施錯誤
  • 聚合指標:按類別統計錯誤,追蹤趨勢
  • 優先修復:關注錯誤率最高的類別

結構化日誌模式

為所有日誌定義必需欄位。一致性使自動化處理成為可能。

{
  "timestamp": "2020-11-01T10:30:00Z",
  "level": "ERROR",
  "category": "INFRA.DATABASE",
  "message": "連線池耗盡",
  "service": "payment-service",
  "request_id": "req-abc-123",
  "user_id": "user-456",
  "error_code": "DB_POOL_EXHAUSTED",
  "context": {
    "pool_size": 100,
    "active_connections": 100,
    "wait_time_ms": 5000
  }
}

必需欄位

  • timestamp:ISO8601 格式,便於一致解析
  • level:ERROR、WARNING、INFO、DEBUG、CRITICAL
  • category:用於路由和過濾的錯誤類別
  • message:人類可讀的描述
  • service:產生此日誌的服務(對微服務至關重要)
  • request_id:追蹤 ID,用於追蹤跨服務的請求
  • user_id:了解使用者影響(如果適用)
  • error_code:應用程式特定的代碼,用於程式化處理

可選上下文:特定於事件類型的附加欄位。資料庫錯誤包括連線池統計資訊。支付錯誤包括金額和閘道。

安全事件標準

定義什麼構成安全事件以及如何記錄它。

# 認證事件
WARNING [SECURITY.AUTH]: 登入失敗 | user={username} ip={ip} attempts={count}
INFO [SECURITY.AUTH]: 登入成功 | user={username} ip={ip}
ALERT [SECURITY.AUTH]: 帳戶被鎖定 | user={username} reason={too_many_attempts}

# 授權事件
WARNING [SECURITY.AUTHZ]: 未授權的存取嘗試 | user={username} resource={path}
CRITICAL [SECURITY.AUTHZ]: 權限提升嘗試 | user={username} action={attempted_action}

# 資料存取事件
INFO [SECURITY.DATA]: 存取敏感資料 | user={username} resource={customer_records}
ALERT [SECURITY.DATA]: 批次資料匯出 | user={username} records={count}

為什麼安全日誌很重要

  • 合規性:PCI-DSS、HIPAA、SOC2 要求記錄安全事件
  • 事件回應:了解攻擊模式,識別被入侵的帳戶
  • 鑑識:重建安全事件期間發生的事情
  • 威懾:知道操作被記錄會阻止惡意行為

業務事件標準

定義需要記錄和監控的關鍵業務事件。

# 交易事件
INFO [BUSINESS.PAYMENT]: 支付成功 | amount={amount} user={user_id}
ERROR [BUSINESS.PAYMENT]: 支付失敗 | amount={amount} reason={reason}
ALERT [BUSINESS.PAYMENT]: 高額支付 | amount={amount} threshold={10000}

# 庫存事件
WARNING [BUSINESS.INVENTORY]: 庫存不足 | product={sku} quantity={count}
ERROR [BUSINESS.INVENTORY]: 缺貨 | product={sku}
ALERT [BUSINESS.INVENTORY]: 庫存不符 | expected={100} actual={95}

# 訂單事件
INFO [BUSINESS.ORDER]: 訂單建立 | order_id={id} total={amount}
ERROR [BUSINESS.ORDER]: 訂單失敗 | order_id={id} reason={reason}
ALERT [BUSINESS.ORDER]: 退款處理 | order_id={id} amount={amount}

為什麼要記錄業務事件

  • 收入追蹤:監控交易成功率,識別收入損失
  • 客戶支援:使用完整的交易歷史調查客戶投訴
  • 商業智慧:分析模式,最佳化流程
  • 詐欺偵測:識別交易中的可疑模式

📝 日誌標準文件

在設計階段建立「日誌標準」文件。包括:日誌層級、類別、必需欄位、安全事件定義、業務事件定義和範例。將其作為程式碼審查檢查清單的一部分。

設計便於監控的錯誤處理

建構錯誤處理以產生有用的日誌。

# 不好:通用錯誤,難以監控
try:
    process_payment()
except Exception as e:
    log.error(f"錯誤: {e}")

# 好:分類、結構化、可監控
try:
    process_payment()
except PaymentGatewayTimeout as e:
    log.error(
        "支付閘道逾時",
        extra={
            "category": "INFRA.INTEGRATION",
            "gateway": "stripe",
            "amount": payment.amount,
            "retry_count": payment.retries,
            "error_code": "PAYMENT_TIMEOUT"
        }
    )
except InsufficientFunds as e:
    log.warning(
        "支付被拒絕:餘額不足",
        extra={
            "category": "BUSINESS.PAYMENT",
            "amount": payment.amount,
            "error_code": "INSUFFICIENT_FUNDS"
        }
    )

為什麼這很重要

  • 特定告警:對 category=INFRA.INTEGRATION AND error_code=PAYMENT_TIMEOUT 發出告警
  • 上下文:知道哪個閘道、多少金額、重試了多少次
  • 分類:將基礎設施錯誤路由到維運團隊,業務錯誤路由到產品團隊
  • 可操作:清晰的錯誤代碼使自動回應成為可能

在使用者故事中包含監控需求

將日誌記錄作為一等需求,而不是事後考慮。

使用者故事:處理支付
驗收標準:
- 透過 Stripe API 處理支付
- 使用者收到確認郵件
- 監控:失敗時記錄 ERROR [BUSINESS.PAYMENT],包含金額和原因
- 監控:如果 5 分鐘內支付失敗率 > 5%,發出告警
- 監控:如果任何 > $10,000 的支付失敗,發出告警

好處

  • 日誌被測試:QA 驗證日誌是否正確產生
  • 從第一天起就完整:無需稍後添加日誌
  • 一致:所有功能遵循相同的日誌標準
  • 被監控:在部署之前設定告警

⚠️ 改造日誌成本高昂

在部署後添加適當的日誌意味著:分析現有程式碼、更新數百條日誌陳述式、重新部署所有服務、更新監控規則。從一開始就正確設計。

記錄什麼

不是所有內容都值得記錄。專注於有助於除錯、安全和業務分析的事件。

錯誤模式

ERROR: 資料庫連線失敗
ERROR: OutOfMemoryError
ERROR: PaymentService 中的 NullPointerException
FATAL: 應用程式啟動失敗

何時告警:錯誤計數超過閾值(> 10 個錯誤/分鐘)或特定關鍵錯誤出現一次。

安全事件

WARNING: 使用者 admin 登入嘗試失敗(1 分鐘內 5 次嘗試)
ALERT: 來自 IP 192.168.1.100 的未授權 API 存取
CRITICAL: 偵測到 SQL 注入嘗試

何時告警:任何安全事件發生時。對安全問題零容忍。

業務異常

ERROR: 支付被拒絕:餘額不足
WARNING: 訂單總額不符:預期 $100,實際 $1
ALERT: 退款金額超過 $10,000

何時告警:高價值交易失敗或偵測到異常模式。

整合失敗

ERROR: 第三方 API 逾時:payment-gateway
WARNING: 郵件服務不可用,訊息排隊中
ERROR: S3 上傳失敗:存取被拒絕

何時告警:關鍵整合反覆失敗。

日誌監控模式

日誌監控模式是可重用的告警策略,定義如何從日誌資料中偵測問題。這些模式不是手動監視日誌,而是在特定條件發生時自動觸發告警。

每個模式回答三個問題:

  1. 尋找什麼:哪些日誌訊息或條件表明存在問題
  2. 何時告警:觸發告警的閾值或條件
  3. 採取什麼行動:通知誰以及緊急程度如何

模式 1:錯誤率閾值

ALERT: count("ERROR") > 50 in last 5 minutes
操作:呼叫值班工程師
上下文:錯誤率激增表明系統性問題

用例:偵測應用程式中錯誤的突然增加。

模式 2:特定錯誤偵測

ALERT: any("OutOfMemoryError") in last 1 minute
操作:立即呼叫 + 自動重啟服務
上下文:OOM 意味著即將崩潰

用例:需要立即採取行動的關鍵錯誤。

模式 3:錯誤率變化

ALERT: count("ERROR", 5m) > 2x count("ERROR", 1h average)
操作:向團隊發送 Slack 通知
上下文:錯誤率比基線翻倍

用例:偵測與歷史基線相比的異常錯誤模式。

模式 4:預期日誌缺失

ALERT: count("Batch job completed") == 0 in last 24 hours
操作:向維運團隊發送郵件
上下文:每日批次處理作業未執行

用例:偵測預期事件未發生的靜默失敗。

模式 5:相關日誌模式

ALERT: count("Database timeout") > 10 AND count("Connection pool exhausted") > 5
操作:呼叫資料庫團隊
上下文:資料庫連線問題影響多個服務

用例:透過關聯相關錯誤來偵測級聯故障。

結構化與非結構化日誌

結構化日誌使監控、搜尋和分析變得更加容易。

非結構化(難以監控)

ERROR: Payment failed for user john@neo01.com amount 99.99 reason card_declined

為什麼非結構化難以處理

需要正規表示式解析:要提取金額,你需要像 amount (\d+\.\d+) 這樣的正規表示式。不同的日誌格式需要不同的正規表示式模式。一個拼寫錯誤就會破壞一切。

格式不一致:開發人員 A 寫 “amount 99.99”,開發人員 B 寫 “$99.99”,開發人員 C 寫 “amount: 99.99 USD”。你的監控就會失效。

無法高效查詢:想要所有超過 $1000 的支付?你必須掃描每一行日誌,解析文字,轉換為數字,然後過濾。緩慢且昂貴。

難以聚合:計算平均支付金額需要解析數百萬個文字字串。結構化欄位讓資料庫高效完成這項工作。

脆弱的告警:對 amount > 1000 的告警需要從文字中解析 “amount 99.99”。如果格式更改為 “total 99.99”,告警會靜默失效。

結構化(易於監控)

{
  "level": "ERROR",
  "message": "支付失敗",
  "user_email": "john@neo01.com",
  "amount": 99.99,
  "reason": "card_declined",
  "timestamp": "2020-11-01T10:30:00Z"
}

為什麼結構化更好

直接欄位存取:直接查詢 amount > 1000。無需解析,無需正規表示式,不會失效。

型別安全amount 是數字,不是文字。資料庫知道如何比較、聚合和計算。

一致的格式:每個日誌都有相同的欄位。監控規則在所有服務中可靠工作。

快速查詢:資料庫在 amount 欄位上建立索引。查詢在毫秒內執行,而不是分鐘。

易於聚合AVG(amount)SUM(amount)MAX(amount) 立即工作。無需文字解析。

現在你可以告警:level=ERROR AND reason=card_declined AND amount > 1000

而且它可靠地工作,永遠,無論誰寫日誌或何時寫。

日誌監控工具

選擇適合你規模和預算的工具。

CloudWatch Logs Insights

AWS 原生,與 AWS 服務無縫整合。使用類似 SQL 的語法查詢日誌。

fields @timestamp, @message
| filter @message like /ERROR/
| stats count() by bin(5m)

優點:易於 AWS 整合,無需管理基礎設施
缺點:搜尋能力有限,大規模時昂貴
最適合:AWS 重度環境,中小規模

ELK Stack(Elasticsearch、Logstash、Kibana)

強大的搜尋和視覺化。日誌聚合的業界標準。

優點:強大的搜尋,豐富的視覺化,龐大的生態系統
缺點:資源密集,操作複雜,大規模時昂貴
最適合:大型組織,複雜的搜尋需求

Splunk

企業級日誌管理和分析。

優點:強大的分析,出色的支援,全面的功能
缺點:非常昂貴,複雜的授權
最適合:有預算的企業,合規要求

Loki + Grafana

ELK 的輕量級替代方案。專為 Kubernetes 環境設計。

優點:輕量級,與 Prometheus 和 Grafana 整合,成本效益高
缺點:搜尋能力不如 Elasticsearch 強大
最適合:Kubernetes 環境,注重成本的團隊

💡 高容量日誌採樣

如果你每分鐘記錄數百萬個事件,對非關鍵日誌進行採樣(保留 1%,丟棄 99%)。始終保留 ERROR 和 CRITICAL 日誌。這降低了成本,同時保持對問題的可見性。

日誌記錄最佳實踐

正確使用日誌層級

  • DEBUG:用於除錯的詳細資訊(在生產環境中停用)
  • INFO:一般資訊性訊息(「使用者登入」)
  • WARNING:意外但已處理的情況(「API 慢,正在重試」)
  • ERROR:某些操作失敗但應用程式繼續執行(「支付失敗」)
  • CRITICAL/FATAL:應用程式無法繼續執行(「資料庫無法存取」)

包含上下文

每個日誌都應該回答:誰、什麼、何時、何地、為什麼。

  • 請求 ID:跨服務追蹤請求
  • 使用者 ID:了解使用者影響
  • 服務名稱:在微服務中識別來源
  • 時間戳記:關聯事件
  • 錯誤詳情:堆疊追蹤、錯誤代碼、相關變數

避免日誌垃圾

  • 不要在緊密迴圈中記錄:在處理數百萬項的迴圈內記錄會產生雜訊
  • 限制重複錯誤的速率:記錄「資料庫逾時發生 50 次」而不是 50 條單獨的日誌
  • 聚合類似錯誤:分組相關錯誤,不要重複相同的訊息
  • 使用適當的日誌層級:不要在 DEBUG 層級記錄 INFO 訊息

保護敏感資料

  • 永遠不要記錄密碼、權杖、信用卡:顯而易見但經常被違反
  • 遮罩 PII:編輯電子郵件地址、電話號碼、社會安全號碼
  • 編輯敏感欄位:在結構化日誌中,遮罩敏感值
  • 遵守法規:GDPR、HIPAA、PCI-DSS 有嚴格的日誌記錄要求
# 不好:記錄敏感資料
log.info(f"使用者登入: {username} 密碼: {password}")

# 好:遮罩敏感資料
log.info(f"使用者登入: {username} 密碼: ****")

# 更好:根本不記錄密碼
log.info(f"使用者登入: {username}")

⚠️ 日誌量與成本

記錄所有內容是昂貴的。一個中等規模的應用程式每月可以產生數 TB 的日誌。CloudWatch Logs 成本為每 GB 擷取 $0.50 + 每 GB 儲存 $0.03。在可見性和預算之間取得平衡。

應用程式日誌保留策略

應用程式日誌應該保留多長時間?在除錯需求、事後分析和儲存成本之間取得平衡。

應用程式日誌的保留層級

熱儲存(7-30 天):可立即搜尋,昂貴,用於主動除錯。

  • 內容:所有應用程式日誌的完整詳細資訊(DEBUG、INFO、WARNING、ERROR、CRITICAL)
  • 原因:大多數錯誤在部署後幾天內被偵測和除錯
  • 成本:高(CloudWatch 中每 GB 擷取 $0.50 + 每 GB 儲存 $0.03)
  • 用例:主動除錯、最近的部署問題、效能故障排除

溫儲存(30-90 天):存取較慢,更便宜,用於事後分析。

  • 內容:完整詳細資訊的 ERROR 和 CRITICAL 日誌,採樣的 INFO/WARNING(10%)
  • 原因:事後調查通常在事件發生數週後進行
  • 成本:中等(S3 標準:每 GB 每月 $0.023)
  • 用例:事後分析、模式識別、比較一段時間內的行為

冷儲存(90 天 - 1 年):僅歸檔,最便宜,用於罕見的調查。

  • 內容:僅 ERROR 和 CRITICAL 日誌,已壓縮
  • 原因:罕見情況需要歷史上下文來處理重複問題
  • 成本:低(S3 Glacier:每 GB 每月 $0.004)
  • 用例:長期模式分析、罕見的錯誤調查
graph LR A["應用程式日誌"] --> B["熱儲存
7-30 天
$0.50/GB"] B --> C["溫儲存
30-90 天
$0.023/GB"] C --> D["冷儲存
90 天 - 1 年
$0.004/GB"] D --> E["刪除"] style A fill:#4dabf7,stroke:#1971c2,color:#fff style B fill:#ff6b6b,stroke:#c92a2a,color:#fff style C fill:#ffd43b,stroke:#f59f00,color:#000 style D fill:#51cf66,stroke:#2f9e44,color:#fff style E fill:#868e96,stroke:#495057,color:#fff

按應用程式日誌層級的保留

DEBUG 日誌

  • 保留:7 天熱儲存,然後刪除
  • 原因:極其冗長,初始除錯後很少需要
  • 容量:總日誌量的 40-50%
  • 成本影響:刪除 DEBUG 日誌可節省 40-50% 的儲存成本

INFO 日誌

  • 保留:30 天熱儲存,然後刪除(或採樣 10% 用於溫儲存)
  • 原因:在除錯期間有助於理解應用程式流程
  • 容量:總日誌量的 30-40%
  • 採樣:如果需要,隨機保留 10% 用於趨勢分析

WARNING 日誌

  • 保留:30 天熱儲存,60 天溫儲存
  • 原因:警告通常先於錯誤;對事後分析有用
  • 容量:總日誌量的 5-10%
  • 模式分析:審查警告以防止未來的錯誤

ERROR 日誌

  • 保留:90 天熱儲存,1 年溫儲存
  • 原因:對除錯、事後分析和識別重複問題至關重要
  • 容量:總日誌量的 5-10%
  • 始終保留:永遠不要過早採樣或刪除 ERROR 日誌

CRITICAL 日誌

  • 保留:90 天熱儲存,1 年溫儲存,7 年冷儲存(如果需要合規)
  • 原因:影響服務的事件需要長期保留以進行模式分析
  • 容量:總日誌量的 < 1%
  • 不可變:考慮對關鍵事件使用一次寫入儲存

成本最佳化

採樣非關鍵日誌:保留 100% 的 ERROR 日誌,10% 的 INFO 日誌,1% 的 DEBUG 日誌。

# 採樣前:1TB/天 = 每月 $15,000
# 採樣後:100GB/天 = 每月 $1,500
# 節省:每月 $13,500 = 每年 $162,000

歸檔前壓縮:日誌壓縮 5-10 倍。1TB 變成 100-200GB。

積極刪除 DEBUG 日誌:DEBUG 日誌佔容量的 80%,但 7 天後很少需要。

使用生命週期原則:自動化從熱儲存 → 溫儲存 → 冷儲存 → 刪除的轉換。

# S3 生命週期原則範例
Rules:
  - Id: "LogRetention"
    Status: Enabled
    Transitions:
      - Days: 30
        StorageClass: STANDARD_IA  # 溫儲存
      - Days: 90
        StorageClass: GLACIER      # 冷儲存
    Expiration:
      Days: 2555  # 7 年

合規要求

PCI-DSS:稽核日誌至少 1 年,系統日誌 3 個月。

HIPAA:醫療資料存取日誌至少 6 年。

SOC 2:至少 1 年,但稽核員通常要求 2-3 年。

GDPR:沒有具體的保留要求,但必須應請求刪除。不要保留日誌超過必要時間。

金融服務:交易記錄通常為 7 年。

⚠️ 合規優先於成本

如果法規要求 7 年,你必須保留日誌 7 年。不合規的罰款遠遠超過儲存成本。單次 HIPAA 違規可能花費 $50,000 以上。

實用的應用程式日誌保留策略

新創公司/小型企業

DEBUG: 7 天
INFO: 14 天
WARNING: 30 天
ERROR/CRITICAL: 90 天
事後分析:根據需要延長至 90 天
成本:每月 $200-1,000

中型公司

DEBUG: 7 天熱儲存
INFO: 30 天熱儲存
WARNING: 30 天熱儲存,60 天溫儲存
ERROR: 90 天熱儲存,1 年溫儲存
CRITICAL: 90 天熱儲存,1 年溫儲存
事後分析:自動延長 90 天
成本:每月 $2,000-10,000

企業

DEBUG: 7 天熱儲存(生產環境採樣 1%)
INFO: 30 天熱儲存,10% 採樣 90 天溫儲存
WARNING: 90 天熱儲存,1 年溫儲存
ERROR: 90 天熱儲存,1 年溫儲存
CRITICAL: 1 年熱儲存,7 年冷儲存
事後分析:帶審批工作流程的自動延長
成本:每月 $10,000-50,000

何時更長時間保留應用程式日誌

事後調查:在進行詳細的事後分析時延長保留期。

# 場景:10 月 15 日發生重大故障
# 正常保留:30 天
# 延長保留:將 10 月 1-31 日的所有日誌保留 90 天
# 原因:事後分析可能需要數週;需要完整的上下文

重複問題:除錯間歇性問題時保留日誌更長時間。

# 場景:記憶體洩漏每 2-3 週出現一次
# 正常保留:30 天
# 延長保留:將 ERROR/WARNING 日誌保留 90 天
# 原因:需要多次發生來識別模式

模式分析:為效能最佳化或容量規劃保留日誌更長時間。

# 場景:分析季節性流量模式
# 正常保留:30 天
# 延長保留:將採樣的 INFO 日誌(1%)保留 1 年
# 原因:比較跨季節的行為

部署關聯:在重大部署前後保留日誌。

# 場景:部署重大架構變更
# 正常保留:30 天
# 延長保留:將部署前後 7 天的所有日誌保留 90 天
# 原因:比較變更前後的行為

🔍 事後保留

當發生重大事件時,立即延長受影響時間段的日誌保留期。事後分析通常需要 2-4 週才能完成,你需要事件之前、期間和之後的日誌。

何時更早刪除應用程式日誌

GDPR 刪除權:應請求刪除使用者資料,包括包含 PII 的應用程式日誌。

# 實作特定使用者的日誌刪除
def delete_user_logs(user_id):
    # 從熱儲存中刪除
    delete_logs_where(user_id=user_id, storage="hot")
    # 從溫儲存中刪除
    delete_logs_where(user_id=user_id, storage="warm")
    # 在冷儲存中標記為刪除
    mark_for_deletion(user_id=user_id, storage="cold")

儲存成本超過價值:如果 DEBUG/INFO 日誌從未被搜尋,減少保留期。

# 分析:DEBUG 日誌每月花費 $5,000,90 天內搜尋 0 次
# 操作:將 DEBUG 保留期從 30 天減少到 7 天
# 節省:每月 $3,750 = 每年 $45,000

開發/測試環境:比生產環境短得多的保留期。

生產環境:30 天熱儲存,90 天溫儲存
測試環境:7 天熱儲存,然後刪除
開發環境:3 天熱儲存,然後刪除

💡 從保守開始,向下調整

從較長的保留期(90 天)開始,監控你存取舊日誌的頻率,如果你從未搜尋超過 30 天的日誌,則減少保留期。減少保留期比解釋為什麼刪除了調查所需的日誌更容易。

應用程式日誌保留策略範本

記錄你的應用程式日誌保留策略:

# 應用程式日誌保留策略

## 標準保留

### 生產應用程式日誌
- DEBUG: 7 天(熱儲存),然後刪除
- INFO: 30 天(熱儲存),然後刪除
- WARNING: 30 天(熱儲存),60 天(溫儲存)
- ERROR: 90 天(熱儲存),1 年(溫儲存)
- CRITICAL: 90 天(熱儲存),1 年(溫儲存)

### 非生產應用程式日誌
- 測試環境:7 天(熱儲存),然後刪除
- 開發環境:3 天(熱儲存),然後刪除
- 測試:1 天(熱儲存),然後刪除

## 延長保留觸發器

### 事後調查
- 觸發器:重大事件(P0/P1)
- 操作:將事件時間段 ± 7 天的保留期延長至 90 天
- 持續時間:直到事後分析完成 + 30 天
- 審批:工程經理

### 重複問題
- 觸發器:30 天內同一錯誤發生 3 次以上
- 操作:將 ERROR/WARNING 保留期延長至 90 天
- 持續時間:直到識別並修復根本原因
- 審批:團隊負責人

### 重大部署
- 觸發器:架構變更、重大版本發布
- 操作:將部署前後 7 天的所有日誌保留 90 天
- 持續時間:部署後 90 天
- 審批:自動

## 成本管理

### 月度審查
- 審查儲存成本與搜尋頻率
- 識別未使用的日誌層級或服務
- 如果日誌從未被搜尋,調整保留期

### 季度最佳化
- 分析 DEBUG/INFO 日誌的價值
- 如果合適,實作採樣
- 根據實際使用情況更新保留期

## GDPR 合規
- 使用者資料刪除:請求後 30 天內
- 自動刪除:透過 user_id 欄位實作
- 驗證:每月稽核刪除請求

## 例外情況
- 事後調查:根據需要延長
- 重複錯誤:延長直到解決
- 效能分析:採樣並延長
- GDPR 請求:立即刪除

常見的日誌記錄錯誤

記錄太多:生產環境中的 DEBUG 日誌會產生雜訊並花費金錢。使用適當的日誌層級。

記錄太少:「發生錯誤」而沒有上下文是無用的。包含相關詳細資訊。

格式不一致:每個開發人員使用不同的日誌格式使搜尋變得不可能。使用結構化日誌。

記錄敏感資料:日誌中的密碼、權杖、信用卡會產生安全風險和合規違規。

沒有日誌輪替:日誌填滿磁碟空間會導致應用程式崩潰。實作日誌輪替和保留策略。

忽略日誌量:每分鐘記錄數百萬個事件每月花費數千美元。對非關鍵日誌進行採樣。

建立日誌文化

將日誌作為要求:在驗收標準、程式碼審查檢查清單和完成定義中包含日誌。

定期審查日誌:不要等待事件。定期審查日誌以識別模式並改進日誌記錄。

從事件中學習:每個事件都會揭示日誌缺口。缺少什麼資訊?添加它。

分享知識:記錄日誌標準,分享範例,培訓新團隊成員。

慶祝良好的日誌記錄:當良好的日誌記錄節省了數小時的除錯時間時,認可它。讓日誌記錄成為一項有價值的技能。

做出選擇

日誌記錄不是可選的——它是必不可少的。問題是你是從一開始就正確設計它,還是在生產故障後改造它。

從標準開始:日誌層級、類別、結構化格式。將日誌記錄作為使用者故事中的一等要求。選擇適合你規模和預算的工具。實作平衡成本和合規性的保留策略。

記住:日誌是應用程式的黑盒子記錄器。當事情出錯時——而且它們會出錯——日誌通常是你理解發生了什麼的唯一方式。

從一開始就正確設計日誌。你未來的自己——在凌晨 3 點除錯時——會感謝你。

分享到