CLOVER🍀

That was when it all began.

PythonのOpenTelemetry計装ライブラリーの導入方法がよくわからなかったので、pipとuvを使ってFastAPIで試してみる

これは、なにをしたくて書いたもの?

Grafana Tempoにトレースシグナルを送信しようとPythonで簡単なアプリケーションを作成したら、
OpenTelemetry計装ライブラリーの導入方法でちょっと苦労したのでちゃんと見てみようということで…。

Grafana Tempo 2.8+MinIO+GrafanaをUbuntu Linux 24.04 LTSにインストールして、トレースデータを見てみる - CLOVER🍀

特にuvと組み合わせた時にハマったので…。

OpenTelemetryのPython APISDK

OpenTelemetryのPython APISDKに関するドキュメントはこちらです。

Python | OpenTelemetry

一方で、ゼロコード計装と呼ばれるものについてのドキュメントはこちらです。

Python zero-code instrumentation | OpenTelemetry

基本的にはゼロコード計装に焦点を当てていこうと思います。

まず、Getting Startedの計装のインストールですが、opentelemetry-distroというパッケージをインストールして
opentelemetry-bootstrap -a installコマンドを実行しています。

$ pip install opentelemetry-distro
$ opentelemetry-bootstrap -a install

Getting Started / Instrumentation

これ、なんでしょうね?

このページではFlaskに対する計装ライブラリーの話をしているようですが、これでFlaskの計装ライブラリーがインストール
されると書かれています。

This will install Flask instrumentation.

そして、アプリケーションはopentelemetry-instrumentコマンド経由で実行するようです。

$ opentelemetry-instrument \
    --traces_exporter console \
    --metrics_exporter console \
    --logs_exporter console \
    --service_name dice-server \
    flask run -p 8080

OpenTelemetry Protocolで送信する場合は、opentelemetry-exporter-otlpというライブラリーが必要になります。

$ pip install opentelemetry-exporter-otlp

Getting Started / Send telemetry to an OpenTelemetry Collector

まあ、これはいいでしょう、と。

各ライブラリー向けには、opentelemetry-instrumentation-[ライブラリー名]で計装ライブラリーがあります。

$ pip install opentelemetry-instrumentation-{instrumented-library}

Using instrumentation libraries / Setup

計装ライブラリーはこちらですね。

https://github.com/open-telemetry/opentelemetry-python-contrib/tree/v0.57b0/instrumentation

ドキュメントはこちらになるようです。

OpenTelemetry-Python-Contrib — OpenTelemetry Python Contrib documentation

よくわからないのがこのあたりですね。

$ pip install opentelemetry-distro
$ opentelemetry-bootstrap -a install

OpenTelemetry Distroを見てみる

opentelemetry-distroはユーザーがよく使うオプションの一部を自動設定するものだそうです。

In order to make using OpenTelemetry and auto-instrumentation as quick as possible without sacrificing flexibility, OpenTelemetry distros provide a mechanism to automatically configure some of the more common options for users.

OpenTelemetry Distro | OpenTelemetry

ソースコードを見たところでは、こういうところでしょうか…?

    # pylint: disable=no-self-use
    def _configure(self, **kwargs):
        os.environ.setdefault(OTEL_TRACES_EXPORTER, "otlp")
        os.environ.setdefault(OTEL_METRICS_EXPORTER, "otlp")
        os.environ.setdefault(OTEL_LOGS_EXPORTER, "otlp")
        os.environ.setdefault(OTEL_EXPORTER_OTLP_PROTOCOL, "grpc")

https://github.com/open-telemetry/opentelemetry-python-contrib/blob/v0.57b0/opentelemetry-distro/src/opentelemetry/distro/__init__.py#L37-L42

実際に使うのはこちらのようなので、このスクリプトを見てみましょう。

$ opentelemetry-bootstrap -a install

こういう環境で

$ python3 --version
Python 3.12.3


$ pip3 --version
pip 24.0 from /usr/lib/python3/dist-packages/pip (python 3.12)

