来自mooon的最简单的日志类CSimpleLogger

/**

 * 单个头文件,可即时独立使用,只要定义了宏NOT_WITH_MOOON,即不依赖于mooon

 * 简单的写日志类,非线程安全,提供按大小滚动功能

 * 不追求功能,也不追求性能,只求简单,若要功能强、性能高,可以使用CLogger

 *

 * 使用方法:

 * 1) 构造一个CSimpleLogger对象

 *    CSimpleLogger logger(".", "test.log", 1024*1024, 10);

 * 2) 调用print方法写日志

 *    logger.print("%s\n", "test");

 */

#ifndef MOOON_SYS_SIMPLE_LOGGER_H

#define MOOON_SYS_SIMPLE_LOGGER_H

// 只要定义了NOT_WITH_MOOON宏,

// 则本文件和mooon无任何关系,方便集成到自己的代码中

#define NOT_WITH_MOOON

#if !defined(NOT_WITH_MOOON)

#include

#endif // NOT_WITH_MOOON

#include

#include

#include

#include

#if !defined(NOT_WITH_MOOON)

SYS_NAMESPACE_BEGIN

#endif // NOT_WITH_MOOON

/***

  * 万能型类型转换函数

  */

template

inline std::string any2string(AnyType any_value)

{

    std::stringstream result_stream;

    result_stream << any_value;

    return result_stream.str();

}

/***

  * 取当前时间,和date_util.h有重复,但为保持simple_logger.h的独立性,在所难免

  */

inline void get_current_datetime(char* datetime_buffer, size_t datetime_buffer_size)

{

    struct tm result;

    time_t now = time(NULL);

    localtime_r(&now, &result);

    snprintf(datetime_buffer, datetime_buffer_size

        ,"%04d-%02d-%02d %02d:%02d:%02d"

        ,result.tm_year+1900, result.tm_mon+1, result.tm_mday

        ,result.tm_hour, result.tm_min, result.tm_sec);

}

class CSimpleLogger

{

public:

    /***

      * 构造一个CSimpleLogger,并创建或打开日志文件

      * @log_dir 日志存放的目录,不需要以斜杠结尾,目录必须已经存在

      * @filename 日志的文件名,不包含目录部分,

      *           由log_dir和filename共同组成日志文件路径

      * @log_size 每个日志文件的大小,单位为字节数,如果小于1024,则会被强制为1024

      * @log_numer 日志滚动的个数

      * @record_size 单条日志的大小,超过会被截断,单位为字节数,如果小于1024,则会被强制为1024

      */

CSimpleLogger(const std::string& log_dir

                 ,const std::string& filename

                 ,unsigned int log_size = 1024*1024*100

                 ,unsigned char log_numer = 10

                 ,unsigned short record_size = 8192);

    ~CSimpleLogger();

    /** 日志文件是否创建或打开成功 */

    bool is_ok() const;

    /** 输出日志,象printf一样使用,不自动加换行符 */

    void print(const char* format, ...);

 /** 刷新日志,因为使用FILE是带缓存的 */

    void flush();

private:

    void reset();    /** 复位状态值 */

    void roll_log(); /** 滚动日志 */

private:

    FILE* _fp;                    /** 当前正在写的日志文件描述符 */

    char* _log_buffer;            /** 存放日志的Buffer */

    int _bytes_writed;            /** 已经写入的字节数 */

    std::string _log_dir;         /** 日志存放目录 */

    std::string _filename;        /** 日志文件名,不包含目录部分 */

    unsigned int _log_size;       /** 单个日志文件的大小 */

    unsigned char _log_numer;     /** 日志滚动的个数 */

    unsigned short _record_size;  /** 单条日志的大小,单位为字节数 */

};

inline CSimpleLogger::CSimpleLogger(

                     const std::string& log_dir 

                    ,const std::string& filename

                    ,unsigned int log_size

                    ,unsigned char log_numer

                    ,unsigned short record_size)

 :_fp(NULL)

 ,_log_buffer(NULL)

 ,_bytes_writed(0)

 ,_log_dir(log_dir)

 ,_filename(filename)

 ,_log_size(log_size)

 ,_log_numer(log_numer)

 ,_record_size(record_size)

{

    std::string log_path = log_dir + std::string("/") + filename;

    _fp = fopen(log_path.c_str(), "a");

    if (_fp != NULL)

    {

        if (-1 == fseek(_fp, 0, SEEK_END))

        {

            // 失败,将不会写日志

            fclose(_fp);

            _fp = NULL;

        }

        else

        {

            // 取得已有大小

            _bytes_writed = ftell(_fp);

            // 不能太小气了          

            if (_log_size < 1024)

            {

                _log_size = 1024;

            }

            // 同样不能太小气

            if (_record_size < 1024)

            {

                _record_size = 1024;

            }

            _log_buffer = new char[_record_size];

        }

    }

}

inline CSimpleLogger::~CSimpleLogger()

{

    if (_fp != NULL)

        fclose(_fp);

    delete []_log_buffer;

}

inline bool CSimpleLogger::is_ok() const

{

    return _fp != NULL;

}

