microservicesの調査に向けて〜Golang製のzipking tracerのgo-kitを利用してみる

## 1. やりたいこと

[以前の投稿](http://qiita.com/letusfly85/items/58fd4bb2d2f083d8d274)で、docker-composeを利用して、zipkinサービスを手元で動かすことができるようになったので、golangでも、zipkinにレコードを登録できるかを試してみようと思いました。

下記を一通り読むと、addsrvのセクションで簡単なサンプルが紹介されていました。

* https://github.com/go-kit/kit/blob/master/examples/README.md

## 2. やってみた

### 2-1. ソースコードをダウンロード 

```bash
git clone https://github.com/go-kit/kit.git

cd kit/examples/addsvc/
```

### 2-2. 依存するライブラリをgo getする

```bash
go get github.com/go-kit/kit/tracing/zipkin
go get github.com/codahale/hdrhistogram
go get github.com/prometheus/client_golang/prometheus
```

### 2-3. ビルドしてサーバを起動する

```bash
go build

./addsvc --zipkin.collector.addr=*.*.*.*:9410
```

### 2-4. curlで、起動したサーバにGETメソッドを送る

```bash
curl  -H "Content-Type: application/json" -L  "http://localhost:8001/sum" -d '{"a":10,"b":12}'
```

上記を実行すると、下記のようなエラーが出ちゃいました。。

```
ts=2016-**-**T14:10:40Z caller=stdlib.go:89 file="http: panic serving [::1" msg="]:50391: interface conversion: interface {} is server.SumRequest, not *server.SumRequest"
```

### 2-5. でもzipkinのuiを見てみる

`addsvc`というサービスがトレースされていることが確認できました。

![スクリーンショット 2016-03-23 23.27.57.png](https://qiita-image-store.s3.amazonaws.com/0/49547/c18a4df7-26a5-43e4-6031-7ee6447b0c38.png)

まだ、コミットが直近でも入っているようなので発展途上なのかもしれません。もうちょっと時間をおいてまた見てみようと思います。

## 3. ちょっとだけソースも眺めてみた

`main.go`を起点に、httpサーバをgolangで立てたときにどのようにトレーサーを仕込んでいくのかを見てみました。

### 3-1. zipkin collectorの変数を生成

まず、tracer自体については、`go-kit/kit/tracing/zipkin`パッケージの`zipkin`の`zipkin.NewScribeCollector`を読んで生成しているようでした。

```main.go
	// package tracing
	var collector zipkin.Collector
	{
		zipkinLogger := log.NewContext(logger).With("component", "zipkin")
		collector = loggingCollector{zipkinLogger} // TODO(pb)
		if *zipkinCollectorAddr != "" {
			var err error
			if collector, err = zipkin.NewScribeCollector(
				*zipkinCollectorAddr,
				*zipkinCollectorTimeout,
				zipkin.ScribeBatchSize(*zipkinCollectorBatchSize),
				zipkin.ScribeBatchInterval(*zipkinCollectorBatchInterval),
				zipkin.ScribeLogger(zipkinLogger),
			); err != nil {
				zipkinLogger.Log("err", err)
				os.Exit(1)
			}
		}
	}
```

### 3-2. httpリクエストをトレースする

上記を、おそらくhttpのリクエストに食わせていると思い眺めて、とってもざっくりな理解ですが、

1. `zipkin.AnnotateServer(newSumSpan, collector)(sum)`で処理実行のサーバとdurationの開始をハンドル
2. `net/http`のmux.Handlerに、zipkintの`transport/http`パッケージの[ファンクション](https://github.com/go-kit/kit/blob/master/transport/http/server.go#L26:L45)をかまして、終了をキャッチ

のような感触を得ました。

```main.go
		var (
			transportLogger = log.NewContext(logger).With("transport", "HTTP/JSON")
			tracingLogger   = log.NewContext(transportLogger).With("component", "tracing")
			newSumSpan      = zipkin.MakeNewSpanFunc(*zipkinHostPort, *zipkinServiceName, "sum")
			newConcatSpan   = zipkin.MakeNewSpanFunc(*zipkinHostPort, *zipkinServiceName, "concat")
			traceSum        = zipkin.ToContext(newSumSpan, tracingLogger)
			traceConcat     = zipkin.ToContext(newConcatSpan, tracingLogger)
			mux             = http.NewServeMux()
			sum, concat     endpoint.Endpoint
		)

		sum = makeSumEndpoint(svc)
		sum = zipkin.AnnotateServer(newSumSpan, collector)(sum)
		mux.Handle("/sum", httptransport.NewServer(
			root,
			sum,
			server.DecodeSumRequest,
			server.EncodeSumResponse,
			httptransport.ServerBefore(traceSum),
			httptransport.ServerErrorLogger(transportLogger),
		))
```

## 4. 所感

* Golangでもできるんだー、と思いました。Elixir/Phoenixでもできないのかな。
* `net/http`でrouteごとに上記のように実装するのはちょっと冗長かも、と思いました。
* go getが動かずに動作確認できませんでしたが、[go-zipkin](https://github.com/elodina/go-zipkin)だと上記のような冗長な箇所が解消されているのかな、とちょっと期待。ソース見てみよー。
* いろいろ眺めてみたけれど満足に動くライブラリとかサンプルが少ないような。。みんなトレーシングはfluentなどのロギングベースでいくのかな。mix inとかDIみたいにさりげなくzipkinのような仕組みをフレームワークに組み込めたら素敵だと思うのだけれども。。。

## 5. 参考

* https://golang.org/pkg/net/http/#NewServeMux
* https://github.com/go-kit/kit

---

本日は以上となります。