計装

OpenTelemetry Pythonの手動計装

計装とは、あなた自身がアプリにオブザーバビリティコードを追加する行為です。

アプリを計装する場合、あなたが使用する言語に対応したOpenTelemetry SDKを使用する必要があります。 次に、SDKを使用してOpenTelemetryを初期化し、APIを使用してコードを計装します。 これにより、アプリ本体だけでなく、計装が含まれるライブラリからもテレメトリーが出力されるようになります。

ライブラリを計装する場合、使用する言語に対応したOpenTelemetry APIパッケージのみをインストールしてます。 ライブラリ自体はテレメトリーを出力しません。 ライブラリの計装についての詳細は、ライブラリを参照してください。

OpenTelemetry APIとSDKについての詳細は、仕様を参照してください。

セットアップ

まず、APIとSDKパッケージがインストールされていることを確認します。

pip install opentelemetry-api
pip install opentelemetry-sdk

トレース

トレーサーの取得

トレースを開始するには、TracerProviderを初期化し、オプションでグローバルデフォルトとして設定する必要があります。

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
    BatchSpanProcessor,
    ConsoleSpanExporter,
)

provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)

# グローバルデフォルトのトレーサープロバイダーを設定する
trace.set_tracer_provider(provider)

# グローバルトレーサープロバイダーからトレーサーを作成する
tracer = trace.get_tracer("my.tracer.name")

スパンの作成

通常、スパンを作成するには、現在のスパンとして開始します。

def do_work():
    with tracer.start_as_current_span("span-name") as span:
        # 'span'が追跡する作業を行う
        print("doing some work...")
        # 'with'ブロックのスコープを抜けると、'span'は自動的に閉じられる

start_spanを使用して、現在のスパンにせずにスパンを作成することもできます。 これは通常、並行処理や非同期処理を追跡するために使用します。

ネストされたスパンの作成

別の操作の一部として追跡したい個別のサブ操作がある場合、その関係を表すスパンを作成できます。

def do_work():
    with tracer.start_as_current_span("parent") as parent:
        # 'parent'が追跡する作業を行う
        print("doing some work...")
        # ネストされた作業を追跡するためのネストされたスパンを作成する
        with tracer.start_as_current_span("child") as child:
            # 'child'が追跡する作業を行う
            print("doing some nested work...")
            # ネストされたスパンはスコープを抜けると閉じられる

        # このスパンもスコープを抜けると閉じられる

トレースの可視化ツールでスパンを表示すると、childparentの下にネストされたスパンとして追跡されます。

デコレーターによるスパンの作成

単一のスパンで関数全体の実行を追跡することはよくあります。 そのような場合、コードを削減するためにデコレーターを使用できます。

@tracer.start_as_current_span("do_work")
def do_work():
    print("doing some work...")

デコレーターの使用は、do_work()内でスパンを作成し、do_work()の完了時にスパンを終了することと同等です。

デコレーターを使用するには、関数宣言のグローバルスコープでtracerインスタンスが利用可能である必要があります。

現在のスパンの取得

ある時点で現在のスパンにアクセスし、追加情報を付与したい場合があります。

from opentelemetry import trace

current_span = trace.get_current_span()
# 'current_span'に情報を付与する

スパンへの属性の追加

属性を使用すると、スパンにキーバリューのペアを付与でき、追跡中の現在の操作に関するより多くの情報を保持できます。

from opentelemetry import trace

current_span = trace.get_current_span()

current_span.set_attribute("operation.value", 1)
current_span.set_attribute("operation.name", "Saying hello!")
current_span.set_attribute("operation.other-stuff", [1, 2, 3])

セマンティック属性の追加

セマンティック属性は、一般的な種類のデータに対するよく知られた命名規則として事前定義された属性です。 セマンティック属性を使用すると、システム全体でこの種の情報を正規化できます。

Pythonでセマンティック属性を使用するには、セマンティック規約パッケージがインストールされていることを確認してください。

