`

log

 
阅读更多
log.h
#ifndef __LOG_H__
#define __LOG_H__
#include <stdio.h>
#include <pthread.h>

namespace log
{

#define LOG_MAX_LENGTH 4096
#define FLUSH_LINE 2

#define EMERG 8   //
#define ALERT 7   //
#define CRIT  6   //
#define WARNING 5 //
#define ERR   4   //错误
#define NOTICE 3  //注意信息
#define INFO  2   //普通信息
#define DEBUG 1   //调试信息
#define NONE  0   //

static const char g_alertStr[128] = "[Alert]:" ;//比warning级别要高,表示系统可能处于异常运行状态,如连接数据库失败,无法正常向数据库进行操作等
static const char g_errorStr[128] = "[Error]:" ;//可以确定是程序上bug,需开发人员检查程序逻辑
static const char g_warningStr[128] = "[Warning]:" ;//虽不是服务器端错误,但需要高度关注
static const char g_infoStr[128] = "[Info]:" ;//一些有用信息,它比普通信息要略高,但可能没有Warning那么严重
static const char g_messageStr[128] = "[Message]:" ;//普通信息
static const char g_sqlStr[128] = "[Sql]:";//数据库操作语句

#ifndef TIME_CHN_FMT
#define TIME_CHN_FMT "%Y-%m-%d %H:%M:%S"
#endif

/*
    time_t转时间字符串
*/
char* timeToString(time_t tmTime, const char *fmt,char *strTime, int len);

class CLog
{
public:
    //the singleton
    static CLog* getInstance();

    //初始化
    int init(const char* path,const char* fileName, short level=DEBUG,unsigned int logFileMaxNum=50,unsigned int logFileMaxSize=10*1024*1024);

    //关闭
    int close();

    //写日志
    void plog(short level, const char *fmt, ...);
private:
    CLog();

    virtual ~CLog();

    //检测文件大小是否超过上限
    bool fileSizeOverflow(const char *fileName);

    //创建新文件
    void createNewFile();
private:
    FILE *mFile;

    //日志文件路径
    char mFilePath[1024];

    //日志缓冲区
    char mLogBuf[LOG_MAX_LENGTH];

    //lock
    pthread_mutex_t mWriteLogLock;

    //上一条日志重复次数
    int  mRepeatCount;

    //当前日志文件大小
    unsigned int mCurrLogFileSize;

    //日志文件大小上限
    unsigned int mLogFileMaxSize;

    //当前的日志级别
    int mLogLevel;

    //是否已关毕
    bool mClosed;

    //日志的最大文件数
    unsigned int mLogFileMaxNum;

    //日志的当前文件数
    unsigned int mLogFileCurrNum;
};

}//end of namespace log

#endif



log.cpp
#include "log.h"
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <string.h>

using std::cout;
using std::endl;

namespace log
{

/*
    时间转字符串
*/
char* timeToString(time_t tmTime, const char *fmt,char *strTime, int len)
{
    struct tm gmTime;
    localtime_r(&tmTime, &gmTime);
    strftime(strTime, (size_t) len, fmt, &gmTime);
    return strTime;
}

/*
    the singleton
*/
CLog* CLog::getInstance()
{
    static CLog log;
    return &log;
}

CLog::CLog()
{
    mFile = NULL;
    mRepeatCount = 0;
    mCurrLogFileSize = 0;
    mLogFileMaxSize = 0;
    mLogFileMaxNum = 0;
    memset(mLogBuf, 0, sizeof(mLogBuf));
    mClosed = false;
    mLogFileCurrNum = 0;
}

CLog::~CLog()
{
    close();
}

/*
    关闭
*/
int CLog::close()
{
    if(mClosed){
        return -1;
    }
    if (mFile)
    {
        fflush(mFile);
        fclose(mFile);
    }

    pthread_mutex_destroy(&mWriteLogLock);
    mClosed = true;
    return 0;
}

/*
    初始化
*/
int CLog::init(const char *path, const char *fileName, short level, unsigned int logFileMaxNum, unsigned int logFileMaxSize)
{
    if (path == NULL || fileName == NULL || logFileMaxNum<1 || level < NONE || logFileMaxSize<1){
        return -1;
    }

    if(pthread_mutex_init(&mWriteLogLock, NULL)!=0)
    {
        pthread_mutex_destroy(&mWriteLogLock);
        return -1;
    }

    mLogFileMaxNum = logFileMaxNum;
    mLogFileMaxSize = logFileMaxSize;

    if(access(path,F_OK)<0)
    {
#ifdef _WIN32
        mkdir(path);
#else
        mkdir(path,0777);
#endif
    }

    char fileFullName[256];
    memset(fileFullName,0,sizeof(fileFullName));
    strcpy(fileFullName,path);
    strcat(fileFullName,fileName);

    memset(mFilePath, 0, sizeof(mFilePath));
    strncpy(mFilePath, fileFullName, sizeof(mFilePath)-1);

    //备份老日志,创建新日志。
    if(fileSizeOverflow(fileFullName)){
        createNewFile();
    }

    mFile = fopen(fileFullName, "a+");
    if (mFile == NULL){
        return -1;
    }

    mLogLevel = level;
    fprintf(mFile, "\n\n\n\n\n");
    fprintf(mFile, "--------------------------------------------------------\n");
    fprintf(mFile, "                   日志建立日期: %s %s\n", __DATE__, __TIME__);
    fprintf(mFile, "--------------------------------------------------------\n");
    fprintf(mFile, "\n");
    fflush(mFile);
    return 0;
}

/*
    写日志
*/
void CLog::plog(short level, const char *fmt, ...)
{
    //与配置文件中的日志级别对比,选择输出日志
    if (0 == mLogLevel || level < mLogLevel){
        return;
    }
    if (NULL == mFile)
    {
        mFile = fopen(mFilePath, "a+");
        if (NULL == mFile){
            return;
        }
        mCurrLogFileSize = 0;
    }
    pthread_mutex_lock(&mWriteLogLock);
    static int lastBufLen = 0;
    static char lastBuf[LOG_MAX_LENGTH];
    static int flushCount = 0;

    time_t t = time(NULL);
    char timeStr[64];
    memset(timeStr,0,sizeof(timeStr));
    timeToString(t, TIME_CHN_FMT, timeStr, sizeof(timeStr)-1);

    char printf_buf[LOG_MAX_LENGTH];
    memset(printf_buf,0,sizeof(printf_buf));
    va_list args;
    va_start(args, fmt);
    vsprintf(printf_buf, fmt, args);
    va_end(args);

    int len = strlen(printf_buf) + 1;
    if (len == lastBufLen)
    {
        if (strcmp(lastBuf, printf_buf) == 0)
        {
            ++mRepeatCount;
            pthread_mutex_unlock(&mWriteLogLock);
            return;
        }
    }
    else
    {
        if (mRepeatCount > 0){
            mCurrLogFileSize += fprintf(mFile, "[%s]: 上一条日志重复%u次。\n", timeStr, mRepeatCount);
        }

        lastBufLen = len;
        mRepeatCount = 0;
        memcpy(lastBuf, printf_buf, len);
    }

    mCurrLogFileSize += fprintf(mFile, "[%s] ", timeStr);
    mCurrLogFileSize += fprintf(mFile, "%s", printf_buf);

    if (INFO < level)
    {
        fflush(mFile);
    }else if (++flushCount >= FLUSH_LINE)
    {
        flushCount = 0;
        fflush(mFile);
    }

    if (mCurrLogFileSize > mLogFileMaxSize)
    {
        createNewFile();
        mFile = fopen(mFilePath, "a+");
        if (mFile)
        {
            mCurrLogFileSize = 0;
            timeToString(t, TIME_CHN_FMT, timeStr, sizeof(timeStr)-1);
            mCurrLogFileSize += fprintf(mFile, "[%s]: ", timeStr);
            mCurrLogFileSize += fprintf(mFile, "%s", printf_buf);
        }
    }
    //如果是调试模式,则会将日志输出在终端上
    if(mLogLevel==DEBUG){
        cout << printf_buf << endl;
    }
    pthread_mutex_unlock(&mWriteLogLock);
}

/*
    重命名旧文件,创建新文件
*/
void CLog::createNewFile()
{
    char newFullName[1024];
    memset(newFullName,0,sizeof(newFullName));

    //如果是第一次则先遍历一次
    if(mLogFileCurrNum==0)
    {
        for(unsigned int i=1;i<=mLogFileMaxNum;i++)
        {
            snprintf(newFullName,sizeof(newFullName), "%s.%02d", mFilePath, i);
            //不存在,则创建
             if((access(newFullName,F_OK))<0)
             {
                 mLogFileCurrNum = i;
                 break;
             }
            //如果文件存在,则继续找,如果找到最后也存在则删除第一个
            if(i==mLogFileMaxNum)
            {
                snprintf(newFullName,sizeof(newFullName), "%s.%02d", mFilePath, 1);
                unlink(newFullName);
                mLogFileCurrNum = 1;
            }
        }
    }else
    {
        mLogFileCurrNum++;
        if(mLogFileCurrNum>mLogFileMaxNum){
            mLogFileCurrNum = 1;
        }
        snprintf(newFullName,sizeof(newFullName), "%s.%02d", mFilePath, mLogFileCurrNum);
        //已存在,则删除
         if((access(newFullName,F_OK))>=0){
             unlink(newFullName);
         }
         fclose(mFile);
         mFile = NULL;
    }

    if (0 != rename(mFilePath, newFullName)){
        return;
    }

    int ret = creat(mFilePath, 0664);
    ::close(ret);
}

/*
    检测文件大小是否超过上限
*/
bool CLog::fileSizeOverflow(const char *fileName)
{
    if (NULL == fileName){
        return false;
    }
    char path[1024];
    memset(path,0,sizeof(path));
    strncpy(path, fileName, sizeof(path)-1);
    path[sizeof(path)-1] = '\0';

    FILE *fp = fopen(path, "r");
    if (fp == NULL){
        return false;
    }
    int ret = fseek(fp, 0, SEEK_END);
    if (0 != ret)
    {
        fclose(fp);
        return false;
    }
    mCurrLogFileSize = ftell(fp);
    if (mCurrLogFileSize < mLogFileMaxSize)
    {
        fclose(fp);
        return false;
    }
    mCurrLogFileSize = 0;
    fclose(fp);
    return true;
}

}//end of namespace log




main
#include "log.h"
#include <unistd.h>
using namespace log;

int main()
{
    CLog::getInstance()->init("/usr/local/code/MyLog_debug/","test.log"/*,1,10,1024*1024*/);
    int i = 0;
    while(true)
    {
        i++;
        CLog::getInstance()->plog(NOTICE,"%s h:%d\n",g_messageStr,i);
        usleep(1000);
    }
}

分享到:
评论

相关推荐

    log4cplus 源码(C++编写的开源的日志系统)

    log4cplus是C++编写的开源的日志系统,功能非常全面,用到自己开发的工程中会比较专业的,:),本文介绍了log4cplus基本概念,以及如何安装,配置。 ### 简介 ### log4cplus是C++编写的开源的日志系统,前身是java...

    老生常谈Log4j和Log4j2的区别(推荐)

    Log4j和Log4j2的区别 Log4j和Log4j2是两个常用的日志记录工具,它们都来自Apache开源项目。虽然它们都是日志记录工具,但是它们之间有很多区别。下面我们将从配置文件类型、核心JAR包、文件渲染和Log调用四个方面来...

    若依框架使用的log4j2.16.0,修复log4j漏洞log4j2下载最新log4j2.16.0下载

    Log4j是一个广泛使用的Java日志记录框架,它允许开发者在应用程序中轻松地记录各种级别的日志信息,如DEBUG、INFO、WARN、ERROR等。在2021年底,一个重大的安全漏洞(CVE-2021-44228)被发现在Log4j2的早期版本中,...

    C# log4net自动删除多少天前的log文件

    5. 关键配置来了:`&lt;param name="DatePattern" value="'.'yyyy-MM-dd'.txt'" /&gt;`,这将使日志文件名为`log.yyyy-MM-dd.txt`的形式,便于识别和清理。 6. 最后,添加`...

    log4cplus日志封装log

    **log4cplus日志封装log** 在软件开发过程中,日志记录是一项至关重要的任务,它可以帮助开发者追踪程序运行状态,定位错误,以及进行性能分析。`log4cplus`是一个专门为C++设计的开源日志系统,它提供了一种高效、...

    Log4j2学习用到的jar包及apache-log4j-2.19.0-bin.zip

    分别有disruptor-3.3.4.jar(Log4j2异步日志的底层实现)、log4j-api-2.19.0.jar(log4j门面)、log4j-core-2.19.0.jar(log4j实现)、log4j-slf4j-impl-2.19.0.jar(SLF4J与Log4j绑定)、slf4j-api-1.7.30.jar(SLF...

    log4cxx封装为通用LOG宏

    Log4cxx是Apache软件基金会的一个开源项目,它是C++版的log4j,提供了一套强大的日志处理机制。本文将详细讨论如何将log4cxx封装为通用LOG宏,以及其配置文件的详细内容。 首先,让我们了解log4cxx的基本概念。Log4...

    Log-Log4perl-1.36.tar.gz

    Log4perl是Perl编程语言中一个强大的日志记录框架,其设计灵感来源于Java的Log4j库。在Perl社区中,Log4perl被广泛应用于各种项目,为开发者提供了灵活、可扩展的日志处理机制。"Log-Log4perl-1.36.tar.gz"这个...

    Log4net详细说明使用

    `LogFileAppender`将日志信息写入名为`log-file.txt`的文件,`ConsoleAppender`则将日志输出到控制台。日志格式由`PatternLayout`定义,可以自定义显示内容。`LevelRangeFilter`用于过滤日志级别,只允许`DEBUG`至`...

    logging-log4j2-log4j-2.15.0-rc2.zip maven 资源库

    针对Log4j 2 远程代码执行漏洞,需要用到的升级资源包,适用于maven资源库,包括log4j,log4j-core,log4j-api,log4j-1.2-api,log4j-jpa等全套2.15.0 maven资源库jar包。如果是maven本地仓库使用,需要将zip包解压...

    Log4j2简介及与Log4j效率对比

    ### Log4j2简介 Log4j2是Apache软件基金会推出的日志框架,它是Log4j 1.x的重构版本,旨在提供更为高效且灵活的日志解决方案。与Log4j 1.x相比,Log4j2在设计上进行了重大改进,并解决了Logback等其他日志框架中...

    Log4j2、Fastjson、Log4j的BurpSuite插件亲测有效

    Log4j、Log4j2和Fastjson是Java开发中常用的三个库,它们在软件开发中扮演着重要的角色。Log4j是Apache的一个开源项目,主要用于日志记录,提供了灵活的日志配置,允许开发者根据需求调整日志输出的级别和格式。Log4...

    Log4Cpp使用实例

    自己编译好的log4cpp的DLL 和 LIB 封装了一个使用类,从本地读取配置log级别等信息,可输出多个种类的日志文件,输出示例如下 [2017-02-20 16:09:51.910](NOTICE)Sys : 进入了CPfy_log4cppDlg::OnBnClickedButton1...

    log4j-core-2.15.0.jar log4j-2.15.0-rc2

    Apache log4j2零日漏洞,根据 log4j-2.15.0-rc2 版本编译生成log4j-api-2.15.0.jar 1.解压你的jar jar xvf XXX.jar 2. 删除旧版本jar cd ./BOOT-INF/lib rm -rf log4j-api-*.jar 3. 上传新版本log4j-api-2.15.0....

    log4j-2.18.0

    《log4j-2.18.0:修复重大安全漏洞的紧急更新》 在IT领域,安全性始终是首要关注的问题。近期,一个名为“log4j2”的严重安全漏洞引发了广泛关注,它影响了所有log4j2版本,从2.0开始直到2.18.0版本之前。这个漏洞...

    log4j-api-2.12.4.ja和log4j-core-2.12.4.jar

    Log4j是Java编程语言中最常用的日志记录框架之一,由Apache软件基金会开发。它提供了灵活的日志记录功能,使得开发者能够轻松地控制日志信息的输出格式、输出位置以及输出级别。此次提及的`log4j-api-2.12.4.jar`和`...

    log4z的使用

    `log4z`提供了丰富的日志级别,包括`LOG_TRACE`、`LOG_DEBUG`、`LOG_INFO`、`LOG_WARNING`、`LOG_ERROR`和`LOG_FATAL`。根据项目需求,可以选择性地开启或关闭不同级别的日志。 ```cpp #include "log4z.h" void ...

    log4j-api-2.15.0.jar log4j-2.15.0-rc2

    Apache log4j2零日漏洞,根据 log4j-2.15.0-rc2 版本编译生成log4j-api-2.15.0.jar 1.解压你的jar jar xvf XXX.jar 2. 删除旧版本jar cd ./BOOT-INF/lib rm -rf log4j-api-*.jar 3. 上传新版本log4j-api-...

    maven+springmvc+mybatis+log4j框架搭建

    本教程将详细阐述如何使用四个关键组件——Maven、SpringMVC、MyBatis和Log4j——来搭建一个强大的Web应用框架,旨在提高开发效率并优化项目管理。 **Maven** 是一个流行的项目管理和综合工具,它通过统一的构建...

    SpringBoot框架配置log4j和log4j2的配置代码

    Log4j和Log4j2是两种广泛使用的Java日志框架,它们提供了灵活的日志配置和高性能的日志处理能力。本文将详细介绍如何在SpringBoot项目中配置Log4j和Log4j2。 ### SpringBoot与Log4j Log4j是Apache的一个开源项目,...

Global site tag (gtag.js) - Google Analytics