本文介紹了日誌記錄的過程,包括日誌標準、等級指南、類別、用途和多堆疊近似值。
日誌標準
由於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 |
|
圖 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)。這包括以下詳細資訊:
- 電子郵件地址
- 電話號碼
- 名稱
同樣,某些細節即使沒有明確的個人身份,也被視為敏感。
例如,儘管時區資訊不被視為個人識別訊息,但它確實可以指示使用者的大致位置。
日誌政策和可接受的詳細資訊必須作為發布前安全和隱私審查的一部分進行處理。
設備日誌
對所有裝置日誌的存取(包括使用android.permission.READ_LOGS
受到限制:
- 如果後台應用程式要求存取所有裝置日誌,則該請求將自動拒絕,除非該應用程式:
- 共用系統 UID。
- 使用本機系統進程 (
UID
<APP_UID
)。 - 使用
DropBoxManager
。 - 僅存取事件日誌緩衝區。
- 使用
EventLog
API。 - 使用儀器測試。
- 如果前台有
READ_LOGS
的應用程式要求存取裝置日誌,系統會提示使用者批准或拒絕該存取要求。