Androidアプリケーションから使用するロギングの種類と選択
プログラミングをしてデバッグをする際、ロギングは欠かせません。Androidアプリケーションも昨今は規模が大きくなってきており(なんせGUIからデータベースからネットワーク、そしてデバイスを扱うところまで含まれますから)、デバッグは単純ではなくなってきています。
昔はワークステーションと呼ばれたUNIX計算機や、PC等でデスクトップアプリケーションやサーバーアプリケーション を開発してきた経験上、しっかりとしたロギング機構を使うことが不可欠です。
Androidアプリケーション開発では、標準ライブラリに含まれる android.util.Log を使ってロギングをすることが多いようです。Androidの標準ログ機構に記録されたログを読み出す開発ツールが logcat ですが、ロギングのことを logcat と呼んでいる記事等も数多く見かけます。では、Android アプリケーションのプログラミングではAndroid標準ログ(logcat)を使えば十分でしょうか? ちょっと調べてみました。
Android標準ログ(logcat)を調べたところ
- AndroidのJavaアプリケーション用に提供される標準APIに含まれる
- 設定不要で、複数のレベルから1つを選択してログ出力する
- 引数にはTAGと呼ぶ識別子(文字列)と、メッセージ文字列を指定する
- ログを見るときは、adbシェル経由でlogcatコマンドを実行するが、昨今のIDEにはlogcatに気の利く機能が追加され便利につかえる
- ログはAndroid上で動作するプログラムやOSからの出力が混ざっている。logcatを実行するとデフォルトでは大量のログが表示されるので、logcatのコマンドラインオプションでフィルターすることが多い
- Android StudioなどのIDEではlogcatが常時実行されログが表示される
Android標準ログの問題点
ところが、このAndroid標準ログには問題もあります。
android.util.Log へログを出力すると、JNI呼び出しでネイティブコードからliblogdの関数が実行され、Android端末上にいるlogdプロセスにソケット通信でログエントリが渡され、リングバッファのデバイス(/dev/log/*)に格納されます。UNIX/Linux での syslog に出力するイメージでしょうか。これは気軽にログを出すと性能が著しく劣化しそうです。
また、このLogは基本全てのログ出力呼び出しをだだ流しします。Javaアプリケーション側でログ出力を設定で抑制する手段がないので、if文でログ出力を制御するしかありません。それは避けたい・・・。
Googleのドキュメントにも、アプリケーションをリリースビルドするときはログ出力を削除しようと書かれています。でも、ログはアプリケーションが実際に使われている環境で生じた問題点を追究するほぼ唯一の手がかりです。ログを出さないということは考えにくいことです。
また、ログをためるバッファはそれほど大きくなく、端末により異なりますが手元のPixel 3の場合は256KBです。一日運用してトラブルがあった場合にログファイルを取得するといったことが難しいです。
Android以外の環境と共通化したいモジュールの作成では、Android固有のAPIを使えません。
代替のロギング手段
まずは、Android上でロギングを行うことができるライブラリをざっと調べてみたところ、次がでてきました(2,3年内にリリースがあったもの)。
- Java SE の標準ロギングである java.util.loggingパッケージが利用できる模様
- Timber というオープンソースライブラリを利用する
- SLF4J と Logback for android を組み合わせて使う
- SLF4J と Timber を組み合わせて使う
Timberは、Android標準ログをラッパーしたものです。
ログの出力の抑制がJavaアプリケーション内でif文等の制御をせずにでき、性能がそこそこでリリース時にファイルにログが取れ、他のプラットフォームと共用できるものは、1と3になります。