Viết và xem nhật ký bằng Logcat

Cửa sổ LogcatLog trong Android Studio cho thấy các thông điệp hệ thống (chẳng hạn như khi một sự kiện thu thập rác xảy ra) cũng như các thông điệp mà bạn bổ sung vào ứng dụng qua lớp . Logcat hiện thông điệp theo thời gian thực và lưu nhật ký để bạn có thể xem các thông điệp cũ.

Để chỉ hiện thông tin mà bạn quan tâm, bạn có thể tạo bộ lọc, sửa đổi lượng thông tin xuất hiện trong thông điệp, đặt mức độ ưu tiên, chỉ hiện thông điệp tạo bằng mã ứng dụng và tìm kiếm nhật ký. Theo mặc định, Logcat chỉ cho thấy đầu ra nhật ký liên quan đến ứng dụng mới chạy gần đây nhất.

Khi ứng dụng trả về một ngoại lệ, Logcat sẽ hiện một thông điệp, theo sau là dấu vết ngăn xếp liên quan, trong đó có chứa các đường liên kết đến dòng mã.

Cửa sổ Run (Chạy) hiện thông điệp nhật ký cho ứng dụng đang chạy. Bạn có thể định cấu hình màn hình đầu ra Logcat nhưng không thể định cấu hình cửa sổ Chạy.

Xem nhật ký ứng dụng

Cách hiện thông điệp nhật ký cho một ứng dụng:

  1. Tạo bản dựng và chạy ứng dụng trên một thiết bị.
  2. Nhấp vào View (Xem) > Tool Windows (Cửa sổ công cụ) > Logcat (hoặc nhấp vào biểu tượng Logcat trong thanh công cụ).

Cửa sổ Logcat hiện thông điệp nhật ký cho ứng dụng được chọn trong danh sách thả xuống ở đầu cửa sổ, như ví dụ minh hoạ trong hình 1.

Hình 1. Cửa sổ Logcat.

Theo mặc định, Logcat chỉ hiện thông điệp nhật ký cho ứng dụng chạy trên thiết bị. Để thay đổi giá trị mặc định này, hãy xem cách lọc thông điệp Logcat.

Thanh công cụ Logcat có các nút sau:

  1. Xoá Logcat : Nhấp để xoá nhật ký mà bạn thấy.
  2. Cuộn xuống dưới cùng : Nhấp để chuyển đến cuối nhật ký và xem các thông điệp nhật ký mới nhất. Nếu sau đó bạn nhấp vào một dòng trong nhật ký, khung nhìn sẽ tạm dừng cuộn tại thời điểm đó.
  3. Dấu vết ngăn xếp phía trên Dấu vết ngăn xếp phía dưới : Nhấp để di chuyển lên và xuống giữa các dấu vết ngăn xếp trong nhật ký, chọn tên tệp trước hoặc tiếp theo xuất hiện trong các ngoại lệ đã in. Cách làm này tương tự như khi bạn nhấp vào một tên tệp trong nhật ký.
  4. Dùng chế độ ngắt dòng mềm : Nhấp để bật tính năng cuộn xuống dòng và ngăn thao tác cuộn theo chiều ngang (mặc dù mọi chuỗi không thể ngắt vẫn cần cuộn ngang).
  5. In : Nhấp để in các thông điệp Logcat. Sau khi chọn các chế độ in ưu tiên trong hộp thoại vừa xuất hiện, bạn cũng có thể chọn lưu thông điệp thành một tệp PDF.
  6. Khởi động lại : Nhấp để xoá nhật ký rồi khởi động lại Logcat. Không giống như nút Clear Logcat (Xoá Logcat), nút này sẽ khôi phục và hiện các thông điệp nhật ký trước đó, vì vậy, trong trường hợp Logcat không phản hồi và bạn không muốn mất thông điệp nhật ký, thì nút này sẽ phát huy tác dụng tối đa.
  7. Tiêu đề Logcat : Nhấp để mở hộp thoại Configure Logcat Header (Định cấu hình tiêu đề Logcat). Tại đây, bạn có thể tuỳ chỉnh giao diện của từng thông điệp Logcat, chẳng hạn như việc có hiện ngày giờ hay không.
  8. Chụp ảnh màn hình : Nhấp để chụp ảnh màn hình.
  9. Ghi màn hình : Nhấp để quay video (tối đa 3 phút) về thiết bị.

