Cloud Run の Logging って結局どうなってんの??

Cloud Run の Logging って結局どうなってんの??

Cloud Run の Logging って使ってるとたまに { とかだけが出力されてて, 標準出力に pretty print してるだけなんやけどなーって、お気持ちになるので, 未来の自分のために一筆残しとく.

やりたいことと背景

整理する前にそもそもやりたいことがあってまずはその整理から.

その 1 severity を error にしないけど stacktrace を出したい

なんらかの Exception が throw されたら catch して exponential backoff しながら retry するっていう util function がすでに存在するんやけど, 雑に

try {
  // do something
} catch (e) {
  console.error(e);
}

こんなふうに書いてたら割りとよく起こる Exception (それ自体をつぶせっていう話はあるんやけど, 一旦はそれは置いといて) がじゃんじゃか Error Report に届いてしまって困った(てる). かといって, e.message だけを出力するようにするとマジの Exception になったときに困る.

ので, retry 中に起こった Exception に関しては severity を warn で出力したい

その 2 Log Metrics に使えるように折りたたみ可能な jsonPayload として出力したい

任意の severity で label をくっつけて出力するってのは, 公式にもドキュメントがあって, message プロパティが存在する場合は、ログエントリのメイン表示テキストとして使用されます。特別なプロパティの詳細については、以下のロギング リソース セクションをご覧ください。 って書いてるんですが, それがどのフィールドになるかは書かれてないように見える...

ので, そもそもどうやったらログの文字列としてのメッセージと payload 的な構造化されたメッセージとを両方出力できるのかがよくわからないのでコレを明確にしたい

っというわけで実践

適当な HTTP を受け取れる Cloud Run 環境を作っていくつか試してみる

その 1 の検証

まずは以下のコード

console.log(new Error(`use "console.log"`));
console.error(new Error(`use "console.error"`));

ハイ, console.log で投げようが, console.error で投げようが, Exception を直接投げつけると Error Reporting に乗る

using console.log and console.error to display stacktraces

次, 公式に従って

console.log(
  JSON.stringify({
    severity: 'WARNING',
    message: new Error('structured logging').stack,
    label1: 'stacktrace-as-message-test',
    component: 'stacktrace-as-message-test',
  }),
);

構造化されたログとして吐き出してみると, using structured logging following public docs severity が warn でテキストメッセージっぽい感じで改行を入れつつええ感じになってるぽ

↓ が元のやつ directly logging exception

この形式で吐き出すと Error Report には出なくなるので, 今すぐ対応が必要なエラーじゃないけど stacktrace はほしいみたいな例には対応できそう. ただ, 構造化されたログとして吐き出すと textPayload ではなく jsonPayload になるので検索するときのクエリが変わるってとこは若干注意でしょうかね. (変わってるけどまぁ運用上は特に気にならない)

その 2 の検証

logging metrics として使えそうな値を出してみる. ここでは適当な配列を jsonPayload として吐き出して logging metrics として使えるのか検証.

console.log(
  JSON.stringify({
    severity: 'INFO',
    message: 'is it avialable as logging metrics??',
    paylad: [1, 2, 3, 'hoge', 'kachi-nai-sosu'],
    component: 'logging-metrics-app',
  }),
);

jsonPaylad with array before expantion jsonPaylad with array after expantion

まぁ、よさそう. あとはコレを Log-based metrics として指定してもろて. って思ったけど

methods for log-based metrics

Log based metrics がカウントと数値型しか取れないっぽいので, やるとしたら

const payload = [1, 2, 3, 'hoge', 'kachi-nai-sosu'];
console.log(
  JSON.stringify({
    severity: 'INFO',
    message: 'is it avialable as logging metrics??',
    paylad: payload,
    payloadLength: payload.length,
    component: 'logging-metrics-app',
  }),
);

的なことをやるのがよさそうで, 実際数値として吐き出してあげると

こんなふうに設定ができて configure log based metrics with interger type entry

こんなふうにグラフが出せる graph log based metrics

はい. っというわけでコレにて検証は完了.

感想 (とまとめ)

  • stacktrace は文字列として jsonPayload.message に入れるとログのタイトルにもなるし, まぁまぁわかりやすいし, 任意の severity も付与できる
  • Log based metrics は数値として吐き出す必要があるので, 若干使い勝手に何ありか??
    • custom metrics として Cloud Monitoring に export してあげる方が使い勝手いいかも??
      • ここはもうちょっと使い込んで検証が必要やね

追記: Error Reporting に console.log から送る方法あるんか

調べ終わって, "っさ, 実装するやで" って思った矢先, Error Reporting に対してなんらかの id や label を指定したいときあるやんって思ったので, 試してく. https://cloud.google.com/error-reporting/docs/formatting-error-messages によると

message、stack_trace、exception フィールドを含む jsonPayload。
これらのフィールドは複数指定できます。これらのフィールドが複数指定されている場合、評価は stack_trace、exception、message の順で行われます。

だそうなので,

console.log(
  JSON.stringify({
    severity: 'INFO',
    stack_trace: new Error(`error report??`).stack,
    payloadLength: randomInt(0, 10),
    component: 'error-reporting-app',
    user_id: 'test-user-001',
  }),
);

stack_trace フィールドを jsonPaylod に含められるように吐き出してみました. しかしこちらは予想に反して失敗. severity を ERROR に設定してみる

console.log(
  JSON.stringify({
    severity: 'ERROR',
    stack_trace: new Error(`error report??`).stack,
    payloadLength: randomInt(0, 10),
    component: 'error-reporting-app',
    user_id: 'test-user-001',
  }),
);

無事成功.

error reporting with console.log

っというわけなので, jsonPayload に stack_trace , exception , message としてスタックトレースを severity: 'ERROR' とともに標準出力に吐き出せば OK っということがわかりましたとさ.

参考リンク s

octobot: タコ・ソ・ノモノ