otel-python-style について
Python アプリケーションに OpenTelemetry の規約を適用するコーディングスキルです。トレース、エラー、ログ、初期化、メトリクスを扱います。
主な機能
- 01モジュールスコープのトレースとメトリクス
- 02デコレーターとコンテキストマネージャーによるスパン
- 03例外記録とステータス設定
- 04OTLP ログ設定の指針
- 05メトリクス名とカーディナリティの指針
活用シーン
- 01同期・非同期処理へのトレース追加
- 02アクティブなスパンへの例外記録
- 03ログの OTLP 転送設定
- 04LLM トークンとリクエスト指標の追跡
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ superloglabs/ skills --skill otel-python-styleインストール後、Claude Code で/otel-python-styleを入力して読み込まれたか確認します。
詳細
OTel Python スタイル
OTel オブジェクトはモジュールスコープで取得します。
from opentelemetry import metrics, trace
from opentelemetry.trace import Status, StatusCode
tracer = trace.get_tracer("mugline.voice")
meter = metrics.get_meter("mugline.voice")
greetings = meter.create_counter("voice.greetings.delivered", unit="1")
範囲が定まった処理
tracer.start_as_current_span(...) はデコレーターとしてもコンテキストマネージャーとしても使えます。同じ呼び出しです。関数全体を対象にする場合は、通常、デコレーター形式を使います。
@tracer.start_as_current_span("do_work")
def do_work():
print("doing some work...")
非同期関数やメソッドでも同じように使えます。また、関数本体内で trace.get_current_span() を使ってアクティブなスパンを取得し、属性を設定できます。
@tracer.start_as_current_span("voice.deliver_initial_greeting")
async def _deliver_initial_greeting(*, tenant_id: str, user_id: str) -> None:
span = trace.get_current_span()
span.set_attributes({
"tenant.id": tenant_id,
"user.id": user_id,
"voice.use_case": "initial_greeting",
})
デコレーターが適さない場合(スコープの一部のみを対象にする場合、スパン名が動的な場合など)は、コンテキストマネージャーを使います。
with tracer.start_as_current_span("order.validate") as span:
span.set_attribute("tenant.id", tenant_id)
validate_order(order)
範囲が定まった処理には、分離した tracer.start_span(...); span.end() を使わないでください。
エラー処理
アクティブなスパンに例外を記録します。
try:
result = await client.messages.create(...)
except Exception as exc:
span = trace.get_current_span()
span.record_exception(exc)
span.set_status(Status(StatusCode.ERROR))
logger.exception("llm mug copy failed", extra={"tenant_id": tenant_id})
raise
ログ
ログが OTLP に転送されると説明する場合は、次の両方を設定します。
- OTel LoggerProvider + OTLPLogExporter + LoggingHandler
opentelemetry._logsのset_logger_provider(logger_provider)- 既存レコードのログ相関(例:
LoggingInstrumentor().instrument(...))
既存の logging.basicConfig、コンソール/ファイルハンドラー、およびログレベルは維持してください。
初期化時の動作
init モジュールでは、otel-onboarding-style のソースレベルの公開 Superlog 設定パターンを使います。公開プロジェクトトークンは書き込み専用で、PostHog のプロジェクトトークンや Sentry DSN と同様に、セットアップブロック内のエンドポイントと併せて指定します。
SUPERLOG_ENDPOINT = "https://intake.superlog.sh"
SUPERLOG_PUBLIC_TOKEN = "sl_public_..."
# The token MUST be sent as the `x-api-key` header. Ingest only reads
# `x-api-key` or `Authorization: Bearer <token>`; any other header name 401s.
def superlog_headers(token: str) -> dict[str, str]:
return {"x-api-key": token}
def init_observability() -> None:
exporter = OTLPSpanExporter(
endpoint=f"{SUPERLOG_ENDPOINT}/v1/traces",
headers=superlog_headers(SUPERLOG_PUBLIC_TOKEN),
)
...
アプリからこの関数が複数回呼び出される可能性が現実的にある場合に限り、小規模な _INITIALIZED ガードを追加します。
メトリクス
カウンター:
llm.tokens.inputllm.tokens.output- リクエスト/イベント/ジョブ/エラー
SDK が対応している場合は、セマンティックな単位を使います。トークンカウンターでは unit="tokens" を指定します。通常の LLM 呼び出しでは、アプリ側で llm.cost_usd の価格メトリクスを追加しないでください。Superlog はプロバイダー/モデル/トークンのデータに基づいて、コストを一元的に推定します。
ヒストグラム:
- 処理時間
- レイテンシー
- ペイロードサイズ
メトリクス属性に、生の高カーディナリティ値を使うのは避けてください。ユーザーレベルのメトリクスタグよりも、テナント/組織/プロジェクト、操作/ユースケース、プロバイダー/モデル、および結果のディメンションを優先します。