inline void CSimpleLogger::print(const char* format, ...)

{

    if (_fp != NULL)

    {

        va_list ap;

        va_start(ap, format);

        char datetime_buffer[sizeof("2012-12-21 00:00:00")]; // 刚好世界末日

        get_current_datetime(datetime_buffer, sizeof(datetime_buffer));

        vsnprintf(_log_buffer, _record_size, format, ap);

        int bytes_writed = fprintf(_fp, "[%s]%s", datetime_buffer, _log_buffer);

        if (bytes_writed > 0)

            _bytes_writed += bytes_writed;

        if (_bytes_writed > static_cast(_log_size))

        {

            roll_log();

        }

        va_end(ap);

    }

}

inline void CSimpleLogger::roll_log()

{

    std::string new_path; // 滚动后的文件路径,包含目录和文件名

    std::string old_path; // 滚动前的文件路径,包含目录和文件名

    reset(); // 轮回,一切重新开始

    // 历史滚动

    for (int i=_log_numer-1; i>0; --i)

    {

        new_path = _log_dir + std::string("/") + _filename + std::string(".") + any2string(i);

        old_path = _log_dir + std::string("/") + _filename + std::string(".") + any2string(i-1);

        if (0 == access(old_path.c_str(), F_OK))

        {

            rename(old_path.c_str(), new_path.c_str());

        }

    }

    if (_log_numer > 0)

    {

        // 当前滚动

        new_path = _log_dir + std::string("/") + _filename + std::string(".1");

        old_path = _log_dir + std::string("/") + _filename;

        if (0 == access(old_path.c_str(), F_OK))

        {

            rename(old_path.c_str(), new_path.c_str());

        }

    }

    // 重新创建

    _fp = fopen(old_path.c_str(), "w+");

}

inline void CSimpleLogger::reset()

{

    _bytes_writed = 0;

    if (_fp != NULL)

    {

        fclose(_fp);

        _fp = NULL;

    }

}

inline void CSimpleLogger::flush()

{

    if (_fp != NULL)

        fflush(_fp);

}

/***

  * 测试代码

#include "simple_logger.h"

int main()

{

    CSimpleLogger logger(".", "test.log", 10240);

    for (int i=0; i<100000; ++i)

        logger.print("%d ==> abcdefghijklmnopqrestuvwxyz.\n", i);

    return 0;

}

*/

#if !defined(NOT_WITH_MOOON)

SYS_NAMESPACE_END

#endif // NOT_WITH_MOOON

#endif // MOOON_SYS_SIMPLE_LOGGER_H

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏听雨堂

Mysql高效插入/更新数据

从tushare抓取到的财务数据,最开始只是想存下来,用的办法想简单点,是:插入--报错—update 但发现这个方法太蠢,异常会导致大量无效连接,改为: ...

23450
来自专栏运维

zabbix2.4.5迁移到zabbix3.0

http://qicheng0211.blog.51cto.com/3958621/1744603

26230
来自专栏数据和云

专家出诊:SQL Server 高CPU系列之索引诊断

作者题记:CPU高使用率往往会导致SQL Server服务响应缓慢,查询超时,甚至服务挂起僵死,可以说CPU高使用率是数据库这种后台进程服务的第一大杀手。引发C...

46840
来自专栏Java帮帮-微信公众号-技术文章全总结

Java开发Struts2案例代码

一、struts2综合案例 1、建立一个JavaWeb应用 ? 2、拷贝一下内容到您应用中:美工MM给你准备好的 ? 3、搭建Struts2的开发环境 a、拷贝...

36560
来自专栏Linyb极客之路

MySQL锁

  MySQL的锁机制,就是数据库为了保证数据的一致性而设计的面对并发场景的一种规则。

12610
来自专栏我和PYTHON有个约会

数据库连接引擎那点事儿

天长,地久。天地之所以能长且久者,以其不自生也,故能长生。是以圣人后其身而身先,外其身而身存,非以其无私邪?故能成其私。——老子

9420
来自专栏杨建荣的学习笔记

浅谈exp/imp(下) (r5笔记第84天)

相关链接:浅谈exp/imp(上) (r5笔记第81天) 你可能 不了解的dump文件 在工作中,dump文件对于dba而言是再平常不过的文件了。不过因为dum...

33390
来自专栏王磊的博客

Microsoft SQL Server 2005 提供了一些工具来监控数据库

--WL 09-07-03 /*Microsoft SQL Server 2005 提供了一些工具来监控数据库。方法之一是动态管理视图。动态管理视图 (DMV)...

35750
来自专栏哎_小羊

私信基本功能数据库设计

上一篇写了基于resin4.0+websocket实现私信功能服务端消息推送文章,趁热打铁,在写一篇关于私信功能的数据库设计文章,非代码篇,希望想对第一次做设计...

46870
来自专栏听雨堂

Mysql高效插入/更新数据

从tushare抓取到的财务数据,最开始只是想存下来,用的办法想简单点,是:插入--报错—update 但发现这个方法太蠢,异常会导致大量无效连接,改为: ...

39070

扫码关注云+社区

领取腾讯云代金券