Echoを使ってGAE/Go1.12(第二世代)でいい感じにログを出す

# 概要
[GAE第二世代+Go v1.12でechoサーバーを構築する(2019年度版)](https://qiita.com/br_branch/items/a26480a05ecb97ac20b3) ではこんなこと書きました。

> 上記の通り、もう google.golang.org/appengine は使えなくなりました。
> 代わりに、標準のlogパッケージを使えばいいみたいです。
> (省略)
> うん。こいつは楽ですね。

はい、こんな感じで表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/6fbe3d18-3503-7c63-e8d8-ce83e93d99b4.png)

たしかに表示はされるのですが、以前のGAEログとくらべて非常に貧弱です。このログの出力で開発をすすめるのにはちょっと不安がありました。

AppEngineの第二世代からは、規則にのっとってログを出力する必要があるようです。
https://cloud.google.com/appengine/docs/standard/go112/writing-application-logs

ただちょっとそれを独自実装するのは面倒だなーって思ってて、探したところありました。

**stackdriver-request-context-log**
https://github.com/yfuruyama/stackdriver-request-context-log

というわけで、こちらをEchoに組み込むところを記載します。

# やり方
といっても、基本的な使い方は上記のREADMEに丁寧に記載があったので楽でした。
結論をいうと、こんな感じでやるといい感じに出力されます。

```go:main.go
func main() {
	// ロギングの設定
	config := stackdriver.NewConfig("PROJECT_ID")
	config.RequestLogOut = os.Stderr            // request log to stderr
	config.ContextLogOut = os.Stdout            // context log to stdout
	config.Severity = stackdriver.SeverityInfo          // only over INFO logs are logged
	config.AdditionalData = stackdriver.AdditionalData{ // set additional fields for all logs
		"service": "foo",
		"version": 1.0,
	}

	e := echo.New()
	// 動作確認用
	e.GET("/", func(e echo.Context) error{
		logger := stackdriver.RequestContextLogger(e.Request())
		logger.Debugf("DebugTest")
		logger.Infof("InfoTest")
		logger.Warnf("WarningTest")
		logger.Errorf("ErrorTest")
		return e.String(http.StatusOK, "logger")
	})
	http.Handle("/", e)
	handler := stackdriver.RequestLogging(config)(e)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
		log.Printf("Defaulting to port %s", port)
	}

	log.Printf("Listening on port %s", port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), handler))
}
```

## 動作確認
実際にデプロイして確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/acdc2776-58b2-eea3-2710-731646241dfa.png)

すると、こんな感じで表示がされるようになります。
sourceの場所もわかって素敵。

## ちなみに
ローカルでrunするとこんな感じに表示がされます。 (GCP上へ送信などはされません)

```
{"time":"2019-09-08T15:06:25.871551+09:00","logging.googleapis.com/trace":"projects/xxxx/traces/ea9f26aa103949b80985a8e589d809de","logging.googleapis.com/sourceLocation":{"file":"main.go","line":"43","function":"main.main.func1"},"severity":"INFO","message":"InfoTest","data":{"service":"foo","version":1}}
{"time":"2019-09-08T15:06:25.871942+09:00","logging.googleapis.com/trace":"projects/xxxx/traces/ea9f26aa103949b80985a8e589d809de","logging.googleapis.com/sourceLocation":{"file":"main.go","line":"44","function":"main.main.func1"},"severity":"WARNING","message":"WarningTest","data":{"service":"foo","version":1}}
{"time":"2019-09-08T15:06:25.87196+09:00","logging.googleapis.com/trace":"projects/xxxx/traces/ea9f26aa103949b80985a8e589d809de","logging.googleapis.com/sourceLocation":{"file":"main.go","line":"45","function":"main.main.func1"},"severity":"ERROR","message":"ErrorTest","data":{"service":"foo","version":1}}
{"time":"2019-09-08T15:06:25.871997+09:00","logging.googleapis.com/trace":"projects/xxxx/traces/ea9f26aa103949b80985a8e589d809de","severity":"ERROR","httpRequest":{"requestMethod":"GET","requestUrl":"/","requestSize":"0","status":200,"responseSize":"6","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36","remoteIp":"[","serverIp":"192.168.0.3","referer":"","latency":"0.000565s","cacheLookup":false,"cacheHit":false,"cacheValidatedWithOriginServer":false,"protocol":"HTTP/1.1"},"data":{"service":"foo","version":1}}
```

若干見づらいので、ローカルと本番では分けた方がいいかもですね。

# 参考
GAE のログに憧れて
https://medium.com/google-cloud-jp/gae-%E3%81%AE%E3%83%AD%E3%82%B0%E3%81%AB%E6%86%A7%E3%82%8C%E3%81%A6-895ebe927c4