C语言日志类

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Oyj1020/article/details/76222450

说明:这是一个Linux 环境下的C语言日志类,使用面向对象的编程方式实现。它可以循环生成日志、设置日志最大数量、日志生成周期、日志等级设置

logger.h文件

#ifndef _LOGGER_H
#define _LOGGER_H

/*
作    者: ouyongjiu
说明:这是一个C语言日志文件类,使用面向对象编程方式,参看handy logging类编写。它可以设置循环生成日志,并以时间命名。设置允许的最大日志数量,设置日志生成周期,日志等级
使用方法:
1.初始化日志结构体
    LoggerInit(&gLogger, KLALL,time(NULL));
2.设置日志目录、日志文件名
    gLogger.setFileName(&gLogger, "./log/","mis.log");
3.设置日志循环周期。单位:秒
    gLogger.setRotateInterval(&gLogger, 60);
4.设置日志允许的最大日志数量
    gLogger.setNumOfLog(&gLogger, 2);
5.使用日志类写入日志
    trace("test mis");
6.程序结束时,关闭日志。
    gLogger.closefile(&gLogger);

例子:
LoggerInit(&gLogger, KLALL,time(NULL));
gLogger.setFileName(&gLogger, "./log/","mis.log");
gLogger.setRotateInterval(&gLogger, 60);
gLogger.setNumOfLog(&gLogger, 2);
int cnt = 0;
for (;;)
{
trace("test mis");
sleep(1);
cnt++;
if (cnt==60)
{
printf("60 second\n");
cnt = cnt % 60;
}
}
gLogger.closefile(&gLogger);

*/
#define LFATAL 0
#define LERROR  1
#define LUERR   2
#define LWARN   3
#define LINFO   4
#define LDEBUG  5
#define LTRACE  6
#define LALL    7

#define PRIVATE 
#define PUBLIC

