タイトルの通り、FastAPI サーバのテレメトリデータを Azure Application Insights に送りたくて試行錯誤したのでそのメモ。
初期設定
azure-monitor-opentelemetry と opentelemetry-instrumentation-fastapi を入れて、下記のように設定すれば動いた。
from os import getenv
from azure.monitor.opentelemetry import configure_azure_monitor
from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
app = FastAPI()
APPLICATIONINSIGHTS_CONNECTION_STRING = getenv("APPLICATIONINSIGHTS_CONNECTION_STRING")
if APPLICATIONINSIGHTS_CONNECTION_STRING:
configure_azure_monitor(connection_string=APPLICATIONINSIGHTS_CONNECTION_STRING)
FastAPIInstrumentor.instrument_app(app)
ただしハマったところとして、Application Insights リソースが配置されているリソースグループ名に日本語が含まれていた場合にデータを受け取ってくれなかった。リソースグループ名に非 ASCII 文字を使うのはやめよう...。
Exception を収集する
デフォルトで Exception は収集してくれているっぽい。
試しにこういうエンドポイントを作ってアクセスしてみると、Application Insights の画面でエラー情報を見ることができた。
@app.get("/")
async def get_root():
1 / 0 # ERROR
アクセスしてきたユーザの ID を収集する
デフォルトでリクエストログは収集してくれているが、そのままだと「誰が」アクセスしてきたログなのかわからないので、ユーザ ID を追加で送信できるようにする。
from os import getenv
from azure.monitor.opentelemetry import configure_azure_monitor
from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor, Span
app = FastAPI()
APPLICATIONINSIGHTS_CONNECTION_STRING = getenv("APPLICATIONINSIGHTS_CONNECTION_STRING")
if APPLICATIONINSIGHTS_CONNECTION_STRING:
def server_request_hook(span: Span, scope: dict):
if span and span.is_recording():
try:
# Application Insights に送るデータにユーザ ID を追加する
user_id = ... # TODO: よしなにユーザ ID を取得する
span.set_attribute("enduser.id", user_id)
except KeyError:
pass
configure_azure_monitor(connection_string=APPLICATIONINSIGHTS_CONNECTION_STRING)
FastAPIInstrumentor.instrument_app(app, server_request_hook=server_request_hook)
FastAPIInstrumentor の server_request_hook でカスタム属性を設定することができて1、Azure Application Insights の場合は enduser.id
属性を送信すると requests.user_Id
として保存してくれるらしい。2
server_request_hook がいつ実行されるのかは詳しくわかっていないが、引数 scope
から得られる情報を見る限りではレスポンスを返したあとっぽい。