前言
zlog是一个轻量级、高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库。
一.源码安装
源码获取(源码资源很多,其他安装方法也可以)
spy@ubuntu:~$ git clone https://github.com/HardySimpson/zlog.git //获取源码
spy@ubuntu:~$ cd zlog //进入zlog文件夹
spy@ubuntu:~/zlog/$ ls //查看
Changelog COPYING doc INSTALL makefile README.md src test TODO tools
spy@ubuntu:~/zlog/$ make //进行安装
make install 需要sudo权限 若安装到其他路径 需要cd当前文件src中修改makefile文件修改如下图
spy@ubuntu:~/zlog/$ sudo make install
这里我设置安装的路径为50行 ../bulid_linux 修改该文件后回到上级文件zlog下执行make install即可
执行安装后
二.zlog常用函数接口(API)
1、初始化:
int zlog_init(const char *confpath);
zlog_init()从配置文件confpath中读取配置信息到内存。如果confpath为NULL,会寻找环境变量ZLOG_CONF_PATH的值作为配置文件名。如果环境变量ZLOG_CONF_PATH也没有,所有日志以内置格式写到标准输出上。每个进程只有第一次调用zlog_init()是有效的,后面的多余调用都会失败并不做任何事情
int zlog_reload(const char *confpath);
zlog_reload()从confpath重载配置,并根据这个配置文件来重计算内部的分类规则匹配、重建每个线程的缓存、并设置原有的用户自定义输出函数。可以在配置文件发生改变后调用这个函数。这个函数使用次数不限。如果confpath为NULL,会重载上一次zlog_init()或者zlog_reload()使用的配置文件。如果zlog_reload()失败,上一次的配置依然有效。所以zlog_reload()具有原子性。
void zlog_fini(void);
zlog_fini()清理所有zlog API申请的内存,关闭它们打开的文件。使用次数不限。
返回值如果成功,zlog_init()和zlog_reload()返回0。失败的话,zlog_init()和zlog_reload()返回-1。详细错误会被写在由环境变量ZLOG_PROFILE_ERROR指定的错误日志里面。
2、分类(Category)操作
typedef struct zlog_category_s zlog_category_t;
zlog_category_t *zlog_get_category(const char *cname);
zlog_get_category()从zlog的全局分类表里面找到分类,用于以后输出日志。如果没有的话,就建一个。然后它会遍历所有的规则,寻找和cname匹配的规则并绑定。
配置文件规则中的分类名匹配cname的规律描述如下:
匹配任意cname。
以下划线_结尾的分类名同时匹配本级分类和下级分类。例如aa_匹配aa, aa_, aa_bb, aa_bb_cc这几个cname。
不以下划线_结尾的分类名精确匹配cname。例如aa_bb匹配aa_bb这个cname。
! 匹配目前还没有规则的cname。
每个zlog_category_t *对应的规则,在zlog_reload()的时候会被自动重新计算。不用担心内存释放,zlog_fini() 最后会清理一切。
返回值
如果成功,返回zlog_category_t的指针。如果失败,返回NULL。详细错误会被写在由环境变量ZLOG_PROFILE_ERROR指定的错误日志里面。
void zlog(zlog_category_t * category,
const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const char *format, ...);
void vzlog(zlog_category_t * category,
const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const char *format, va_list args);
void hzlog(zlog_category_t * category,
const char *file, size_t filelen,
const char *func, size_t funclen,
long line, int level,
const void *buf, size_t buflen);
描述
这3个函数是实际写日志的函数,输入的数据对应于配置文件中的%m。category来自于调用zlog_get_category()。
宏原型:
zlog_fatal(cat, format, …)
zlog_error(cat, format, …)
zlog_warn(cat, format, …)
zlog_notice(cat, format, …)
zlog_info(cat, format, …)
zlog_debug(cat, format, …)
三.zlog使用及文件配置
每一个[ ]代表一个小节,四个小节的顺序需严格按照[global] [levels] [formats] [rules]语法为 key = value
一、文件配置
配置文件格式为
[global]
strict init = true
buffer min = 1024
buffer max = 2MB
rotate lock file = /tmp/zlog.lock
default format = "%d.%us %-6V (%c:%F:%L) - %m%n"
file perms = 600
[levels]
[formats]
[rules]
[global] 全局参数
strict init
如果"strict init"是true,zlog_init()将会严格检查所有的格式和规则,任何错误都会导致zlog_init() 失败并且返回-1。当"strict init"是false的时候,zlog_init()会忽略错误的格式和规则。 这个参数默认为true。
buffer min buffer max
zlog在堆上为每个线程申请缓存。“buffer min"是单个缓存的最小值,zlog_init()的时候申请这个长度的内存。写日志的时候,如果单条日志长度大于缓存,缓存会自动扩充,直到到"buffer max”。 单条日志再长超过"buffer max"就会被截断。如果 “buffer max” 是 0,意味着不限制缓存,每次扩充为原先的2倍,直到这个进程用完所有内存为止。缓存大小可以加上 KB, MB 或 GB这些单位。默认来说"buffer min"是 1K , “buffer max” 是2MB。
rotate lock file
锁文件,确保多线程程序在记录日志时引发的安全问题,默认为日志文件走作为锁。
default format
这个参数是缺省的日志格式,默认值为:"%d %V [%p:%F:%L] %m%n"
这种格式产生的输出类似这样:
2012-02-14 17:03:12 INFO [3758:test_hello.c:39] hello, zlog
[levels] 日志等级
这一小节可以在配置文件中忽略
//默认等级
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
如果修改则需要在配置文件的[level]一节中 定义
配置文件格式为
[global]
[levels]
OTHER = 30, LOG_DEBUG
[formats]
[rules]
配置文件中配置后 对于zlog 整数30 代表了一个等级字符串(OTHER) 这个整数必须位于[1,253]之间,不能超过这个范围,数字越大等级越高。
[Formats] 格式
用来定义日志的格式。语法为:
name) = “(actual formats)”
(name)被后面的规则使用。(name)必须由数字和字母组成,下划线"_"也算字母。(actual format)前后需要有双引号。
配置文件格式为
[gloabal]
[levels]
[formats]
ms = "%d.%ms %m%n"
us = "%d.%us %m%n"
nu1 = "%m%n"
nu2 = "%d(%m-%d %T) %-10V [%p:%F:%L] %m%n"
nu3 = "%d(%m-%d %T) %-5c [%p:%F:%L] %m%n"
[rules]
#%n: 换行符
#%m: 用户从zlog函数输入的日志信息
#%c: 分类名
#%V: 日志级别
#%p: 进程id
#%F: 源代码文件名
#%L: 源代码行数
#%ms: 毫秒,3位数字字符串
#%us: 微秒,6位数字字符串
#%d(): 日志的时间。 如果不跟小括号,默认是%d(%F %T) | %F: 年-月-日 (%Y-%m-%d) | %T: 小时:分钟:秒 (%H:%M:%S)
#%-5c: 左对齐,最小宽度5
[rules] 规则
用于描述日志是怎么被过滤、格式化以及被输出的。这节可以若忽略不写,日志输没有输出,这也是配置文件中不可缺省的重要部分。
[global]
[levels]
[formats]
[rules]
my.ERROR "./test.log";nu1 //my为zlog_get_category("my");定义的要匹配的字符串('my.ERROR' 表示代码内等级大于等于ERROR 输出到文件./test.log中);nu1为format中定义的格式类型
my.=DEBUG >stdout .= 表示代码内等级为DEBUG 输出到标准输出
1.级别匹配
2.分类匹配
四、简单测试
配置文件 vim test.conf (可省略的为默认状态)
[global]
strict init = true
[levels]
DEBUG = 20,LOG_DEBUG
INFO = 40,LOG_INFO
[rules]
my.ERROR "./test.log"
my.=error >stdout
测试代码:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "zlog.h"
int main (char argc, char **argv)
{
zlog_category_t *zc = NULL;
char *conf_file = "./test.conf";
int rv = -1;
rv = zlog_init(conf_file);
if(rv)
{
printf("init zlog failed\n");
return -1;
zlog_fini();
}
zc = zlog_get_category("my");
if( !zc ) {
printf("zlog_get_category false\n");
return -2;
}
zlog_debug(zc, "zlog, debug\n");
//zlog_debug(zc, "zlog, debug %d\n",a); 可加格式控制
zlog_info(zc, "zlog ,info\n ");
zlog_notice(zc, "zlog, notice\n");
zlog_warn(zc, "zlog, warn\n");
zlog_error(zc, "zlog, error\n");
zlog_fatal(zc, "zlog,fatal\n");
zlog_fini();
return 0;
}
输出结果
查看日志 test.log