Tìm hiểu về tính năng ghi nhật ký

Bài viết này trình bày quy trình ghi nhật ký, bao gồm các tiêu chuẩn nhật ký, nguyên tắc về cấp độ, các lớp, mục đích và các phép tính gần đúng nhiều ngăn xếp.

Tiêu chuẩn về nhật ký

Việc ghi nhật ký trong Android rất phức tạp do sự kết hợp của các tiêu chuẩn được dùng và kết hợp trong logcat. Sau đây là thông tin chi tiết về các tiêu chuẩn chính được sử dụng:

Nguồn Ví dụ Hướng dẫn về cấp độ ngăn xếp
RFC 5424 (syslog tiêu chuẩn) Nhân Linux, nhiều ứng dụng Unix Kernel, system daemons
android.util.Log Khung Android + ghi nhật ký ứng dụng Khung Android và ứng dụng hệ thống
java.util.logging.Level Ghi nhật ký chung trong Java ứng dụng không phải là ứng dụng hệ thống

Hình 1: Các tiêu chuẩn về cấp độ nhật ký.

Mặc dù mỗi tiêu chuẩn này đều có cấu trúc cấp độ tương tự nhau, nhưng chúng khác nhau về độ chi tiết. Sau đây là các giá trị tương đương gần đúng giữa các tiêu chuẩn:

Cấp độ RFC 5424 Mức độ nghiêm trọng theo RFC 5424 Nội dung mô tả RFC 5424 android.util.Log java.util.logging.Level
0 Khẩn cấp Hệ thống không sử dụng được Log.e / Log.wtf SEVERE
1 Cảnh báo Bạn phải hành động ngay lập tức Log.e / Log.wtf SEVERE
2 Quan trọng Điều kiện quan trọng Log.e / Log.wtf SEVERE
3 Lỗi Điều kiện lỗi Log.e SEVERE
4 Cảnh báo Điều kiện cảnh báo Log.w WARNING
5 Lưu ý Bình thường nhưng đáng kể Log.w WARNING
6 Nút thông tin Thông báo thông tin Log.i INFO
7 Gỡ lỗi Thông báo ở cấp gỡ lỗi Log.d CONFIG, FINE
- - Thông báo chi tiết Log.v FINER / FINEST

Hình 2: syslog, Android và các cấp độ ghi nhật ký Java.

Nguyên tắc về cấp độ nhật ký

Có các nguyên tắc hiện hành cho từng tiêu chuẩn nhật ký. Cấp nhật ký đã chọn tuân theo tiêu chuẩn thích hợp đang được sử dụng, chẳng hạn như sử dụng tiêu chuẩn syslog để phát triển hạt nhân.

Thứ tự cấp nhật ký, từ ít nhất đến nhiều nhất, được minh hoạ trong 3 hình dưới đây:

ERROR Những nhật ký này luôn được lưu giữ.
WARN Những nhật ký này luôn được lưu giữ.
INFO Những nhật ký này luôn được lưu giữ.
DEBUG Những nhật ký này được biên dịch nhưng bị xoá vào thời gian chạy.
VERBOSE Các nhật ký này không bao giờ được biên dịch thành một ứng dụng, ngoại trừ trong quá trình phát triển.

Hình 3: android.util.Log

CONFIG Cấp độ thông báo cho thông báo về cấu hình tĩnh
FINE Cấp thông báo cung cấp thông tin theo dõi
FINER Cho biết một thông báo theo dõi khá chi tiết
FINEST Cho biết một thông báo theo dõi có độ chi tiết cao
INFO Cấp độ thông báo cho thông báo thông tin
SEVERE Cấp thông báo cho biết lỗi nghiêm trọng
WARNING Cấp độ thông báo cho biết vấn đề có thể xảy ra

Hình 4: java.util.Logging.Level.

