vlambda博客
学习文章列表

linux c c++ 通过printf收集系统日志

背景:

        在开发大型项目的过程中,总是避免不了收集系统日志的需要,要不然自己编写的项目出现问题了,一问三不知,或者没有踪迹可查,那将会是一个非常可怕的事情,因此,小菜鸡分享一下以前参与到的某个大项目的日志收集模块做法,关于本文的编码已经进行了信息脱敏处理,因此,可以放心使用~

实现思路

  • 利用C中的宏函数重新定义printf的功能;

  • 重定向printf的输出方向;

  • 设置日志输出等级;

详细实现

#ifndef WT_BACKGROUND_APPLICATION_LOG_H#define WT_BACKGROUND_APPLICATION_LOG_H
#include <stdio.h>#include <stddef.h>#include <time.h>
#define __DEBUG //日志模块总开关,注释掉将关闭日志输出
#ifdef __DEBUG#define DEBUG(format, ...) printf (format, ##__VA_ARGS__)#else#define DEBUG(format, ...)#endif
//定义日志级别enum LOG_LEVEL {LOG_LEVEL_OFF=0,LOG_LEVEL_FATAL,LOG_LEVEL_ERR,LOG_LEVEL_WARN,LOG_LEVEL_INFO,LOG_LEVEL_ALL,};extern enum LOG_LEVEL debug_level;//模块日志输出级别
static void wt_get_log_time(){time_t timer;//time_t就是long int 类型struct tm *tblock;timer = time(NULL);tblock = localtime(&timer);printf("\n%s", asctime(tblock));}
#define log_fatal(level,format, ...) \do { \if(level>=LOG_LEVEL_FATAL){\wt_get_log_time();\DEBUG("->FATAL @ FUNC:%s FILE:%s LINE:%d " format "\n",\__func__, __FILE__, __LINE__, ##__VA_ARGS__ );\}\} while (0)
#define log_err(level,format, ...) \do { \if(level>=LOG_LEVEL_ERR){\wt_get_log_time();\DEBUG("->ERR @ FUNC:%s FILE:%s LINE:%d " format "\n",\__func__, __FILE__, __LINE__, ##__VA_ARGS__ );\}\} while (0)
#define log_warn(level,format, ...) \do { \if(level>=LOG_LEVEL_WARN){\wt_get_log_time();\DEBUG("->WARN @ FUNC:%s " format "\n",__func__, ##__VA_ARGS__ );\}\} while (0)
#define log_info(level,format, ...) \do { \if(level>=LOG_LEVEL_INFO){\wt_get_log_time();\DEBUG("->INFO " format"\n",##__VA_ARGS__ );\}\} while (0)
#define log_debug(level,format, ...) \do { \if(level>=LOG_LEVEL_ALL){\wt_get_log_time();\DEBUG("->DEBUG " format"\n",##__VA_ARGS__ );\}\} while (0)
extern void wt_set_background_application_log_level(int log_level);extern void wt_log_test();
#endif // WT_BACKGROUND_APPLICATION_LOG_H

使用提示:将上方代码做成头文件即可!

#include "wt_background_application_log.h"
#define NSWT_LOG_DIRECTORY "/var/log/watchtower"#define NSWT_LOG_FILE "/var/log/watchtower/watchtower.log"
static int save_standard_output_descriptor_symbol;static int log_file_descriptor_symbol;
enum LOG_LEVEL debug_level;//模块日志输出级别

void wt_log_ouput_init(){fflush(stdout); //刷新流 stream 的输出缓冲区setvbuf(stdout,NULL,_IONBF,0); //定义流 stream 不使用缓冲save_standard_output_descriptor_symbol = dup(STDOUT_FILENO); //保存标准输出文件描述符if(!IsFileExist(NSWT_LOG_DIRECTORY)){mkdir(NSWT_LOG_DIRECTORY,S_IRWXU | S_IRWXG | S_IRWXO);}log_file_descriptor_symbol = open(NSWT_LOG_FILE,(O_RDWR | O_CREAT | O_TRUNC), 0664);if(log_file_descriptor_symbol > 0){dup2(log_file_descriptor_symbol,STDOUT_FILENO); //用fd替换标准输出log_debug(debug_level,"\n wt_log_ouput_init initialization completed! \n");}
}
void wt_log_output_restore(){
close(log_file_descriptor_symbol);dup2(save_standard_output_descriptor_symbol,STDOUT_FILENO); //用完之后恢复标准输出到屏幕
}
void wt_log_test(){
log_debug(debug_level,"The moniter debug level is set successfully!");log_info(debug_level,"The moniter debug level is set successfully!");log_warn(debug_level,"The moniter debug level is set successfully!");log_err(debug_level,"The moniter debug level is set successfully!");
}
void wt_set_background_application_log_level(int log_level){switch (log_level) {case 0:debug_level = LOG_LEVEL_OFF;break;case 1:debug_level = LOG_LEVEL_FATAL;break;case 2:debug_level = LOG_LEVEL_ERR;break;case 3:debug_level = LOG_LEVEL_WARN;break;case 4:debug_level = LOG_LEVEL_INFO;break;case 5:debug_level = LOG_LEVEL_ALL;break;default:debug_level = LOG_LEVEL_OFF;break;
}}
int main(){//sleep(15); //wait for the system initwt_log_ouput_init();
wt_set_background_application_log_level(LOG_LEVEL_ALL);
wt_log_test();
log_debug(debug_level,"exit \n");wt_log_output_restore();
return 0;}

使用提示:将上方代码做成源文件即可!

最后

    虽然,在Linux中还可以通过很多种方式实现日志收集,例如syslog等操作,但在,这里小菜鸡只是利用了printf实现了日志收集的功能,主要考虑的是项目的可移植性问题,通过C语言原生的库函数实现,意味着只要移植的平台可以支持C语言,即可兼容!同时,还可以避免使用第三方工具出现的漏洞问题,例如,前段时间出现的Log4j漏洞问题,本文虽然简陋,但却是一个非常经典的参考~

Sentence one day

  The Master said ,"When we see men of worth,we should think of equaling them;when we see men of a contrary character,we should turn inwards and examine ourselves."

点击名片 关注小菜鸡学Linux