背景
封装日志API供平时代码学习使用,顺便学习一下相关的知识点:
- 变参函数
- 时间的格式化输出
c语言版本
log.h
#ifndef _LOG_H_ #define _LOG_H_ #include <stdarg.h> #include <stdio.h> #include <time.h> #include <string.h> #define LOG_DEBUG 0x01 #define LOG_INFOR 0x02 #define LOG_WARNING 0x03 #define LOG_ERROR 0x04 #define LOG_FATAL_ERROR 0x05 #define LOG_DBG(format, ...) WriteLog(LOG_DEBUG, "DEBUG ", __LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) #define LOG_INFO(format, ...) WriteLog(LOG_INFOR, "INFO ", __LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) #define LOG_WARN(format, ...) WriteLog(LOG_WARNING, "WARN ", __LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) #define LOG_ERR(format, ...) WriteLog(LOG_ERROR, "ERR ", __LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) #define LOG_FATAL(format, ...) WriteLog(LOG_FATAL_ERROR, "FATAL", __LINE__, __FUNCTION__, __FILE__, format, ##__VA_ARGS__) FILE *log_file; int log_level; int LogInit(const int level, const char *path) { log_level = level; log_file = fopen(path, "a"); if (NULL == log_file) { return -1; }
//---行缓冲 setvbuf(log_file, NULL, _IOLBF, 0); /**/ return 0; } int WriteLog(int v_level,const char *level, int line, const char *func, const char *file, const char * format, ...) { if (log_level > v_level){return -1;} //---文件名,行号,函数名 char log_pos[64] = {0}; sprintf(log_pos, " %s %s:%d [%s] ", level, file, line, func); //---时间戮 char log_time[64] = {0}; time_t t = time(NULL); struct tm ptm; localtime_r(&t, &ptm); sprintf(log_time, "%4d-%02d-%02d %02d:%02d:%02d", ptm.tm_year + 1900, ptm.tm_mon + 1, ptm.tm_mday, ptm.tm_hour, ptm.tm_min, ptm.tm_sec); //---日志内容 char log_msg[5*1024] = {0}; va_list arg_ptr; va_start(arg_ptr, format); int nWrittenBytes = vsnprintf(log_msg,sizeof(log_msg), format, arg_ptr); if (nWrittenBytes < 0) { perror("vsnprintf"); return -1; } va_end(arg_ptr); //---拼接 char log_output[6*1024] = {0}; strcat(log_output, log_time); strcat(log_output, log_pos); strcat(log_output, log_msg); fprintf(log_file, "%s ", log_output); return nWrittenBytes; } #endif
测试
#include "log.h" int main() { if(LogInit(LOG_INFOR, "forever.log")) { printf("log init failed. "); return -1; } int tmp = 123; LOG_DBG("***********"); LOG_INFO("***********"); LOG_INFO("%d", tmp); LOG_INFO("%s%p", "infor log", &tmp); LOG_WARN("%s***%d", "warning log", tmp); LOG_ERR("%s %d", "error log", tmp); LOG_FATAL("%s %d", "fatal error log", tmp); return 0; }
日志输出
[root@localhost]# gcc main.c [root@localhost]# ./a.out [root@localhost]# tail -f forever.log 2019-05-09 13:40:06 INFO main.c:13 [main] *********** 2019-05-09 13:40:06 INFO main.c:14 [main] 123 2019-05-09 13:40:06 INFO main.c:15 [main] infor log0x7ffd443c729c 2019-05-09 13:40:06 WARN main.c:16 [main] warning log***123 2019-05-09 13:40:06 ERR main.c:17 [main] error log 123 2019-05-09 13:40:06 FATAL main.c:18 [main] fatal error log 123
c++版本
log.h
#ifndef _LOG_H_ #define _LOG_H_ enum LogLevel { ALL = 0, INFO, WARN, ERR }; class LOG { public: static void INFO(const char *msg, ...); static void WARN(const char *msg, ...); static void ERR(const char *msg, ...); static void SetLogLevel(LogLevel level) { logLevel = level; } private: static void write(const char *msg); static LogLevel logLevel; }; #endif
log.cc
#include "log.h" #include <stdarg.h> #include <string.h> #include <time.h> #include <sys/time.h> #include <stdio.h> LogLevel LOG::logLevel = LogLevel::ALL; void LOG::write(const char *msg) { struct timeval tv; struct tm tm_time; long mseconds, useconds; static char cur_timestr[32] = ""; gettimeofday(&tv, NULL); gmtime_r(&tv.tv_sec, &tm_time); mseconds = tv.tv_usec / 1000; useconds = tv.tv_usec % 1000; sprintf(cur_timestr, "%d/%d/%d %d:%d:%d:%ld:%ld", tm_time.tm_year +1900, tm_time.tm_mon, tm_time.tm_mday, tm_time.tm_hour +8, tm_time.tm_min, tm_time.tm_sec, mseconds, useconds); printf("%s %s", cur_timestr, msg); } void LOG::INFO(const char *msg, ...) { if (logLevel > LogLevel::INFO) {return;} if (!msg) {return;} char pTemp[1024] = { 0 }; va_list arg_ptr; va_start(arg_ptr, msg); vsprintf(pTemp + strlen(pTemp), msg, arg_ptr); va_end(arg_ptr); LOG::write(pTemp); } void LOG::WARN(const char *msg, ...) { if (logLevel > LogLevel::WARN) return; if (!msg) {return;} char pTemp[1024] = { 0 }; va_list arg_ptr; va_start(arg_ptr, msg); vsprintf(pTemp + strlen(pTemp), msg, arg_ptr); va_end(arg_ptr); LOG::write(pTemp); } void LOG::ERR(const char *msg, ...) { if (!msg) {return;} char pTemp[1024] = { 0 }; va_list arg_ptr; va_start(arg_ptr, msg); vsprintf(pTemp + strlen(pTemp), msg, arg_ptr); va_end(arg_ptr); LOG::write(pTemp); }
测试
#include "log.h" #include <iostream> int main() { LOG::SetLogLevel(LogLevel::ERR); LOG::INFO("%s ", "久旱逢甘露"); LOG::WARN("%s ", "他乡遇故知"); LOG::ERR("%s ", "洞房花烛夜"); LOG::ERR("%s ", "金榜题名时"); }
日志输出
orejia@debian9:log$ ./demo 2019/11/29 15:1:49:255:949 洞房花烛夜 2019/11/29 15:1:49:256:25 金榜题名时
参考资料
简洁版 https://blog.csdn.net/iw1210/article/details/53591565
纯C日志函数库zlog使用手册 http://hardysimpson.github.io/zlog/UsersGuide-CN.html#htoc1
C-log https://www.cnblogs.com/prophet-ss/p/8025825.html
日志切割 https://www.cnblogs.com/areyouready/p/9334872.html
日志切割之logrotate https://www.cnblogs.com/clsn/p/8428257.html