iT邦幫忙

2025 iThome 鐵人賽

DAY 13
0

在前 12 天,我們已經建立了環境、依賴、目錄結構、測試、設定與秘密管理的基礎。專案「能跑、能測、能設定」。

但還缺一個關鍵拼圖:日誌(Logging)

日誌不只是 debug 工具,它更是系統運行過程中的「黑盒紀錄器」。

如果沒有良好的日誌,你會遇到這些情況:

  • 線上服務出錯,只看到一堆 print()
  • 不同模組輸出的日誌格式不一致,難以追蹤。
  • CI/CD pipeline 或雲端監控系統無法解析字串,導致錯誤訊息被淹沒。

因此,我們需要從 「文字日誌」進化到「結構化日誌」,讓日誌不只是人能讀,還能被機器分析。


一、傳統 logging:字串堆疊的起點

Python 內建的 logging 模組,是最常見的起手式:

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

logger.info("user logged in: %s", "alice")
logger.error("failed to fetch data: %s", "timeout")

輸出結果:

INFO:__main__:user logged in: alice
ERROR:__main__:failed to fetch data: timeout

👉 優點:

  • 標準庫內建,零依賴。
  • 支援 log level、formatter、handler。

👉 缺點:

  • 輸出是單純字串。
  • 缺乏結構,無法直接被 JSON parser 或 ELK / Loki 等工具分析。

二、structlog:讓日誌成為資料

structlog 是 Python 生態中最成熟的結構化日誌套件,它的理念是:

日誌不應只是字串,而是 key-value 結構化資料。

安裝:

pip install structlog

使用:

import structlog

logger = structlog.get_logger()

logger.info("user_logged_in", user="alice", ip="127.0.0.1")
logger.error("db_error", query="SELECT * FROM users", error="timeout")

輸出結果(預設 JSON 格式化器後):

{"event": "user_logged_in", "user": "alice", "ip": "127.0.0.1", "level": "info"}
{"event": "db_error", "query": "SELECT * FROM users", "error": "timeout", "level": "error"}

👉 好處:

  • Key-value 結構,方便過濾與分析。
  • 能與 logging 整合,不用重寫所有程式碼。
  • 適合導入 ELK (Elasticsearch + Logstash + Kibana)、Grafana Loki 等監控平台。

三、JSON Log:與雲端 / 分散式環境接軌

在容器化與雲端部署的場景(如 Kubernetes),日誌最佳實務就是 JSON 輸出

  1. 標準輸出 (stdout):由容器 runtime 收集,避免寫檔案。
  2. JSON 格式:方便 log collector 解析,例如 Fluent Bit、Vector、Datadog agent。

設定範例(structlog + JSONRenderer):

import logging
import structlog

logging.basicConfig(level=logging.INFO)

structlog.configure(
    processors=[
        structlog.processors.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer()
    ]
)

logger = structlog.get_logger()

logger.info("payment_success", order_id="A123", amount=100)

輸出結果:

{
  "event": "payment_success",
  "order_id": "A123",
  "amount": 100,
  "level": "info",
  "timestamp": "2025-09-21T16:00:00Z"
}

👉 優點:

  • 機器可解析,適合大規模服務。
  • 日誌平台可根據 order_idlevel 快速搜尋、聚合。
  • 天然支援雲端監控(ELK / Loki / Datadog / CloudWatch)。

四、專案整合:從本地到雲端

延續 Day 4 的 src/ + tests/ 結構,可以把日誌設定集中到一個檔案:

my_project/
├─ src/my_project/
│   ├─ __init__.py
│   ├─ logging_config.py   # logging/structlog 設定
│   ├─ core.py
│   └─ adapters/
│       └─ web.py
└─ tests/
    └─ test_logging.py

logging_config.py

import logging
import structlog

def setup_logging():
    logging.basicConfig(level=logging.INFO)
    structlog.configure(
        processors=[
            structlog.processors.add_log_level,
            structlog.processors.TimeStamper(fmt="iso"),
            structlog.processors.JSONRenderer()
        ]
    )

然後在 main.py 或 FastAPI/CLI entrypoint 啟動時呼叫 setup_logging(),即可統一全專案日誌行為。


五、測試與驗證

pytest 提供 caplog fixture,可以驗證日誌輸出(延續 Day 11 的測試策略):

def test_logging_json(caplog):
    import json
    from my_project.logging_config import setup_logging
    import structlog

    setup_logging()
    logger = structlog.get_logger()

    logger.info("test_event", key="value")

    log = json.loads(caplog.text.splitlines()[0])
    assert log["event"] == "test_event"
    assert log["key"] == "value"


六、最佳實務清單(Checklist)

  • logging:小型專案或快速原型。
  • structlog:結構化、可擴充,適合進階專案。
  • JSON log + stdout:容器化與雲端最佳實務。
  • 集中設定檔:避免每個模組自行定義格式。
  • 測試日誌:確保關鍵事件被記錄,避免遺漏。

結語

日誌是專案的「黑盒紀錄器」。

從傳統字串到結構化 JSON,我們能讓日誌不只給人看,更能被機器理解與分析。

這正是工程化 Python 的精神:讓每一份輸出都能成為可靠的資料流。 🚀

明天 Day 14,我們將探討 失敗即常態:例外分層、重試與降級(tenacity),看看如何把「錯誤」設計成系統的一部分,而不是臨時的補丁。


上一篇
Day 12 -設定與祕密管理:dotenv、pydantic-settings、雲端祕密服務
下一篇
Day 14 - 失敗即常態:例外分層、重試與降級(tenacity)
系列文
30 天 Python 專案工坊:環境、結構、測試到部署全打通14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言