［Android］android.util.Logの使い方を理解しよう

# はじめに

Androidではandroid.util.Logを使うことでLogcatにログを出力できます。
LogcatとはAndroid Studioに表示されている次のウィンドウのことです。

android.util.Logは簡単に使えるのでなんとなく仕様を理解しているそんな方も多いと思います。
筆者もその一人なのですがログの仕組みを理解してよいログを書けるように知識をまとめたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/7272b175-ac20-d8ec-c03f-607c6612619c.png)

# どうやったらログを出力できるのか？

まずはログをどうやったら出力できるのかというところだと思います。
android.util.Logでは次の2種類の方法でログを出力できます。

## (1) ログレベルごとに定義される関数を利用する

次のようにLogでは各レベルのログを出力するための関数が用意されていて
簡単に特定のレベルのログを出力できるようになっています。

| ログレベル | 関数名 | 
| ------- | ------- | 
| VERBOSE | Log.v |
| DEBUG | Log.d |
| INFO  | Log.i |
| WARN | Log.w | 
| ERROR | Log.e | 
| ASSERT | なし |

次のようにタグとメッセージを関数に渡すことでログを出力できます。

```kotlin:サンプルコード
Log.v("MainActivity", "verbose")
Log.d("MainActivity", "debug")
Log.i("MainActivity", "info")
Log.w("MainActivity", "warn")
Log.e("MainActivity", "error")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/d08f3dc3-bb45-5cd5-ef93-83a94a5de8e4.png)


またタグとメッセージの他にExceptionも渡せるようになっています。
ですのでキャッチしたExceptionをログに簡単に出力できるようになっています。


```kotlin:サンプルコード
try {
    throw Exception("Unknown Error")
} catch (e : Exception) {
    Log.v("TAG", "Message", e)
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/11afac48-8da1-7692-3bbf-2b74b40ed24c.png)

## (2) Printlnでログレベルを指定して出力する

その他にLog.println()を利用してログを出力することができます。
Log.println()ではタグとメッセージの他にログレベルも指定できるようになっています。
例えばASSERTレベルのログを出力したい場合に利用できる関数だと思います。


```kotlin:サンプルコード
Log.println(Log.ASSERT, "MainActivity", "ASSERT")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/3854d491-6ac1-45b2-d7dd-7908458f6ecf.png)

#### 💡TIPS ログレベルの優先度はどうなっているのか？

ちらっと出てきましたがログレベルは6段階で定義されています。
Androidではログレベルの定数値が大きいほど重要なログを表すように設計されているようです。

```txt:ログレベルの優先度
フォーマット : [レベル名称](定数値)

[VERBOSE](2) < [DEBUG](3) < [INFO](4) < [WARN](5) < [ERROR](6) < [ASSERT](7)
```


# どうやって出力するログレベルを制御するのか？

次に気になるのは出力するログレベルを制御できるのかだと思います。
android.util.LogではisLoggableで出力できるか判定する必要があります。
また出力できるか判定するためにログレベルをあわせて設定する必要があります。

## (1) isLoggableでログを出力するかどうか判定する
Log.isLoggableという関数が用意されており、どのレベルのログを出力するか判定できるようになっています。
次のようにLog.isLoggableにタグとレベルを渡して出力するかどうか判定し制御します。

```kotlin:サンプルコード
if (Log.isLoggable("MainActivity", Log.DEBUG)) {
    Log.d("MainActivity", "Good Debug Log")
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/073bdf26-fbeb-972c-dd8b-01c7ad71d1e5.png)

## (2) ログレベルを指定し出力するログをフィルタリングする

Log.isLoaggableでは出力すべきログレベルを判定することはできますが、
android.util.Logから出力すべきログレベルを設定することができません。
ログレベルは次のADBコマンドを使ってAndroidシステムに設定することができます。
（これがかなり使いづらく面倒なところだなと思いました）

### (a) デバイスのIDを確認する
次のコマンドでadbで接続するデバイスのIDを確認します。


```bash:デバイスIDの確認
» adb devices
List of devices attached
emulator-5554   device
```

### (b) デバイスのIDを指定してシェルを起動する
次のコマンドでadbを使ってデバイスのシェルを起動します。

```bash:シェル起動
» adb -s emulator-5554  shell
```

### (c) デバイスのログレベルを指定する
次のコマンドでタグに紐づくログレベルを指定します。

```bash:ログレベル設定
generic_x86:/ $ setprop log.tag.<タグ> <ログレベル>
generic_x86:/ $ setprop log.tag.MainActivity VERBOSE
```

次のコードでisLoggableの判定が変わっているか確認します。

```Kotlin:サンプルコード
Log.println(Log.ASSERT, "MainAcitivty", "VERBOSE : ${Log.isLoggable("MainActivity", Log.VERBOSE)}")
Log.println(Log.ASSERT, "MainAcitivty", "DEBUG   : ${Log.isLoggable("MainActivity", Log.DEBUG)}")
Log.println(Log.ASSERT, "MainAcitivty", "INFO    : ${Log.isLoggable("MainActivity", Log.INFO)}")
Log.println(Log.ASSERT, "MainAcitivty", "WARN    : ${Log.isLoggable("MainActivity", Log.WARN)}")
Log.println(Log.ASSERT, "MainAcitivty", "ERROR   : ${Log.isLoggable("MainActivity", Log.ERROR)}")
Log.println(Log.ASSERT, "MainAcitivty", "ASSERT  : ${Log.isLoggable("MainActivity", Log.ASSERT)}")
```

ログレベルをVERBOSEに設定したので、全てTRUEになっていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/8b2207a7-ce6a-1c8e-abcc-70458ecb8859.png)

例えばログレベルをINFOに設定するとVERBOSEとDEBUG以外がTRUEになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/50bbd48d-8c82-01ad-cf5b-e86508ab9d85.png)

# おわりに
次にandroid.util.Logについて調べてわかった特徴についてまとめます。
ん〜こう見るとandroid.util.Logは最低限の機能しかサポートしていないことがわかりますね。

* Logcatにログを出力することができる
* Logcatにログを出力する際には6段階のログレベルを指定できる
* 出力するログレベルかどうか判断するときにはisLoggableが使える
* 出力するログレベルを設定するにはADBコマンドが設定する必要がある

ログの出力先を変更できなかったりアプリリリース時にログを消したりもできないんですよね。
だからTimberを導入してリリース時のログを制御したりしているんだな〜ということがわかります。
ロガーは後から入れると面倒ですし、導入コストも小さいので有名なロガーを入れておくのが良さそうです。

## 参考
- [Log | Android Developers](https://developer.android.com/reference/android/util/Log)