一,模块接口

模块接口比较简单,因为主要只有写日志的操作。

  1. 创建日志模块变量

    log_t log_new(log_type_t type,const char *file, const char *facility);

    log_type_t用于控制日志的类型,可以标识为系统日志,文件以及标准输出,是一个枚举类型,定义如下:

    typedef enum {  log_STDOUT,log_SYSLOG,log_FILE
    } log_type_t;

    file:这个字段有两种意思,如果日志类型为文件时,该字段表示文件名。如果日志类型为系统日志,该字段表示ident值。
    facility:这个参数用于指明记录日志的程序的类型,我们传递的格式都是系统保留的,并且以这种形式传递local3。

  2. 写日志
    void  log_write(log_t log, int level, const char *msgfmt, ...);

    level表示写入日志的级别,如:通告,错误,警告之类的,可以按照通用的错误类型划分。分别定义字符串如下:

    static const char *_log_level[] =
    {"emergency","alert","critical","error","warning","notice","info","debug"
    };
  3. 释放日志模块变量
    void  log_free(log_t log);

二,数据结构

定义数据结构如下:

typedef struct log_st
{log_type_t  type;FILE        *file;
} *log_t;

只有日志类型和一个文件结构指针。

下面说一下记录日志的程序类型,主要有以下几种日志程序的类型:

LOG_AUTH :安全/授权消息
LOG_AUTHPRIV:安全/授权消息
LOG_CRON:时间守护进程(cron和at)专用
LOG_DAEMON:其它系统守护进程
LOG_KERN:核心消息
LOG_LOCAL0到LOG_LOCAL7:系统保留
LOG_LPR:printer子系统
LOG_MAIL:mail子系统
LOG_NEWS:USENET新闻子系统
LOG_SYSLOG:syslogd进程内部所产生的消息
LOG_USER(缺省):一般使用者缺省使用消息
LOG_UUCP:UUCP子系统
LOG_FTP:FTP子系统使用

我们在这里用的是系统保留,也就是只有LOG_LOCAL0到LOG_LOCAL7,那就要求必须重新封装,以做到以下两点:

  1. 如果传递的facility不属于local0~local7,就默认local0~local7中的一个。
  2. 需要将传递的local0转换成LOG_LOCAL0,以此类推。

这里为什么传递local0,而不直接传递LOG_LOCAL0?直接传递也是可以的,只所以传递字符串,是因为大多数的日志都是在配置文件中,而配置文件以字符串的形式存取。而LOG_LOCAL0,并不是一个固定的整数值。

typedef struct log_facility_st
{
const char  *facility;
int         number;
} log_facility_t;static log_facility_t _log_facilities[] = {{ "local0", LOG_LOCAL0 },{ "local1", LOG_LOCAL1 },{ "local2", LOG_LOCAL2 },{ "local3", LOG_LOCAL3 },{ "local4", LOG_LOCAL4 },{ "local5", LOG_LOCAL5 },{ "local6", LOG_LOCAL6 },{ "local7", LOG_LOCAL7 },{ NULL, -1 }
};

这是定义的一个常量数组,分别和系统日志设备对映起来。在操作的日志文件中,可以看到和这相关的配置,位于/etc/syslog.conf文件中,如:

# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.*                                                 /dev/console# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none                /var/log/messages# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure# Log all the mail messages in one place.
mail.*                                                  -/var/log/maillog# Log cron stuff
cron.*                                                  /var/log/cron# Everybody gets emergency messages
*.emerg                                                 *# Save news errors of level crit and higher in a special file.
uucp,news.crit                                          /var/log/spooler# Save boot messages also to boot.log
local7.*                                                /var/log/boot.log
local5.*                                                /var/log/client.log

这上面就配置了local7和local5这两个本地日志设备,其实就是两个日志文件。其实在系统的头文件中就是<sys/syslog.h>中,也定义了这样的一个数组:

#ifdef SYSLOG_NAMES
CODE facilitynames[] ={{ "auth", LOG_AUTH },{ "authpriv", LOG_AUTHPRIV },{ "cron", LOG_CRON },{ "daemon", LOG_DAEMON },{ "ftp", LOG_FTP },{ "kern", LOG_KERN },{ "lpr", LOG_LPR },{ "mail", LOG_MAIL },{ "mark", INTERNAL_MARK },          /* INTERNAL */{ "news", LOG_NEWS },{ "security", LOG_AUTH },           /* DEPRECATED */{ "syslog", LOG_SYSLOG },{ "user", LOG_USER },{ "uucp", LOG_UUCP },{ "local0", LOG_LOCAL0 },{ "local1", LOG_LOCAL1 },{ "local2", LOG_LOCAL2 },{ "local3", LOG_LOCAL3 },{ "local4", LOG_LOCAL4 },{ "local5", LOG_LOCAL5 },{ "local6", LOG_LOCAL6 },{ "local7", LOG_LOCAL7 },{ NULL, -1 }};
#endif

