メインコンテンツまでスキップ

ログの利用

開発時のデバッグ用途に利用

開発時のデバッグ用途でログを出力します。

基本的な利用方法
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に保存すると仮定します。

ソースコードとのマッピング

次に、ソースマップを使って、スタックトレースとソースコードをマッピングします。

【Android】の場合
cat stack-trace.txt | npm run symbolicate:android
【iOS】の場合
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