typedef struct _tgLogger
{
PRIVATE //私有成员变量
    char levelStrs_[LALL + 1][20];      //日志等级名称,写日志内容时,一并写入日志等级
    int fd_;                            //文件描述符
    int level_;                         //日志等级
    long lastRotate_;                   //最近一次周期时间戳
    long long  realRotate_;             //新文件开始的时间戳
    long rotateInterval_;               //新建文件周期,单位:秒
    char fileFullname_[100];            //文件全名=文件路径+文件名
    char filedir_[100];                 //文件路径、文件目录
    char filename_[100];                //文件名
    int nNumofLog_;                     //允许的最大日志文件数

PUBLIC  //公有函数指针变量
/*************************************************************************************
作    者: ouyongjiu
函数功能:将日志写入到文件
输入参数:
logger  日志结构体
level   日志等级
file    日志内容记录的文件名
line    日志内容所在目标记录文件所在行
func    __VA_ARGS__,可变参数
fmt     可变参数
...     可变参数    
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void(*logv)(struct _tgLogger*  logger, int level, const char* file, int line, const char* func, const char* fmt ,...);

/*************************************************************************************
作    者: ouyongjiu
函数功能:设置文件路径和文件名
输入参数:
logger      日志结构体
filedir     文件路径
filename    文件名
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void(*setFileName)(struct _tgLogger* logger, const char* filedir, const char* filename);
/*************************************************************************************
作    者: ouyongjiu
函数功能:设置文件路径和文件名
输入参数:
logger      日志结构体
level       日志等级,取值域={KLFATAL,KLERROR, KLUERR, KLWARN, KLINFO, KLDEBUG, KLTRACE, KLALL}
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void(*setLogLevel)(struct _tgLogger* logger, int level);

/*************************************************************************************
作    者: ouyongjiu
函数功能:关闭文件描述符
输入参数:
logger  日志结构体
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void(*closefile)(struct _tgLogger* logger);

/*************************************************************************************
作    者: ouyongjiu
函数功能:日志文件生成周期
输入参数:
logger          日志结构体
rotateInterval  日志文件生成周期,建议>=60s。单位:秒 
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void(*setRotateInterval)(struct _tgLogger* logger, long rotateInterval);

/*************************************************************************************
作    者: ouyongjiu
函数功能:设置日志最大的个数
输入参数:
logger  日志结构体
nNum    允许的最大日志数
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void(*setNumOfLog)(struct _tgLogger* logger, int nMaxNum);

PRIVATE //私有函数指针变量
/*************************************************************************************
作    者: ouyongjiu
函数功能:检查文件周期,文件从生成的到现在时间大于时间周期,则保存文件并重命名,开启新的文件
输入参数:
logger  日志结构体
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void(*_maybeRotate)(struct _tgLogger* logger);

/*************************************************************************************
作    者: ouyongjiu
函数功能:删除时间最早的文件。约束条件:1.日志目录下的文件个数大于允许生成的日志数。
输入参数:
logger  日志结构体
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void(*_delFileRecursive)(struct _tgLogger*);
}Logger;


PUBLIC  //提供外部使用的函数

void logv(Logger* logger, int level, const char* file, int line, const char* func, const char* fmt, ...);
void setFileName(Logger* logger, const char* filedir, const char* filename);
void setLogLevel(Logger* logger, int level);
void setRotateInterval(Logger* logger, long rotateInterval);
void setNumOfLog(Logger* logger, int nNum);
void closefile(Logger* logger);


PRIVATE //内部使用
void _maybeRotate(Logger*);
void _delFileRecursive(Logger* logger);
//////////////////////////////////////////////////////////////////////////
/*************************************************************************************
作    者: ouyongjiu
函数功能:初始化日志结构体
输入参数:
logger  日志结构体
level   日志等级
lastRotate  初始化的时间戳
输出参数: 无
返 回 值: 无
备    注:
*************************************************************************************/
void LoggerInit(Logger* logger, int level, long lastRotate);


extern Logger gLogger;//定义一个全局的日志类
Logger gLogger;

#define hlog(level, ...) \
    do { \
        if (level<=gLogger.level_) { \
            gLogger.logv(&gLogger,level, __FILE__, __LINE__, __func__, __VA_ARGS__); \
                        } \
            } while(0)

#define trace(...) hlog(LTRACE, __VA_ARGS__)
#define info(...) hlog(LINFO, __VA_ARGS__)
#define debug(...) hlog(LDEBUG, __VA_ARGS__)
#define warn(...) hlog(LWARN, __VA_ARGS__)
#define error(...) hlog(LERROR, __VA_ARGS__)
#define fatal(...) hlog(LFATAL, __VA_ARGS__)
#define fatalif(b, ...) do { if((b)) { hlog(LFATAL, __VA_ARGS__); } } while (0)
#define check(b, ...) do { if((b)) { hlog(LFATAL, __VA_ARGS__); } } while (0)
#define exitif(b, ...) do { if ((b)) { hlog(LERROR, __VA_ARGS__); _exit(1); }} while(0)

#define Logger_setloglevel(l) gLogger.setLogLevel(&gLogger,l)

#endif

logger.c文件

#include "logger.h"
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <time.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <syslog.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <syslog.h>
#include <stdio.h>
#include <dirent.h>
#define MIN(x,y) (((x)<(y))?(x) : (y))
void LoggerInit(Logger* logger, int level, long lastRotate)
{
    logger->logv = logv;
    logger->setFileName = setFileName;
    logger->setLogLevel = setLogLevel;
    logger->closefile = closefile;

    logger->_maybeRotate = _maybeRotate;
    logger->setRotateInterval = setRotateInterval;
    logger->setNumOfLog = setNumOfLog;
    logger->_delFileRecursive= _delFileRecursive;


    memset(logger->levelStrs_, 0, sizeof(logger->levelStrs_));
    strcpy(logger->levelStrs_[0], "FATAL");
    strcpy(logger->levelStrs_[1], "ERROR");
    strcpy(logger->levelStrs_[2], "UERR");
    strcpy(logger->levelStrs_[3], "WARN");
    strcpy(logger->levelStrs_[4], "INFO");
    strcpy(logger->levelStrs_[5], "DEBUG");
    strcpy(logger->levelStrs_[6], "TRACE");
    strcpy(logger->levelStrs_[8], "ALL");

    memset(logger->fileFullname_, 0, sizeof(logger->fileFullname_));
    memset(logger->filedir_, 0, sizeof(logger->filedir_));
    memset(logger->filename_, 0, sizeof(logger->filename_));

    logger->rotateInterval_ = 60 * 60 * 24;
    logger->nNumofLog_ = 24;
    logger->fd_ = -1;
    logger->level_ = level;
    logger->realRotate_ = logger->lastRotate_ = lastRotate;
}
void closefile(Logger* logger)
{
    if (logger->fd_ != -1) {
        close(logger->fd_);
    }
}
void logv(Logger* logger, int level, const char* file, int line, const char* func, const char* fmt, ...)
{
    if (level > logger->level_) {
        return;
    }
    logger->_maybeRotate(logger);
    char buffer[4 * 1024];
    char* p = buffer;
    char* limit = buffer + sizeof(buffer);

    struct timeval now_tv;
    gettimeofday(&now_tv, NULL);
    const time_t seconds = now_tv.tv_sec;
    struct tm t;
    localtime_r(&seconds, &t);
    p += snprintf(p, limit - p,
        "%04d/%02d/%02d-%02d:%02d:%02d.%06d %s:",
        t.tm_year + 1900,
        t.tm_mon + 1,
        t.tm_mday,
        t.tm_hour,
        t.tm_min,
        t.tm_sec,
        (int)(now_tv.tv_usec),
        logger->levelStrs_[level]);
    va_list args;
    va_start(args, fmt);
    p += vsnprintf(p, limit - p, fmt, args);
    va_end(args);
    p = MIN(p, limit - 2);
    //trim the ending \n
    while (*--p == '\n') {
    }
    *++p = '\n';
    *++p = '\0';
    int fd = logger->fd_ == -1 ? 1 : logger->fd_;
    int err = write(fd, buffer, p - buffer);
    if (err != p - buffer) {
        printf("write log file %s failed. written %d errmsg: %s\n",logger->fileFullname_);
    }
    if (level <= LERROR) {
        syslog(LOG_ERR, "%s", buffer + 27);
    }
    if (level == LFATAL) {
        printf("%s", buffer);
        assert(0);
    }
}

void setFileName(Logger* logger, const char* filedir, const char* filename)
{
    char file[100];
    memset(file, 0, 100);
    strcat(file, filedir);
    strcat(file, filename);
    int fd = open(file, O_APPEND | O_CREAT | O_WRONLY | O_CLOEXEC, DEFFILEMODE);
    if (fd < 0) {
        printf("open log file %s failed. msg: %s ignored\n");
        return;
    }
    strcpy(logger->filedir_, filedir);  
    strcpy(logger->filename_, filename);
    strcpy(logger->fileFullname_, file);

    if (logger->fd_ == -1) {
        logger->fd_ = fd;
    }
    else {
        int r = dup2(fd, logger->fd_);
        printf("dup2 failed");
        close(fd);
    }
}

void setLogLevel(Logger* logger, int level)
{   
    if (level<LALL+1)
    {
        logger->level_ = level;
    }
    else
    {
        logger->level_ = LINFO;
    }       
}



void _maybeRotate(Logger* logger)
{
    time_t now = time(NULL);
    if (strlen(logger->fileFullname_)==0 || (now - timezone) / logger->rotateInterval_ == (logger->lastRotate_ - timezone) / logger->rotateInterval_) {
        return;
    }
    logger->lastRotate_ = now;

    long old = logger->realRotate_;
    logger->realRotate_ = now;

    //如果realRotate的值是新的,那么返回,否则,获得了旧值,进行rotate
    if ((old - timezone) / logger->rotateInterval_ == (logger->lastRotate_ - timezone) / logger->rotateInterval_) {
        return;
    }
    struct tm ntm;
    localtime_r(&now, &ntm);
    char newname[4096];
    snprintf(newname, sizeof(newname), "%s.%d%02d%02d%02d%02d",
        logger->fileFullname_, ntm.tm_year + 1900, ntm.tm_mon + 1, ntm.tm_mday,
        ntm.tm_hour, ntm.tm_min);
    const char* oldname = logger->fileFullname_;    
    int err = rename(oldname, newname);
    if (err != 0) {
        printf("rename logfile %s -> %s failed \n", oldname, newname);
        return;
    }
    printf("rename logfile %s -> %s \n", oldname, newname);
    int fd = open(logger->fileFullname_, O_APPEND | O_CREAT | O_WRONLY | O_CLOEXEC, DEFFILEMODE);
    if (fd < 0) {
        printf("open log file %s failed. msg: %s ignored\n");
        return;
    }
    dup2(fd, logger->fd_);
    close(fd);
    _delFileRecursive(logger);
}


void setRotateInterval(Logger* logger, long rotateInterval)
{
    logger->rotateInterval_ = rotateInterval;
}
void setNumOfLog(Logger* logger, int nNum)
{
    logger->nNumofLog_ = nNum;
}

int  _runShell(char* cmd, char* result, int resultsize,int n)
{
    FILE *fstream = NULL; char buff[1024] = { 0 }; int cntc = 0; int irtimes = 0;
    if (strlen(cmd) == 0 || NULL==result || n <0){ return 0; }
    if (NULL == (fstream = popen(cmd, "r"))){ return -1; }
    while (NULL != fgets(buff, sizeof(buff), fstream)){
        cntc += strlen(buff);
        irtimes++;
        if (cntc > resultsize ){ break; }
        if (irtimes > n){ break; }
        strcat(result, buff);

    }
    pclose(fstream);

}

void _delFileRecursive(Logger* logger)
{
    int cameraCount = 0;
    FILE *fstream = NULL;
    char buff[1024] = {0};
    char cmdls[100] = {0};
    char cmdsort[100] = { 0 };
    char cmdDel[100] = {0};
    char delFilename[100] = { 0 };
    char cmdCntFileNum[100] = { 0 };
    char result[1024 * 1024] = { 0 };
    char cntresult[10] = { 0 };
    int cnt = 0; int fileNum = 0; char*token;

    sprintf(cmdCntFileNum, "ls %s -l |grep \"^-\"|wc -l", logger->filedir_);
    _runShell(cmdCntFileNum, cntresult, sizeof(cntresult),1);
    result[strlen(cntresult) - 1] = 0;
    fileNum = atoi(cntresult);
    if (fileNum > logger->nNumofLog_)
    {
        sprintf(cmdls, "ls %s > list.txt", logger->filedir_);
        system(cmdls);
        sprintf(cmdsort, "%s", "sort -u list.txt");
        _runShell(cmdsort, result, sizeof(result),2);
        token = strtok(result, "\n");
        if (strcmp(token, logger->filename_) == 0)
        {
            token = strtok(NULL, "\n");
        }
        strcpy(delFilename, token);
        sprintf(cmdDel, "rm -f %s/%s", logger->filedir_, delFilename);
        system(cmdDel);     
        trace("del %s/%s\n", logger->filedir_, delFilename);
        printf("del %s/%s\n", logger->filedir_, delFilename);
    }       
}

猜你喜欢

转载自blog.csdn.net/Oyj1020/article/details/76222450