Soạn thông điệp nhật ký

Lớp Log cho phép bạn tạo thông điệp nhật ký xuất hiện trong Logcat. Mỗi thông điệp nhật ký trên Android đều có một thẻ và mức độ ưu tiên gắn với thẻ đó. Thẻ của thông điệp nhật ký là một chuỗi ngắn cho biết thành phần hệ thống nơi bắt nguồn thông điệp.

Sử dụng các phương thức ghi nhật ký được liệt kê theo thứ tự ưu tiên từ cao nhất đến thấp nhất:

Thẻ do người dùng xác định có thể là chuỗi bất kỳ mà bạn thấy hữu ích, chẳng hạn như tên của lớp hiện tại. Bạn sẽ xác định thẻ này trong lệnh gọi phương thức Log, ví dụ:

Kotlin

Log.d(tag, message)

Java

Log.d(tag, message);

Hãy xem nội dung mô tả lớp Log để nắm được danh sách tuỳ chọn đầy đủ hơn.

Bạn không nên biên dịch nhật ký chi tiết vào ứng dụng, ngoại trừ trong quá trình phát triển. Nhật ký gỡ lỗi được biên dịch nhưng bị xoá vào thời gian chạy. Còn nhật ký lỗi, cảnh báo và thông tin luôn được giữ lại.

Đối với mỗi phương thức ghi nhật ký, tham số đầu tiên nên là một thẻ riêng biệt và tham số thứ hai là thông điệp. Thẻ của thông điệp nhật ký là một chuỗi ngắn cho biết thành phần hệ thống nơi bắt nguồn thông điệp. Thẻ có thể là một chuỗi nào đó mà bạn thấy hữu ích, chẳng hạn như tên của lớp hiện tại.

Có một quy ước hay là khai báo một hằng số TAG trong lớp để sử dụng trong tham số đầu tiên. Ví dụ: bạn có thể tạo một thông điệp nhật ký dạng thông tin như sau:

Kotlin

private const val TAG = "MyActivity"
...
Log.i(TAG, "MyClass.getView() — get item number $position")

Java

private static final String TAG = "MyActivity";
...
Log.i(TAG, "MyClass.getView() — get item number " + position);

Lưu ý: Tên thẻ có hơn 23 ký tự sẽ bị cắt bớt trong đầu ra Logcat.

Định dạng thông điệp Logcat

Định dạng thông điệp nhật ký là:

date time PID-TID/package
priority/tag: message

PID là từ viết tắt cho mã nhận dạng quá trình (process identifier) và TID là mã nhận dạng luồng (thread identifier). Các giá trị này có thể giống nhau nếu chỉ có một luồng duy nhất.

Ví dụ: thông điệp nhật ký sau đây có mức độ ưu tiên là V và thẻ AuthZen:

12-10 13:02:50.071 1901-4229/com.google.android.gms V/AuthZen: Handling delegate intent.

Thiết lập cấp độ nhật ký

Bạn có thể thiết lập cấp độ nhật ký để kiểm soát việc Logcat cho thấy tất cả thông điệp hay chỉ những thông điệp cho biết những điều kiện nghiêm trọng nhất.

Logcat sẽ tiếp tục thu thập tất cả thông điệp, bất kể chế độ cài đặt cấp độ nhật ký. Chế độ cài đặt trên chỉ xác định nội dung Logcat cho thấy.

