GCP にはログの収集、保管、検索を容易に行えるStackdriver Loggingという機能がある。Elixir を使ってログを Stackdriver Logging へ送る方法を書く。

Stackdriver は GCP の永久無料枠(always free)で利用可能であり、Pricingによると、プロジェクト毎に 1 ヶ月あたり 50GiB が無料枠となるそうだ。(50GiB という表記は何かの間違いではないかと思えるほどの量であるが、ドキュメントにはそう書いてある)

Elixir を使ってログを Stackdrive Logging へ送る最小限の設定を発見できた。2019-08-25 現在は Google や Github のコード検索をしてみたものの見つけられなかった。この記録が誰かの役に立つとうれしい。

利用するライブラリ

インストール/セットアップ

  • GCP にプロジェクトを作成する。今回は my-project というプロジェクトを作成した
  • 作成したプロジェクトに Editor role を付加したサービスアカウントを作成する
  • mix.exsgothgoogle_api_logging の依存を追加する
  • goth のために Elixir で json 形式の private key を読みこむ
    • Service accountsからサービスアカウントの private key を json 形式でダウンロードする
    • ダウンロードした json を読み込むよう Elixir の config を設定する
      • 私は GCP_CREDENTIALS という環境変数に json を 1 行にしたものを直接書きこむ方法を採用した
      • TIPS: jq -c . lateral-yew-251023-06197db86c63.json のような形で json を 1 行にしたものを取得できる

実行

# GCPに作成したprojectのID。Nameではなく、IDの方。
my_project_id = "lateral-yew-251023"

# 以下を満たす任意のログ名
# - 512文字以下
# - 大文字、小文字の英文字
# - スラッシュ(/)、アンダースコア(_)、ハイフン(-)、ピリオド(.)
my_log_name = "my_log_name"

# Gothを利用しStackdriverに送付する権限を持ったtokenを取得する
#
# 有効な文字列は以下のURLを参照のこと。
# https://cloud.google.com/logging/docs/access-control#scopes
{:ok, %{token: token}} = Goth.Token.for_scope("https://www.googleapis.com/auth/logging.write")
conn = GoogleApi.Logging.V2.Connection.new(token)

# 監視しているリソースの種類および名前
#
# https://hexdocs.pm/google_api_logging/0.12.0/api-reference.html
#
# typeとlobalの有効な組み合わせは以下のURLを参照のこと。
# https://cloud.google.com/logging/docs/api/v2/resource-list#resource-types
#
# GCPでもAWSでもない場所から利用しようとするときのtypeはglobalくらいしか該当するものがなさそうだった。
# GCPやAWSからの場合はgeneric_nodeやgeneric_taskも検討に値するかもしれない。
monitored_resource = %GoogleApi.Logging.V2.Model.MonitoredResource{type: "global", labels: %{project_id: my_project_id}}

# Stackdriverに送りたいログを作る
#
# https://hexdocs.pm/google_api_logging/0.12.0/GoogleApi.Logging.V2.Model.LogEntry.html
#
# logNameではどのような値が有効かは以下のURLにあるlogNameフィールドの解説が読みやすい。
# https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry
#
# Stackdriverが初めてのlogNameを受けとると、そのlogNameのlogsが新規作成される。
# logNameを収める場所を作成するという手順は必要ない。
# https://cloud.google.com/logging/docs/api/tasks/creating-logs#creating_logs
entry = %GoogleApi.Logging.V2.Model.LogEntry{resource: monitored_resource, logName: "projects/#{my_project_id}/logs/#{my_log_name}", textPayload: "Hello StackDriver!!"}

# Stackdriverへ送りたいログのまとまりを作る
#
# https://hexdocs.pm/google_api_logging/0.12.0/GoogleApi.Logging.V2.Model.WriteLogEntriesRequest.html
#
# ドキュメントによると、ログを沢山送るような環境では、送信のスループット向上やStackdriverのクォータ制限にかからないようにEntryを複数リストにして送るとよいようだ。
entries = %GoogleApi.Logging.V2.Model.WriteLogEntriesRequest{entries: [entry]}

# Stackdriverへログを送る
#
# https://hexdocs.pm/google_api_logging/GoogleApi.Logging.V2.Api.Entries.html#logging_entries_write/3
{:ok, _} = GoogleApi.Logging.V2.Api.Entries.logging_entries_write(conn, body: entries)

Viewerを開き、Resouce の選択画面を Global にすると Stackdriver へ書きこんだログが表示されている。