Zlog日志框架
Zlog介绍
Zlog是一个高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库。它支持日志分级、切片、自定义格式等操作。
以下是对Zlog的简单介绍:
- Zlog是一个高可靠性、高性能(笔记本上达到25万条日志每秒)、线程安全、灵活、概念清晰的纯C日志函数库。
- 它支持日志分级、切片、自定义格式等操作。
- Zlog具有三个重要的概念:分类(Category)、规则(Rule)和格式(Format)。
- 分类(Category)用于区分不同的输入,可以根据需要获取不同分类名的category来输出不同分类的日志,用于不同的目的。
- 格式(Format)用来描述输出日志的格式,比如是否带有时间戳,是否包含文件位置信息等。
- 规则(Rule)则是把分类、级别、输出文件和格式组合起来,决定一条代码中的日志是否输出,输出到哪里,以什么格式输出。
- Zlog的行为大部分取决于配置文件,比如把日志打到哪里去,用什么格式,怎么转档,都由配置文件来决定。
Zlog使用方法
以下是使用Zlog框架的步骤:
- 安装Zlog库:使用git获取Zlog库,然后进行编译和安装。
- 引入头文件:在代码开头增加
#include "zlog.h"
。 - 初始化Zlog:使用
zlog_init
函数从配置文件中读取配置信息到内存。 - 获取分类:使用
zlog_get_category
函数从全局分类表中找到分类,用于以后输出日志。 - 记录日志:使用
zlog
函数增加一条新日志。
下面是一个简单的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include "zlog.h"
zlog_category_t *g_zc;
int main() {
int rc;
rc = zlog_init("log.ini");
if (rc) {
printf("初始化失败\n");
exit(-1);
}
g_zc = zlog_get_category("zlogdemo");
if (!g_zc) {
printf("获取分类失败\n");
zlog_fini();
exit(-2);
}
zlog_info(g_zc, "Zlog info message!");
zlog_warn(g_zc, "Zlog warn message!");
zlog_error(g_zc, "Zlog error message!");
zlog_fini();
}
zlogdemo
是一个分类名称,用于标识日志的输出. 在示例代码中,通过调用zlog_get_category
函数,我们从全局分类表中获取了名为zlogdemo
的分类. 这个分类用于以后输出日志.
至于具体内容,示例代码中的内容是一个简单的C语言程序,使用了Zlog框架记录了三条日志信息:info、warn和error. 这些日志信息将被写入到配置文件中指定的日志文件中. 示例代码中的配置文件log.ini
定义了日志的格式和输出方式.
以下是示例代码中的log.ini
文件的具体内容:
#DEBUG = 20, LOG_DEBUG
#INFO = 40, LOG_INFO
#NOTICE = 60, LOG_NOTICE
#WARN = 80, LOG_WARNING
#ERROR = 100, LOG_ERR
#FATAL = 120, LOG_ALERT
#UNKNOWN = 254, LOG_ERR
[global]
default format = "%d.%us %-6V (%F:%L) - %m%n"
[rules]
zlogdemo.info "../log/zlogdemo.log", 1 MB ~ "../log/zlogdemo-%d (%Y%m%d).#2s.log"
zlogdemo.info >stdout;
基本原理
直接上代码
#include <stdio.h>
#include <stdarg.h>
#define OPEN_LOG 1 // 定义日志是否开始
#define LOG_LEVEL LOG_INFO //定义日志开启的等级
// 定义一个log等级的枚举类型
typedef enum{
LOG_DEBUG =0,
LOG_INFO,
LOG_WARN,
LOG_ERROR,
}E_LOGLEVEL;
// 根据level等级返回对应的日志等级名
char * EM_LOGLevelGet(const int level){
if(level == LOG_DEBUG){
return "DEBUG";
}else if(level == LOG_INFO){
return "INFO";
}else if(level == LOG_WARN){
return "WARN";
}else if(level == LOG_ERROR){
return "ERROR";
}
return "UNKNOW";
}
void EM_LOG(const level, const char *fun, const int line, const char *fmt, ...){
#if OPEN_LOG // 根据OPEN_LOG是否开始来开始LOG模式
va_list arg;
va_start(arg, fmt);
char buf[1+vsnprintf(NULL,0,fmt,arg)];//获取整体的字符串所需要占的大小,并申请一个同等大小的buf缓存,加一是为了存结束符。
vsnprintf(buf,sizeof(buf), fmt, arg); // 将内容存储到buf中
va_end(arg);
if(level >= LOG_LEVEL) printf("[%s] [%s %d] %s\n",EM_LOGLevelGet(level),fun,line,buf); // 等级大于LOG_LEVEL,打印日志等级、执行所处函数、所在行号、以及buf内容。
#endif
}
#define EMlog(level, fmt...) EM_LOG(level, __FUNCTION__, __LINE__, fmt);
void main(){
int a = 10, b = 20;
// EM_LOG(LOG_WARN, __FUNCTION__, __LINE__, "A = %d", a);
// EMlog(LOG_DEBUG,"App start");
EMlog(LOG_WARN,"A = %d", a);
}
当然我们也可以把这把EMLog封装成一个方法,只需要引入
log.h
头文件,即可使用。代码如下
log.h
#include <stdio.h>
#include <stdarg.h>
#define OPEN_LOG 1 // 定义日志是否开始
#define LOG_LEVEL LOG_DEBUG //定义日志开启的等级
// 定义一个log等级的枚举类型
typedef enum{
LOG_DEBUG =0,
LOG_INFO,
LOG_WARN,
LOG_ERROR,
}E_LOGLEVEL;
void EM_LOG(const int level, const char *fun, const int line, const char *fmt, ...);
#define EMlog(level, fmt...) EM_LOG(level, __FUNCTION__, __LINE__, fmt);
log.c
#include <stdio.h>
#include <stdarg.h>
#include "log.h"
// 根据level等级返回对应的日志等级名
char * EM_LOGLevelGet(const int level){
if(level == LOG_DEBUG){
return "DEBUG";
}else if(level == LOG_INFO){
return "INFO";
}else if(level == LOG_WARN){
return "WARN";
}else if(level == LOG_ERROR){
return "ERROR";
}
return "UNKNOW";
}
void EM_LOG(const int level, const char *fun, const int line, const char *fmt, ...){
#if OPEN_LOG // 根据OPEN_LOG是否开始来开始LOG模式
va_list arg;
va_start(arg, fmt);
char buf[1+vsnprintf(NULL,0,fmt,arg)];//获取整体的字符串所需要占的大小,并申请一个同等大小的buf缓存,加一是为了存结束符。
vsnprintf(buf,sizeof(buf), fmt, arg); // 将内容存储到buf中
va_end(arg);
if(level >= LOG_LEVEL) printf("[%s] [%s %d] %s\n",EM_LOGLevelGet(level),fun,line,buf); // 等级大于LOG_LEVEL,打印日志等级、执行所处函数、所在行号、以及buf内容。
#endif
}
app.c
#include <stdio.h>
#include "log.h"
void main(){
int a = 10, b = 20;
// EM_LOG(LOG_WARN, __FUNCTION__, __LINE__, "A = %d", a);
EMlog(LOG_DEBUG,"App start");
EMlog(LOG_WARN,"A = %d", a);
}
我们只需要在所处文件的位置打开命令行,执行
gcc app.c log.c -o app
生成 app.exe,之后直接执行即可。