Trong trình đơn Log level (Cấp độ nhật ký), hãy chọn một trong các giá trị sau:

  • Verbose (Chi tiết): Cho thấy tất cả thông điệp nhật ký (mặc định).
  • Debug (Gỡ lỗi): Chỉ cho thấy các thông điệp nhật ký gỡ lỗi hữu ích trong quá trình phát triển cũng như các thông điệp có cấp độ thấp hơn trong danh sách này.
  • Info (Thông tin): Cho thấy thông điệp nhật ký dự kiến cho mức sử dụng thông thường cũng như các thông điệp có cấp độ thấp hơn trong danh sách này.
  • Warn (Cảnh báo): Cho thấy các vấn đề chưa phải là lỗi cũng như các thông điệp có cấp độ thấp hơn trong danh sách này.
  • Error (Lỗi): Cho thấy các vấn đề gây ra lỗi cũng như các thông điệp có cấp độ thấp hơn trong danh sách này.
  • Assert (Khẳng định): Cho thấy các vấn đề nhà phát triển cho rằng không bao giờ xảy ra.

Tìm kiếm thông điệp Logcat

Để tìm kiếm các thông điệp đang xuất hiện trong Logcat:

  1. Chọn Regex (Biểu thức chính quy) (không bắt buộc) nếu bạn muốn sử dụng một quy luật tìm kiếm dạng biểu thức chính quy.
  2. TNhập một chuỗi ký tự vào trường tìm kiếm .

    Màn hình đầu ra Logcat thay đổi tương ứng.

  3. Nhấn Enter để lưu chuỗi tìm kiếm trên trình đơn trong phiên này.
  4. Để tìm kiếm lại một nội dung, hãy chọn nội dung đó trên trình đơn tìm kiếm. Chọn hoặc bỏ chọn Regex (Biểu thức chính quy) nếu cần.

Lọc thông điệp Logcat

Một cách để giảm đầu ra nhật ký ở mức có thể quản lý được là dùng bộ lọc để hạn chế.

Lưu ý: Bộ lọc sẽ áp dụng cho toàn bộ nhật ký Logcat, không chỉ các thông điệp xuất hiện trong Logcat. Hãy đảm bảo các tuỳ chọn hiển thị khác đã được thiết lập thích hợp để bạn có thể thấy đầu ra bộ lọc mà bạn muốn kiểm tra.

Cách xác định và áp dụng bộ lọc:

  1. Trên trình đơn bộ lọc, hãy chọn một loại bộ lọc:
    • Show only selected application (Chỉ hiện ứng dụng đã chọn): Chỉ hiện các thông điệp do mã nguồn ứng dụng tạo ra (mặc định). Logcat lọc thông điệp nhật ký bằng PID của ứng dụng đang hoạt động.
    • No Filters (Không dùng bộ lọc): Không áp dụng bộ lọc nào. Logcat cho thấy tất cả thông điệp nhật ký từ thiết bị, bất kể bạn đã chọn quy trình nào.
    • Edit Filter Configuration (Chỉnh sửa cấu hình bộ lọc): Tạo hoặc sửa đổi một bộ lọc tuỳ chỉnh. Ví dụ: bạn có thể tạo bộ lọc để xem thông điệp nhật ký từ hai ứng dụng cùng lúc.

    Sau khi xác định các bộ lọc, bạn cũng có thể chọn các bộ lọc đó trong trình đơn. Để gỡ các bộ lọc này khỏi trình đơn, hãy xoá nội dung của các bộ lọc đó.

  2. Nếu bạn chọn Edit Filter Configuration (Chỉnh sửa cấu hình bộ lọc), hãy tạo hoặc sửa đổi một bộ lọc:
    1. Chỉ định tham số bộ lọc trong hộp thoại Create New Logcat Filter (Tạo bộ lọc Logcat mới):
      • Filter Name (Tên bộ lọc): Nhập tên của bộ lọc mà bạn muốn xác định hoặc chọn trong ngăn bên trái để sửa đổi một bộ lọc hiện có. Tên này chỉ chứa các ký tự viết thường, dấu gạch dưới và chữ số.
      • Log Tag (Thẻ nhật ký): Tuỳ ý chỉ định một thẻ.
      • Log Message (Thông điệp nhật ký): Tuỳ ý chỉ định văn bản thông điệp nhật ký.
      • Package Name (Tên gói): Tuỳ ý chỉ định tên gói.
      • PID: Tuỳ ý chỉ định mã nhận dạng quá trình.
      • Log Level (Cấp độ nhật ký): Tuỳ ý chọn một cấp độ nhật ký.
      • Regex (Biểu thức chính quy): Chọn tuỳ chọn này để sử dụng cú pháp biểu thức chính quy cho tham số.
    2. Nhấp vào dấu + để bổ sung định nghĩa bộ lọc vào ngăn bên trái.

      Để xoá bộ lọc, hãy chọn trong ngăn bên trái rồi nhấp vào biểu tượng -.

    3. Khi hoàn tất, hãy nhấp vào OK.

