ログの利用
開発時のデバッグ用途に利用
開発時のデバッグ用途でログを出力します。
import {log} from 'framework';
log.debug("デバッグ用の文字列") // デバッグログを出力
ロガーのログレベルをビルドタイプ毎に分けることで、コードを変えることなくデバッグ情報の出力有無を切り替えできます。 このアプリケーションでは、ビルドタイプ毎に以下のログレベルのログを出力します。
Release
: エラーレベルDebug
: 全てのログレベル
リリース時の障害解析
ビルドタイプがRelease
の場合は、エラーレベルのログをFirebase Crashlyticsに送信します。
WebViewでのエラー発生時とHTTPステータス5xx系のエラー発生時は、基盤部品で自動的にエラーログが出力されます。
それ以外にも障害として検知するべきエラーが発生した場合には、エラーログを出力してください。
デバッグ情報のためのログなど、障害には当たらないログはエラーレベルでは出力しないでください。
Firebase Crashlyticsのコンソールに表示されるスタックトレースとソースコードのマッピング
Firebase Crashlyticsコンソールで、送信されたメッセージやスタックトレースが確認できます。 しかし、次の例で示すようにMinify処理されたソースコードのスタックトレースが表示されるため、元のソースコードとのマッピングがないと直感的にわからない表示となります。
Fatal Exception: com.facebook.react.common.JavascriptException: Error: Error has occurred in synchronous process., stack:
<unknown>@855:884
<unknown>@677:2461
value@231:8208
value@231:7464
onResponderRelease@231:6218
p@96:384
b@96:527
T@96:581
w@96:876
ke@96:12621
forEach@-1
_@96:2057
<unknown>@96:12968
xe@96:89236
Se@96:12419
Re@96:12808
receiveTouches@96:13600
value@32:3350
<unknown>@32:747
value@32:2610
value@32:719
value@-1
そこで、以下の手順を行うことでソースコードとのマッピングを解決して表示できます。
- ソースマップの作成
- ソースコードとのマッピング
それぞれの手順を次に示します。
ソースマップの作成
まず、次のコマンドでソースマップを作成します。
npm run bundle
[プロジェクトルート]/generated
に、index.android.bundle.map
, index.ios.bundle.map
が作成されます。
次に、Firebase Crashlyticsのコンソールに表示されているスタックトレースをコピーして、任意のファイル、ディレクトリに格納します。
ここでは、[プロジェクトルート]/stack-trace.txt
に保存すると仮定します。
ソースコードとのマッピング
次に、ソースマップを使って、スタックトレースとソースコードをマッピングします。
cat stack-trace.txt | npm run symbolicate:android
cat stack-trace.txt | npm run symbolicate:ios
(※)cat
コマンドがインストールされていない場合は、type
コマンドなどで代用してください。
実行後に、ソースコードの行数と関数名のマッピング解決済みのスタックトレースが標準出力され、エラー発生箇所がわかるようになります。
Fatal Exception: com.facebook.react.common.JavascriptException: Error: Error has occurred in synchronous process., stack:
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/src/screens/error/ErrorInEventHandler.tsx:8:useCallback$argument_0
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native-elements/dist/buttons/Button.js:35:useCallback$argument_0
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Pressability/Pressability.js:691:_performTransitionSideEffects
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Pressability/Pressability.js:628:_receiveSignal
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Pressability/Pressability.js:524:responderEventHandlers.onResponderRelease
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:32:invokeGuardedCallbackImpl
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:50:invokeGuardedCallback
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:63:invokeGuardedCallbackAndCatchFirstError
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:82:executeDispatch
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:976:executeDispatchesAndReleaseTopLevel
forEach@-1
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:155:forEachAccumulated
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1007:batchedUpdates$argument_0
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:7566:batchedUpdatesImpl
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:957:batchedUpdates
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:988:_receiveRootNodeIDEvent
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1053:ReactNativePrivateInterface.RCTEventEmitter.register$argument_0.receiveTouches
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:416:__callFunction
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:109:__guard$argument_0
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:364:__guard
~/dev/src/github.com/ws-4020/mobile-app-crib-notes/example-app/SantokuApp/node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:108:callFunctionReturnFlushedQueue
value@-1