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

Cửa sổ Logcat 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 Log. Cửa sổ này 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 đưa ra trường hợp ngoại lệ, logcat sẽ cho thấy một thông điệp, theo sau là dấu vết ngăn xếp được liên kết chứa các đường liên kết đến dòng mã.

Kể từ Android Studio 2.2, cửa sổ Run (Chạy) cũng sẽ hiện thông điệp nhật ký cho ứng dụng đang chạy. Xin lưu ý rằng 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ổ Run (Run).

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 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 cho thấy thông điệp nhật ký cho những ứ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 trên Dấu vết ngăn xếp dưới : Nhấp để di chuyển giữa các dấu vết ngăn xếp trên và dưới trong nhật ký, chọn tên tệp tiếp theo (và xem số dòng tương ứng trong trình chỉnh sửa) 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à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 Xoá logcat, tính năng này sẽ khôi phục và cho thấy các thông điệp nhật ký trước đó, vì vậy hữu ích nhất là 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ý.
  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 về thiết bị (tối đa 3 phút).

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. Nhìn chung, bạn nên sử dụng các phương thức ghi nhật ký sau đây, liệt kê theo thứ tự ưu tiên từ cao nhất đến thấp nhất (hoặc ít đến nhiều chi tiết nhất):

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, trong khi 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 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ý hệ thống 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 (ví dụ: ActivityManager). Thẻ có thể là một 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.

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ẻ dài hơn 23 ký tự được cắt ngắn trong đầu ra logcat.

Định dạng thông điệp 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ý hệ thống 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 (ví dụ: ActivityManager). 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 (thẻ được đề xuất). Bạn xác định mã này bằng lệnh gọi phương thức Log, ví dụ:

Kotlin

Log.d(tag, message)

Java

Log.d(tag, message);

Mức độ ưu tiên là một trong những giá trị sau:

  • V: Chi tiết (mức độ ưu tiên thấp nhất)
  • D: Gỡ lỗi
  • I: Thông tin
  • W: Cảnh báo
  • E: Lỗi
  • A: Khẳng định

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

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

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.

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

Đặt cấp độ nhật ký

Bạn có thể kiểm soát số lượng thông điệp xuất hiện trong logcat bằng cách đặt cấp độ nhật ký. Bạn có thể cho hiện tất cả thông điệp, hoặc chỉ những thông điệp chỉ báo tình trạng nghiêm trọng nhất.

Hãy nhớ rằng logcat 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ý như thế nào. 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. Nhập một trình tự 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 (chế độ cài đặt này không được lưu lại).

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 chế độ 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ẻ. Để biết thêm thông tin, hãy xem nội dung Định dạng thông điệp logcat.
      • Log Message (Thông điệp nhật ký): Tuỳ ý chỉ định văn bản thông điệp nhật ký. Để biết thêm thông tin, hãy xem nội dung Định dạng thông điệp logcat.
      • Package Name (Tên gói): Tuỳ ý chỉ định tên gói. Để biết thêm thông tin, hãy xem nội dung Định dạng thông điệp logcat.
      • PID: Tuỳ ý chỉ định mã nhận dạng quá trình. Để biết thêm thông tin, hãy xem nội dung Định dạng thông điệp logcat.
      • Log Level (Cấp độ nhật ký): Tuỳ ý chọn một cấp độ nhật ký. Để biết thêm thông tin, hãy xem nội dung Đặ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 bạn hoàn tất, hãy nhấp vào OK.

Nếu bạn cho rằng mình không thấy thông điệp nhật ký mình muốn, hãy thử 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 điệp 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 Trình phân tích bộ nhớ (Memory Profiler).

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
GC Reason (Lý do thu thập rác)
Yếu tố kích hoạt GC và kiểu GC. Có thể xuất hiện những lý do sau:
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ố 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() (bạn nên tránh gọi hàm này và thay vào đó hãy tin tưởng GC sẽ chạy khi cần).
GC_EXTERNAL_ALLOC
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). 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).
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ệ 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).
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 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.

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 (giá trị 3571K/9991K trong ví dụ trên). Nếu giá trị này tiếp tục tăng, có thể bạn bị rò rỉ bộ nhớ.

Thông điệp 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. GC chỉ được in khi bị coi là chậm. Nói chính xác hơn, nếu thời điểm tạm dừng GC vượt quá 5 mili giây hoặc 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ó GC nào bị coi là chậm. Các GC rõ ràng luôn được ghi vào nhật ký.

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
GC Reason (Lý do thu thập rác)
Yếu tố kích hoạt GC và kiểu GC. Có thể xuất hiện những lý do sau:
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 vì ứng dụng của bạn đã cố gắng phân bổ bộ nhớ khi vùng nhớ khối xếp của bạn đã đầy. 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 gc() hoặc gc(). Giống như Dalvik, trong ART, phương pháp hay nhất là bạn nên 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
Sự kiện thu thập rác là 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
Sự kiện thu thập rác là do quá trình chuyển đổi vùng nhớ khối xếp gây ra; nguyên nhân là sự 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 GetPrimitiveArrayCritica 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.
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 trong không gian đối tượng lớn đã được lấy lại qua sự kiện thu thập rác này.
Large object size freed (Dung lượng đối tượng lớn được giải phóng)
Số byte trong không gian đối tượng lớn đã được lấy lại qua sự kiện thu thập rác này.
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 chuyển động 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 GC trong logcat, hãy tìm mức tăng trong số liệu thống kê của vùng nhớ khối xếp (giá trị 25MB/38MB trong ví dụ trên). 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 GC vì lý do "Alloc", thì tức là bạn đã hoạt động gần mức dung lượng vùng nhớ khối xếp và có thể thấy các trường hợp ngoại lệ liên quan đến OOM trong tương lai gần.