ぽくつなです

Cloud Functions でログをグルーピングする

または Cloud Functions で httpRequest ログを書く方法。

Cloud Logging (もう Stackdriver ブランドなくなりましたね)の好きな機能に、リクエスト内のログをまとめて表示する機能がある。アプリケーション内での一連のログをまとめて追えてとても便利。

medium.com

という先達のエントリで GAE 環境について書かれているように、Cloud Functions でもリクエスト内でのログを Cloud Logging 上でまとめて表示したい!!

f:id:pokutuna:20200408050942p:plain
まとまった状態

先のエントリでも書かれているように、ログを紐付けるための条件は

  • parent, child で同一 GCP プロジェクトであること
  • parent, child で logName が別々であること
  • parent が httpRequest であること
  • trace が同一であること

である。

経験上 Monitored Resource は region が異なっていてもログが紐付けられるし、GAE Standard のように httpRequest.requestUrl がなくて protoPayload に同等の構造が入っていても httpRequest と見なされて parent として扱われるみたい。

しかし Cloud Functions は、httpRequest ログを書かないので、紐付ける parent が存在しない... のだけど、Logging のクライアントライブラリを使って httpRequest 相当の構造を書くことで、parent になるログを作ることができる。

httpRequest の構造自体は Logging の LogEntry の構造を参考にく立てればよい。他にも規定のフィールドについて書いてあるので、グループ化に興味なくとも一度みておくとへーってなると思う。

そしてリクエストヘッダの X-Cloud-Trace-Context${traceId}/${spanId} がやってくるので、traceId を取り出してアプリケーションログといっしょに書けば晴れてログをまとめることができる。

とはいえ都度作るのは割と面倒だし、個人的にもよく使いたいので、httpRequest を書く Express ミドルウェアを npm package として作っておいた。

www.npmjs.com

実装はほぼ @google-cloud/logging-winston の提供するミドルウェアと同じである。Cloud Functions では明に書かないように作られていたし、Apache V2 の範囲で改変してよかろうと、ちょこちょこいじって package 化した。

これ単体では httpRequest を書くだけなので、@google-cloud/logging-winston@google-cloud/logging-bunyan などの trace をいい感じにハンドルしてくれるロガーを使うか、trace を自前で書く必要がある。

自前で trace をハンドルするならこういう感じ

const { Logging } = require("@google-cloud/logging");
 
const projectId = "<YOUR_PROJECT_ID>";
const logging = new Logging({ projectId });
const log = logging.log("application_log");
 
exports.app = async (req, res) => {
  const [traceId] = req.header("X-Cloud-Trace-Context").split("/");
  const trace = `projects/${projectId}/traces/${traceId}`;
 
  // log.entry(metadata, data)
  const entry = log.entry(
    { trace },
    { message: "this is a message", obj: { key: "value" } }
  );
  await log.write(entry);
};

という感じで、ログを紐付けて幸せに暮らしています。
新しいプレビュー版のログビューワーは念願の child のログも展開することができる!!

その他

Cloud Functions は Default Credential 問題が起きやすいので、ログを書くならサービスアカウントキーも常に指定しておくのがよいと思う。

blog.pokutuna.com

とはいえ、未だに nodejs10 runtime が Beta とか言ってるのは厳しいものがある。Storage や Firestore イベントで起動する必要もなくて、ちゃんと trace したり調査したいような規模ならもう GAE でいいんじゃないかな...と思う。

4/20 から Cloud Function のデプロイに Cloud Build API が必要という予告もあったし、デプロイサイクルや Default Credential 問題なんかが大きく改善しないかな〜楽しみですね。

COVID-19 でオンライン開催に変わった Google Cloud Next ’20 はその後音沙汰無い!!!