golang Echoで使えるstats handlerを作ってみた

golangのパフォーマンスを見れるライブラリがないか探していて、
[golang-stats-api-handler](https://github.com/fukata/golang-stats-api-handler)というパッケージを見つけました。

## [golang-stats-api-handler](https://github.com/fukata/golang-stats-api-handler)を利用してみる
まずはInstallから

```bash
$ go get -u github.com/fukata/golang-stats-api-handler
```

以下が`net/http`を利用して書いたコードです。

```go:main.go
package main

import (
        "github.com/fukata/golang-stats-api-handler"
        "net/http"
)

func main() {
        http.HandleFunc("/stats", stats_api.Handler)
        http.ListenAndServe(":8000", nil)
}
```

`localhost:8000/stats`にアクセスすると以下のように表示されます。

```bash
$ curl -i localhost:8000/stats
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Thu, 14 Dec 2017 13:43:20 GMT
Content-Length: 520

{
  "time": 1513259000865514903,
  "go_version": "go1.8.3",
  "go_os": "darwin",
  "go_arch": "amd64",
  "cpu_num": 4,
  "goroutine_num": 4,
  "gomaxprocs": 4,
  "cgo_call_num": 1,
  "memory_alloc": 383784,
  "memory_total_alloc": 383784,
  "memory_sys": 3084288,
  "memory_lookups": 15,
  "memory_mallocs": 5071,
  "memory_frees": 140,
  "memory_stack": 327680,
  "heap_alloc": 383784,
  "heap_sys": 1769472,
  "heap_idle": 950272,
  "heap_inuse": 819200,
  "heap_released": 917504,
  "heap_objects": 4931,
  "gc_next": 4473924,
  "gc_last": 0,
  "gc_num": 0,
  "gc_per_second": 0,
  "gc_pause_per_second": 0,
  "gc_pause": []
}
```

メモリなどの情報を取得することができました。
apiを追加するだけなのでとても簡単に利用することができます。
これだけでも十分使いやすいライブラリなのですが、
[echo](https://github.com/labstack/echo)などのフレームワークに組み込むとなるとHandlerがフレームワーク独自のものなのでそのままでは使えません。

## [echo](https://github.com/labstack/echo)にstatsを確認するようのapiを実装
では、[echo](https://github.com/labstack/echo)にstats確認用apiを追加してみます。

```go:main.go
package main

import (
	"net/http"

	"github.com/fukata/golang-stats-api-handler"
	"github.com/labstack/echo"
)

func main() {
	e := echo.New()
	e.GET("/hello", hello)
	e.GET("/stats", stats_api.Handler)
	e.Start(":8000")
}

func hello() echo.HandlerFunc {
	return func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello World!")
	}
}
```

このまま実行すると

```bash
$ go run main.go
# command-line-arguments
./main.go:12: cannot use stats_api.Handler (type func(http.ResponseWriter, *http.Request)) as type echo.HandlerFunc in argument to e.GET
```

と表示されて実行することができません。
なので以下のように書き換えてみます。

```go:main.go
package main

import (
	"log"
	"net/http"

	"github.com/fukata/golang-stats-api-handler"
	"github.com/labstack/echo"
)

func main() {
	go func() {
		http.HandlerFunc("/stats", stats_api.Handler)
		log.Fatal(http.ListenAndServe(":8080", nil))
	}()

	e := echo.New()
	e.GET("/hello", hello)
	e.Start(":8000")
}

func hello() echo.HandlerFunc {
	return func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello World!")
	}
}
```
これで実行すると以下のように結果を取得することができます。

```bash
$ go run main.go
$ curl -i localhost:8080/stats
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Thu, 14 Dec 2017 13:43:20 GMT
Content-Length: 520

{
  "time": 1513259000865514903,
  "go_version": "go1.8.3",
  "go_os": "darwin",
  "go_arch": "amd64",
  "cpu_num": 4,
  "goroutine_num": 4,
  "gomaxprocs": 4,
  "cgo_call_num": 1,
  "memory_alloc": 383784,
  "memory_total_alloc": 383784,
  "memory_sys": 3084288,
  "memory_lookups": 15,
  "memory_mallocs": 5071,
  "memory_frees": 140,
  "memory_stack": 327680,
  "heap_alloc": 383784,
  "heap_sys": 1769472,
  "heap_idle": 950272,
  "heap_inuse": 819200,
  "heap_released": 917504,
  "heap_objects": 4931,
  "gc_next": 4473924,
  "gc_last": 0,
  "gc_num": 0,
  "gc_per_second": 0,
  "gc_pause_per_second": 0,
  "gc_pause": []
}
```

これでメモリなどの情報をフレームワークを利用したapiでも取得することができました。
しかし、ここで`groutine`使うのもなーって感じがするので[echo](https://github.com/labstack/echo)用のHandlerをライブラリ化してみました。

## [echo](https://github.com/labstack/echo)用のHandlerを実装したライブラリ
[github](https://github.com/y-ogura/stats-handler)にHandler用のパッケージを作成しました。

まずはinstall

```bash
go get -u github.com/y-ogura/stats-handler
```

コードに書くと下記のようになります。

```go:main.go
package main

import (
	"net/http"

	"github.com/labstack/echo"
	"github.com/y-ogura/stats-handler"
)

func main() {
	e := echo.New()
	e.GET("/hello", hello())
	e.GET("/stats", stats_handler.EchoStatsHandler)
	e.Start(":8000")
}

func hello() echo.HandlerFunc {
	return func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello World!")
	}
}
```

コードの見た目も多少スッキリしました。
ポートも余計に使用しなくて済みました。
実行結果も問題なく取得することができます。

```bash
$ go run main.go
$ curl -i localhost:8000/stats
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Thu, 14 Dec 2017 13:43:20 GMT
Content-Length: 520

{
  "time": 1513259000865514903,
  "go_version": "go1.8.3",
  "go_os": "darwin",
  "go_arch": "amd64",
  "cpu_num": 4,
  "goroutine_num": 4,
  "gomaxprocs": 4,
  "cgo_call_num": 1,
  "memory_alloc": 383784,
  "memory_total_alloc": 383784,
  "memory_sys": 3084288,
  "memory_lookups": 15,
  "memory_mallocs": 5071,
  "memory_frees": 140,
  "memory_stack": 327680,
  "heap_alloc": 383784,
  "heap_sys": 1769472,
  "heap_idle": 950272,
  "heap_inuse": 819200,
  "heap_released": 917504,
  "heap_objects": 4931,
  "gc_next": 4473924,
  "gc_last": 0,
  "gc_num": 0,
  "gc_per_second": 0,
  "gc_pause_per_second": 0,
  "gc_pause": []
}
```

## さいごに
こんな感じでフレームワークを利用していても[golang-stats-api-handler](https://github.com/fukata/golang-stats-api-handler)が使えるようになりました。
ちょっとしたときに確認したいときにapiを追加しておけば簡単に確認できるので[golang-stats-api-handler](https://github.com/fukata/golang-stats-api-handler)は普段から使っています。
普段は[goa](https://github.com/goadesign/goa)で開発を行っているのでgoa用のHandlerも作る予定でいます。
まだ、パフォーマンスチェックに関しては知識不足が多いので、もっといい方法あるよって方や良いツール知ってるよって方がいましたらコメントをお待ちしています。