0 Khẩn cấp Hệ thống không sử dụng được
1 Cảnh báo Bạn phải hành động ngay lập tức
2 Quan trọng Điều kiện quan trọng
3 Lỗi Điều kiện lỗi
4 Cảnh báo Điều kiện cảnh báo
5 Lưu ý Tình trạng bình thường nhưng đáng kể
6 Thông tin Thông báo thông tin
7 Gỡ lỗi Thông báo ở cấp gỡ lỗi

Hình 5: RFC 5424 – Phần 6.2.1.

Ghi nhật ký ứng dụng

Tính năng ghi nhật ký có chọn lọc được thực hiện bằng TAG theo lớp android.util.Log bằng cách sử dụng Log#isLoggable, như minh hoạ bên dưới:

if (Log.isLoggable("FOO_TAG", Log.VERBOSE)) {
 Log.v("FOO_TAG", "Message for logging.");
}

Bạn có thể điều chỉnh nhật ký trong thời gian chạy để cung cấp một cấp độ ghi nhật ký được chọn như minh hoạ bên dưới:

adb shell setprop log.tag.FOO_TAG VERBOSE

Các thuộc tính log.tag.* sẽ được đặt lại khi khởi động lại. Ngoài ra, còn có các biến thể cố định vẫn giữ nguyên sau khi khởi động lại. Xem bên dưới:

adb shell setprop persist.log.tag.FOO_TAG VERBOSE

Log#isLoggable kiểm tra các dấu vết nhật ký còn lại trong mã ứng dụng. Cờ boolean DEBUG bỏ qua các dấu vết nhật ký bằng cách sử dụng các chế độ tối ưu hoá trình biên dịch được đặt thành false, như minh hoạ dưới đây:

private final static boolean DEBUG = false;

… If (DEBUG) { Log.v("FOO_TAG", "Extra debug logging."); }

Bạn có thể xoá tính năng ghi nhật ký trên cơ sở từng APK thông qua các quy tắc ProGuard bằng cách R8 tại thời gian biên dịch. Ví dụ sau đây sẽ xoá mọi nội dung bên dưới hoạt động ghi nhật ký cấp INFO cho android.util.Log:

# 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

Điều này hữu ích khi xử lý nhiều loại bản dựng ứng dụng (ví dụ: bản dựng phát triển so với bản phát hành) trong đó mã cơ bản dự kiến sẽ giống nhau, nhưng các cấp độ nhật ký được phép lại khác nhau. Bạn phải đặt và tuân theo một chính sách rõ ràng cho các ứng dụng (đặc biệt là ứng dụng hệ thống) để quyết định cách các loại bản dựng và kỳ vọng phát hành ảnh hưởng đến đầu ra nhật ký.

Ghi nhật ký hệ thống trong Android Runtime (ART)

Có một số lớp có sẵn cho các ứng dụng và dịch vụ hệ thống:

Lớp học Mục đích
android.telephony.Rlog Ghi nhật ký radio
android.util.Log Ghi nhật ký chung về ứng dụng
android.util.EventLog Ghi nhật ký sự kiện chẩn đoán của nhà tích hợp hệ thống
android.util.Slog Ghi nhật ký khung nền tảng

Hình 6: Các lớp nhật ký hệ thống và mục đích có sẵn.

Mặc dù android.util.Logandroid.util.Slog sử dụng cùng một tiêu chuẩn cấp độ nhật ký, nhưng Slog là một lớp @hide mà chỉ nền tảng mới có thể sử dụng. Các cấp EventLog được liên kết với các mục trong tệp event.logtags trong /system/etc/event-log-tags.

Ghi nhật ký gốc

Việc ghi nhật ký trong C/C++ tuân theo tiêu chuẩn syslog, trong đó syslog(2) tương ứng với syslog của nhân Linux kiểm soát vùng đệm printksyslog(3) tương ứng với trình ghi nhật ký hệ thống chung. Android sử dụng thư viện liblog để ghi nhật ký hệ thống chung.

liblog cung cấp trình bao bọc cho các nhóm nhật ký phụ bằng cách sử dụng biểu mẫu macro sau:

