参数
描述
-b
加载一个可使用的日志缓冲区供查看,比如event和radio。默认值是main
-c
清除缓冲区中的全部日志并退出(清除完后可以使用-g查看缓冲区)
-d
将缓冲区的log转存到屏幕中然后退出
-f
将log输出到指定的文件中<文件名>.默认为标准输出(stdout)
-g
打印日志缓冲区的大小并退出
-n
设置日志的最大数目
-r
没
-s
设置过滤器
-v
设置输出格式的日志消息。默认是短暂的格式。支持的格式列表
一般长时间输出log的话建议-f,-n,-r三个参数连用,这样当一个文件日志输出满了之后可以马上在另一个中进行输出
优先级语法
优先级使用字符标识,一下优先级从低到高
V –Verbose(最低优先级)
D – Debug
I – Info
W – Warning
E – Error
F – Fatal
S – Silent
为了减少不想要日志的输出,可以建立一个过滤器
过滤语法:tag:priority
//过滤TAG为ActivityManager输出级别大于I的日志与TAG为MyApp输出级别大于D的日志
adb logcat ActivityManager:I My App:D *:S
adb logcat *:W
设置过滤级别为W以上
如果用的比较多可以设置环境变量:
export ANDROID_LOG_TAGS="ActivityManager:I MyApp:D*:S"
logcat源码分析
logat源码主要分布在:
system/core/logcat/logcat.cpp system/core/include/cutils/logger.h
使用了liblog库,编译出来的结果是可执行程序logcat。
我们从logcat.cpp的main函数开始分析。
主函数代码:
1 int main(int argc, char **argv)
2 {
3 ......
4
5 //1. 参数check和解析
6 g_logformat = android_log_format_new();
7
8 if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
9 logprint_run_tests();
10 exit(0);
11 }
12
13 if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
14 android::show_help(argv[0]);
15 exit(0);
16 }
17
18 // 参数的继续处理
19 for (;;) {
20 int ret;
21 ret = getopt(argc, argv, "cdt:gsQf:r::n:v:b:B");
22
23 if (ret < 0) {
24 break;
25 }
26
27 switch(ret) {
28 case 's':
29 // default to all silent
30 android_log_addFilterRule(g_logformat, "*:s");
31 break;
32
33 case 'c':
34 clearLog = 1;
35 mode = O_WRONLY;
36 break;
37 ......
38 }
39
40 //2. devices的过滤
41 if (!devices) {
42 devices = new log_device_t(strdup("/dev/"LOGGER_LOG_MAIN), false, 'm');
43 android::g_devCount = 1;
44 int accessmode =
45 (mode & O_RDONLY) ? R_OK : 0
46 | (mode & O_WRONLY) ? W_OK : 0;
47 // only add this if it's available
48 if (0 == access("/dev/"LOGGER_LOG_SYSTEM, accessmode)) {
49 devices->next = new log_device_t(strdup("/dev/"LOGGER_LOG_SYSTEM), false, 's');
50 android::g_devCount++;
51 }
52 }
53
54 //dev = devices;
55 while (dev) {
56 dev->fd = open(dev->device, mode);
57
58 ......
59
60 //3.读取一行
61 android::readLogLines(devices);
62 }
根据输入的参数,进行相应的分析和处理:
例如,输入--help,就调用
android::show_help(argv[0]);
//显示help信息。
然后进入for无限循环。在for循环中,进一步进行参数处理。包括getopt中的这些值。
ret = getopt(argc, argv, "cdt:gsQf:r::n:v:b:B");
函数用于过滤参数中是否包含cdt:gsQf:r::n:v:b:B中的值,并且返回这个值。
对于ret的处理就是switch case
对devices的分析:
devices的类型定义在logger.h中,如下:
#define LOGGER_LOG_MAIN "log/main"
#define LOGGER_LOG_RADIO "log/radio"
#define LOGGER_LOG_EVENTS "log/events"
#define LOGGER_LOG_SYSTEM "log/system"
可见,logcat -b后面的参数对应于文件系统中的某一个(几个)文件。
readLines函数的实现:
实现原理,实现一个无限循环,采用select多路复用,从
devices
中获取数据,这里的devices就是前面提到的
system, events , radio, main
多路复用select: 监听devices设备,超时时间设置为5ms。将结果通过read函数读取到内存中,即读取到queued_entry_t相关的内存中。
C 输出log到LogCat
1 #include
2 #include
3 #include
4 #include
5
6 #define LOG "c_log"
7 #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG,__VA_ARGS__)
8 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__)
9 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__)
10 #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__)
11 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)
12 #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__)
13
14 JNIEXPORT void JNICALL
15 Java_com_myc_jni_Jni_cLog(JNIEnv *env, jobject instance) {
16 LOGV("c输出测试: 等级v");
17 LOGD("c输出测试: 等级d");
18 LOGI("c输出测试: 等级i");
19 LOGW("c输出测试: 等级w");
20 LOGE("c输出测试: 等级e");
21 LOGF("c输出测试: 等级f");
22 }
View Code