仮想環境を作成してインストール。

$ python3 -m venv .venv
$ . .venv/bin/activate
$ pip3 install opentelemetry-distro


$ pip3 list
Package                            Version
---------------------------------- -------
importlib_metadata                 8.7.0
opentelemetry-api                  1.36.0
opentelemetry-distro               0.57b0
opentelemetry-instrumentation      0.57b0
opentelemetry-sdk                  1.36.0
opentelemetry-semantic-conventions 0.57b0
packaging                          25.0
pip                                24.0
typing_extensions                  4.14.1
wrapt                              1.17.2
zipp                               3.23.0

スクリプトの中身はこんな感じでした。

$ cat $(which opentelemetry-bootstrap)
#!/path/to/.venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from opentelemetry.instrumentation.bootstrap import run
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(run())

つまり、こちらですね。

https://github.com/open-telemetry/opentelemetry-python-contrib/blob/v0.57b0/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py

どうやらinstallrequirementsというアクションがあるようです。これが-aで指定しているアクションですね。
デフォルトはrequirementsのようです。

https://github.com/open-telemetry/opentelemetry-python-contrib/blob/v0.57b0/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py#L162-L173

試しにFastAPIをインストールしてみましょう。

$ pip3 install 'fastapi[standard]'

opentelemetry-bootstrapコマンドを実行すると、こういう結果になります。

$ opentelemetry-bootstrap
opentelemetry-instrumentation-asyncio==0.57b0
opentelemetry-instrumentation-dbapi==0.57b0
opentelemetry-instrumentation-logging==0.57b0
opentelemetry-instrumentation-sqlite3==0.57b0
opentelemetry-instrumentation-threading==0.57b0
opentelemetry-instrumentation-urllib==0.57b0
opentelemetry-instrumentation-wsgi==0.57b0
opentelemetry-instrumentation-click==0.57b0
opentelemetry-instrumentation-fastapi==0.57b0
opentelemetry-instrumentation-httpx==0.57b0
opentelemetry-instrumentation-jinja2==0.57b0
opentelemetry-instrumentation-starlette==0.57b0
opentelemetry-instrumentation-tortoiseorm==0.57b0
opentelemetry-instrumentation-urllib3==0.57b0

現在のpipでインストールしているライブラリーから、必要な計装ライブラリーを選んでいるようです。

ちなみに、こちらでも同じです。

$ opentelemetry-bootstrap -a requirements

なので、この結果をインストールするのがこちらのスクリプト、というわけですね。

$ opentelemetry-bootstrap -a install

プロジェクトにインストールされているライブラリーの確認は、こちらのスクリプト経由で

https://github.com/open-telemetry/opentelemetry-python/blob/v1.36.0/opentelemetry-api/src/opentelemetry/util/_importlib_metadata.py

Pythonの標準ライブラリーで参照しているようです。

importlib.metadata -- パッケージメタデータへのアクセス — Python 3.12.12 ドキュメント

opentelemetry-instrumentコマンドは?

それから、アプリケーションを起動する時にはopentelemetry-instrumentコマンド経由になっていましたね。

$ opentelemetry-instrument \
    --traces_exporter console \
    --metrics_exporter console \
    --logs_exporter console \
    --service_name dice-server \
    flask run -p 8080

これはなんでしょう?

OpenTelemetry Distroをインストールすると使えるようになっているので、確認してみます。

$ cat $(which opentelemetry-instrument)
#!/path/to/.venv/bin/python3
# -*- coding: utf-8 -*-
import re
import sys
from opentelemetry.instrumentation.auto_instrumentation import run
if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(run())

実体はこのスクリプトのようですね。

https://github.com/open-telemetry/opentelemetry-python-contrib/blob/v0.57b0/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py

スクリプトではrun関数を呼び出しているだけですが、実際のセットアップはinitialize関数で行われます。
initialize関数がどうやって呼び出されるかというと、以下のスクリプトですね。

https://github.com/open-telemetry/opentelemetry-python-contrib/blob/v0.57b0/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py

