android中的log有很多级别,合理的控制log可以提高的解决问题的效率,减少工作量
1. log输出级别
android中的log级别如下

    ANDROID_LOG_UNKNOWN,
    ANDROID_LOG_DEFAULT,   
    ANDROID_LOG_VERBOSE,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_INFO,
    ANDROID_LOG_WARN,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_FATAL,
    ANDROID_LOG_SILENT,

2. log所在的文件
java中Log.java所对应的源码路径

  • frameworks/base/core/java/android/util/Log.java

使用时只需导入该Log类,如:
import android.util.Log;

native中log文件对应的源码路径

  • system/core/include/utils/Log.h
  • system/core/include/cutils/log.h
  • system/core/include/log/log.h

以上三个头文件依次include(包含)关系,使用时#include


3. log的级别说明

  • Verbose: 开发调试过程中一些详细信息,不应该编译进产品中,只在开发阶段使用。(参考api文档的描述:Verbose should never be compiled into anapplication except during development)
  • Debug: 用于调试的信息,编译进产品,但可以在运行时关闭。(参考api文档描述:Debug logs are compiled in but stripped atruntime)
  • Info:例如一些运行时的状态信息,这些状态信息在出现问题的时候能提供帮助。
  • Warn:警告系统出现了异常,即将出现错误。
  • Error:系统已经出现了错误。

Info、Warn、Error这三个等级的Log的警示作用依次提高,需要一直保留。这些信息在系统异常时能提供有价值的分析线索。
VERBOSE DEBUG信息应当只存在于开发中,INFO,WARN,ERROR这三种log将出现在发布版本中。

4. native中打印控制
在system/core/include/log/log.h文件中有如下代码

 #ifndef LOG_NDEBUG
 #ifdef NDEBUG
 #define LOG_NDEBUG 1
 #else
 #define LOG_NDEBUG 0
 #endif
 #endif

以上宏定义的意思不解析,不明白可以baidu
通常在使用之前要在文件头加上如下代码来在打印中输入对就模块

#ifndef LOG_TAG
#define LOG_TAG ""
#endif

Android的编译参数中,加入了-DNDEBUG,也就是默认是no debug的,

当然还需要LOG_NDEBUG LOG_NIDEBUG LOG_NDDEBUG这三个宏设置。
当-DNDEBUG被打上后,默认ALOGV会被禁止。
LOG_NDEBUG

LOG_NIDEBUG

LOG_NDDEBUG

这三个宏控制 LOG_PRI(priority, tag, ...)

NDEBUG 是总开关,默认在编译参数中加入,如果要控制打印级别,如下:
打开ALOGV:   #define LOG_NDEBUG 0      //允许Verbose级别打印
打开ALOGI:  #define LOG_NIDEBUG 0     //允许Info级别打印
打开ALOGD:#define LOG_NDDEBUG 0    //允许Debug级别打印
打开全部LOG:#undef NDEBUG    //允许所有级别打印

5. 在native中自定义log函数
第一步:在对应的mk文件中加入:LOCAL_LDLIBS := -llog
第二步:在要使用LOG的cpp文件中加入:
#include //
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, fmt, __VA_ARGS__)
第三步:这样就可以使用了:LOGD("调试信息^_^"); 这样,在logcat端看到的输出是:D/keymatch( 32):我要看到的调试信息^_^ 如果想改变输出中的各项内容,可以参考相应颜色的标示,比如,如果想定义LOGE,就可以把上面的ANDROID_LOG_DEBUG改成ANDROID_LOG_ERROR,同理,LOGI神马的也都以此类推:

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "ProjectName", __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "ProjectName", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , "ProjectName", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , "ProjectName", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "ProjectName", __VA_ARGS__)

fmt:格式化字符串可以指定log格式

6. c++中的预定义宏
__LINE__: 当前源文件的行号,整数
__FILE__: 当前源文件名,char 字符串,使用 /FC 选项产生全路径
__DATE__: 当前编译日期,char 字符串,格式 Aug 28 2011
__TIME__: 当前编译时间,char 字符串,格式 06:43:59
__STDC__: 整数 1,表示兼容 ANSI/ISO C 标准,配合 #if 使用
__TIMESTAMP__: 最后一次修改当前文件的时间戳,char 字符串,格式 Sun Aug 28 06:43:57 2011
__cplusplus: 以 C++ 方式而非 C 语言方式编译时定义,VC 2005 中定义为 199711L,配合 #ifdef 使用
__VA_ARGS__: 在函数式宏中,代表变长部分参数 (...),参考 MSDN: Variadic Macros
__COUNTER__: include 展开编译单元后,编译时第一次遇到 __COUNTER__ 替换为 0,以后在这个编译每遇到一次 __COUNTER__ 自增一。不同的编译单元之间 __COUNTER__ 不互相积累叠加,均从 0 开始计数,但预编译头 .pch 文件会记录 __COUNTER__ 的历史值,则每个编译单元均从历史值 + 1 开始计数。__COUNTER__ 支持宏的嵌套展开
__FUNCTION__, __FUNCDNAME__, __FUNCSIG__: 表示所在函数的函数名的 char 字符串。例如,对于 void test_funcname_macro() 函数原型,它们的值如下:

(1). __FUNCTION__ = test_funcname_macro: 函数的原始名/非修饰名 (undecorated)
(2). __FUNCDNAME__ = ?test_funcname_macro@@YAXXZ: 函数的修饰名 (decorated),可用工具 undname "decorated_name" 得出函数原型和调用规范,即 __FUNCSIG__ 所表示的
(3). __FUNCSIG__ = void __cdecl test_funcname_macro(void): 函数的 signature 名,即调用约定、返回值类型、参数类型

7. 以下是我自定义log函数
#define LOGD(...) \
    __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, "[%s,%s,%d]:%s", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)

转自:http://blog.sina.com.cn/s/blog_8acf1be10102vqv5.html

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