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" />