これはこちらの仕組みを利用しているようです。

site --- サイト固有の設定フック — Python 3.12.12 ドキュメント

なんとなく、ここまでの流れはわかった感じです。

uvとの組み合わせ

ところでuvでハマったということを書きましたが、ドキュメントにトラブルシュートの方法が載っているくらいです。

Troubleshooting Python automatic instrumentation issues / Installation issues / Bootstrap using uv

少し試してみましょう。uvでFastAPIとopentelemetry-distroをインストール。

$ uv add 'fastapi[standard]'
$ uv add opentelemetry-distro

そしてopentelemetry-bootstrap -a installを実行すると、pip installに失敗することになります。

$ uv run opentelemetry-bootstrap -a install
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-asyncio==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-dbapi==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-logging==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-sqlite3==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-threading==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-urllib==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-wsgi==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-click==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-fastapi==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-httpx==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-jinja2==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-starlette==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-tortoiseorm==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip
Command '['/path/to/.venv/bin/python3', '-m', 'pip', 'install', '-U', '--upgrade-strategy', 'only-if-needed', 'opentelemetry-instrumentation-urllib3==0.57b0']' returned non-zero exit status 1.
/path/to/.venv/bin/python3: No module named pip

よって、回避方法としてはこうしていたわけですね。

$ uv run opentelemetry-bootstrap -a requirements | uv pip install --requirement -

ただ、これだとpyproject.tomlでの管理からは外れるんですよね…。uv.lockにも載りません。

なので、注意事項としてライブラリーを更新した場合は計装ライブラリーを再インストール、つまり回避方法に記載されている
コマンドを実行することが書かれています。

Please note that you have to reinstall the auto instrumentation every time you run uv sync or update existing packages. It is therefore recommended to make the installation part of your build pipeline.

どうなんでしょうね、以下のコマンドではダメなのでしょうか?

$ uv run opentelemetry-bootstrap -a requirements | xargs uv add

uvで管理すること自体がダメなのかがよくわかりません。

もとのissueを見ると、インストールが失敗するだけのようですが…?

Add `uv` package manager instructions to Python zero-code docs by jord1e · Pull Request #5635 · open-telemetry/opentelemetry.io · GitHub

それでは、だいたい確認できたので少し動かしてみましょう。

お題

FastAPIを使った簡単なアプリケーションにOpenTelemetry計装ライブラリーを組み込んで、メトリクスを送信してみます。

こういう感じにしましょう。

flowchart LR
    A["FastAPI"] -- OTLP over http/protobuf --> B["OpenTelemetry Collector"]
    B -- Remote Write --> C["Prometheus"]

ソースコードはこちらにしましょう。

OpenTelemetry FastAPI Instrumentation — OpenTelemetry Python Contrib documentation

またpipとuvの2種類で試してみます。

環境

今回の環境はこちらです。

$ python3 --version
Python 3.12.3


$ pip3 --version
pip 24.0 from /usr/lib/python3/dist-packages/pip (python 3.12)


$ uv --version
uv 0.8.8

OpenTelemetry Collector Contrib。172.18.0.2で動作しているものとします。

$ otelcol-contrib --version
otelcol-contrib version 0.131.1

Prometheus。172.18.0.3で動作しているものとします。

$ ./prometheus --version
prometheus, version 3.5.0 (branch: HEAD, revision: 8be3a9560fbdd18a94dedec4b747c35178177202)
  build user:       root@4451b64cb451
  build date:       20250714-16:15:23
  go version:       go1.24.5
  platform:         linux/amd64
  tags:             netgo,builtinassets

またPrometheusはリモート書き込みを有効にして起動しているものとします。

$ ./prometheus --web.enable-remote-write-receiver

準備

OpenTelemetry Collector Contribの設定。

/etc/otelcol-contrib/config.yaml

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:

exporters:
  prometheusremotewrite:
    endpoint: "http://172.18.0.3:9090/api/v1/write"
    resource_to_telemetry_conversion:
      enabled: true

service:
  pipelines:
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheusremotewrite]

