日常工作中常常需要输出日志进行调试,本文提供了一个C语言编写的日志框架。可以输出日志到文件或者是终端,支持日志等级设置,不同日志等级可以设置不同的颜色,另外还可以设置进程名、模块名、函数名等的输出,能够打印毫秒级时间,能够限制文件大小,使用方便,架构小巧灵活。本架构多线程的支持有待验证,每次日志调用都会使用写入,性能有待验证,另外,写满切换文件没有实现。
SimpleLog.h
/*****************************************************************************
simple log frame for test
*****************************************************************************/
#ifndef _SIMPLE_LOG_H_
#define _SIMPLE_LOG_H_
#include <stdbool.h>
#define COLOR_CTRL_CODE "\033[0;"
#define COLOR_CTRL_CLOSE "\033[0m"
#define F_RED "31m"
#define F_GREEN "32m"
#define F_YELLOW "33m"
#define F_NONE "0m"
#define COLOR_ERROR F_RED // 错误
#define COLOR_WARN F_YELLOW // 警告
#define COLOR_INFO F_GREEN // 信息
#define COLOR_DEBUG F_NONE // 调试
// 日志级别
#define LOG_LEVEL_ERROR 0 // 错误
#define LOG_LEVEL_WARN 1 // 警告
#define LOG_LEVEL_INFO 2 // 信息
#define LOG_LEVEL_DEBUG 3 // 调试
#define LOG_LEVEL_MAX LOG_LEVEL_DEBUG
// 日志输出目标
#define LOG_TARGET_TERM 0 //输出到终端
#define LOG_TARGET_FILE 1 //输出到文件
bool SlogInit(int _iTarget, int _iLevel, const char *_strPath);
bool SlogDeinit();
bool SlogSetLevel(int _iLevel);
bool SlogGetLevel(int *_iLevel);
void Slog(int _iLevel, const char* format, ...);
//重定位日志接口
#define LOG_MAIN "logtest" //进程名
#define LOG_SUB "test" //模块名
#define Sdebug(arg, vl...) \
Slog(LOG_LEVEL_DEBUG, "[%s][%s][%s]" COLOR_CTRL_CODE COLOR_DEBUG arg COLOR_CTRL_CLOSE, LOG_MAIN, LOG_SUB, __FUNCTION__, ##vl)
#define Sinfo(arg, vl...) \
Slog(LOG_LEVEL_INFO, "[%s][%s][%s]" COLOR_CTRL_CODE COLOR_INFO arg COLOR_CTRL_CLOSE, LOG_MAIN, LOG_SUB, __FUNCTION__, ##vl)
#define Swarn(arg, vl...) \
Slog(LOG_LEVEL_WARN, "[%s][%s][%s]" COLOR_CTRL_CODE COLOR_WARN arg COLOR_CTRL_CLOSE, LOG_MAIN, LOG_SUB, __FUNCTION__, ##vl)
#define Serror(arg, vl...) \
Slog(LOG_LEVEL_ERROR, "[%s][%s][%s]" COLOR_CTRL_CODE COLOR_ERROR arg COLOR_CTRL_CLOSE, LOG_MAIN, LOG_SUB, __FUNCTION__, ##vl)
#endif //_SIMPLE_LOG_H_
SimpleLog.c
/*****************************************************************************
simple log frame for test
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include "SimpleLog.h"
#define LOG_DEFAULT_PATH "./test.log"
#define LOG_MAX_SZIE (10 * 1024 * 1024) // M
char *g_strLevel[] = {
"error", "warn ", "info ", "debug"
};
typedef struct _TSimpleLog_ {
FILE *fp;
int iTarget;
int iLevel;
int iSize;
char strPath[256];
}TSimpleLog;
// 日志全局信息
static TSimpleLog g_tLog = {0};
bool TimeToString(const time_t _time, char *_strTime, int iLen) {
struct tm *p = NULL;
p = localtime(&_time);
p->tm_year = p->tm_year + 1900;
p->tm_mon = p->tm_mon + 1;
snprintf(_strTime, iLen, "%04d-%02d-%02d %02d:%02d:%02d",
p->tm_year, p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
return true;
}
bool SlogInit(int _iTarget, int _iLevel, const char *_strPath) {
g_tLog.iTarget = _iTarget;
g_tLog.iLevel = _iLevel;
g_tLog.iSize = 0;
if(g_tLog.iLevel > LOG_LEVEL_MAX) {
g_tLog.iLevel = LOG_LEVEL_MAX;
}
if(NULL == _strPath) {
strncpy(g_tLog.strPath, LOG_DEFAULT_PATH, sizeof(g_tLog.strPath)-1);
} else {
strncpy(g_tLog.strPath, _strPath, sizeof(g_tLog.strPath)-1);
}
printf("Log path is %s\n", g_tLog.strPath);
g_tLog.fp = fopen(g_tLog.strPath, "w+");
if(NULL == g_tLog.fp) {
printf("fp is null !");
return false;
}
return true;
}
bool SlogDeinit() {
if(NULL != g_tLog.fp) {
fflush(g_tLog.fp);
fclose(g_tLog.fp);
}
return true;
}
bool SlogSetLevel(int _iLevel) {
g_tLog.iLevel = _iLevel;
if(g_tLog.iLevel > LOG_LEVEL_MAX) {
g_tLog.iLevel = LOG_LEVEL_MAX;
}
return true;
}
bool SlogGetLevel(int *_iLevel) {
*_iLevel = g_tLog.iLevel;
return true;
}
void Slog(int _iLevel, const char* format, ...) {
if(_iLevel > LOG_LEVEL_MAX) {
_iLevel = LOG_LEVEL_MAX;
}
if(NULL == g_tLog.fp || _iLevel > g_tLog.iLevel) {
return;
}
va_list ap;
char strTimeBuf[32] = {0};
struct timeval sCurTm = {0};
gettimeofday(&sCurTm, NULL);
TimeToString(sCurTm.tv_sec, strTimeBuf, sizeof(strTimeBuf));
if(LOG_TARGET_TERM == g_tLog.iTarget) {
printf("[%s.%03d][%s]", strTimeBuf, (int)sCurTm.tv_usec/1000, g_strLevel[_iLevel]);
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
return;
}
//大于最大重新打开
if (g_tLog.iSize > LOG_MAX_SZIE) {
fclose(g_tLog.fp);
g_tLog.fp = fopen(g_tLog.strPath, "w+");
if (NULL == g_tLog.fp) {
printf("fp is null !");
return;
}
g_tLog.iSize = 0;
}
g_tLog.iSize += fprintf(g_tLog.fp, "[%s.%03d][%s]", strTimeBuf, (int)sCurTm.tv_usec/1000, g_strLevel[_iLevel]);
va_start(ap, format);
g_tLog.iSize += vfprintf(g_tLog.fp, format, ap);
va_end(ap);
fflush(g_tLog.fp);
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "SimpleLog.h"
int main() {
SlogInit(LOG_TARGET_TERM, LOG_LEVEL_DEBUG, "./test.log");
Slog(LOG_LEVEL_ERROR, "hello world!\n");
Slog(LOG_LEVEL_WARN, "hello world!\n");
Slog(LOG_LEVEL_INFO, "hello world!\n");
Slog(LOG_LEVEL_DEBUG, "hello world!\n");
Serror("hello world!\n");
Swarn("hello world!\n");
Sinfo("hello world!\n");
Sdebug("hello world!\n");
SlogDeinit();
return 0;
}