浅谈Android系统开发中LOG的使用

在程序开发过程中,LOG是广泛使用的用来记录程序执行过程的机制,它既可以用于程序调试,也可以用于产品运营中的事件记录。在Android系统中,提供了简单、便利的LOG机制,开发人员可以方便地使用。在这一篇文章中,我们简单介绍在Android内核空间和用户空间中LOG的使用和查看方法。

一. 内核开发时LOG的使用。Android内核是基于Linux Kerne 2.36的,因此,Linux Kernel的LOG机制同样适合于Android内核,它就是有名的printk,与C语言的printf齐名。与printf类似,printk提供格式化输入功能,同时,它也具有所有LOG机制的特点--提供日志级别过虑功能。printk提供了8种日志级别(<linux/kernel.h>):

  1. #defineKERN_EMERG"<0>"/*systemisunusable*/
  2. #defineKERN_ALERT"<1>"/*actionmustbetakenimmediately*/
  3. #defineKERN_CRIT"<2>"/*criticalconditions*/
  4. #deinfeKERN_ERR"<3>"/*errorconditions*/
  5. #deinfeKERN_WARNING"<4>"/*warningconditions*/
  6. #deinfeKERN_NOTICE"<5>"/*normalbutsignificantcondition*/
  7. #deinfeKERN_INFO"<6>"/*informational*/
  8. #deinfeKERN_DEBUG"<7>"/*debug-levelmessages*/
printk的使用方法:

printk(KERN_ALERT"This is the log printed by printk in linux kernel space.");

KERN_ALERT表示日志级别,后面紧跟着要格式化字符串。

在Android系统中,printk输出的日志信息保存在/proc/kmsg中,要查看/proc/kmsg的内容,参照在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)一文,在后台中运行模拟器:

USER-NAME@MACHINE-NAME:~/Android$ emulator &

启动adb shell工具:

USER-NAME@MACHINE-NAME:~/Android$ adb shell

查看/proc/kmsg文件:

root@android:/ # cat /proc/kmsg

二. 用户空间程序开发时LOG的使用。Android系统在用户空间中提供了轻量级的logger日志系统,它是在内核中实现的一种设备驱动,与用户空间的logcat工具配合使用能够方便地跟踪调试程序。在Android系统中,分别为C/C++ 和Java语言提供两种不同的logger访问接口。C/C++日志接口一般是在编写硬件抽象层模块或者编写JNI方法时使用,而Java接口一般是在应用层编写APP时使用。

Android系统中的C/C++日志接口是通过宏来使用的。在system/core/include/android/log.h定义了日志的级别:

  1. /*
  2. *Androidlogpriorityvalues,inascendingpriorityorder.
  3. */
  4. typedefenumandroid_LogPriority{
  5. ANDROID_LOG_UNKNOWN=0,
  6. ANDROID_LOG_DEFAULT,/*onlyforSetMinPriority()*/
  7. ANDROID_LOG_VERBOSE,
  8. ANDROID_LOG_DEBUG,
  9. ANDROID_LOG_INFO,
  10. ANDROID_LOG_WARN,
  11. ANDROID_LOG_ERROR,
  12. ANDROID_LOG_FATAL,
  13. ANDROID_LOG_SILENT,/*onlyforSetMinPriority();mustbelast*/
  14. }android_LogPriority;