Prometheusの設定。

prometheus.yml

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:

Prometheusはスクレイピング対象なしです。

pipで試す

最初はpipで試してみます。

$ mkdir instrument-fastapi-pip
$ cd instrument-fastapi-pip
$ python3 -m venv .venv
$ . .venv/bin/activate

FastAPIとOpenTelemetry Distro、Exporterのインストール。

$ pip3 install 'fastapi[standard]'
$ pip3 install opentelemetry-distro opentelemetry-exporter-otlp

計装ライブラリーをインストール。

$ opentelemetry-bootstrap -a install

インストールされたライブラリーの一覧。

$ pip3 list
Package                                   Version
----------------------------------------- --------
annotated-types                           0.7.0
anyio                                     4.10.0
asgiref                                   3.9.1
certifi                                   2025.8.3
charset-normalizer                        3.4.3
click                                     8.2.1
dnspython                                 2.7.0
email_validator                           2.2.0
fastapi                                   0.116.1
fastapi-cli                               0.0.8
fastapi-cloud-cli                         0.1.5
googleapis-common-protos                  1.70.0
grpcio                                    1.74.0
h11                                       0.16.0
httpcore                                  1.0.9
httptools                                 0.6.4
httpx                                     0.28.1
idna                                      3.10
importlib_metadata                        8.7.0
Jinja2                                    3.1.6
markdown-it-py                            3.0.0
MarkupSafe                                3.0.2
mdurl                                     0.1.2
opentelemetry-api                         1.36.0
opentelemetry-distro                      0.57b0
opentelemetry-exporter-otlp               1.36.0
opentelemetry-exporter-otlp-proto-common  1.36.0
opentelemetry-exporter-otlp-proto-grpc    1.36.0
opentelemetry-exporter-otlp-proto-http    1.36.0
opentelemetry-instrumentation             0.57b0
opentelemetry-instrumentation-asgi        0.57b0
opentelemetry-instrumentation-asyncio     0.57b0
opentelemetry-instrumentation-click       0.57b0
opentelemetry-instrumentation-dbapi       0.57b0
opentelemetry-instrumentation-fastapi     0.57b0
opentelemetry-instrumentation-grpc        0.57b0
opentelemetry-instrumentation-httpx       0.57b0
opentelemetry-instrumentation-jinja2      0.57b0
opentelemetry-instrumentation-logging     0.57b0
opentelemetry-instrumentation-requests    0.57b0
opentelemetry-instrumentation-sqlite3     0.57b0
opentelemetry-instrumentation-starlette   0.57b0
opentelemetry-instrumentation-threading   0.57b0
opentelemetry-instrumentation-tortoiseorm 0.57b0
opentelemetry-instrumentation-urllib      0.57b0
opentelemetry-instrumentation-urllib3     0.57b0
opentelemetry-instrumentation-wsgi        0.57b0
opentelemetry-proto                       1.36.0
opentelemetry-sdk                         1.36.0
opentelemetry-semantic-conventions        0.57b0
opentelemetry-util-http                   0.57b0
packaging                                 25.0
pip                                       24.0
protobuf                                  6.31.1
pydantic                                  2.11.7
pydantic_core                             2.33.2
Pygments                                  2.19.2
python-dotenv                             1.1.1
python-multipart                          0.0.20
PyYAML                                    6.0.2
requests                                  2.32.4
rich                                      14.1.0
rich-toolkit                              0.14.9
rignore                                   0.6.4
sentry-sdk                                2.34.1
shellingham                               1.5.4
sniffio                                   1.3.1
starlette                                 0.47.2
typer                                     0.16.0
typing_extensions                         4.14.1
typing-inspection                         0.4.1
urllib3                                   2.5.0
uvicorn                                   0.35.0
uvloop                                    0.21.0
watchfiles                                1.1.0
websockets                                15.0.1
wrapt                                     1.17.2
zipp                                      3.23.0

スクリプトを作成。

app.py

import fastapi
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

app = fastapi.FastAPI()

