Logcat on Eclipse: Best practices in Android Developement

Logcat

Làm gì nếu bạn không biết crash xảy ra ở vị trí nào trong code?

Chắc hẳn là bất cứ bạn Android dev nào cũng đã từng gặp crash khi phát triển app đúng không nào?! Nếu các bạn dùng Eclipse để phát triển app, thì Eclipse sẽ báo ngay cho các bạn biết vị trí xảy ra crash tại lúc đó. Nhưng đôi khi có những lúc Eclipse báo crash ở tầng rất thấp và bạn không thể truy ngược lại đoạn code mà mình có thể can thiệp. Cho nên khi gặp tình huống như vậy, có người sẽ đoán vị trí crash, rồi đặt breakpoint ở vài vị trí “khả nghi”. Việc này cũng gây ngốn thời gian của chúng ta cũng khá nhiều đấy! Và việc làm như vậy cũng rất là bị động…

crash unknown

Eclipse bắt crash ở tầng thấp (low-level)

CHỦ ĐỘNG tìm vị trí crash nhờ Logcat

Mình xin chia sẻ với các bạn hướng để mình có thể biết được vị trí crash ở mức độ tên hàm dù gặp bất cứ crash nào. Chắc các bạn đã biết rằng Logcat trong Eclipse, đó là một tính năng của Android cho phép bạn có thể xem những đoạn log từ app truyền ra. Mỗi dòng log của Logcat có 3 đặc tính quan trọng:

  1. Nhiều loại level như debug, verbose, info, error… với những màu sắc khác nhau.
  2. Tag’s field.
  3. Text’s field.
Logcat overview markup

3 đặc trưng của một dòng log trong Logcat

Mình sử dụng Logcat một cách chủ động bằng cách chưa có bug thì mình cũng ghi log lại ở những vị trí mà mình cho là cần thiết. Ngoài việc lấy log khi phát triển sản phẩm, đôi khi mình cũng cần lấy log khi gửi cho người dùng test thông qua các ứng dụng crash report (ví dụ như Crashlytics, HockeyApp hay Flurry…), vì thế mình wrap các hàm của Logcat lại vào một class LogManager như sau:

Vì log một cách chủ động như vậy, mỗi dòng log của mình cần có cách để xác định vị trí của nó trong code. Để biết được vị trí, thì mình cần biết tên class và tên hàm, vì thế mình sẽ đặt tên class ở Tag’s field, và tên hàm ở phần Text’s field. Vậy là với một dòng log như vậy thì mình có thể biết chính xác vị trí code ở đâu rồi đó! Việc tiếp theo mình cần biết là cách tận dụng màu sắc cũng như phân loại Logcat ra để nhìn log một cách dễ dàng nhất. Cho nên 5 loại của Logcat được mình dùng ở các vị trí như sau:

  1. LogManager.i : khi bắt đầu hàm (trừ hàm action) (màu xanh lá cây)
  2. LogManager.v : khi bắt đầu hàm thể hiện action (onClick(), onTouch()…) (màu đen)
  3. LogManager.e : trong phần catch của try catch exception nếu mình không expect lỗi này xảy ra vì có thể ảnh hưởng đến chương trình. (màu đỏ)
  4. LogManager.w : trong phần catch của try catch exception nếu lỗi này xảy ra nhưng nó không ảnh hưởng đến chương trình, mình có thể đã biết lỗi này rồi. (màu vàng)
  5. LogManager.d : dành cho những trường hợp còn lại, log bất cứ chỗ nào quan tâm. (màu xanh dương)

Và đây là ví dụ cho những chỗ cần “gài” để lấy log như đã nêu trên:

ClassName.java

Phòng bệnh > Chữa bệnh

Tuy nhìn có vẻ phiền phức và dư thừa, nhưng nó thực sự rất hữu ích khi các bạn track bug cho những device của mình và của cả những người dùng khác. Vì thiết bị Android có rất là nhiều loại và bug của nó có thể xảy ra bất cứ ở đâu, có thể ở những chỗ mình không ngờ và bạn không có đúng loại device đó để test.

Mục đích chính của bài post này là chia sẻ các bạn tư tưởng đặt log một cách chủ động và sắp xếp log sao cho hợp lý, còn về chi tiết thì các bạn có thể phát triển những cách riêng của mình sao cho phù hợp.

Những góp ý hoặc chia sẻ từ các bạn luôn được hoan nghênh!

SSS Full-stack Engineer

Love Silicon Straits and want to know more about our company culture, working environment or job vacancies?
Find out more at careers.siliconstraits.vn.