Nếu bạn không thấy thông điệp nhật ký mình muốn, hãy chọn No filter (Không dùng bộ lọc) rồi tìm thông điệp nhật ký cụ thể.

Đọc thông báo thu thập rác

Đôi khi một sự kiện thu thập rác (garbage collection – GC) diễn ra, sự kiện đó sẽ được in vào Logcat.

Để biết thêm thông tin chi tiết về bộ nhớ ứng dụng, hãy sử dụng Memory Profiler (Trình phân tích bộ nhớ).

Thông điệp nhật ký Dalvik

Trong Dalvik (nhưng không phải ART), mọi sự kiện thu thập rác (GC) sẽ in những thông tin sau vào Logcat:

D/dalvikvm(PID): GC_Reason Amount_freed,
Heap_stats, External_memory_stats, Pause_time

Ví dụ:

D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms

Trong lúc những thông điệp nhật ký này được tích luỹ, hãy chú ý đến mức tăng trong số liệu thống kê của vùng nhớ khối xếp. Nếu giá trị này tiếp tục tăng, có thể bạn bị rò rỉ bộ nhớ.

Trong thông điệp nhật ký Dalvik có các thuật ngữ sau:

GC Reason (Lý do thu thập rác)
Yếu tố kích hoạt GC và kiểu thu thập. Lý do có thể xuất hiện bao gồm:
GC_CONCURRENT
Một GC đồng thời giải phóng bộ nhớ khi vùng nhớ khối xếp bắt đầu lấp đầy.
GC_FOR_MALLOC
Một GC bị lỗi do ứng dụng của bạn đã cố phân bổ bộ nhớ khi vùng nhớ khối xếp đã đầy, vì vậy, hệ thống phải dừng ứng dụng và thu hồi bộ nhớ.
GC_HPROF_DUMP_HEAP
Một GC xảy ra khi bạn yêu cầu tạo một tệp HPROF để phân tích vùng nhớ khối xếp.
GC_EXPLICIT
Một GC rõ ràng, chẳng hạn như khi bạn gọi gc(). Tuy nhiên, bạn nên tránh gọi phương thức này mà hãy tin tưởng rằng GC sẽ chạy khi cần.
GC_EXTERNAL_ALLOC
Một GC cho bộ nhớ phân bổ bên ngoài (chẳng hạn như dữ liệu pixel lưu trữ trong bộ nhớ gốc hoặc vùng đệm byte NIO). Tình trạng này chỉ xảy ra với API cấp 10 trở xuống Các phiên bản mới hơn sẽ phân bổ mọi thứ trong vùng nhớ khối xếp Dalvik.
Amount freed (Dung lượng được giải phóng)
Lượng bộ nhớ thu hồi qua GC này.
Heap stats (Số liệu thống kê về vùng nhớ khối xếp)
Tỷ lệ vùng nhớ khối xếp còn trống tính theo phần trăm và (số đối tượng đang hoạt động)/(tổng kích thước của vùng nhớ khối xếp).
External memory stats (Số liệu thống kê về bộ nhớ ngoài)
Bộ nhớ được phân bổ bên ngoài ở cấp API từ 10 trở xuống (lượng bộ nhớ được phân bổ)/(giới hạn kiểu sự kiện thu thập rác sẽ xảy ra).
Pause time (Thời điểm tạm dừng)
Các vùng nhớ khối xếp càng lớn sẽ càng có nhiều thời điểm tạm dừng. Các thời điểm tạm dừng đồng thời cho thấy hai thời điểm tạm dừng: một ở đầu và một gần cuối sự kiện thu thập rác.