前面说为了便宜传递参数,我们假设我们传递的系统日志设备为local5这种形式,但要求是LOG_LOCAL5这个宏,因此我们根据上面的数组,作个转换:

static int _log_facility(const char *facility) {log_facility_t *lp;if (facility == NULL) {return -1;}for (lp = _log_facilities; lp->facility; lp++) {if (!strcasecmp(lp->facility, facility)) {break;}}return lp->number;
}

这个函数会根据local5,找到并返回LOG_LOCAL5。

三,创建日志模块

代码如下:

log_t log_new(log_type_t type,const char *ident, const char *facility)
{log_t log;int fnum = 0;log = (log_t) calloc(1, sizeof(struct log_st));log->type = type;if(type == log_SYSLOG) {   // 系统日志 fnum = _log_facility(facility);if (fnum < 0)fnum = LOG_LOCAL7;openlog(ident, LOG_PID, fnum); //  下面会对openlog系统调用进行说明。return log;}else if(type == log_STDOUT) {   // 标准输出。log->file = stdout;return log;}log->file = fopen(ident, "a+");  if(log->file == NULL)   //  文件,如果打开文件失败,会将其定义为标准输出。{ log->type = log_STDOUT;log->file = stdout;}return log;
}

四,关于openlog调用

在写系统日志时,不是必须要调用openlog,如果没有调用openlog,那么在第一次调用syslog时,会自动调用openlog,此函数原型如下:

void openlog(const char *ident, int option, int facility);

这个函数用来打开一个到系统日志记录程序的连接,打开之后就可以用syslog或vsyslog函数向系统日志里记录日志。

  1. ident:这个参数是一个标记,在写入日志时,每行都会在前面自动的加上这个标记,通常可以写成当前程序的名称或者是同一程序不同的端口调用。
  2. option:该参数可以取值LOG_CONS, LOG_NDELAY, LOG_NOWAIT, LOG_ODELAY, LOG_PERROR, LOG_PID。都表示不同的意思,我们这里取LOG_PID表示每一行日志都包含当前程序的进程ID号。
  3. facility:表示往哪个日志里写,其实也是表示由哪个具体的系统日志类型来记录日志。

五,写日志

在调用log_new之后,此时log_st有两种可能:

  1. 类型为系统日志类型,那么已经打开了系统日志。接下来只要直接调用syslog函数就OK了。
  2. 日志类型不是系统日志,而是文件或者标准输出,此时log_st结构体的域FILE *file,已经指向了具体的文件,后面只要调用fwrite类函数就可以了。
代码如下:
#define MAX_LOG_LINE (1024)
void log_write(log_t log, int level, const char *msgfmt, ...)
{va_list ap;char *pos, message[MAX_LOG_LINE+1];int sz, len;time_t t;if(log->type == log_SYSLOG) { //  写入系统日志 va_start(ap, msgfmt);len = vsnprintf(message, MAX_LOG_LINE, msgfmt, ap);if (len > MAX_LOG_LINE)message[MAX_LOG_LINE] = '\0';elsemessage[len] = '\0';syslog(level, "%s", message); // 下面会说明syslog调用。va_end(ap);return;}t = time(NULL);   // 时间戳pos = ctime(&t);sz = strlen(pos);pos[sz-1]=' ';len = snprintf(message, MAX_LOG_LINE, "%s[%s] ", pos, _log_level[level]);if (len > MAX_LOG_LINE)message[MAX_LOG_LINE] = '\0';elsemessage[len] = '\0'; for (pos = message; *pos != '\0'; pos++); /*empty statement */sz = pos - message;va_start(ap, msgfmt);vsnprintf(pos, MAX_LOG_LINE - sz, msgfmt, ap);  va_end(ap);   // 根据传入参数,组织文本信息fprintf(log->file,"%s", message);  // 写入文件。fprintf(log->file, "\n");fflush(log->file);
}

六,syslog调用


函数的声明如下:

void syslog(int priority, const char * message, ...);
  1. priority:消息的紧急级别。
  2. message:第二个参数是消息及其格式,之后是格式对应的参数,如同C语言里面printf输出函数一样使用。

第一个参数priority,它是由severity level和facility组成的,Facility已经在上面介绍了,下面介绍一下severity level,也就是消息的重要级别,它主要包括:

LOG_EMERG:紧急状况
LOG_ALERT:高优先级问题,比如说数据库崩溃等,必须要立即采取反应行动
LOG_CRIT:重要状况发生,比如硬件故障
LOG_ERR:错误发生
LOG_WARNING:警告发生
LOG_NOTICE:一般状况,需要引起注意
LOG_INFO:信息状况
LOG_DEBUG:调试消息

七,释放

这个操作就很简单了,

void log_free(log_t log) {if(log->type == log_SYSLOG)closelog();else if(log->type == log_FILE)fclose(log->file);free(log);
}

八,使用的例子

这个使用也是很简单的,分成三部:创建,写入,释放

log_t log = log_new(log_SYSLOG, "Example", "local5"); // 创建日志模块变量。
log_write(log, LOG_NOTICE, "应用程序正在启动中");
log_free(log);

日志模块的C语言实现相关推荐

  1. python日志模块_Python之日志处理(logging模块)

    转载自:https://www.cnblogs.com/yyds/p/6901864.html 本节内容 日志相关概念 logging模块简介 使用logging提供的模块级别的函数记录日志 logg ...

  2. python 日志输出为json格式文件_Py修行路 python基础 (二十一)logging日志模块 json序列化 正则表达式(re)...

    一.日志模块 两种配置方式:1.config函数 2.logger #1.config函数 不能输出到屏幕 #2.logger对象 (获取别人的信息,需要两个数据流:文件流和屏幕流需要将数据从两个数据 ...

  3. 文献日志:EMNLP2020-自适应性语言普适分析器

    文献日志:EMNLP2020-自适应性语言普适依存分析器 基本信息(Basic Information) 目标(Aim) 问题(Problem) 直感(Intuition) 相关工作(Related ...

  4. 极简系列|日志模块-clog

    日志作为应用程序调试和维护的基本手段被广泛使用,像是谷歌的glog,java领域的log4j,它们都是功能强大的大型日志中间件.可是,在特殊的领域,比如是嵌入式开发领域,由于资源的限制,可能不能直接应 ...

  5. 日志模块 logging

    举例:# 1.办公室# 2.负责往控制台里面输出日志信息的# 3.往日志文件里面写日志的,按天生成日志,清理日志 import logging #导入日志模块 from logging import ...

  6. day31 logging 日志模块

    1 # logging 日志模块 ****** 2 # 记录用户行为或者代码执行过程 3 # print 来回注释比较麻烦的 4 # logging 5 # 我能够"一键"控制 6 ...

  7. Python之配置日志模块logging

    一.定义日志打印方式 如果我们运行自己的程序,有时候需要记录程序运行过程中出现的问题或者信息.可以运用日志模块logging来记录,该模块日志格式可以根据用户需求来自己定义. 常见打印日志信息形式如下 ...

  8. python logging模块的作用_Python 日志模块logging分析及使用-2

    本文作为Python日志模块的补充,主要介绍日志回滚RotatingFileHandler和TimedRotatingFileHandler的使用,以及其所带来的问题.Logger对象的日志等级是如何 ...

  9. DPDK — RTE_LOG 日志模块

    目录 文章目录 目录 DPDK 的日志系统 RTE_LOG 宏 rte_log 和 rte_vlog 函数 日志模块初始化 第一阶段初始化 第二阶段初始化 注册新的日志类型 复用现有日志类型 参考文档 ...

最新文章

  1. 安卓和ios抓包神器
  2. 【Ubuntu-Opencv】Ubuntu14.04 Opencv3.3.0 使用中出现OpenCV Error: Unspecified error
  3. 用three.js写一个简单的3D射门游戏
  4. Jupyter notebook 入门教程
  5. sci的figure怎么做_SCI论文中Figure图如何制作?
  6. MySQL批量插入测试数据
  7. 通过stm32cubemx配置DCMI驱动ov5640摄像头
  8. 我去图书馆-抢座助手
  9. 手脱aspack变形壳
  10. FPGA / IC 设计(一)
  11. Kteer软件 创建.ktr文件
  12. 困境下的SEO,站长如何自渡?
  13. TSW(Tencent Server Web)源码阅读指南
  14. 【华人学者风采】刘小平 中山大学
  15. python中4j_GitHub - Byron4j/PythonVeterans: Python新手到老鸟的历程;基于Python 3.6
  16. java中policelisten的用法,中考英语简单句和主谓一致专项语法复习
  17. 7-15 计算圆周率
  18. 在IPhone/IPad上建立反弹后门
  19. ADC中的SPS单位
  20. 【C++】1074:津津的储蓄计划(信息学奥赛)

热门文章

  1. 为什么越来越多的实体商企开始使用VR全景?如何在激烈竞争中占得一席之地呢?
  2. 045 中值定理总结(罗尔定理,拉格朗日定理,柯西定理,泰勒公式)及型一二三四五
  3. div 绝对定位覆盖
  4. icann 注册域名_ICANN推出的新顶级域名
  5. 多维数组的全排列问题
  6. mysql 安全插件
  7. UML--状态图的基本概念和作用
  8. oracle函数isnull,SQL中的ISNULL函数使用介绍
  9. 2018日本机器人周,思岚科技展现机器人智能行走技术
  10. cesium动态水面