[Sublog Buffer ID] LOG [Log Level ID]

Ví dụ: RLOGD tương ứng với [Radio log buffer ID] LOG [Debug Level]. Sau đây là các trình bao bọc liblog chính:

Lớp trình bao bọc Ví dụ về hàm
log_main.h ALOGV, ALOGW
log_radio.h RLOGD, RLOGE
log_system.h SLOGI, SLOGW

Hình 7: Trình bao bọc liblog.

Android có các giao diện cấp cao hơn để ghi nhật ký, được ưu tiên hơn việc sử dụng trực tiếp liblog, như bạn thấy bên dưới:

Thư viện Cách sử dụng
async_safe Thư viện chỉ để ghi nhật ký từ các môi trường an toàn cho tín hiệu không đồng bộ
libbase Thư viện ghi nhật ký cung cấp giao diện luồng C++ để ghi nhật ký, tương tự như tính năng ghi nhật ký theo kiểu của Google (glog). libbase có thể dùng được trong cả dự án bên ngoài và có trong các ứng dụng dùng libbase_ndk.

Hình 8: Thư viện nhật ký cấp cao hơn.

Xấp xỉ nhiều ngăn xếp

Do sự khác biệt về mức độ chi tiết và ý định cấp độ, nên không có sự so khớp rõ ràng hoặc chính xác giữa các tiêu chuẩn ghi nhật ký khác nhau. Ví dụ: các cấp java.util.logging.Levelandroid.util.Log cho nhật ký lỗi không khớp 1:1:

java.util.Logging.Level android.util.Log
NGHIÊM TRỌNG Log.wtf
NGHIÊM TRỌNG Log.e

Hình 9: Cấp độ lỗi trong hoạt động ghi nhật ký Java tiêu chuẩn so với hoạt động ghi nhật ký Android.

Trong những trường hợp như thế này, hãy sử dụng từng tiêu chuẩn để xác định cấp độ cần áp dụng.

Trong quá trình phát triển hệ thống với nhiều thành phần cấp ngăn xếp, hãy làm theo Hình 1 để xác định tiêu chuẩn cần sử dụng cho mỗi thành phần. Để biết hướng dẫn sơ bộ về việc nhắn tin theo cấp, hãy xem Hình 2.

Bảo mật và quyền riêng tư

Không ghi nhật ký Thông tin nhận dạng cá nhân (PII). Trong đó có những thông tin như:

  • Địa chỉ email
  • Số điện thoại
  • Tên

Tương tự, một số thông tin nhất định được coi là nhạy cảm ngay cả khi không phải là thông tin nhận dạng cá nhân một cách rõ ràng.

Ví dụ: mặc dù thông tin về múi giờ không được coi là thông tin nhận dạng cá nhân, nhưng thông tin này cho biết vị trí ước chừng của người dùng.

Chính sách nhật ký và các thông tin chi tiết chấp nhận được phải được xử lý trong quá trình đánh giá bảo mật và quyền riêng tư trước khi phát hành.

Nhật ký thiết bị

Quyền truy cập vào toàn bộ nhật ký thiết bị, kể cả khi sử dụng android.permission.READ_LOGS, sẽ bị hạn chế:

  • Nếu một ứng dụng ở chế độ nền yêu cầu cấp quyền truy cập vào toàn bộ nhật ký thiết bị, thì yêu cầu đó sẽ tự động bị từ chối, trừ phi ứng dụng:
    • Chia sẻ UID hệ thống.
    • Sử dụng một quy trình hệ thống gốc (UID < APP_UID).
    • Sử dụng DropBoxManager
    • Chỉ truy cập vào vùng đệm nhật ký sự kiện.
    • Sử dụng API EventLog.
    • Sử dụng kiểm thử đo lường.
  • Nếu một ứng dụng ở nền trước có READ_LOGS yêu cầu cấp quyền truy cập vào nhật ký thiết bị, hệ thống sẽ nhắc người dùng phê duyệt hoặc từ chối yêu cầu truy cập đó.