Thông báo nhật ký ART

Không giống như Dalvik, ART không ghi lại thông điệp cho các GC không được yêu cầu rõ ràng. Thông tin về GC chỉ được in khi GC rõ ràng hoặc thời điểm tạm dừng GC vượt quá 5 mili giây/thời lượng GC vượt quá 100 mili giây. Nếu ứng dụng không ở trạng thái tạm dừng dễ nhận biết, chẳng hạn như khi ứng dụng đang chạy ở chế độ nền, nơi người dùng không thể nhận biết việc tạm dừng GC, thì sẽ không có thông tin GC nào được in trừ các GC rõ ràng.

ART chứa các thông tin sau trong thông điệp nhật ký thu thập rác:

I/art: GC_Reason GC_Name Objects_freed(Size_freed) AllocSpace Objects,
    Large_objects_freed(Large_object_size_freed) Heap_stats LOS objects, Pause_time(s)

Ví dụ:

I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects,
    21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms

Trong thông điệp nhật ký ART có các thuật ngữ sau:

GC Reason (Lý do thu thập rác)
Yếu tố kích hoạt GC và kiểu thu thập. Lý do có thể xuất hiện bao gồm:
Concurrent
Một GC đồng thời không tạm ngưng các luồng ứng dụng. GC này chạy trong một luồng ở chế độ nền và không ngăn chặn việc phân bổ.
Alloc
Một GC được khởi động do ứng dụng của bạn đã cố phân bổ bộ nhớ khi vùng nhớ khối xếp đã đầy, vì vậy, hệ thống phải dừng ứng dụng và thu hồi bộ nhớ. Trong trường hợp này, sự kiện thu thập rác sẽ xảy ra trong luồng phân bổ.
Explicit
Một ứng dụng đã yêu cầu thu thập rác, chẳng hạn như bằng cách gọi System.gc() hoặc Runtime.gc(). Tuy nhiên, tương tự với Dalvik, trong ART, phương pháp hay nhất là tin tưởng vào GC và tránh yêu cầu GC rõ ràng (nếu có thể). Bạn không nên sử dụng các GC rõ ràng vì chúng sẽ chặn các luồng phân bổ và rác CPU không cần thiết. GC rõ ràng cũng có thể gây ra hiện tượng giật (gián đoạn, giật hoặc dừng ứng dụng) nếu những sự kiện này khiến các luồng khác bị chặn trước.
NativeAlloc
Một GC có thể do áp lực của bộ nhớ gốc trong các quá trình phân bổ gốc gây ra, chẳng hạn như các đối tượng phân bổ bitmap hoặc RenderScript.
CollectorTransition
Một GC cũng có thể do quá trình chuyển đổi vùng nhớ khối xếp gây ra. Nguyên nhân là do thay đổi chiến lược GC vào thời gian chạy (chẳng hạn như khi ứng dụng thay đổi giữa các trạng thái tạm dừng dễ nhận biết). Quá trình chuyển đổi thu thập rác bao gồm việc sao chép tất cả đối tượng từ không gian sao lưu danh sách dưới dạng tự do sang không gian con trỏ nhấn (hoặc ngược lại).

Việc này chỉ xảy ra trên thiết bị có dung lượng RAM thấp trước Android 8.0, khi ứng dụng thay đổi từ trạng thái tạm dừng dễ nhận biết (chẳng hạn như khi ứng dụng chạy trên nền trước, tại đó người dùng có thể nhận biết thao tác tạm dừng GC) sang trạng thái tạm dừng không nhận biết được (hoặc ngược lại).

