GCP 外のアプリケーションのログを Stackdriver Logging で集める

2020/02/27 18:29:212020/02/27 23:42:55

Stackdriver logging は無償枠で50GB使えるので Heroku 等で動いてるアプリなどと連携させたくなる時があるかもしれません。
しかし、このプロダクトは GCP 内もしくは接続された AWS アカウントからのメトリックを集めるのに特化した構造になっており、そのほかのアプリケーションなどからログデータを集めようとすると多少の誤魔化しが必要になります。
今回は、私が現時点で実際に Heroku で動かしているアプリケーションへの設定を基に、Stackdriver logging にログを集めつつ Error Reporting でエラーも検知する方法について解説します。

下準備

SA の発行
  • GCP でロギングに使用するプロジェクトを選択し、API とサービスのライブラリから Stackdriver Logging API と Stackdriver Error Reporting API を有効化します。
  • 既に有効化されている場合が多い
  • IAM & Admin に行き、サービスアカウントを追加します
  • 名前
  • 自由
  • 自分は logging にしました
  • 権限
  • Logging 管理者
  • Error Reporting 管理者
  • ここら辺に関してはもう少し権限を絞っても用途的には十分な気がします
  • JSON 形式のキーを発行します

Heroku への設定
環境変数に GCP_SERVICE_ACCOUNT のような名前で発行された json のキーを設定します。

アプリケーションへの組み込み
今回は Heroku で動く Node + TypeScript アプリケーションに組み込みます。
ロガーについては bunyan を使用します。

インストール
install.sh
$ yarn add bunyan @google-cloud/logging-bunyan 
$ yarn add -D @types/bunyan

ロガー
src 以下に logger.ts とでもファイルを作成します。
  • logger.ts で環境変数を取り込みます。値のバリデーションには transform-ts を用いますが、これはまだ Stable ではないので、Stable なほうが良い場合は @hapi/joi とかを用いてください。
  • @hapi/joi は戻り値に勝手に型つかない記憶があります
logger.ts
import $ from "transform-ts" 
 
export const serviceAccount = $.obj({ 
    type: $.string, 
    project_id: $.string, 
    private_key_id: $.string, 
    private_key: $.string, 
    client_email: $.string, 
    client_id: $.string, 
    auth_uri: $.string, 
    token_uri: $.string, 
    auth_provider_x509_cert_url: $.string, 
    client_x509_cert_url: $.string, 
}).transformOrThrow(JSON.parse(process.env.GCP_SERVICE_ACCOUNT))
  • 他のスクリプトから読み出すためのロガーを作成していきます。
  • ロガーを定義します
logger.ts
import { LoggingBunyan } from "@google-cloud/logging-bunyan" 
import { name } from '../package.json' 
 
export const loggingBunyan = new LoggingBunyan({ 
    logName: name, 
    projectId: serviceAccount.project_id, 
    credentials: { 
        client_email: serviceAccount.client_email, 
        private_key: serviceAccount.private_key, 
    }, 
    resource: { 
        type: "gae_app", 
        labels: { 
            project_id: serviceAccount.project_id, 
            module_id: name, 
            version_id: process.env.HEROKU_SLUG_COMMIT || "", 
            zone: "", 
        }, 
    }, 
    serviceContext: process.env.HEROKU_SLUG_COMMIT 
        ? { 
              service: name, 
              version: process.env.HEROKU_SLUG_COMMIT, 
          } 
        : {}, 
})
  • エラーレポートさせるためのログとして、gae_app を採用しているのがコツです。
  • GAE にアプリケーションが実在する必要はありません
  • Error Reporting で module_id や version_id から動作アプリのコードに飛んだりする機能はもちろん使用できません。
  • logging_log などでは Error Reporting が発火しないので注意してください。
  • Heroku のコミットハッシュを環境変数経由で取得し、バージョンとして用いています。
  • ロガーを作成します。
logger.ts
export const getLogger = (s: string) => { 
    return bunyan.createLogger({ 
        name: s.replace(`${__dirname}/`, ""), 
        streams: [{ stream: process.stdout, level: process.env.HEROKU_SLUG_COMMIT ? "info" : "debug" }, loggingBunyan.stream("debug")], 
    }) 
}
  • 引数として __filename を与えることを想定しています。
  • コミットハッシュの存在によってロガーの動作を切り替えています。

ロガーの呼び出し
main.ts
import { getLogger } from "./logger" 
 
const logger = getLogger(__filename) 
 
const main = async () => { 
	logger.debug("ロガー") 
}

変な部分があったら Twitter まで連絡ください


著者の画像

ci7lus

@ci7lus

Caramelize - Made withCaramelizeand / Privacy