pip install opentelemetry-semantic-conventions

その後、コード内で使用できます。

from opentelemetry import trace
from opentelemetry.semconv.trace import SpanAttributes

// ...

current_span = trace.get_current_span()
current_span.set_attribute(SpanAttributes.HTTP_METHOD, "GET")
current_span.set_attribute(SpanAttributes.HTTP_URL, "https://opentelemetry.io/")

イベントの追加

イベントは、スパンのライフタイム中に「何かが起こった」ことを表す、人間が読めるメッセージです。 プリミティブなログと考えることができます。

from opentelemetry import trace

current_span = trace.get_current_span()

current_span.add_event("Gonna try it!")

# 処理を行う

current_span.add_event("Did it!")

スパンは、別のスパンと因果関係を持つゼロ個以上のスパンリンクを持つように作成できます。 リンクを作成するにはスパンコンテキストが必要です。

from opentelemetry import trace

tracer = trace.get_tracer(__name__)

with tracer.start_as_current_span("span-1"):
    # 'span-1'が追跡する処理を行う
    ctx = trace.get_current_span().get_span_context()
    link_from_span_1 = trace.Link(ctx)

with tracer.start_as_current_span("span-2", links=[link_from_span_1]):
    # 'span-2'が追跡する処理を行う
    # 'span-2'のリンクは'span-1'と因果関係がありますが、
    # 子スパンではありません
    pass

スパンステータスの設定

ステータススパンに設定でき、通常はスパンが正常に完了しなかったことを示すために使用されます。 つまりErrorです。 デフォルトでは、すべてのスパンはUnsetであり、これはスパンがエラーなく完了したことを意味します。 Okステータスは、デフォルトのUnset(つまり「エラーなし」)のままにするのではなく、スパンを明示的に成功としてマークする必要がある場合に予約されています。

ステータスは、スパンが終了する前であればいつでも設定できます。

from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode

current_span = trace.get_current_span()

try:
    # 失敗する可能性のある処理
except:
    current_span.set_status(Status(StatusCode.ERROR))

スパンでの例外の記録

例外が発生した場合に記録することは良いプラクティスです。 スパンステータスの設定とあわせて行うことをお勧めします。

from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode

current_span = trace.get_current_span()

try:
    # 失敗する可能性のある処理

# コード内ではより具体的な例外をキャッチすることを検討してください
except Exception as ex:
    current_span.set_status(Status(StatusCode.ERROR))
    current_span.record_exception(ex)

デフォルトの伝搬(伝搬)フォーマットの変更

デフォルトでは、OpenTelemetry Pythonは以下の伝搬(伝搬)フォーマットを使用します。

  • W3C Trace Context
  • W3C Baggage

デフォルトを変更する必要がある場合は、環境変数またはコードで設定できます。

環境変数の使用

OTEL_PROPAGATORS環境変数にカンマ区切りのリストを設定できます。 受け入れられる値は以下のとおりです。

  • "tracecontext": W3C Trace Context
  • "baggage": W3C Baggage
  • "b3": B3 Single
  • "b3multi": B3 Multi
  • "jaeger": Jaeger
  • "xray": AWS X-Ray(サードパーティ)
  • "ottrace": OT Trace(サードパーティ)
  • "none": 自動設定されるプロパゲーターなし

デフォルトの設定はOTEL_PROPAGATORS="tracecontext,baggage"と同等です。

SDK APIの使用

かわりに、コード内でフォーマットを変更することもできます。

たとえば、ZipkinのB3伝搬(伝搬)フォーマットを使用する必要がある場合は、B3パッケージをインストールします。

pip install opentelemetry-propagator-b3

そして、トレースの初期化コードでB3プロパゲーターを設定します。

from opentelemetry.propagate import set_global_textmap
from opentelemetry.propagators.b3 import B3Format

set_global_textmap(B3Format())

環境変数はコードで設定されたものを上書きすることに注意してください。

