本文介紹了日誌記錄的過程,包括日誌標準、級別指南、類、用途和多堆棧近似。
日誌標準
由於在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 | 指示潛在問題的消息級別 |
圖 4: java.util.Logging.Level
。
0 | 緊急情況 | 系統無法使用 |
1 | 警報 | 必須立即採取行動 |
2 | 危急 | 關鍵條件 |
3 | 錯誤 | 錯誤條件 |
4 | 警告 | 警告條件 |
5 | 注意 | 正常但重要的情況 |
6 | 信息性 | 信息性消息 |
7 | 調試 | 調試級消息 |
圖 5: RFC 5424
- 第 6.2.1 節。
應用程序日誌
android.util.Log
類使用Log#isLoggable
使用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 |
---|
這對於處理預期底層代碼相同但允許的日誌級別不同的多種應用程序構建類型(例如,開發構建與發布構建)很有用。必須為應用程序(尤其是系統應用程序)設置並遵循明確的策略,以決定構建類型和發布預期如何影響日誌輸出。
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 | 僅用於從異步信號安全環境進行日誌記錄的庫 |
libbase | 為日誌記錄提供 C++ 流接口的日誌庫,類似於 Google 樣式 (glog) 日誌記錄。 libbase 在兩個外部項目中都可用,並且在使用libbase_ndk 的應用程序中可用。 |
圖 8:更高級別的日誌庫。
多棧近似
由於粒度和級別意圖的差異,不同的日誌記錄標準沒有明確或精確的匹配。例如,錯誤日誌的java.util.logging.Level
和android.util.Log
級別不是 1:1 匹配的:
java.util.Logging.Level | android.util.Log |
---|---|
嚴重的 | Log.wtf |
嚴重的 | Log.e |
圖 9:標準 Java 日誌記錄與 Android 日誌記錄的錯誤級別。
在這種情況下,請使用單獨的標準來確定應用哪個級別。
在具有多個堆棧級組件的系統開發過程中,請按照圖 1 確定每個組件使用哪個標準。有關分層消息傳遞的大致指南,請參見圖 2。
安全和隱私
不要記錄個人身份信息 (PII)。這包括以下詳細信息:
- 電子郵件地址
- 電話號碼
- 名稱
同樣,某些細節即使沒有明確的個人身份,也被認為是敏感的。
例如,雖然時區信息不被視為個人身份信息,但它確實提供了用戶大致位置的指示。
日誌政策和可接受的細節必須在發布前作為安全和隱私審查的一部分進行處理。