@app.get("/foobar")
async def foobar():
    return {"message": "hello world"}

FastAPIInstrumentor.instrument_app(app)

※ opentelemetry-instrument経由で使うのであれば、FastAPIInstrumentorは使わなくてもよかったです…

Pythonアプリケーションに対して、opentelemetry-instrumentを使わずにOpenTelemetryのゼロ計装を行う - CLOVER🍀

起動して

$ fastapi run app.py

動作確認。

$ curl localhost:8000/foobar
{"message":"hello world"}

OKですね。

OpenTelemetryに関する環境変数を設定。

$ export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
$ export OTEL_TRACES_EXPORTER=none
$ export OTEL_METRICS_EXPORTER=otlp
$ export OTEL_LOGS_EXPORTER=none
$ export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://172.18.0.2:4318/v1/metrics
$ export OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf
$ export OTEL_SERVICE_NAME=app

opentelemetry-instrument越しに起動。

$ opentelemetry-instrument fastapi run app.py

あとはリクエストを送り続けて

$ curl localhost:8000/foobar
{"message":"hello world"}

Prometheus側を見ると、メトリクスが送信されていることが確認できます。

uvで試す

次はuvで試してみましょう。

$ uv init --vcs none instrument-fastapi-uv
$ cd instrument-fastapi-uv

ライブラリーをインストール。

$ uv add 'fastapi[standard]'
$ uv add opentelemetry-exporter-otlp
$ uv add --dev opentelemetry-distro

opentelemetry-distroは、開発用パッケージではないのかなと思います。
※違ったかもしれません…

計装ライブラリーをインストールしてみましょう。

$ uv run opentelemetry-bootstrap -a requirements | xargs uv add

pyproject.tomlはこうなりました。

pyproject.toml

[project]
name = "instrument-fastapi-uv"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "fastapi[standard]>=0.116.1",
    "opentelemetry-exporter-otlp>=1.36.0",
    "opentelemetry-instrumentation-asyncio==0.57b0",
    "opentelemetry-instrumentation-click==0.57b0",
    "opentelemetry-instrumentation-dbapi==0.57b0",
    "opentelemetry-instrumentation-fastapi==0.57b0",
    "opentelemetry-instrumentation-grpc==0.57b0",
    "opentelemetry-instrumentation-httpx==0.57b0",
    "opentelemetry-instrumentation-jinja2==0.57b0",
    "opentelemetry-instrumentation-logging==0.57b0",
    "opentelemetry-instrumentation-requests==0.57b0",
    "opentelemetry-instrumentation-sqlite3==0.57b0",
    "opentelemetry-instrumentation-starlette==0.57b0",
    "opentelemetry-instrumentation-threading==0.57b0",
    "opentelemetry-instrumentation-tortoiseorm==0.57b0",
    "opentelemetry-instrumentation-urllib==0.57b0",
    "opentelemetry-instrumentation-urllib3==0.57b0",
    "opentelemetry-instrumentation-wsgi==0.57b0",
]

[dependency-groups]
dev = [
    "opentelemetry-distro>=0.57b0",
]

インストールされたライブラリーの一覧。