参考資料

メトリクス

メトリクスの収集を開始するには、MeterProviderを初期化し、オプションでグローバルデフォルトとして設定する必要があります。

from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import (
    ConsoleMetricExporter,
    PeriodicExportingMetricReader,
)

metric_reader = PeriodicExportingMetricReader(ConsoleMetricExporter())
provider = MeterProvider(metric_readers=[metric_reader])

# グローバルデフォルトのメータープロバイダーを設定する
metrics.set_meter_provider(provider)

# グローバルメータープロバイダーからメーターを作成する
meter = metrics.get_meter("my.meter.name")

同期計装の作成と使用

計装は、アプリケーションの計測に使用されます。 同期計装は、リクエストの処理や別のサービスの呼び出しなど、アプリケーションやビジネスの処理ロジックと連動して使用されます。

まず、計装を作成します。 計装は通常、モジュールまたはクラスレベルで一度作成され、ビジネスロジックと連動して使用されます。 この例では、完了した作業項目の数をカウントするためにCounter計装を使用します。

work_counter = meter.create_counter(
    "work.counter", unit="1", description="Counts the amount of work done"
)

Counterのadd操作を使用して、以下のコードでは作業項目のタイプを属性としてカウントを1つ増やします。

def do_work(work_item):
    # 実行中の作業をカウントする
    work_counter.add(1, {"work.type": work_item.work_type})
    print("doing some work...")

非同期計装の作成と使用

非同期計装は、オンデマンドで呼び出されるコールバック関数を登録する方法を提供します。 これは、直接計装できない値を定期的に計測するのに便利です。 非同期計装は、メトリクス収集中に呼び出されるゼロ個以上のコールバックとともに作成されます。 各コールバックはSDKからのオプションを受け取り、その観測値を返します。

この例では、HTTPエンドポイントをスクレイピングして設定サーバーから提供される現在の設定バージョンを報告するために、非同期ゲージ計装を使用します。 まず、観測値を作成するコールバックを記述します。

from typing import Iterable
from opentelemetry.metrics import CallbackOptions, Observation


def scrape_config_versions(options: CallbackOptions) -> Iterable[Observation]:
    r = requests.get(
        "http://configserver/version_metadata", timeout=options.timeout_millis / 10**3
    )
    for metadata in r.json():
        yield Observation(
            metadata["version_num"], {"config.name": metadata["version_num"]}
        )

OpenTelemetryはタイムアウトを含むオプションをコールバックに渡すことに注意してください。 コールバックは無限にブロックしないよう、このタイムアウトを尊重する必要があります。 最後に、コールバックとともに計装を作成して登録します。

meter.create_observable_gauge(
    "config.version",
    callbacks=[scrape_config_versions],
    description="The active config version for each configuration",
)

参考資料

ログ

ログAPIおよびSDKは現在開発中です。 ログの収集を開始するには、LoggerProviderを初期化し、オプションでグローバルデフォルトとして設定する必要があります。 その後、Pythonの組み込みロギングモジュールを使用して、OpenTelemetryが処理できるログレコードを作成します。

import logging
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor, ConsoleLogRecordExporter # 1.39.0より前のバージョンではConsoleLogExporter
from opentelemetry._logs import set_logger_provider

provider = LoggerProvider()
processor = BatchLogRecordProcessor(ConsoleLogRecordExporter())
provider.add_log_record_processor(processor)
# グローバルデフォルトのロガープロバイダーを設定する
set_logger_provider(provider)

handler = LoggingHandler(level=logging.INFO, logger_provider=provider)
logging.basicConfig(handlers=[handler], level=logging.INFO)

logging.getLogger(__name__).info("This is an OpenTelemetry log record!")

参考資料

次のステップ

テレメトリーデータのエクスポートを行うために、適切なエクスポーターを設定することも必要です。


最終更新 April 18, 2026: Results from /fix directive (3e8b4048)