【Golang】GCP用のフォーマットでログ出力する

# 概要
GCPにはログ管理用プロダクトCloud Logging(旧Stackdriver Logging)があります。
GKEやCloud Runを使う場合、標準出力で出したログを自動で収集してくれてとても便利です。

<img width="1440" alt="“” 2020-07-04 18.28.16.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56893/1f757758-0ad7-b0fd-fad4-509d2a331ffb.jpeg">

これだけでも全然嬉しいのですが、GCPの定義しているフォーマットで構造化したログを出力すればもう少しいい感じに出来るので試してみます。

# GCPのログについて
https://cloud.google.com/logging/docs/agent/configuration#special-fields
GCPのfluentdではこの「構造化ペイロード」のJSONフォーマットで出力すれば、
Cloud Loggingのログ構造であるLogEntryに対応付けてくれます。

## LogEntry
https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
今回は以下3点のfieldを意識します。

- `severity`
  - ログレベル
  - INFOやERROR、FATALなどが定義してある
     - [ログレベル詳細](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity)
  - Cloud Logging上ではUIでログレベルによる絞り込みが容易に可能
- `timestamp`
  - おそらく`timestamp`を定義していない場合はfluentdがログを検出したタイミングやCloud LoggingにLogEntryが登録されたタイミングのログがtimestampに登録されるはず
  - `timestamp`を出力に含めておけばログ出力したタイミングを残せる
- `jsonPayload`
  - ログ出力したいメッセージ
  - 前途の構造化ペイロードの`message`に対応付けられる

## HttpRequest
https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#httprequest
HTTPのリクエストはこの構造で出力するとCloud Loggingでかなりいい感じに表示してくれます。

(背景色が灰色なログ)
<img width="1153" alt="“” 2020-07-04 19.15.47.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56893/3425434e-fef1-46a3-45b5-f00ecc5f3b85.jpeg">

## Error Reporting
https://cloud.google.com/error-reporting
GCPではリアルタイムにエラーを管理するのにError Reportingの使用を推奨しています。
エラー発生時の通知はもちろん、エラー発生頻度や発生したコード位置なども表示してくれます。
<img width="468" alt="“” 2020-07-04 19.18.42.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56893/8e854188-a0e7-d4fe-29f9-6c4f9122bff4.jpeg">

このError Reportingへのエラー報告はクライアントライブラリを使う方法がありますが、
特定フォーマットのログを標準出力しCloud Logging経由で報告する方法もあります。
https://cloud.google.com/error-reporting/docs/formatting-error-messages

特定フォーマットは以下の`ReportedErrorEvent`になります。
https://cloud.google.com/error-reporting/reference/rest/v1beta1/projects.events/report?hl=ja#ReportedErrorEvent

ただし、埋めるところが多いので...
`@type`fieldで`type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent`をvalueに持ったJSONフォーマットのログを出力することでもOKです。
https://cloud.google.com/error-reporting/docs/formatting-error-messages#@type

# 実際に出力
## logrusとechoをカスタマイズしてみる
コード
https://github.com/suecideTech/sample-codes/tree/master/go-gcp-logging/logrusLogging

出力
<img width="1156" alt="“” 2020-07-04 19.38.33.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56893/0eb87f6a-7cee-a513-0999-8599b9688ec6.jpeg">

`severity `によるログマークの違い、HttpRequestによるリクエスト情報の可視化が出来ているかなと思います。

## zap(zapdriver)を使ってみる
爆速ロギングパッケージzapをcloud logging用にカスタマイズしたパッケージ、`zapdriver`が既にあるためそれを利用してみます。
https://github.com/blendle/zapdriver

コード
https://github.com/suecideTech/sample-codes/tree/master/go-gcp-logging/zapLogging

出力
<img width="1156" alt="“” 2020-07-04 19.38.33.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56893/5cae5b81-fdf5-5309-a260-bc9dcff357ed.jpeg">

ちなみに`zapdriver`はちゃんと`ReportedErrorEvent`でErrorReporting報告をしているみたいです。

# 所感
クラウドではログ管理や解析ツールが揃っているので...
何も考えずにただの文字列を出力しちゃうよりは、早い段階でログ設計をして構造化したログを出したほうがいいのかなと感じました。

# 参考にした記事
https://future-architect.github.io/articles/20200205/
https://note.com/_yoshioka/n/n513cbf9fd5ad
https://k11i.biz/blog/2018/10/03/stackdriver-logging-friendly-layout-java/