Silicon Straits
Be Challenged. Be Inspired. Be Different.




  • Có một vấn đề thảo luận nho nhỏ ngoài lề một chút… Trước em cũng hay dùng LogUtil (tương tự thằng LogManager) để quản lí log của mình tuy nhiên là sau khi dùng một thời gian thì em thấy mục tiêu của dùng thằng này là để ngăn bắn ra các đoạn log không có lợi sau quá trình phát triển tuy nhiên bù lại thì có rất nhiều code dư thừa. Cụ thể thì {“methodName with param1 = %s param2 = %s”, param1, param2} sẽ được thực hiện dù cho biến AppConfig.IS_DEBUG có là true hay false. Chưa kể đến việc gọi con trỏ hàm các kiểu và đặc biệt dư thừa khi đặt log này trong phương thức getView của adapter truyền vào của ListView chẳng hạn…
    Em hay chuyển qua gọi trần đoạn code cần log chứ không đặt vào một phương thức tĩnh như trước nữa. Không biết cách đó với cách đang dùng cái nào thì hợp lí hơn anh chị nhỉ?

    • Hung Le Thanh

      - Hi Tâm, đầu tiên là mình cảm ơn bạn đã góp ý nhé! Có điều cho mình hỏi “gọi trần đoạn code cần Log” là sao bạn nhỉ ? Khi nào thì log?

      Như phần cuối bài viết cũng có nói là việc đặt log như vậy sẽ giúp cho các bạn không cần phải quan tâm đến vị trí cần log ban đầu, cứ theo guideline mà đặt log. Và đương nhiên sẽ có những hàm như bạn nói là nó lặp đi lặp lại như getView, thì mình cần phải bỏ nó ra khi đoạn code mình đã chạy ổn định ở phần đó vì nó thực sự gây tốn nhiều tài nguyên.

      Ban đầu thì mình tập trung để hoàn thành tính năng là chủ yếu, sau đó khi chức năng đã chạy đúng mục đích thì mình sẽ bắt đầu bỏ những đoạn Log dư thừa quá nhiều khi nhìn vào Logcat chẳng hạn để tăng thêm performance.

      Cách này thì hiệu quả cho những bạn beginner luôn để hiểu được flow app mình có đúng như những gì mình viết ra không, Còn khi đã kinh nghiệm nhiều rồi thì mình sẽ bắt đầu bỏ những log nào mà mình chắc chắn nó là dư thừa ^^.

      • Àh không anh! Ý em không phải là code trên là đúng hay sai. Chỉ là em ngồi đọc source code của google thường có đoạn kiểu {if (false) Log.v(TAG, “Finishing self: token=” + mToken);} chẳng hạn. Về sau thì em xác định là mấy đoạn đó là {if (Config.IS_DEBUG) Log.v(TAG, “Finishing self: token=” + mToken);} tức là gọi luôn chứ không thông qua class LogManager. Chính vì thế khi đọc bài viết của anh thì em mới tạo thêm chủ đề nữa để trao đổi vì biết đâu lại có ý tưởng hay ho.

        • Hung Le Thanh

          À, việc thông qua class LogManager là để phục vụ cho các ứng dụng lấy log khác như Crashlytics , vì thông qua Crashlytics thì mình mới biết được logcat của các device test mà không phải qua debug đó bạn. Nếu mà đặt trần đoạn code thì việc code sẽ thành ra khó khăn hơn vì phải đặt 2 dòng code trong cùng 1 chỗ log, hoặc sau này nếu mình dùng các service log khác như Crittercism, Flurry, HockeyApp… thì sẽ lại phải đổi & thêm những dòng này. Nên mình tập trung chỉ qua cái class LogManager là thay đổi chỉ ở chỗ đó thôi. Còn việc đặt LogManager ở các đoạn code khác là nhằm mục đích “đặt chỗ” các vị trí cần lấy log, đúng là theo lý thuyết thì nó sẽ chậm ở chỗ bạn nói khi thay thế trong String.format, nhưng trên thực tế thì mình test cho các device cấp thấp dùng Android 2.x thì thấy chạy khá bình thường đó bạn ^^ Còn nếu muốn hạn chế dùng String.format khi không lấy log thì làm vậy luôn :
          if (Config.IS_DEBUG) LogManager.v …

          Bạn thấy sao hen ?

  • Mưa Phùn

    Chào anh.Em có thấy anh nói đến sử dụng LogManager và Crashlysrics , anh có thể nói về cách nó hoạt động không anh?
    EM xin cảm ơn1

    • Hung Le Thanh

      @m_a_ph_n:disqus Hi bạn, việc dùng Crashlytics trong LogManager là để lấy log khi mà có crash xảy ra trên device. Khi mà có crash trên device, thì Crashlytics sẽ báo bug về, bên cạnh đó, nó cũng có chức năng show log mà mình ghi lại nữa. Dựa vào đó thì mình có nhiều thông tin để track bug đó hơn, có thể xử lý nhanh mà không cần phải debug lại chẳng hạn :)

      • Mưa Phùn

        vậy có nghĩa là chỉ cần mình add Crashlyrics vào thì khi có Crash thì nó tự báo cho mình hả a?
        Dù mình k viết log gì trong đó.

        • Hung Le Thanh

          Nó sẽ báo log cho mình. Thực ra mình để trong LogManager, nên mỗi lần mình gọi LogManager là nó gửi log cho LogCat và Crashlytics tùy vào biến bool em chỉnh cho AppConfig.IS_DEBUG hoặc
          AppConfig.IS_CRASHLYTICS_DEBUG.

Posted by

on July 27, 2014

in , ,

Comments

Follow us for more later

or subscribe with