1、linux内核的log输出
在标准的linux内核开发过程中,使用 printk ,这是一个与printf输出打印齐名的函数,同样提供格式化输出功能,只是其有
打印级别且将信息保存到 /proc/kmsg 日志中,使用cat命令查看其信息[cat /proc/kmsg]
[cpp] view plain copy
- <span style="font-size:14px;color:#003333;">#define KERN_EMERG "<0>"
- #define KERN_ALERT "<1>"
- #define KERN_CRIT "<2>"
- #deinfe KERN_ERR "<3>"
- #deinfe KERN_WARNING "<4>"
- #deinfe KERN_NOTICE "<5>"
- #deinfe KERN_INFO "<6>"
- #deinfe KERN_DEBUG "<7>" </span>
2、android中log输出
Android系统在用户空间中提供了轻量级的logger日志系统,它是在内核中实现的一种设备驱动,与用户空间的logcat工具配合使用能够方便地跟踪调试程序。
Android系统中的C/C++日志接口是通过宏来使用的。在system/core/include/android/log.h定义了日志的级别:
typedef enum android_LogPriority {
ANDROID_LOG_UNKNOWN = 0,
ANDROID_LOG_DEFAULT,
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT,
} android_LogPriority;
为了使用方便,在system/core/include/cutils/log.h定义了相对应的宏:
#define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#define LOGD(...) ((void)LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGI(...) ((void)LOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGW(...) ((void)LOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)LOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
因为如果需要使用log输出,包含其头文件:#include <cutils/log.h> 并link其动态库:liblog.so 即可
#define LOG_TAG "XX_LOG_TAG" // 这里可以定义其输出的TAG
#include <cutils/log.h>
JAVA层打印:
import android.util.Log;
private static final String TAG = "XX_LOG_TAG";
Log.e(TAG, "This is the error log printed by Log.i in android user space.");
内核代码路径:
kernel/drivers/staging/android/logger.h
kernel/drivers/staging/android/logger.c
1、Logger驱动程序的相关数据结构
首先来看logger.h头文件的内容:
[cpp] view plain copy
- #ifndef _LINUX_LOGGER_H
- #define _LINUX_LOGGER_H
- #include <linux/types.h>
- #include <linux/ioctl.h>
- struct logger_entry {
- __u16 len;
- __u16 __pad;
- __s32 pid;
- __s32 tid;
- __s32 sec;
- __s32 nsec;
- char msg[0];
- };
- #define LOGGER_LOG_RADIO "log_radio"
- #define LOGGER_LOG_EVENTS "log_events"
- #define LOGGER_LOG_SYSTEM "log_system"
- #define LOGGER_LOG_MAIN "log_main"
- #define LOGGER_ENTRY_MAX_LEN (4*1024)
- #define LOGGER_ENTRY_MAX_PAYLOAD \
- (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
- #define __LOGGERIO 0xAE
- #define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1)
- #define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2)
- #define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3)
- #define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4)
- #endif
struct logger_entry是一个用于描述一条Log记录的结构体。
其中len成员变量记录了这条记录的有效负载的长度,有效负载指定的日志记录本身的长度,但是不包括用于描述这个记录的struct logger_entry结构体。
从struct logger_entry中也可以看出:优先级别Priority、Tag字符串以及Msg字符串,pid和tid成员变量分别用来记录是哪条进程写入了这条记录。sec和nsec成员变量记录日志写的时间。msg成员变量记录的就有效负载的内容了,它的大小由len成员变量来确定
#define LOGGER_ENTRY_MAX_LEN(4*1024)
#define LOGGER_ENTRY_MAX_PAYLOAD \
(LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
这两个宏定义记录了 最大有效负载长度。
再分析下logger.c实现文件:
[cpp] view plain copy
- struct logger_log {
- unsigned char *buffer;
- struct miscdevice misc;
- wait_queue_head_t wq;
- struct list_head readers;
- struct mutex mutex;
- size_t w_off;
- size_t head;
- size_t size;
- };
结构体struct logger_log就是真正用来保存日志的地方了。buffer成员变量变是用保存日志信息的内存缓冲区,它的大小由size成员变量确定。
buffer是一个循环使用的环形缓冲区,缓冲区中保存的内容是以struct logger_entry为单位的,其组成方式是:
struct logger_entry | priority | tag | msg