Android的日志機制和普通的Java項目有一些不一樣, 這里記錄一下
安卓內建的Log
安卓應用類型(在build.gradle里定義 android {...})的模塊, 可以直接引用內建的android.util.Log, 這是最常用的日志機制, 和服務器端開發的區別在於, 內建的Log需要一個TAG, 這個TAG用於在控制台過濾日志, 一般使用類名. 日志級別從verbose開始, 分為 v, d, i, w, e. 其中, v不應該被編譯進入發布版本, d會被編譯但是會在運行時去掉. 長度大於23個字符的TAG在Logcat輸出中會被截斷. 如果需要對某個TAG設置單獨的日志級別, 需要通過setprop設置
setprop log.tag.<YOUR_LOG_TAG> <LEVEL> # 例如 adb shell setprop log.tag.MainActivity VERBOSE
如果需要寫入文件, 不能在android.util.Log的基礎上實現, 需要自己實現一個Log類.
使用slf4j + Logback classic
對於非安卓應用模式的模塊, 例如Java/Kotlin Library, 無法直接使用安卓內建Log, 可以使用slf4j. 網絡上可以找到的android slf4j變體很多, 但是經典的org.slf4j:slf-api還是可用的, 需要在build.gradle添加dependency, 這里使用了和服務器環境一樣的ch.qos.logback. logback-core會被logback-classic引用加入, 可以不寫在dependencies里面.
dependencies {
...
implementation 'org.slf4j:slf4j-api:1.7.25'
implementation 'ch.qos.logback:logback-classic:1.2.3'
...
}
添加上門的dependency之后, 就可以在代碼中輸出日志, 這個輸出對於logcat, 和命令行執行main()方法都是有效的.
private static final Logger Log = LoggerFactory.getLogger(NetworkUtil.class); ... Log.error(e.getMessage(), e); ...
使用slf4j + tony19:logback-android
在Java/Kotlin Library的build.gradle中只添加slf4j, 在app module的build.gradle中添加tony19:logback-android
dependencies {
...
implementation 'com.github.tony19:logback-android:2.0.0'
...
然后在app module中, 與main和res目錄平級添加assets目錄, 添加logback.xml, 寫入
<configuration>
<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
<tagEncoder>
<pattern>%logger{12}</pattern>
</tagEncoder>
<encoder>
<pattern>[%-20thread] %msg</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="logcat" />
</root>
</configuration>
這樣就可以在運行app時, 使用slf4j輸出日志.
注意: assets/logback.xml 這個文件是必須的, 如果沒有找到配置文件, tony19:logback-android不會輸出任何日志.
logback-classic 與 logback-android 並存
如果在lib中只添加slf4j, 在運行main()時會報錯 SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
如果在lib中添加tony19:logback-android, 依然會報上面的錯誤
如果在lib中添加logback-classic, 運行main()會正常輸出日志, 但是在編譯app時, 會提示"Duplicate class ch.qos.logback.classic"
這是因為這兩個logback實現類產生了沖突, 需要在app的build.gradle中配置排除lib引入的logback-classic, 添加
android {
...
configurations {
all {
exclude group: 'ch.qos.logback', module: 'logback-classic'
}
}
...
之后就可以正常編譯了
Logback-android日志寫入文件
使用以下配置, 可以將日志寫入文件, 注意這里的文件路徑 ${DATA_DIR} 會指向應用在內部存儲的目錄, 這個不需要讀寫權限, 並且其他應用無權訪問. 對應文件系統中的實際路徑為 /storage/emulated/0/com.rockbb.app.pocketserver/files/logs/app.log 或 /data/user/0/com.rockbb.app.pocketserver/files/logs/app.log , 但是如果在<file>中直接指定這個路徑, 就需要讀寫權限.
<configuration>
<!-- Create a file appender for a log in the application's data directory -->
<property name="LOG_HOME" value="${DATA_DIR}" />
<appender name="file" class="ch.qos.logback.core.FileAppender">
<file>${LOG_HOME}/logs/app.log</file>
<encoder>
<tagEncoder>
<pattern>%35.35logger{70}#%4.4line</pattern>
</tagEncoder>
<encoder>
<pattern>%8.8thread %msg%n</pattern>
</encoder>
</encoder>
</appender>
<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
<tagEncoder>
<pattern>%25.25logger{50}#%3.3line</pattern>
</tagEncoder>
<encoder>
<pattern>%8.8thread %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="logcat" />
<appender-ref ref="file" />
</root>
</configuration>
需要寫入其他公共路徑, 需要在AndroidManifest.xml中申請權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