HomogeneousSpaceCompact
Trạng thái nén không gian đồng nhất là không gian danh sách dưới dạng tự do sang sự kiện nén danh sách dưới dạng tự do. Việc này thường xảy ra khi một ứng dụng được chuyển sang trạng thái tạm dừng không xử lý được. Lý do chính cho việc này nhằm giảm mức sử dụng RAM và phân mảnh vùng nhớ khối xếp.
DisableMovingGc
Đây không phải là lý do thực tế khiến GC xảy ra, nhưng xin lưu ý rằng sự kiện thu thập rác đã bị chặn do sử dụng GetPrimitiveArrayCritical trong khi tình trạng nén của các vùng nhớ khối xếp đồng thời cũng đang diễn ra. Nhìn chung, bạn không nên sử dụng GetPrimitiveArrayCritical do các hạn chế về việc di chuyển trình thu thập rác.
HeapTrim
Đây không phải lý do khiến GC xảy ra, nhưng xin lưu ý rằng sự kiện thu thập rác đã bị chặn cho đến khi thu gọn xong vùng nhớ khối xếp.
GC Name (Tên GC)
ART có nhiều loại hình GC có thể chạy được:
Concurrent mark sweep (CMS)
Một trình thu thập toàn bộ vùng nhớ khối xếp thu thập trên mọi không gian ngoài không gian hình ảnh và zygote.
Concurrent partial mark sweep
Một trình thu thập gần như toàn bộ vùng nhớ khối xếp thu thập trên mọi không gian ngoài không gian hình ảnh và zygote.
Concurrent sticky mark sweep
Một trình thu thập dạng trình tạo chỉ có thể giải phóng đối tượng đã được phân bổ sau khi sự kiện GC trước đó diễn ra. Loại hình thu thập rác này được chạy thường xuyên hơn so với dạng quét toàn bộ hoặc một phần nhãn vì thao tác này loại hình này nhanh và có thời điểm tạm dừng ngắn hơn.
Marksweep + semispace
Một GC sao chép và không đồng thời dùng cho các lượt chuyển đổi trong vùng nhớ khối xếp cũng như không gian nén đồng nhất (để chống phân mảnh vùng nhớ khối xếp).
Objects freed (Đối tượng được giải phóng)
Số lượng đối tượng được lấy lại qua GC này từ không gian đối tượng không lớn.
Size freed (Dung lượng được giải phóng)
Số byte được lấy lại qua GC này từ không gian đối tượng không lớn.
Large objects freed (Đối tượng lớn được giải phóng)
Số lượng đối tượng đã được lấy lại qua sự kiện thu thập rác này trong không gian đối tượng lớn.
Large object size freed (Dung lượng đối tượng lớn được giải phóng)
Số byte đã được lấy lại qua sự kiện thu thập rác này trong không gian đối tượng lớn.
Heap stats (Số liệu thống kê về vùng nhớ khối xếp)
Tỷ lệ phần trăm không bao gồm vùng nhớ khối xếp và (số đối tượng đang hoạt động)/(tổng kích thước của vùng nhớ khối xếp).
(Pause times) Thời điểm tạm dừng
Nhìn chung, thời điểm tạm dừng tỷ lệ thuận với số tệp tham chiếu đối tượng được sửa đổi trong khi GC đang chạy. Hiện tại, GC CMS ART chỉ có một thời điểm tạm dừng gần cuối GC. Các GC di chuyển có thời điểm tạm dừng kéo dài trong phần lớn thời gian của GC.

Nếu bạn thấy một lượng lớn thông báo GC trong Logcat, hãy tìm mức tăng trong số liệu thống kê về vùng nhớ khối xếp. Nếu giá trị này tiếp tục tăng và dường như không giảm, thì có thể bạn đã bị rò rỉ bộ nhớ.

Hoặc nếu bạn thấy các GC chỉ định lý do là "Alloc", thì tức là bạn đã dùng gần hết mức dung lượng vùng nhớ khối xếp cho các tác vụ và có thể gặp phải các ngoại lệ hết bộ nhớ trong tương lai gần.