在system/core/include/cutils/log.h中,定义了对应的宏,如对应于ANDROID_LOG_VERBOSE的宏LOGV:

  1. /*
  2. *Thisisthelocaltagusedforthefollowingsimplified
  3. *loggingmacros.Youcanchangethispreprocessordefinition
  4. *beforeusingtheothermacrostochangethetag.
  5. */
  6. #ifndefLOG_TAG
  7. #defineLOG_TAGNULL
  8. #endif
  9. /*
  10. *SimplifiedmacrotosendaverboselogmessageusingthecurrentLOG_TAG.
  11. */
  12. #ifndefLOGV
  13. #ifLOG_NDEBUG
  14. #defineLOGV(...)((void)0)
  15. #else
  16. #defineLOGV(...)((void)LOG(LOG_VERBOSE,LOG_TAG,__VA_ARGS__))
  17. #endif
  18. #endif
  19. /*
  20. *Basiclogmessagemacro.
  21. *
  22. *Example:
  23. *LOG(LOG_WARN,NULL,"Failedwitherror%d",errno);
  24. *
  25. *ThesecondargumentmaybeNULLor""toindicatethe"global"tag.
  26. */
  27. #ifndefLOG
  28. #defineLOG(priority,tag,...)\
  29. LOG_PRI(ANDROID_##priority,tag,__VA_ARGS__)
  30. #endif
  31. /*
  32. *Logmacrothatallowsyoutospecifyanumberforpriority.
  33. */
  34. #ifndefLOG_PRI
  35. #defineLOG_PRI(priority,tag,...)\
  36. android_printLog(priority,tag,__VA_ARGS__)
  37. #endif
  38. /*
  39. *================================================================
  40. *
  41. *Thestuffintherestofthisfileshouldnotbeuseddirectly.
  42. */
  43. #defineandroid_printLog(prio,tag,fmt...)\
  44. __android_log_print(prio,tag,fmt)
因此,如果要使用C/C++日志接口,只要定义自己的LOG_TAG宏和包含头文件system/core/include/cutils/log.h就可以了:

#define LOG_TAG "MY LOG TAG"

#include <cutils/log.h>

就可以了,例如使用LOGV:

LOGV("This is the log printed by LOGV in android user space.");

再来看Android系统中的Java日志接口。Android系统在Frameworks层中定义了Log接口(frameworks/base/core/java/android/util/Log.java):

[java] view plain copy
  1. ................................................
  2. publicfinalclassLog{
  3. ................................................
  4. /**
  5. *Priorityconstantfortheprintlnmethod;useLog.v.
  6. */
  7. publicstaticfinalintVERBOSE=2;
  8. /**
  9. *Priorityconstantfortheprintlnmethod;useLog.d.
  10. */
  11. publicstaticfinalintDEBUG=3;
  12. /**
  13. *Priorityconstantfortheprintlnmethod;useLog.i.
  14. */
  15. publicstaticfinalintINFO=4;
  16. /**
  17. *Priorityconstantfortheprintlnmethod;useLog.w.
  18. */
  19. publicstaticfinalintWARN=5;
  20. /**
  21. *Priorityconstantfortheprintlnmethod;useLog.e.
  22. */
  23. publicstaticfinalintERROR=6;
  24. /**
  25. *Priorityconstantfortheprintlnmethod.
  26. */
  27. publicstaticfinalintASSERT=7;
  28. .....................................................
  29. publicstaticintv(Stringtag,Stringmsg){
  30. returnprintln_native(LOG_ID_MAIN,VERBOSE,tag,msg);
  31. }
  32. publicstaticintv(Stringtag,Stringmsg,Throwabletr){
  33. returnprintln_native(LOG_ID_MAIN,VERBOSE,tag,msg+'\n'+getStackTraceString(tr));
  34. }
  35. publicstaticintd(Stringtag,Stringmsg){
  36. returnprintln_native(LOG_ID_MAIN,DEBUG,tag,msg);
  37. }
  38. publicstaticintd(Stringtag,Stringmsg,Throwabletr){
  39. returnprintln_native(LOG_ID_MAIN,DEBUG,tag,msg+'\n'+getStackTraceString(tr));
  40. }
  41. publicstaticinti(Stringtag,Stringmsg){
  42. returnprintln_native(LOG_ID_MAIN,INFO,tag,msg);
  43. }
  44. publicstaticinti(Stringtag,Stringmsg,Throwabletr){
  45. returnprintln_native(LOG_ID_MAIN,INFO,tag,msg+'\n'+getStackTraceString(tr));
  46. }
  47. publicstaticintw(Stringtag,Stringmsg){
  48. returnprintln_native(LOG_ID_MAIN,WARN,tag,msg);
  49. }
  50. publicstaticintw(Stringtag,Stringmsg,Throwabletr){
  51. returnprintln_native(LOG_ID_MAIN,WARN,tag,msg+'\n'+getStackTraceString(tr));
  52. }
  53. publicstaticintw(Stringtag,Throwabletr){
  54. returnprintln_native(LOG_ID_MAIN,WARN,tag,getStackTraceString(tr));
  55. }
  56. publicstaticinte(Stringtag,Stringmsg){
  57. returnprintln_native(LOG_ID_MAIN,ERROR,tag,msg);
  58. }
  59. publicstaticinte(Stringtag,Stringmsg,Throwabletr){
  60. returnprintln_native(LOG_ID_MAIN,ERROR,tag,msg+'\n'+getStackTraceString(tr));
  61. }
  62. ..................................................................
  63. /**@hide*/publicstaticnativeintprintln_native(intbufID,
  64. intpriority,Stringtag,Stringmsg);
  65. }

因此,如果要使用Java日志接口,只要在类中定义的LOG_TAG常量和引用android.util.Log就可以了:

private static final String LOG_TAG = "MY_LOG_TAG";

Log.i(LOG_TAG, "This is the log printed by Log.i in android user space.");

要查看这些LOG的输出,可以配合logcat工具。如果是在Eclipse环境下运行模拟器,并且安装了Android插件,那么,很简单,直接在Eclipse就可以查看了:

浅谈Android系统开发中LOG的使用_第1张图片

如果是在自己编译的Android源代码工程中使用,则在后台中运行模拟器:

USER-NAME@MACHINE-NAME:~/Android$ emulator &

启动adb shell工具:

USER-NAME@MACHINE-NAME:~/Android$ adb shell

使用logcat命令查看日志:

root@android:/ # logcat

这样就可以看到输出的日志了。

你可能感兴趣的:(android)