Studyplus Engineering Blog

スタディプラスの開発者が発信するブログ

Firebase Functionsのロギングを改善した話

はじめまして、モバイルクライアントグループの市川です。昨年9月からポルトの開発にジョインしました!

porto-book.jp

ポルトはFlutterとFirebaseで開発しているサービスです。 サーバサイドの処理は全てFirebase Functionsで実装されており、エンドポイントの数は40近くあります。 その中には、課金に関するクリティカルなAPIや外部サービスと連携するAPIなど、問題が起きるとサービスの継続に大きな影響を与えるものも多くあります。 今回はサービスを安定運用するため、Firebase Functionsのロギング改善した話を3つ書こうと思います。

ロガーの変更 と エラーレポーティング

ポルトのFunctionsのロギングは、consoleを利用していました。現状では、ロガーSDK loggerが公開されており、そちらが推奨されているので、すべてのロギングをロガーSDKに変更しました。 FunctionsのロギングはCloud Loggingと統合されていますが、ロガーSDKを利用することで、より適切なログの管理できます。特に便利だと感じた点は以下の2つです。

①重大度レベルの反映

  • consoleの場合、console.errorでロギングしてもCloud Logging上では重大度レベルが反映されません。なのでエラーログもデバックログと同等に扱われてしまい、致命的な問題が起きているかを把握することが難しい状況でした。ロガーSDKを使うと適切に重大度レベルが設定されます。
  • さらにCloud LoggingはError Reportingと連携しており、重大度レベルがエラーのログは自動的にレポーティングされます。デフォルトでメールにも通知してくれるので、リアルタイムで問題に気がつくことができました。Sentryなどを導入しなくてもGCPだけでエラーレポーティングできるのはかなり便利です。

②ロガーの引数が柔軟

  • consoleの場合、Objectを渡すと、ログが複数に分割されたり、意図しないログ出力になってしまうため、渡す値を文字列にするなど工夫が必要でした。
  • ロガーSDKの場合、Objectを渡しても、自動で文字列に展開してくれます。また最後の引数に渡したObjectはログエントリのjsonPayloadとしてjson形式で保存してくれる機能もあります。
    • なお、jsonPayload内の値はCloud Loggingで検索可能なので、各Functionsの最初でリクエストパラメータやユーザ情報(UID)をしまっておくと、あるユーザが実行したAPIをトレースできるようになるのでオススメです。

参考情報

ロガーSDKやエラーレポーティングについては公式ドキュメントに日本語で書かれていますので、とても参考になります。

ログの保持期間の変更

Functionsのログはデフォルトでは30日しか保存されません。30日だと月単位で実行される処理において、前回の状況を確認できず困ったことがありました。 ただ、ログの保持期間を長くしすぎるとその分だけ費用がかかってしまうので、ポルトでは一旦100日に変更しました。

Functionsのログは、Cloud Loggingのログバケット_Defaultに保存されますので、その保持期間を変更することで対応できます。

f:id:popobot:20210531151723p:plain

不要ログの排除

ポルトではFirestoreの重要なコレクションについては、変更履歴を確認できるように、Firebase ExtensionsのExport Collections to BigQueryを利用してFirestoreの更新をBigQueryにエクスポートしています。この拡張機能はFunctionsを追加する形で実装されていますが、実行時に勝手にログを書き込みます。Firestoreに変更があるたびに実行されるので、ログ量はかなり多くなっていました。 不要なログが増えてると、Cloud Loggingのコンソール画面で閲覧するとき邪魔ですし、費用も余計にかかってしまいます。

そこでCloud Loggingのログルーター機能を利用して、Firebase Extensionsのロギングを除外しました。

除外の設定方法

  • Cloud Loggingのメニューから「ログルーター」を選び、シンク_Defaultの編集画面を開きます
  • 「シンクに含めないログの選択」から「除外設定を追加」を選んでフィルタを作成します
  • フィルタを設定します
    • 除外フィルタ名: ext-firestore-bigquery-export (これはなんでもよい)
    • 除外フィルタ率: 100
    • 除外フィルタ: 以下の条件式
resource.type="cloud_function"
resource.labels.function_name=~"^ext-firestore-bigquery-export"

f:id:popobot:20210531151657p:plain

まとめ

今回はポルトのFunctionsのログ管理について紹介しました。ログを適切に管理することで、大きく2つの安心を得ることができました。

  • エラーレポーティングによって、問題があったらすぐに気がつける安心
  • トラブルが発生した際に、問題を切り分けるための情報がある安心

また、これらの機能をGCPだけで簡単に実現できるのはFirebaseの強みだと感じました!