コンテンツにスキップ

トレーシング

トレーシングは、分散システムの監視とデバッグのための強力なツールです。Vaporのトレーシング APIを使用すると、開発者はリクエストのライフサイクルを簡単に追跡し、メタデータを伝播し、OpenTelemetryなどの人気のあるバックエンドと統合できます。

Vaporのトレーシング APIはswift-distributed-tracingの上に構築されているため、swift-distributed-tracingのすべてのバックエンド実装と互換性があります。

Swiftでのトレーシングとスパンに馴染みがない場合は、OpenTelemetryトレースドキュメントswift-distributed-tracingドキュメントを確認してください。

TracingMiddleware

各リクエストに対して完全に注釈付きのスパンを自動的に作成するには、アプリケーションにTracingMiddlewareを追加します。

app.middleware.use(TracingMiddleware())

正確なスパン測定を取得し、トレーシング識別子が他のサービスに正しく渡されるようにするには、このミドルウェアを他のミドルウェアの前に追加してください。

スパンの追加

ルートハンドラーにスパンを追加する場合、それらをトップレベルのリクエストスパンに関連付けることが理想的です。これは「スパン伝播」と呼ばれ、自動または手動の2つの方法で処理できます。

自動伝播

Vaporは、ミドルウェアとルートコールバック間でスパンを自動的に伝播する機能をサポートしています。これを行うには、設定時にApplication.traceAutoPropagationプロパティをtrueに設定します。

app.traceAutoPropagation = true

Note

自動伝播を有効にすると、スパンが作成されるかどうかに関係なく、すべてのルートハンドラーでリクエストスパンメタデータを復元する必要があるため、最小限のトレーシングニーズを持つ高スループットAPIではパフォーマンスが低下する可能性があります。

その後、通常の分散トレーシング構文を使用してルートクロージャでスパンを作成できます。

app.get("fetchAndProcess") { req in
    let result = try await fetch()
    return try await withSpan("getNameParameter") { _ in
        try await process(result)
    }
}

手動伝播

自動伝播のパフォーマンスへの影響を避けるために、必要に応じて手動でスパンメタデータを復元できます。TracingMiddlewareは自動的にRequest.serviceContextプロパティを設定し、これをwithSpancontextパラメータで直接使用できます。

app.get("fetchAndProcess") { req in
    let result = try await fetch()
    return try await withSpan("getNameParameter", context: req.serviceContext) { _ in
        try await process(result)
    }
}

スパンを作成せずにスパンメタデータを復元するには、ServiceContext.withValueを使用します。これは、ダウンストリームの非同期ライブラリが独自のトレーシングスパンを発行し、それらが親リクエストスパンの下にネストされるべきであることがわかっている場合に有用です。

app.get("fetchAndProcess") { req in
    try await ServiceContext.withValue(req.serviceContext) {
        try await fetch()
        return try await process(result)
    }
}

NIOに関する考慮事項

swift-distributed-tracingTaskLocalプロパティを使用して伝播するため、スパンが正しくリンクされるようにするには、NIO EventLoopFutureの境界を越えるたびに手動でコンテキストを再復元する必要があります。これは自動伝播が有効かどうかに関係なく必要です

app.get("fetchAndProcessNIO") { req in
    withSpan("fetch", context: req.serviceContext) { span in
        fetchSomething().map { result in
            withSpan("process", context: span.context) { _ in
                process(result)
            }
        }
    }
}