伝搬

Python SDK のコンテキスト伝搬

伝搬は、サービスやプロセス間でデータを移動させる仕組みです。 トレースに限ったものではありませんが、プロセス境界やネットワーク境界をまたいで任意に分散したサービス群の間で、システムに関する因果関係の情報をトレースが構築できるようにするものです。

OpenTelemetry は、W3C Trace Context の HTTP ヘッダーを使用して、リモートサービスにコンテキストを伝搬するためのテキストベースの方法を提供します。

自動的なコンテキスト伝搬

Jinja2、Flask、Django、Celery などの一般的な Python フレームワークやライブラリ向けの計装ライブラリは、サービス間でコンテキストを自動的に伝搬します。

手動でのコンテキスト伝搬

次の汎用的な例は、トレースコンテキストを手動で伝搬する方法を示しています。

まず、送信側のサービスで現在の context を注入します。

from flask import Flask
import requests
from opentelemetry import trace, baggage
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from opentelemetry.baggage.propagation import W3CBaggagePropagator
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor

app = Flask(__name__)

trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

tracer = trace.get_tracer(__name__)

@app.route('/')
def hello():
    with tracer.start_as_current_span("api1_span") as span:
        ctx = baggage.set_baggage("hello", "world")

        headers = {}
        W3CBaggagePropagator().inject(headers, ctx)
        TraceContextTextMapPropagator().inject(headers, ctx)
        print(headers)

        response = requests.get('http://127.0.0.1:5001/', headers=headers)
        return f"Hello from API 1! Response from API 2: {response.text}"

if __name__ == '__main__':
    app.run(port=5002)

受信側のサービスでは、たとえば解析済みの HTTP ヘッダーから context を抽出し、それを現在のトレースコンテキストとして設定します。

from flask import Flask, request
from opentelemetry import trace, baggage
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, BatchSpanProcessor
from opentelemetry.baggage.propagation import W3CBaggagePropagator

app = Flask(__name__)

trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))

tracer = trace.get_tracer(__name__)

@app.route('/')
def hello():
    # 例: API 2 のリクエストで受信したヘッダーをログに出力
    headers = dict(request.headers)
    print(f"Received headers: {headers}")
    carrier ={'traceparent': headers['Traceparent']}
    ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
    print(f"Received context: {ctx}")

    b2 ={'baggage': headers['Baggage']}
    ctx2 = W3CBaggagePropagator().extract(b2, context=ctx)
    print(f"Received context2: {ctx2}")

    # 新しいスパンを開始
    with tracer.start_span("api2_span", context=ctx2):
       # 伝搬されたコンテキストを使用
        print(baggage.get_baggage('hello', ctx2))
        return "Hello from API 2!"

if __name__ == '__main__':
    app.run(port=5001)

このようにして、デシリアライズされたアクティブなコンテキストが得られたら、別のサービスからの同じトレースの一部であるスパンを作成できます。

sqlcommenter

一部の Python 計装は sqlcommenter をサポートしており、コンテキスト情報でデータベースクエリ文を拡張します。 sqlcommenter を有効にして行われたクエリには、設定可能なキーと値のペアが追加されます。 たとえば、次のようになります。

"select * from auth_users; /*traceparent=00-01234567-abcd-01*/"

これは、データベースのログレコードが有効になっている場合に、データベースクライアントとサーバー間のコンテキスト伝搬をサポートします。 詳細は、以下を参照してください。

次のステップ

伝搬の詳細については、Propagators API を参照してください。