$ uv pip list
Package                                   Version
----------------------------------------- --------
annotated-types                           0.7.0
anyio                                     4.10.0
asgiref                                   3.9.1
certifi                                   2025.8.3
charset-normalizer                        3.4.3
click                                     8.2.1
dnspython                                 2.7.0
email-validator                           2.2.0
fastapi                                   0.116.1
fastapi-cli                               0.0.8
fastapi-cloud-cli                         0.1.5
googleapis-common-protos                  1.70.0
grpcio                                    1.74.0
h11                                       0.16.0
httpcore                                  1.0.9
httptools                                 0.6.4
httpx                                     0.28.1
idna                                      3.10
importlib-metadata                        8.7.0
jinja2                                    3.1.6
markdown-it-py                            3.0.0
markupsafe                                3.0.2
mdurl                                     0.1.2
opentelemetry-api                         1.36.0
opentelemetry-distro                      0.57b0
opentelemetry-exporter-otlp               1.36.0
opentelemetry-exporter-otlp-proto-common  1.36.0
opentelemetry-exporter-otlp-proto-grpc    1.36.0
opentelemetry-exporter-otlp-proto-http    1.36.0
opentelemetry-instrumentation             0.57b0
opentelemetry-instrumentation-asgi        0.57b0
opentelemetry-instrumentation-asyncio     0.57b0
opentelemetry-instrumentation-click       0.57b0
opentelemetry-instrumentation-dbapi       0.57b0
opentelemetry-instrumentation-fastapi     0.57b0
opentelemetry-instrumentation-grpc        0.57b0
opentelemetry-instrumentation-httpx       0.57b0
opentelemetry-instrumentation-jinja2      0.57b0
opentelemetry-instrumentation-logging     0.57b0
opentelemetry-instrumentation-requests    0.57b0
opentelemetry-instrumentation-sqlite3     0.57b0
opentelemetry-instrumentation-starlette   0.57b0
opentelemetry-instrumentation-threading   0.57b0
opentelemetry-instrumentation-tortoiseorm 0.57b0
opentelemetry-instrumentation-urllib      0.57b0
opentelemetry-instrumentation-urllib3     0.57b0
opentelemetry-instrumentation-wsgi        0.57b0
opentelemetry-proto                       1.36.0
opentelemetry-sdk                         1.36.0
opentelemetry-semantic-conventions        0.57b0
opentelemetry-util-http                   0.57b0
packaging                                 25.0
protobuf                                  6.31.1
pydantic                                  2.11.7
pydantic-core                             2.33.2
pygments                                  2.19.2
python-dotenv                             1.1.1
python-multipart                          0.0.20
pyyaml                                    6.0.2
requests                                  2.32.4
rich                                      14.1.0
rich-toolkit                              0.14.9
rignore                                   0.6.4
sentry-sdk                                2.34.1
shellingham                               1.5.4
sniffio                                   1.3.1
starlette                                 0.47.2
typer                                     0.16.0
typing-extensions                         4.14.1
typing-inspection                         0.4.1
urllib3                                   2.5.0
uvicorn                                   0.35.0
uvloop                                    0.21.0
watchfiles                                1.1.0
websockets                                15.0.1
wrapt                                     1.17.2
zipp                                      3.23.0

スクリプトは、ファイル名が変わりました…。

main.py

import fastapi
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

app = fastapi.FastAPI()

@app.get("/foobar")
async def foobar():
    return {"message": "hello world"}

FastAPIInstrumentor.instrument_app(app)

※ opentelemetry-instrument経由で使うのであれば、FastAPIInstrumentorは使わなくてもよかったです…

Pythonアプリケーションに対して、opentelemetry-instrumentを使わずにOpenTelemetryのゼロ計装を行う - CLOVER🍀

あとは環境変数を設定して

$ export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
$ export OTEL_TRACES_EXPORTER=none
$ export OTEL_METRICS_EXPORTER=otlp
$ export OTEL_LOGS_EXPORTER=none
$ export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://172.18.0.2:4318/v1/metrics
$ export OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf
$ export OTEL_SERVICE_NAME=app

opentelemetry-instrument越しに起動。

$ uv run opentelemetry-instrument fastapi run main.py

リクエストを送り続けて

$ curl localhost:8000/foobar
{"message":"hello world"}

Prometheusで確認。

OKですね。

おわりに

PythonのOpenTelemetry計装ライブラリーの導入方法がよくわからなかったので、pipとuvを使ってFastAPIで試してみました。

OpenTelemetryの計装ライブラリーは前にJavaとNode.jsを見たのですが、PythonPythonでだいぶ雰囲気が違いますね…。

最初はよくわからなかったのですが、ひとつひとつ紐解くとやっていることがなんとなくわかった気がします。それから、
知らないPythonの標準ライブラリーもいろいろと出てきましたし。

どちらにしても、これでPythonでOpenTelemetryの計装ライブラリーを扱えそうです。