Linux日志系统与日志库zlog


一、Linux日志

  • 在Linux系统下有大量的日志,用于记录系统、程序运行中发生的各种事件,通过阅读日志,有助于诊断和解决系统故障。在开发项目时加入日志系统也会方便调试分析,找到问题。zlog是一个轻量级、高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库,比较适合嵌入式开发。

1、系统常用的日志(日志是用来记录重大事件的工具)

/var/log/message      系统信息日志,包含错误信息等

/var/log/secure         系统登录日志

/var/log/cron            定时任务日志

/var/log/maillog         邮件日志

/var/log/boot.log       系统启动日志

2、日志管理服务 rsyslog

【1】作用:主要用来采集日志,不产生日志

【2】配置文件:/etc/rsyslog.conf

3、日志级别分为:

 debug  ##有调试信息的,日志通信最多

 info    ##一般信息日志,最常用
 
 notice   ##最具有重要性的普通条件的信息
 
 warning   ##警告级别
 
 err     ##错误级别,阻止某个功能或者模块不能正常工作的信息

crit     ##严重级别,阻止整个系统或者整个软件不能正常工作的信息

alert     ##需要立刻修改的信息

emerg   ##内核崩溃等重要信息

none     ##什么都不记录 

二、zlog安装与使用

本文简摘自zlog使用手册,更详细的使用规则请参考:zlog使用手册

1.下载与安装

  1. GitHut下载: https://github.com/HardySimpson/zlog.
  2. 解压进入目录:
lzl@ubuntu18:~/zlog-master$ ls
Changelog  COPYING  doc  INSTALL  makefile  README.md  src  test  TODO  tools
  1. 编译:make
lzl@ubuntu18:~/zlog-master$ make
  1. 安装:make install
lzl@ubuntu18:~/zlog-master$ make install

安装成功后会显示安装到了/usr/local/lib路径下。

  • 安装到这个路径基本就成功了,不过在链接器链接是找不到库,会出现以下错误:
    error while loading shared libraries: xxx.so.x

这时需要手动给链接器加路径:
$ sudo vim /etc/li.so.conf
加入:
/usr/local/lib

  • 然后执行命令:
$ sudo ldconfig

ldconfig作用是在默认搜寻目录(/lib和/usr/lib)下, 以及动态库配置文件(/etc/ld.so.conf和/etc/ld.so.conf.d/.conf) 里所列的目录下, 搜索出可共享的动态库(格式如lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件. 缓存文件默认为/etc/ld.so.cache, 此文件保存动态库名字列表.


三. zlog使用

一、配置文件

# comments
[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]
TRACE = 10
CRIT = 130, LOG_CRIT

 

[formats]
simple = "%m%n"
normal = "%d %m%n"

 

[rules]
default.*               >stdout; simple

*.*                     "%12.2E(HOME)/log/%c.log", 1MB*12; simple

my_.INFO                >stderr;

my_cat.!ERROR           "/var/log/aa.log"

my_dog.=DEBUG           >syslog, LOG_LOCAL0; simple

my_mice.*               $user_define;

1. 全局参数[global]

[]代表一个节的开始,四个小节的顺序不能变,依次为global-levels-formats-rules。这一节可以忽略不写。语法为
(key) = (value)

  • 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

2、日志等级[levels]

用于定义用户自己的日志等级、这一节可以忽略不写。语法为:

(level string) = (level int), (syslog level, optional)

用户自定义等级

在配置文件中定义新的等级

[global]

default format  =               "%V %v %m%n"

[levels]

TRACE = 30, LOG_DEBUG

[rules]

my_cat.TRACE            >stdout;

内置的默认等级是(这些不需要写在配置文件里面)

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

这样在zlog看来,一个整数(30)还有一个等级字符串(TRACE)代表了等级。这个整数必须位于[1,253]之间,其他数字是非法的。数字越大代表越重要。现在TRACE比DEBUG重要(30>20),比INFO等级低(30<40)。在这样的定义后,TRACE就可以在下面的配置文件里面用了。例如这句话:

my_cat.TRACE >stdout; 

意味着等级>=TRACE的,包括INFO, NOTICE, WARN, ERROR, FATAL会被写到标准输出。

3、格式(Formats)

用来定义日志的格式。语法为:

(name) = “(actual formats)”

(name)被后面的规则使用。(name)必须由数字和字母组成,下划线"_"也算字母。(actual format)前后需要有双引号。

4、规则(Rules)

用于描述日志是怎么被过滤、格式化以及被输出的。这节可以若忽略不写,日志输没有输出,这也是配置文件中不可缺省的重要部分。

1.级别匹配
表达式含义
*所有等级
aa.debug代码内等级>=debug
aa.=debug代码内等级=debug
aa.!debug代码内等级!=debug
2.分类匹配

分类必须由数字和字母组成,下划线"_"也算字母。

描述匹配规则匹配样式不匹配样式
*表示匹配所有*.*aa, aa_bb, aa_cc, xx, yy …none
以_结尾的分类匹配本级及下级分类aa_.*aa, aa_bb, aa_cc, aa_bb_ccxx, yy
不以_结尾的精确匹配分类名aa.*aaaa_bb, aa_cc, aa_bb_cc
!匹配那些没有找到规则的分类!.*未定义的都匹配aa(as it matches rules above)

例子:
比如我想将等级大于或等于warn的日志输出到"./test.log"文件中,不等于ERROR 的日志输出到终端。
配置:

[rules]

my.=WARN           "./test.log" 

my.!error          >stdout

API调用:
zc = zlog_get_category("my");
结果:

lzl@ubuntu18:~/my/test/zlog$ ./test
2021-04-18 20:28:22 DEBUG [5879:test.c:44] zlog, debug

2021-04-18 20:28:22 INFO [5879:test.c:45] zlog ,info
 
2021-04-18 20:28:22 NOTICE [5879:test.c:46] zlog, notice

2021-04-18 20:28:22 WARN [5879:test.c:47] zlog, warn

2021-04-18 20:28:22 FATAL [5879:test.c:49] zlog,fatal

lzl@ubuntu18:~/my/test/zlog$ cat test.log 
2021-04-18 20:28:22 WARN [5879:test.c:47] zlog, warn

二、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指定的错误日志里面。

3、写日志函数和宏

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, …)

3、测试代码

配置文件:

[global]
strict init = true

[rules]
my.=WARN           "./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;
    int             flag = 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;
    }

    while(flag)
    {

        zlog_debug(zc, "zlog, debug\n"); 
        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");
        flag--;
    }
    zlog_fini();
    return 0;
    
}

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值