Firebase Clound Functionsのログ監視でSentryを使う時の試行錯誤
はじめに
Vue.jsのエラーログをsentryに送信することは、sentryでサインアップ後、示された手順に沿って進めていけば、簡単に設定ができました。
Firebase Cloud Functions(以下、Functionsと略します)のエラーログもsentryに送信したいと思い、試行錯誤したことをまとめておきたいと思います。
sentry以外の選択肢
まず、sentry以外のログ監視ツールを紹介します。
1.Fuctionsの管理コンソール
管理コンソールからも、ログを確認できます。シンプルなツールで、エラーを通知する機能などはなさそうです。
2.GCPのCloud Logging Error Reporting
下記のページに記載されていますが、GCPのログ監視ツールがあります。
もしかしたら、こちらを使うのが、一般的な選択かもしれません。今回は、フロントエンドのVue.jsと同じ監視ツールを使いたいという理由でFunctionsでもsentryを使うことにしました。sentryに不都合があれば、Cloud Logging Error Reportingに移行するかもしれません。
sentryのPlatformを選択
使えそうなPlatformは、下記の2種類あります。
- Node
- GCP Cloud Functions (Node)
Firebase Cloud Functionsは、GCP Cloud Functionsを元に作られているとはいえ、別物です。2の「GCP Cloud Functions (Node)」を使えるかどうかは、ドキュメントをざっと確認したり、ググっても判断できるドキュメントは見つかりませんでした。
まあ、とりあえず使ってみようということで、2のGCP Cloud Functions (Node)を選択しました。
GCP Cloud Functions (Node)を選択した理由
自分でラップ関数を書かなくていいからというのが理由です。
NodeのPlatformを使うと、汎用的に使うには、下記の記事のように、自分でラップ関数を書かないといけません。
「GCP Cloud Functions (Node)」であれば、ラップ関数もsentryのSDKに含まれているので、便利です。
const Sentry = require("@sentry/serverless");
// dsnは自分の環境の設定を入力してください
Sentry.GCPFunction.init({
dsn: "https://{xxxxx}@{yyyyy}.ingest.sentry.io/{zzzzz}",
tracesSampleRate: 1.0,
});
exports.helloEvents = Sentry.GCPFunction.wrapEventFunction((data, context, callback) => {
throw new Error('oh, hello there!');
});
Sentryの公式ドキュメント
導入には、sentryの管理画面で新規プロジェクトを追加し、Platformで「GCP Cloud Functions (Node)」を選択します。その後、「@sentry/serverless」というnpmパッケージがあるので、それをnpm installし、上記のようなコードを追加します。
試した「@sentry/serverless」のバージョンは、5.29.2です。
発生した問題
HTTPS callable functionsで、同期的に処理できない。エラーが発生しても、エラーを返せない
exports.joinSpace = functions.https.onCall(async (data, context) => {
// ...
});
exports.joinSpace = functions.https.onCall(
Sentry.GCPFunction.wrapEventFunction(async (data, context) => {
// ...
})
);
const joinSpace = functions.httpsCallable("joinSpace");
await joinSpace()
.then(function(result) {
console.log(result.data);
})
.catch(error => {
console.log(error)
})
フロントエンドから、HTTPS callable functionsを通して、Fucntionsを実行した時に、HTTPS callable functionsの実行完了後にthen()の内容を実行したいのですが、sentryのラップ関数を追加すると、実行完了前にthen()が実行されてしまいます。さらに、Functionsでエラーが発生した時に、catch()の内容が実行されません(エラー時もthen()が実行されます)。
この問題を回避する方法は見つからなかったので、sentryのラップ関数を使うのはやめ、普通にtry catch時にSentryのログ送信を行うように修正しました。
Trigger Background FunctionsでWarningが発生する
exports.addXX = functions
.region("asia-northeast1")
.firestore.document("xxx/{yyy}")
.onUpdate(
Sentry.GCPFunction.wrapEventFunction((change, { eventId, params }) => {
// ..
})
);
{"severity":"WARNING","message":"Function returned undefined, expected Promise or value"}
Trigger Background Functionsでは、処理の最後に値をreturnしないとwarningが出るのですが、sentryのラップ関数を追加すると、値をreturnする方法がなく、Warningが出続けてしまいます。
こちらはWarningは出てしまいますが、そのまま使い続けることにしました。
2022/06/21 追記
sentry serverlessのバージョンを7.1.1にしたところ、
Exception from a finished function: TypeError: callback is not a function
というエラーが出るようになった。
callbackは、FirebaseのCloud Functionsでは指定できないので、やはりsentry serverlessはFirebase Cloud Functionsで使うには適していない。Sentry.GCPFunction.wrapEventFunction
を使うのをやめにした。
参考URL:
結論: 現状では、PlatformはNodeにして、自分でラップ関数を書いた方が良い
僕は既に、「GCP Cloud Functions (Node)」を導入してしまったし、問題も軽微なので、そのまま「GCP Cloud Functions (Node)」を使い続けますが、新規に導入するのであれば、Platformは、「Node」を導入し、自分でラップ関数を書いた方が良いと思います。僕も時間ができた時に、自分のラップ関数にリファクタリングするかもしれません。
最後に
もし、発生した問題を回避する方法をご存知な方がいれば、コメントいただければ幸いです。
今後もVue.js、Firebase関連の記事を書いていく予定なので、良ければフォローお願いいたします!
Discussion