本文将介绍日志记录流程,包括日志标准、级别准则、类、用途和多堆栈类似项。
日志标准
由于在 logcat
中合并使用了多个标准,Android 中的日志记录较为复杂。使用的主要标准详情如下:
来源 | 示例 | 堆栈级别准则 |
---|---|---|
RFC 5424 (syslog 标准) |
Linux 内核、许多 Unix 应用 | 内核、系统守护程序 |
android.util.Log |
Android 框架 + 应用日志记录 | Android 框架和系统应用 |
java.util.logging.Level |
Java 中的常规日志记录 | 非系统应用 |
图 1:日志级别标准。
尽管这些标准都有类似的级别结构,但它们在粒度上存在差异。各个标准的近似等效项如下所示:
RFC 5424 级别 | RFC 5424 严重性 | RFC 5424 说明 | android.util.Log | java.util.logging.Level |
---|---|---|---|---|
0 | 紧急情况 | 系统无法使用 | Log.e / Log.wtf |
SEVERE |
1 | 提醒 | 必须立即采取措施 | Log.e / Log.wtf |
SEVERE |
2 | 严重 | 严重情况 | Log.e / Log.wtf |
SEVERE |
3 | 错误 | 错误情况 | Log.e |
SEVERE |
4 | 警告 | 警告情况 | Log.w |
WARNING |
5 | 通知 | 正常,但值得注意 | Log.w |
WARNING |
6 | 信息 | 提供参考信息 | Log.i |
INFO |
7 | 调试 | 调试级消息 | Log.d |
CONFIG 、FINE |
- | - | 提供详细消息 | Log.v |
FINER / FINEST |
图 2:syslog
、Android 和 Java 日志记录级别。
日志级别准则
各个日志标准都有现有的准则。所选日志级别遵循正在使用的适当标准,例如使用 syslog
标准进行内核开发。
以下三个图表按照由少到多的顺序显示了日志级别顺序:
ERROR |
这些日志始终会保留。 |
WARN |
这些日志始终会保留。 |
INFO |
这些日志始终会保留。 |
DEBUG |
这些日志会被编译,但在运行时会被删除。 |
VERBOSE |
除开发期间外,系统不会将这些日志编译到应用中。 |
图 3:android.util.Log
CONFIG |
静态配置消息的消息级别 |
FINE |
提供跟踪信息的消息级别 |
FINER |
表示相当详细的跟踪消息 |
FINEST |
表示非常详细的跟踪消息 |
INFO |
参考性消息的消息级别 |
SEVERE |
表示严重故障的消息级别 |
WARNING |
表示潜在问题的消息级别 |
0 | 紧急情况 | 系统无法使用 |
1 | 提醒 | 必须立即采取措施 |
2 | 严重 | 严重情况 |
3 | 错误 | 错误情况 |
4 | 警告 | 警告情况 |
5 | 通知 | 正常,但值得注意的情况 |
6 | 参考消息 | 参考性消息 |
7 | 调试 | 调试级消息 |
图 5:RFC 5424
- 第 6.2.1 节。
应用日志记录
选择性日志记录是由使用 Log#isLoggable
的 android.util.Log
类通过 TAG
执行的,如下所示:
if (Log.isLoggable("FOO_TAG", Log.VERBOSE)) { Log.v("FOO_TAG", "Message for logging."); } |
---|
在运行时可以调整日志,以提供特定级别的日志记录,如下所示:
adb shell setprop log.tag.FOO_TAG VERBOSE |
---|
log.tag.*
属性会在重启时重置。此外,还有永久变体在重启后保持不变。请参阅下文:
adb shell setprop persist.log.tag.FOO_TAG VERBOSE |
---|
Log#isLoggable
检查会在应用代码中留下日志轨迹。布尔值 DEBUG
标志会使用已设置为 false
的编译器优化来绕过日志跟踪记录,如下所示:
private final static boolean DEBUG = false; |
---|
在编译时,R8
可利用 ProGuard 规则集逐个 APK 地移除其上的日志记录。以下示例可为 android.util.Log
移除 INFO
级别以下的所有日志记录:
# This allows proguard to strip isLoggable() blocks containing only <=INFO log # code from release builds. -assumenosideeffects class android.util.Log { static *** i(...); static *** d(...); static *** v(...); static *** isLoggable(...); } -maximumremovedandroidloglevel 4 |
---|
当多个应用 build 类型(例如开发 build 与发布 build)的底层代码预计相同、但所允许的日志级别不同时,这对于处理这些 build 类型将非常有用。必须设置并遵循显式政策,以便应用(尤其是系统应用)确定 build 类型和发布预期如何影响日志输出。
Android 运行时 (ART) 中的系统日志记录
有多个类可用于系统应用和服务:
类 | 用途 |
---|---|
android.telephony.Rlog |
电台日志记录 |
android.util.Log |
常规应用日志记录 |
android.util.EventLog |
系统集成商诊断事件日志记录 |
android.util.Slog |
平台框架日志记录 |
图 6:可用的系统日志类和用途。
虽然 android.util.Log
和 android.util.Slog
使用相同的日志级别标准,但 Slog
是一个仅供平台使用的 @hide
类。EventLog
级别会映射到 /system/etc/event-log-tags
中 event.logtags
文件中的条目。
原生日志记录
C/C++ 中的日志记录遵循 syslog
标准,其中 syslog
(2) 对应于用于控制 printk
缓冲区的 Linux 内核 syslog
,而 syslog
(3) 对应于常规系统日志记录器。Android 将 liblog
库用于常规系统日志记录。
liblog
使用以下宏表单提供用于子日志组的封装容器:
[Sublog Buffer ID] LOG [Log Level ID] |
例如,RLOGD
对应于 [Radio log buffer ID] LOG [Debug Level]
。主要的 liblog
封装容器如下所示:
封装容器类 | 示例函数 |
---|---|
log_main.h |
ALOGV 、ALOGW |
log_radio.h |
RLOGD 、RLOGE |
log_system.h |
SLOGI 、SLOGW |
图 7:liblog
封装容器。
Android 提供更高级别的日志记录接口,比直接使用 liblog
更受欢迎,如下所示:
库 | 用法 |
---|---|
async_safe |
此库仅适合来自 async-signal-safe 环境的日志记录 |
libbase |
此日志记录库提供日志记录的 C++ 流接口,类似于 Google 样式 (glog) 的日志记录。libbase 可在外部项目中使用,并可用于使用 libbase_ndk 的应用。 |
图 8:更高级别的日志库。
多堆栈类似项
由于粒度和级别 intent 方面存在差异,不同日志记录标准不存在明确或完全的匹配。例如,错误日志的 java.util.logging.Level
级别和 android.util.Log
级别不是一对一匹配的:
java.util.Logging.Level | android.util.Log |
---|---|
SEVERE | Log.wtf |
SEVERE | Log.e |
图 9:标准 Java 日志记录与 Android 日志记录的错误级别对比。
在这类情况下,请使用单独标准来确定要应用的级别。
在具有多个堆栈级组件的系统开发中,请按照图 1 确定每个组件要使用的标准。如需关于分层消息传递的大致指南,请见图 2。
安全和隐私设置
不得记录个人身份信息 (PII),包括诸如以下的详细信息:
- 电子邮件地址
- 电话号码
- 名称
类似地,某些详细信息即便不是明确的个人身份信息,也被视为敏感信息。
例如,虽然时区信息不被视为个人身份信息,但它确实可以指示用户的大概位置。
作为安全和隐私审核的一部分,必须在发布之前对日志政策和可接受的详细信息进行处理。
设备日志
限制访问所有设备日志,包括使用 android.permission.READ_LOGS
:
- 如果有后台应用请求访问所有设备日志,除非应用符合以下条件,否则系统会自动拒绝该请求:
- 共用系统 UID。
- 使用原生系统进程 (
UID
<APP_UID
)。 - 使用
DropBoxManager
。 - 仅访问事件日志缓冲区。
- 使用
EventLog
API。 - 使用插桩测试。
- 如果具有
READ_LOGS
的前台应用请求访问设备日志,系统会提示用户批准或拒绝访问请求。