应用层log打印

应用层一般log打印函数都经过封装了,这样可以设置log等级,方便调试,可以直接屏幕输出,也可以保存到文件或者发送到云端。现只看屏幕输出部分,跟进这些函数,最终就是输出到 stderr 或者 stdout 或者调用printf。

先看一个函数:

void std_err_out(void)
{
	fprintf(stdout,"Hello ");
	fprintf(stderr,"World!");
}

打印结果是:World!Hello 。原因是在默认情况下,stdout是行缓冲的,他的输出会放在一个buffer里面,只有到换行的时候,才会输出到屏幕,而stderr是无缓冲的,会直接输出。

第二个函数:

void simple_out(void)
{
	fprintf(stderr, "%s_%d,stderr output!\n",__FUNCTION__,__LINE__); 
	fprintf(stdout, "%s_%d,stdout output!\n",__FUNCTION__,__LINE__); 
	printf("%s_%d,printf output!\n",__FUNCTION__,__LINE__); 
}

打印结果是:

simple_out_27,stderr output!
simple_out_28,stdout output!
simple_out_29,printf output!

看来加了换行符后, stderr ,stdout ,printf没有任何区别。但是生成的可执行文件重定向输出到文件呢?

$ ./stdtest > tmp.txt 
simple_out_11,stderr output!

那么tmp.txt里面的内容是:



simple_out_12,stdout output!
simple_out_13,printf output!

这样看差异就出来了,原因是因为:

stdout -- 标准输出设备, printf(".."))同 stdout。 
stderr -- 标准错误输出设备 
两者默认向屏幕输出。

但如果用转向标准输出到磁盘文件,则可看出两者区别。
stdout输出到磁盘文件,stderr在屏幕。

第三个函数:

#define print_case_frist(fmt,...)  \
  do { if (1) fprintf(stderr, "print_frist_case: %s:%s():%d " fmt, __FILE__, __func__,__LINE__, ##__VA_ARGS__); } while (0)

这个宏定义结构在代码里经常出现,关于‘##’运算符可以用于类函数宏的替换部分, __VA_ARGS__ 是一个可变参数的宏,替换省略号所代表的字符串。

这样调用 print_case_frist("|case %d\n",one);,打印结果如下:

print_frist_case: std-printf.c:main():110 |case 1

关于宏定义中do while(0) 这个结构是必须,说明如下:

do while(0) 作用:
1. 替代{},实现局部作用域..
2. 避免使用goto,用break做跳出.

例子:
#define AB1    a; b;     // 下面语句b不能被执行: if (cond) AB1;
#define AB2    { a; b; } // 下面语句编译出错:if (cond) AB2; else ...;
#define AB3    a, b      // 有运算符优先级问题
#define AB4    do { a; b; } while (0)

第四个函数:

#define print_case_second(fmt, args...)		second_log_error("[%s:%d]  "fmt, __func__, __LINE__, ##args)

void second_log_error(const char *fmt, ...)
{
    va_list ap;       //指向当前参数的一个指针
    va_start(ap, fmt);//对va_list变量进行初始化,将ap指针指向参数列表中的第一个参数
    vfprintf(stdout, fmt, ap);//将ap(通常是字符串) 按format格式写入stdout中
    va_end(ap);//回收ap指针
}

这第三个函数区别是输出到 stdout,没有用fprintf,而是用vfprintf这个函数,具体函数已经注释很清楚了。

这样调用 print_case_second("|case %d\n",two);,打印结果如下:

[main:113]  |case 2

第五个函数:

#define LOG_DEBUG_MAX_LEN 4096	

#define LOG_DEBUG_WAY_ALL  3

#define LOG_DEBUG_LEVEL_ERROR 1

//增加log打印等级
#define print_case_third(fmt, args...)\
        third_log_error(LOG_DEBUG_WAY_ALL, "%d [%s:%d] "fmt, LOG_DEBUG_LEVEL_ERROR, __func__, __LINE__, ##args)

void third_log_error(int way, const char* fmt, ...)
{
    char buf[LOG_DEBUG_MAX_LEN] = {0};
    int len = 0;
    char *pos = NULL;
    va_list ap;

    va_start(ap, fmt);
    len = vsnprintf(buf, LOG_DEBUG_MAX_LEN - 1, fmt, ap);
    if (len <= 0)
    {
        return ;
    }

    if (len > LOG_DEBUG_MAX_LEN - 1 )
    {
        len = LOG_DEBUG_MAX_LEN - 1;
    }

    if ((LOG_DEBUG_LEVEL_ERROR == 1) && (way > 2))
    {
        printf("%s\n", buf);
    }

    va_end(ap);
}

这个函数可以设置log等级了,log是保存在buf中,意味着可以根据对应参数(bug_level和way)发送到需要的地方,当然也可以写入对应系统文件中。函数三和函数四的log也可以很容易保存到文件。

其实还有一种系统log是保存在/var/log/messages里,函数接口是syslog():

配置文件:/etc/syslog.conf;
log文件:/var/log/messages
	
syslog():向日志设备(日志工具 facility)发送日志消息

#define ALONE_LOG(fmt,args...)	\
do { \
	snprintf(alone_log_buf, ALONE_LOG_BUF_SIZE, fmt,##args); \
	syslog( LOG_INFO, alone_log_buf );	\
} while(0)

猜你喜欢

转载自blog.csdn.net/jin615567975/article/details/81188985
今日推荐