"criu日志系统整理"

  "日志系统"

Posted by Xu on August 21, 2017

CRIU日志系统整理

这里我们对criu的日志打印系统做一个简单的整理分析:

日志系统的初始化过程

criulogsystem

打印日志过程流程

打印日志我们需要了解几个重要的对象:

日志打印级别:

#define LOG_UNSET	(-1)
#define LOG_MSG		(0) /* Print message regardless of log level */
#define LOG_ERROR	(1) /* Errors only, when we're in trouble */
#define LOG_WARN	(2) /* Warnings, dazen and confused but trying to continue */
#define LOG_INFO	(3) /* Informative, everything is fine */
#define LOG_DEBUG	(4) /* Debug only */

各种级别的日志打印函数


#define pr_msg(fmt, ...)						\
	print_on_level(LOG_MSG,						\
		       fmt, ##__VA_ARGS__)

#define pr_info(fmt, ...)						\
	print_on_level(LOG_INFO,					\
		       LOG_PREFIX fmt, ##__VA_ARGS__)

#define pr_err(fmt, ...)						\
	print_on_level(LOG_ERROR,					\
		       "Error (%s:%d): " LOG_PREFIX fmt,		\
		       __FILE__, __LINE__, ##__VA_ARGS__)

#define pr_err_once(fmt, ...)						\
	print_once(LOG_ERROR, fmt, ##__VA_ARGS__)

#define pr_warn(fmt, ...)						\
	print_on_level(LOG_WARN,					\
		       "Warn  (%s:%d): " LOG_PREFIX fmt,		\
		       __FILE__, __LINE__, ##__VA_ARGS__)

#define pr_warn_once(fmt, ...)						\
	print_once(LOG_WARN, fmt, ##__VA_ARGS__)

#define pr_debug(fmt, ...)						\
	print_on_level(LOG_DEBUG,					\
		       LOG_PREFIX fmt, ##__VA_ARGS__)

这几种打印函数的实现都是靠一个接口实现:

void print_on_level(unsigned int loglevel, const char *format, ...)
{
    //函数的参数传递过程是以栈的方式进行存取的,参数从右至左入栈,由于有时候函数定义的时候无法定义参数的类型和格式,所以在参数中用...来代替多余的参数,并用va_list对象来存放参数链表
	va_list params;

	va_start(params, format);//va_start指定params链表以参数format为链表头
	vprint_on_level(loglevel, format, params);//日志打印函数
	va_end(params);//关闭参数链表params
}

void vprint_on_level(unsigned int loglevel, const char *format, va_list params)
{
	int fd, size, ret, off = 0;
	int __errno = errno;

	if (unlikely(loglevel == LOG_MSG)) {
		fd = STDOUT_FILENO;//LOG_MSG级别标准输出,无视日志级别
		off = buf_off; /* skip dangling timestamp */
	} else {
		if (loglevel > current_loglevel)//判断日志函数的打印级别是否大于设定好的日志级别,大于则不打印
			return;
		fd = log_get_fd();//小于或等于所设定的日志级别,获取日志文件描述符
		if (current_loglevel >= LOG_TIMESTAMP)
			print_ts();
	}

	size  = vsnprintf(buffer + buf_off, sizeof buffer - buf_off, format, params);//将需要打印的内容写入字符串buffer中
	size += buf_off;

	while (off < size) {
		ret = write(fd, buffer + off, size - off);//将buffer中的内容写入日志文件,成功打印日志
		if (ret <= 0)
			break;
		off += ret;
	}

	if (loglevel == LOG_ERROR)
		log_note_err(buffer + buf_off);

	errno =  __errno;
}