概要
このエントリは、「Enterprise "hello, world" 2018 Advent Calendar 2018」の12/25向けのものです。このAdvent Calendarでは、複数個のエントリにまたがる話の流れも鑑みつつ、なるべく1エントリで1つのトピックをカバーできるようにしています。
このエントリで記載するトピックは、JaegerでOpentracing形式の分散トレーシングをGoのサーバに追加することです。
対象とするGoのサーバは、Go-lang+GinでAPIサーバを作る一歩目~EHW2018「アプリ②」で作成したものを利用します。
前提
おことわり
- このEnterpfise "hello, world"シリーズは、ネタのためのエントリです。実環境でそのまま利用ことを目的とはしていません。
- 動かしやすさを優先してセキュリティを意図的に低くする設定など入れてありますのでご注意ください。
想定読者
「Enterprise "hello, world" 2018」的なネタとしては、下記のような状況を想定しています。
作ってきたアプリケーションに対するリクエストを計測するため、分散トレーシングのライブラリを適用する必要がある。ついでに計測データを核にするための仕組みも入れたい。
Jaegerでデータを扱うための準備
Jaegerとは
Jaegerは、CNCF(Cloud Native Computing Foundation)のプロジェクトの一つで、主にマイクロサービス指向のアーキテクチャを持つシステムにおいて、コンポーネント間の呼び出しをトレースするためのツールです。
OpenTracingとは
Jaegerは、データの記録形式としてOpentracing形式を利用しています。Opentracing形式で計測データを取得するためのライブラリが、様々な言語用に提供されています。
Jaegerのサーバをコンテナで立ち上げる
Jaegerは、ログの格納先として、Cassandra、Elasticsearch、Kafkaを利用することもできますが、このエントリでは簡単のため、コンテナ単体で使用します。
Jaegerのサイトに従って作業を進めます。エントリ執筆の3日前にリリース1.10が出ているようなので、これを使います。
サイトの記載をもとに、docker-compose.ymlを書いてみました。下記のような感じです。
version: '3.7'
services:
jaeger:
image: jaegertracing/all-in-one:1.10
container_name: jaeger
environment:
- COLLECTOR_ZIPKIN_HTTP_PORT=9411
ports:
- "5775:5775/udp"
- "6831:6831/udp"
- "6832:6832/udp"
- "5778:5778"
- "16686:16686"
- "14268:14268"
- "9411:9411"
docker-composeで起動します。
$ sudo docker-compose up
アプリ側の対応
利用ライブラリ
JaegerでGo用に提供されているクライアントライブラリを利用します。
ソース
指定されてたクライアントライブラをインポートします。
メトリクスを取得するAPI自体は、opentracingのgo版の形式となります。
import (
"github.com/fvbock/endless"
"github.com/gin-gonic/gin"
opentracing "github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-lib/metrics"
"github.com/uber/jaeger-client-go"
jaegercfg "github.com/uber/jaeger-client-go/config"
jaegerlog "github.com/uber/jaeger-client-go/log"
)
初期化方法は、サンプルが提供されていますので、参考にします。このエントリでは、サンプルで提供されている開発用とプロダクション用の設定のうち、開発用を使用しています。開発用と本番では、対象のイベントをすべて記録するか、ある程度サンプリングして記録するかなどの指定を分けることになります。
// Sample configuration for testing. Use constant sampling to sample every trace
// and enable LogSpan to log every span via configured Logger.
cfg := jaegercfg.Configuration{
Sampler: &jaegercfg.SamplerConfig{
Type: jaeger.SamplerTypeConst,
Param: 1,
},
Reporter: &jaegercfg.ReporterConfig{
LogSpans: true,
},
}
// Example logger and metrics factory. Use github.com/uber/jaeger-client-go/log
// and github.com/uber/jaeger-lib/metrics respectively to bind to real logging and metrics
// frameworks.
jLogger := jaegerlog.StdLogger
jMetricsFactory := metrics.NullFactory
// Initialize tracer with a logger and a metrics factory
closer, err := cfg.InitGlobalTracer(
"greetings-server",
jaegercfg.Logger(jLogger),
jaegercfg.Metrics(jMetricsFactory),
)
if err != nil {
log.Printf("Could not initialize jaeger tracer: %s", err.Error())
return
}
defer closer.Close()
APIのエンドポイントで、opentracingの"span"を記録する設定を入れます。
opentracingは、複数個の"span"からなる"trace"を分散環境での一連の流れとして追えることがメリットですが、ここでは、単発のspanとしてトレースするためのコードを入れています。
OpenTracingのライブラリでは、context.Contextを使うことができますが、Ginのgin.Contextも、今回のエントリの範囲では、StartSpanFromContextの引数として使うことができています。
spanはfinishしてあげることが必要なので、goのdeferを使っています。
router.GET("/api/greeting", func(ctx *gin.Context) {
span, _ := opentracing.StartSpanFromContext(ctx, "api-greeting")
defer span.Finish()
ctx.JSON(200, gin.H{
"message": "hello, world",
})
})
アプリ起動
dep ensureして必要なライブラリをインポートして、いざ実行。
$ go run greetings-server.go
実行
APIの呼び出し
ブラウザで、「http://localhost:8080/api/greeting」にアクセスしてみます。
Jaegerサーバでの確認
ブラウザで、「http://localhost:16686」にアクセスしてみます。
左側のFind Tracesメニューで「Service」として”greeting-server”(ソース内で指定したサービス名)を指定し、メニュー下側の「Find Traces」ボタンをクリックします。
画面右上のチャートの中の丸印が、ブラウザからAPIにアクセスがあったタイミングを示します。
ブラウザでAPI呼び出しを何度か行い、再度「Find Traces」ボタンをクリックすると、トレース数が増えて表示されます。
まとめ
このエントリでは、「Enterprise "hello, world" 2018 Advent Calendar 2018」(EHW2018)の25日目として、JaegerでOpentracing形式の分散トレーシングをGoのサーバに追加することことをトピックとして取り上げました。
本エントリのソースコードは、GitHubにあげてあります。
EHW2018、このエントリで25個目となりました。メリークリスマス。