Skip to content
Server Plugin

Ktor Server における OpenTelemetry を使用した分散トレーシング

必要な依存関係: io.opentelemetry.instrumentation:opentelemetry-ktor-3.0

コード例: opentelemetry

Ktor は OpenTelemetry と統合されています。OpenTelemetry は、トレース、メトリクス、ログなどのテレメトリデータを収集するためのオープンソースのオブザーバビリティフレームワークです。アプリケーションを計装し、Grafana や Jaeger などのモニタリングおよびオブザーバビリティツールにデータをエクスポートするための標準的な方法を提供します。

KtorServerTelemetry プラグインは、Ktor サーバーアプリケーションにおける受信 HTTP リクエストの分散トレーシングを有効にします。ルート、HTTP メソッド、ステータスコード情報を含むスパンを自動的に作成し、受信リクエストヘッダーから既存のトレースコンテキストを抽出します。また、スパン名、属性、スパンの種類のカスタマイズも可能です。

クライアント側では、OpenTelemetry は KtorClientTelemetry プラグインを提供しており、外部サービスへの送信 HTTP コールのトレースを収集します。

依存関係の追加

KtorServerTelemetry を使用するには、ビルドスクリプトに opentelemetry-ktor-3.0 アーティファクトを含める必要があります。

Kotlin
Groovy
XML

OpenTelemetry の設定

Ktor アプリケーションに KtorServerTelemetry プラグインをインストールする前に、OpenTelemetry インスタンスを設定して初期化する必要があります。このインスタンスは、トレースやメトリクスを含むテレメトリデータの管理を担当します。

自動設定

OpenTelemetry を設定する一般的な方法は、AutoConfiguredOpenTelemetrySdk を使用することです。これにより、システムプロパティや環境変数に基づいてエクスポーターやリソースを自動的に構成し、セットアップを簡素化できます。

自動的に検出された構成をカスタマイズすることも可能です。例えば、service.name リソース属性を追加する場合は以下のようになります。

kotlin
package com.example

import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk
import io.opentelemetry.semconv.ServiceAttributes

fun getOpenTelemetry(serviceName: String): OpenTelemetry {

    return AutoConfiguredOpenTelemetrySdk.builder().addResourceCustomizer { oldResource, _ ->
        oldResource.toBuilder()
            .putAll(oldResource.attributes)
            .put(ServiceAttributes.SERVICE_NAME, serviceName)
            .build()
    }.build().openTelemetrySdk
}

プログラムによる設定

環境ベースの設定に依存せず、コード内でエクスポーター、プロセッサ、プロパゲーターを定義するには、OpenTelemetrySdk を使用できます。

以下の例は、OTLP エクスポーター、スパンプロセッサ、およびトレースコンテキストプロパゲーターを使用してプログラムで OpenTelemetry を設定する方法を示しています。

kotlin
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator
import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter
import io.opentelemetry.sdk.OpenTelemetrySdk
import io.opentelemetry.sdk.trace.SdkTracerProvider
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor

fun configureOpenTelemetry(): OpenTelemetry {
    val spanExporter = OtlpGrpcSpanExporter.builder()
        .setEndpoint("http://localhost:4317")
        .build()

    val tracerProvider = SdkTracerProvider.builder()
        .addSpanProcessor(BatchSpanProcessor.builder(spanExporter).build())
        .build()

    return OpenTelemetrySdk.builder()
        .setTracerProvider(tracerProvider)
        .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
        .buildAndRegisterGlobal()
}

テレメトリのセットアップを完全に制御する必要がある場合や、デプロイ環境で自動設定に依存できない場合に、このアプローチを使用してください。

詳細については、OpenTelemetry SDK コンポーネントのドキュメントを参照してください。

KtorServerTelemetry のインストール

KtorServerTelemetry プラグインをアプリケーションにインストールするには、指定されたモジュールinstall 関数に渡し、設定済みの OpenTelemetry インスタンスをセットします。

kotlin
    import io.ktor.server.engine.*
    import io.ktor.server.netty.*
    import io.ktor.server.application.*
    import io.opentelemetry.instrumentation.*

    fun main() {
        embeddedServer(Netty, port = 8080) {
            val openTelemetry = getOpenTelemetry(serviceName = "opentelemetry-ktor-sample-server")

            install(KtorServerTelemetry){
                setOpenTelemetry(openTelemetry)
            }
            // ...
        }.start(wait = true)
    }
kotlin

    import io.ktor.server.application.*
    import io.opentelemetry.instrumentation.*
    // ...

    fun Application.module() {
        val openTelemetry = getOpenTelemetry(serviceName = "opentelemetry-ktor-sample-server")

        install(KtorServerTelemetry){
            setOpenTelemetry(openTelemetry)
        }
        // ...
    }

KtorServerTelemetry が、他のロギングまたはテレメトリ関連のプラグインよりも前にインストールされていることを確認してください。

