Goを学ぶ　～番外編 Jaeger～

## 目的
Jaegerって何？
echoとJaegerを使ってみる。

## Jaegerとは
Jaeger（イェーガー）は、Uber Technologies社によって開発され、オープンソース化されたGo言語の分散トレーシングシステム
分散トレーシングとは、近年マイクロサービスも浸透してきており、処理が１つのアプリケーションで完結しなくなってきてる。
その結果、１つの処理の全体像をつかむことが難しいケースがうまれた。
例えば、
処理Aと処理Bの２つの処理があり、処理Aを行ったあとに処理Bを実施する分析処理がある。処理A,Bは別アプリケーションとする。
分析処理が遅延するケースがあることがわかり、処理時間を確認したところ
- 処理A
    - 10秒
    - 3秒
- 処理B
    - 5秒
    - 7秒

という通常より遅くなるものが見受けられた。
安易に考えると処理Aの10秒と処理Bの7秒が改善されればとなるかもしれないが、連動しているので
処理Aが10秒かかったときはもしかしたら処理Bは必ず通常通りに処理しているかもしれないし、5秒かかるかもしれないし、
ケースバイケースかもしれない。
すべてのパターンを検討すればいいといえばそうなのだが、非常に非効率な方針である。
今は2×2なのでたかがしれているが、現実はそんなに甘くないので現実的な方針が必要になる。
分散トレーシングは、分析処理としてみたときにあるときに処理Aが何秒、処理Bが何妙とアプリケーションではなく、さまざまな処理としてみることができるもの。
今回の問題は、どういった組み合わせが多いのかがわからないから全部みる？だったが、
常日頃からこういった処理をしているからこのパターンが顕著だから重点的に確認するといったことが可能になる。
こういった、分散トレーシングシステム非常にたくさんある。
有名なところだとAWS X-Ray、Datadogyとかかな？
当然それらを使ってもいいし、jaegerを使ってもいいとは思う。
先の２つの違いとしては、
jaegerはオープンソースなのでサーバー費用がかかるが、利用は無料な点
ある意味個人開発では非常に便利なのかもしれない。

## Jaegerの理解を深める
JaegerはOpenTracingと互換性のあるデータモデルを持ち、各種言語用の計測ライブラリを提供している。
CNCF卒業プロジェクトとなっており、今後が期待されているOSS。

### OpenTracing
Jaegerを理解するうえで、OpenTracingの理解する必要がある。
重要な概念として
- スパン
- トレース

の２つがある。関係性は下の図になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688298/bbfce6c3-3a7f-68f5-7ecf-7ec3c60e8006.png)
スパンは、処理時間だけでなく、操作名などの作業単位の情報を有しています。
トレースは実行パスも表している。

Jaegerのコンポーネント構成は下の図になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688298/abef7932-1ee7-62bc-0934-38f67e070a03.png)
出典：https://www.jaegertracing.io/docs/1.43/architecture/

<table>
    <tr>
        <th>名前</th>
        <th>説明</th>
    </tr>
    <tr>
        <td>Tracing Trace</td>
        <td>
以前はJaeger Clientと呼ばれていた。アプリケーションにインストルメント化する必要がある。
インストルメント化されたアプリケーションでは、新しいリクエストをうけとるときにスパンを作成し、コンテキスト情報を発信リクエストに添付する。
echoのフレームワークで設定する内容はこの部分
        </td>
    </tr>
    <tr>
        <td>Jaeger Agent</td>
        <td>
公式ドキュメントに非推奨となっているが、UDP経由で送信されたスパンを受け取るネットワークデーモン。
受け取ったスパンをバッチ化してコレクターに送信する。
        </td>
    </tr>
    <tr>
        <td>Jaeger Collector</td>
        <td>
トレースを受け取り、処理パイプラインを介してストレージに保存する。
        </td>
    </tr>
    <tr>
        <td>Jaeger Query</td>
        <td>
ストレージからトレースを取得するAPIを公開し、トレースを検索および分析するためのWebUIを提供する
        </td>
    </tr>
</table>


## ためしに使ってみる
OSSということもDocker提供されているので試しに使ってみる。

docker-compose.ymlを編集
```
version: '3'
services:
  go_echo:
    container_name: goEcho
    build:
      context: ./echo/
    volumes:
      - ./echo:/go/src/app
    tty: true
    environment:
      - TZ=Asia/Tokyo
      - JAEGER_SERVICE_NAME=go_echo_jaeger
      - JAEGER_ENDPOINT=http://jaeger:14268/api/traces
    ports:
      - 1323:1323
    networks:
      - jaeger

  go_echo_db:
    image: mysql:5.7
    container_name: mysqlEcho
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: echo
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./database/data:/var/lib/mysql
    ports:
      - 13306:3306

  jaeger:
    container_name: jaeger
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686"
      - "14268:14268"
    environment:
      - COLLECTOR_OTLP_ENABLED=true
      - LOG_LEVEL=debug
    networks:
      - jaeger

networks:
  jaeger:
```
part1,2のdocker-compose.ymlを使われている場合、
コンテナ名が変わっているので注意してください。
変更理由は、アンダースコアがホスト名として使用できないためです。
含んだものが混じっているでうまく名前解決できなくなり、Jaegerがスパンを受け取れなくなります。
go側に環境変数の宣言を追加しています。
これは公式ドキュメントに従っており、Jaeger関連の設定はデフォルト設定がありますが、環境変数に設定されている場合は、こちらが優先されます。ホスト名は変更する必要があるので設定してください。


server.goに追記
```
package infra

import (
	"app/controllers"
	"github.com/labstack/echo-contrib/jaegertracing"
	"github.com/labstack/echo/v4"
)

type Server struct {
	Echo *echo.Echo
}

func NewServer() *Server {
	return &Server{
		Echo: echo.New(),
	}
}

func (server *Server) Start() {
	server.Echo.GET("/", controllers.NewHelloController().GetMessage)

	c := jaegertracing.New(server.Echo, nil) //追加
	defer c.Close()　// 追加

	server.Echo.Start(":1323")
}

```
こちらは公式ドキュメントに従っているので特別なことはなしです。

変更内容は以上！！！
あとはコンテナを起動して、echoも起動
起動後にlocalhost:1323に接続してHello Worldを表示させたあとに
http://localhost:16686 にブラウザに接続してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688298/ca942034-65c6-4986-7d3e-150c23a6ba5c.png)
こんな画面が表示されたあと、
Serviceのセレクトボックスが1つ以上ある状態になり、「go_echo_jaeger」があればOKです。
詳細を見たいトレースをクリックすると詳細画面に遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688298/f1579334-0044-90dc-199a-ea6713a27770.png)

ソース全体はこちら https://github.com/dsrice/go_echo/tree/jaeger 


今回はリクエストのみ取得していますが、その気になれば別のアプリケーションでなくても細かくスパンをつくることは可能です。
コンテキストの持ち回りが必要だったりそこそこの労力にはなるのでやられる際は注意してください。
コンテキストの持ち回りが必要な理由は同一トレース化の判定に必要になるためです。このあたりは、
jaegerというよりOpenTracingの実装が必要になります。