以下の内容はhttps://nikkie-ftnext.hatenablog.com/entry/uvicorn-practice-default-logging-equivalent-yamlより取得しました。


uvicorn素振りの記:ロギングをデフォルト設定と同値なYAMLファイルで設定する

はじめに

エンジニアニメ、ありがとうございました! nikkieです。

FastAPI製のアプリのサーブに使うASGIサーバ uvicornについて、素振りの模様をお届けします。

目次

ASGIサーバ uvicorn

encode1が開発するASGIサーバ

今回動作させるFastAPIアプリ

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def hello():
    return {"message": "Hello World!"}

動作環境

  • Python 3.12.6
  • FastAPI 0.115.6
    • fastapi-cli 0.0.7
  • uvicorn 0.34.0

uvicorn起動!(app.pyのappを指定しています)

% uvicorn app:app

別のターミナルで

% curl http://127.0.0.1:8000
{"message":"Hello World!"}

なおFastAPIもCLIを導入しており、fastapi devfastapi run経由でもuvicornを動かせます2

uvicornのロギングの設定

uvicorn app:appで起動すると以下のようなロギングがされます。
色付きです。

INFO:     Started server process [14182]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     127.0.0.1:58610 - "GET / HTTP/1.1" 200 OK

uvicornのドキュメントにはロギングの設定の項目があります。
https://www.uvicorn.org/settings/#logging

--log-config <path>

これを設定してみようと思ったのですが、今の私には初手でできませんでした。
どうやら標準ライブラリのlogging.configが前提知識としている模様です。

(なおfastapiコマンドは現時点では--log-configを未サポートのようでした。ヘルプメッセージに見つけられていません)

デフォルトの色付きのログの設定

ドキュメントの記載が控えめだったので、ソースコードに潜りました。
https://github.com/encode/uvicorn/blob/0.34.0/uvicorn/main.py#L428

log_config=LOGGING_CONFIG if log_config is None else log_config,

コマンドラインから--log-configが与えられない場合はLOGGING_CONFIGを渡しています。

LOGGING_CONFIGは以下にある辞書です。
https://github.com/encode/uvicorn/blob/0.34.0/uvicorn/config.py#L67-L98

ここでlogging.config.dictConfig
https://docs.python.org/ja/3/library/logging.config.html#logging.config.dictConfig

この辞書のスキーマはこちら
https://docs.python.org/ja/3/library/logging.config.html#dictionary-schema-details

uvicornのLOGGING_CONFIG(デフォルト)には以下が設定されています

  • version
  • disable_existing_loggers
  • formatters
  • handlers
  • loggers

理解を深めるために、これと同値なYAMLの設定ファイルを作ることにしました。

デフォルトのロギング設定と同値な設定ファイルを作る

フォーマッタに渡しているメッセージの書式、levelprefixclient_addrrequest_linestatus_codeは標準ライブラリにはないものみたいです。
https://docs.python.org/ja/3/library/logging.html#logrecord-attributes

ext://はこちら
https://docs.python.org/ja/3/library/logging.config.html#access-to-external-objects

例えば、リテラル文字列 'ext://sys.stderr' が設定中の値として与えられたら、この ext:// は剥ぎ取られ、この値の残りが普通のインポート機構で処理されます。

いざ--log-configを指定して起動!
ドキュメントによるとpip install uvicorn[standard]するとYAMLのパーサ(PyYAML)もインストールされるそうです3

% uvicorn app:app --log-config log_config.yaml
INFO:     Started server process [20424]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     127.0.0.1:59204 - "GET / HTTP/1.1" 200 OK

再現できています!✌️

defaultハンドラに設定されているdefaultフォーマッタをいじると、uvicorn.errorのログにも時刻を出すことができます!

formatters:
  default:
    class: uvicorn.logging.DefaultFormatter
-    format: '%(levelprefix)s %(message)s'
+    format: '%(asctime)s - %(name)s - %(levelprefix)s - %(message)s'

終わりに

uvicorn--log-configについて、デフォルト設定と同様のYAMLファイルを作って素振りしました。
標準ライブラリのlogging.configを使って、ロガーを設定しているんですね!

  • 今まで気づいていなかったが、uvicornのログは標準エラー出力(uvicorn.error)と標準出力(uvicorn.access)で分かれていた
  • uvicornは色付きで出力するフォーマッタを提供している(uvicorn.loggingDefaultFormatterAccessFormatter

ファイルを使ったuvicornのロガーの設定は理解できた気がするので、カスタマイズをしてみようと思います。
おそらくあるであろう続編でお会いしましょう!


  1. Django REST frameworkやHTTPX、Starletteもencode製です。開発集団...!
  2. 前者(dev)が開発用、後者(run)が本番用です
  3. pip install fastapi[standard]の中でuvicorn[standard]も指定されていました



以上の内容はhttps://nikkie-ftnext.hatenablog.com/entry/uvicorn-practice-default-logging-equivalent-yamlより取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14