`

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...

    Log4net详细说明使用

    1、概述 log4net是.Net下一个非常优秀的开源日志记录组件。log4net记录日志的功能非常强大。它可以将日志分不同的等级,以不同的...&lt;param name="File" value="C:/log-file.txt" /&gt;就写入C盘根目录下log-file.txt文件中

    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包解压...

    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-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-...

    log4j-1.2.9

    设置log4j的根目录,值为 日志等级(DEBUG,INFO,WARN,ERROR,FATAL) , 输出目标名称 log4j.rootLogger=DEBUG,A1 设置输出方式,常用的有: ConsoleAppender 在控制器中输出信息 RollingFileApperder 在文件中输出...

    log4j.jar各个版本

    apache-log4j-1.2.15.jar, apache-log4j-extras-1.0.jar, apache-log4j-extras-1.1.jar, apache-log4j.jar, log4j-1.2-api-2.0.2-javadoc.jar, log4j-1.2-api-2.0.2-sources.jar, log4j-1.2-api-2.0.2.jar, log4j-...

    log_monitor日志监控

    log_file=/data/nginx_logs/access.log log_reg=\[(.*) \+0800\] time_format=%d/%b/%Y:%H:%M:%S retain_seconds=3600 http_port=3344 log_level=INFO log_file: 需要监控的日志的路径 log_reg: 需要匹配的日期...

    apache-log4j-2.17.0 核心jar包

    Log4j 是一个日志记录框架,Log4j 2 是对 Log4j 的升级,提供了重大改进,超越其前身 Log4j 1.x,并提供许多其它现代功能 ,例如对标记的支持、使用查找的属性替换、lambda 表达式与日志记录时无垃圾等。 Apache ...

    Log4j日志包

    log4j.rootLogger=debug,CONSOLE,testfile,A1,MAIL ################### # Console Appender ################### log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Target=...

    C/C++ LOG记录模块

    项目开发中经常需要记录log,上传一个各种场景都可以使用的记录log的DLL 将格式化字符串输出到log文件中,代码会在执行文件的目录,自动创建子目录 log\ 并在其中创建跟执行文件同名的log文件 当记录的log文件超过5...

    log4j-api-2.12.1-API文档-中文版.zip

    赠送jar包:log4j-api-2.12.1.jar; 赠送原API文档:log4j-api-2.12.1-javadoc.jar; 赠送源代码:log4j-api-2.12.1-sources.jar; 赠送Maven依赖信息文件:log4j-api-2.12.1.pom; 包含翻译后的API文档:log4j-api-...

    log4j-api-2.17.1-API文档-中文版.zip

    赠送jar包:log4j-api-2.17.1.jar; 赠送原API文档:log4j-api-2.17.1-javadoc.jar; 赠送源代码:log4j-api-2.17.1-sources.jar; 赠送Maven依赖信息文件:log4j-api-2.17.1.pom; 包含翻译后的API文档:log4j-api-...

    语音增强 logmmse matlab算法

    语音增强 logmmse matlab算法 function logmmse(filename,outfile) %简单来说,这里对噪声谱估计两个步骤 %1、前6帧都当噪声计算,计算出初始噪声功率谱 %2、加上粗略的vad判决更新噪声谱 %后面就是MMSE-LSA也...

    Java Log4j所需Jar包

    Java Log4j 1,2 所需Jar包,一个完整的软件,日志是必不可少的。程序从开发、测试、维护、运行等环节,都需 要向控制台或文件等位置输出大量信息。这些信息的输出,在很多时候是使用 System.out.println()无法完成的。 ...

    log4j中配置日志文件相对路径方法分析

    log4j中配置日志文件相对路径方法分析 方法一、 解决的办法自然是用相对路径代替绝对路径,其实log4j的FileAppender本身就有这样的机制,如:log4j.appender.logfile.File=${WORKDIR}/logs/app.log 其中“${...

    log4j相关jar

    log4j相关支持的jar Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条...

    apache-log4j-extras-1.2.17-API文档-中文版.zip

    赠送jar包:apache-log4j-extras-1.2.17.jar; 赠送原API文档:apache-log4j-extras-1.2.17-javadoc.jar; 赠送Maven依赖信息文件:apache-log4j-extras-1.2.17.pom; 包含翻译后的API文档:apache-log4j-extras-...

    深入学习log4j

    Log4J的组件 Log4j有三个主要的组件,分别是loggers,appenders和layouts.这三种类型的部件工作在一起就能允许开发者根据记录信息的类型和级别来记录日志信息,并且在系统运行时能够按照不同的格式将这三类信息存储在...

Global site tag (gtag.js) - Google Analytics