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 cấp, lớp, mục đích và các phương pháp ước chừng nhiều ngăn xếp.

Tiêu chuẩn nhật ký

Việc đăng nhập vào Android rất phức tạp do sự kết hợp của các tiêu chuẩn được sử dụng được 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 (tiêu chuẩn syslog) Nhân Linux, nhiều ứng dụng Unix Hạt nhân, trình nền hệ thống
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 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ự, 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 Mô tả RFC 5424 android.util.Log java.util.logging.Level
0 Khẩn cấp Không dùng được hệ thống Log.e / Log.wtf SEVERE
1 Cảnh báo Phải hành động ngay lập tức Log.e / Log.wtf SEVERE
2 Quan trọng Điều kiện nghiêm 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 Thông báo Bình thường nhưng có ý nghĩa 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: Các cấp độ ghi nhật ký syslog, Android và Java.

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

Hiện 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ý được 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ừ thấp đến cao, được thể hiện trong ba hình dưới đây:

ERROR Những nhật ký này luôn được giữ lại.
WARN Những nhật ký này luôn được giữ lại.
INFO Những nhật ký này luôn được giữ lại.
DEBUG Các nhật ký này được biên dịch nhưng bị xoá trong thời gian chạy.
VERBOSE Các nhật ký này không bao giờ được biên dịch vào ứ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 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 thông báo theo dõi chi tiết
INFO Cấp thông báo cho thông báo thông tin
SEVERE Mức thông báo cho biết lỗi nghiêm trọng
WARNING Cấp độ thông báo cho biết có thể xảy ra sự cố

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

0 Khẩn cấp Không dùng được hệ thống
1 Cảnh báo Phải hành động ngay lập tức
2 Quan trọng Điều kiện nghiêm 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 Thông báo 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 – Mục 6.2.1.

Ghi nhật ký ứng dụng

Lớp android.util.Log thực hiện việc ghi nhật ký có chọn lọc bằng TAG thông qua Log#isLoggable, như minh hoạ dưới đây:

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ý như minh hoạ dưới đây:

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. Cũng có các biến thể liên tục tồn tại sau khi khởi động lại. Hãy xem bên dưới:

adb shell setprop persist.log.tag.FOO_TAG VERBOSE

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

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 R8 tại thời điểm biên dịch. Ví dụ sau đây xoá mọi nội dung dưới 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 rất 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 thủ 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 mức độ tác động của các loại bản dựng và kỳ vọng phát hành đối với đầ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 Mục đích
android.telephony.Rlog Ghi nhật ký đài
android.util.Log Ghi nhật ký ứng dụng chung
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 nhập 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 với syslog(2) tương ứng với hạt nhân Linux syslog 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 blog con 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 Hàm mẫu
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 so với việc sử dụng trực tiếp liblog, như dưới đây:

Thư viện Cách sử dụng
async_safe Thư viện chỉ dành cho việc ghi nhật ký từ các môi trường an toàn với 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ý kiểu Google (glog). Bạn có thể sử dụng libbase trong cả dự án bên ngoài và trong các ứng dụng sử 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, không có tiêu chuẩn ghi nhật ký nào khớp chính xác hoặc rõ ràng với các tiêu chuẩn ghi nhật ký khác. Ví dụ: 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
NẶNG Log.wtf
NẶNG Log.e

Hình 9: Cấp lỗi trong tính năng ghi nhật ký Java chuẩn so với tính năng ghi nhật ký Android.

Trong trường hợp như vậy, hãy sử dụng tiêu chuẩn riêng lẻ để xác định cấp độ cần áp dụng.

Trong quá trình phát triển hệ thống có 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 nào sẽ sử dụng cho mỗi thành phần. Để biết hướng dẫn gần đúng về cách gửi tin nhắn theo cấp, hãy làm theo Hình 2.

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

Không ghi lại Thông tin nhận dạng cá nhân (PII). Thông tin này bao gồm các chi tiết như:

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

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

Ví dụ: mặc dù thông tin 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à thông tin chi tiết được chấp nhận phải được xử lý trong quá trình xem xét 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 tất cả nhật ký thiết bị, bao gồm cả việc sử dụng android.permission.READ_LOGS bị hạn chế:

  • Nếu một ứng dụng chạy ở chế độ nền yêu cầu quyền truy cập vào tất cả 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 của hệ thống.
    • Sử dụng 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 trên nền trước có READ_LOGS yêu cầu quyền truy cập vào nhật ký thiết bị, thì 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 đó.