iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
Software Development

FastAPI 開發筆記:從新手到專家的成長之路系列 第 20

[Day 20] 日誌系統 (一):Logging

  • 分享至 

  • xImage
  •  

不知道大家有沒有想過,為什會在啟動 FastAPI 時,terminal 會出現這些訊息

這其實是因為 uvicorn 預設使用了 logging 模組 (Python 內建的模組),幫我們在特定的時機記錄下這些日誌 (log),包含:啟動 server、收到 API 請求等。

這邊使用的 Log 系統對後端 server 很重要,它幫我們記錄了這個 server 所發生的大小事,可以讓我們查看過去到底做了哪些事情,以及當發生意外時,讓我們可以透過 log 所紀錄的錯誤訊息找出發生問題的原因。

但是,儘管已經有預設的 log 系統,但目前的設定其實不太好用,主要的問題有以下三點:

  1. 沒有辦法儲存
    一般來說,log 就是為了方便日後查看用,因此需要找地方儲存 log,不論是直接存在本地或是傳送到 log server 都可以。
  2. 沒有辦法自己控制紀錄 log 的時機
    有時候我們希望有 log 紀錄的地方與預設設定不同,因此需要有辦法自己決定何時要產生 log 紀錄
  3. 沒有辦法調整 log 的模板與內容
    有時候預設的資訊並不符合我們的期待,我們會希望記錄更多詳細資訊 (例如:當下的時間),或甚至調整模板,方便 log server 進行解析

因此接下來,接下來會開始介紹如何在 FastAPI 加上符合自己需求的 log 系統。

如果想要在 FastAPI 擁有符合自己需求的 log 系統,大方向大概有兩個

  1. 自己添加新的 logging 設定,與預設的 log 獨立
  2. 修改預設的 logging 的設定

今天以介紹第一個做法為主~

在開始之前,讓我們先來看看 logging 這個模組

logging 簡介

首先,我們先來看一個範例

# log.py
import logging

logging.warning('Watch out!')  # will print a message to the console
logging.info('I told you so')  # will not print anything

這是執行結果

你會發現,loggingprint 有點像,它會在 terminal 印出訊息,但以目前的範例程式來看,只有 warning 的才有印出來,info 卻沒有。

這是因為預設的設定是 log level 要 WARNING 等級以上的才會印出來 (可以調整),常見的 log level 有四個,根據嚴重程度由輕到重依序是

  1. DEBUG
  2. INFO
  3. WARNING
  4. ERROR

完整的可以看這邊

logging 設定

如果要進行設定,可以用 logging.basicConfig()

import logging
logging.basicConfig(filename='example.log', level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
logging.error('And non-ASCII stuff, too, like Øresund and Malmö')

執行後你會發現,terminal 沒有印出訊息了,取而代之的是多了一個 example.log,內容如下

經過觀察可以發現,它有一個預設模板,會一併紀錄 log level 和 root,而這個 root 就是預設的 logger (日誌紀錄器) 的名稱。

如果想要改模板,可以用 logging.basicConfig()format 參數

import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is when this event was logged.')

此時就會看到 terminal 樣式變成這樣了

format 內的參數可以參考這邊

logger

在上面的例子中,你會發現你只能在把 log 「存下來」和「顯示在 terminal」兩個做法中選一個,但這其實不是很方便,現實中往往我們會需要這兩個同時都有,或甚至再多加一個把 log 「送到 log server」,這時,我們就可以使用 logger

讓我們用 logger 把上面的範例整理在一起

import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

ch = logging.StreamHandler()
fh = logging.FileHandler(filename='example.log')
formatter = logging.Formatter("%(asctime)s %(message)s")

ch.setFormatter(formatter)
fh.setFormatter(formatter)
logger.addHandler(ch)
logger.addHandler(fh)

logger.warning('is when this event was logged.')

如此一來,呼叫一次 logger.warning,就可以同時存在 example.log 中和顯示在 terminal 了,而且都是使用我們自訂的格式

當然,兩邊的格式也可以不相同

這樣做還有一個好處,就是可以把 log 設定獨立到一個檔案,其他地方只要 import 這個設定好的 logger 就好了。

在 FastAPI 添加 logging

上面有提到,想要在 FastAPI 添加 log 系統的其中一個做法就是直接添加新的 log 設定,因此最簡單的做法如下

# mian.py
from fastapi import FastAPI
import logging

logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)

app = FastAPI()

@app.get("/")
async def root():
    logging.info('Test info log')
    return {"message": "Hello World"}

啟動 FastAPI 後,用 Postman 觸發 API 後可以在 terminal 看到我們自訂的 log 訊息 (暫時不用存的,直接顯示在 terminal)

也可以使用 logger 來讓主程式乾淨一些

# mian.py
from fastapi import FastAPI
from log import logger

app = FastAPI()

@app.get("/")
async def root():
    logger.info('Test info log')
    return {"message": "Hello World"}


# log.py
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

ch = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s %(message)s")
ch.setFormatter(formatter)

logger.addHandler(ch)

重點回顧

今天開啟新的系列 ── log 系統,目前介紹了

  1. logging 模組
  2. logger
  3. 如何在 FastAPI 添加新的 log 系統

明天的內容我要再規劃一下,這次就不先預告了 XD


上一篇
[Day 19] 錯誤處理 (二):流程優化 與 客製化 HTTPException
下一篇
[Day 21] 日誌系統 (二):操作預設的 Uvicorn logger
系列文
FastAPI 開發筆記:從新手到專家的成長之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言