トレーシングの設定

Ktor サーバーが OpenTelemetry スパンを記録およびエクスポートする方法をカスタマイズできます。以下のオプションを使用して、どのリクエストをトレースするか、スパンの名前、含まれる属性、およびスパンの種類の決定方法を調整できます。

これらの概念の詳細については、OpenTelemetry トレーシングドキュメントを参照してください。

追加の HTTP メソッドのトレース

デフォルトでは、プラグインは標準の HTTP メソッド(GETPOSTPUT など)をトレースします。追加またはカスタムメソッドをトレースするには、knownMethods プロパティを設定します。

kotlin
install(KtorServerTelemetry) {
    // ...
    knownMethods(HttpMethod.DefaultMethods + CUSTOM_METHOD)
}

ヘッダーのキャプチャ

特定の HTTP リクエストヘッダーをスパン属性として含めるには、capturedRequestHeaders プロパティを使用します。

kotlin
install(KtorServerTelemetry) {
    // ...
    capturedRequestHeaders(HttpHeaders.UserAgent)
}

スパンの種類の選択

リクエストの特性に基づいてスパンの種類(SERVERCLIENTPRODUCERCONSUMER など)を上書きするには、spanKindExtractor プロパティを使用します。

kotlin
install(KtorServerTelemetry) {
    // ...
    spanKindExtractor {
        if (httpMethod == HttpMethod.Post) {
            SpanKind.PRODUCER
        } else {
            SpanKind.CLIENT
        }
    }
}

カスタム属性の追加

スパンの開始時または終了時にカスタム属性をアタッチするには、attributesExtractor プロパティを使用します。

kotlin
install(KtorServerTelemetry) {
    // ...
    attributesExtractor {
        onStart {
            attributes.put("start-time", System.currentTimeMillis())
        }
        onEnd {
            attributes.put("end-time", Instant.now().toEpochMilli())
        }
    }
}

追加のプロパティ

アプリケーション全体のトレーシング動作を微調整するために、プロパゲーター、属性制限、インストゥルメンテーションの有効化/無効化などの追加の OpenTelemetry プロパティを設定することもできます。詳細については、OpenTelemetry Java 設定ガイドを参照してください。

Grafana LGTM によるテレメトリデータの検証

テレメトリデータを視覚化して検証するために、トレース、メトリクス、ログを Grafana などの分散トレーシングバックエンドにエクスポートできます。grafana/otel-lgtm オールインワンイメージには、GrafanaTempo (トレース)、Loki (ログ)、Mimir (メトリクス) がバンドルされています。

Docker Compose を使用する

以下の内容で docker-compose.yml ファイルを作成します。

yaml
services:
  grafana-lgtm:
    image: grafana/otel-lgtm:latest
    ports:
      - "4317:4317"   # OTLP gRPC 受信機 (トレース、メトリクス、ログ)
      - "4318:4318"   # OTLP HTTP 受信機
      - "3000:3000"   # Grafana UI
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin
    restart: unless-stopped

Grafana LGTM オールインワンコンテナを起動するには、次のコマンドを実行します。

shell
docker compose up -d

Docker CLI を使用する

あるいは、Docker コマンドラインを使用して直接 Grafana を実行することもできます。

shell
docker run -d --name grafana_lgtm \
    -p 4317:4317 \   # OTLP gRPC 受信機 (トレース、メトリクス、ログ)
    -p 4318:4318 \   # OTLP HTTP 受信機
    -p 3000:3000 \   # Grafana UI
    -e GF_SECURITY_ADMIN_USER=admin \
    -e GF_SECURITY_ADMIN_PASSWORD=admin \
    grafana/otel-lgtm:latest

アプリケーションのエクスポート設定

Ktor アプリケーションから OTLP エンドポイントにテレメトリを送信するには、gRPC プロトコルを使用するように OpenTelemetry SDK を設定します。SDK をビルドする前に、環境変数を介してこれらの値を設定できます。

shell
export OTEL_TRACES_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317

または、JVM フラグを使用します。

text
-Dotel.traces.exporter=otlp -Dotel.exporter.otlp.protocol=grpc -Dotel.exporter.otlp.endpoint=http://localhost:4317

Grafana UI へのアクセス

実行されると、Grafana UI は http://localhost:3000/ で利用可能になります。

  1. Grafana UI を http://localhost:3000/ で開きます。
  2. デフォルトの認証情報でログインします:
    • ユーザー:admin
    • パスワード:admin
  3. 左側のナビゲーションメニューで、Drilldown → Traces に移動します。 Grafana UI Drilldown traces viewTraces ビューでは、以下のことができます:
    • Rate(レート)、Errors(エラー)、または Duration(期間)のメトリクスを選択する。
    • スパンフィルター(サービス名やスパン名など)を適用してデータを絞り込む。
    • トレースを表示し、詳細を調査し、スパンのタイムラインを操作する。