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

原文链接:http://www.cnblogs.com/aquester/archive/2012/07/24/9891776.html

/**
 * 单个头文件,可即时独立使用,只要定义了宏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 <sys/config.h>
#endif // NOT_WITH_MOOON

#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <sstream>
#if !defined(NOT_WITH_MOOON)
SYS_NAMESPACE_BEGIN
#endif // NOT_WITH_MOOON

/***
  * 万能型类型转换函数
  */
template <typename AnyType>
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<int>(_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


转载于:https://www.cnblogs.com/aquester/archive/2012/07/24/9891776.html

展开阅读全文
博主设置当前文章不允许评论。

分享一个简单的日志

11-25

比较简单, 主要实现的功能及特点:rn1.通过Queue作为日志缓存,主线程负责轮询它并持久化到文本文件,因此避免了频繁的I/O,性能还不错。rn2.自动清理历史日志文件,目前存储策略按天保存,每个日志缓存作为一个日志文件;rn3.阀值和其他配置由于 时间仓促没有做成配置,另外功能简单,所以无法与Log4Net 等重量级的类相比。rnrn以下是全部代码和使用方法如下:rnrnRainLogger 类:rn[code=csharp]rnusing System;rnusing System.Collections.Generic;rnusing System.Linq;rnusing System.Text;rnrnusing System.IO;rnusing System.Threading;rnusing System.ComponentModel;rnusing System.Globalization;rnrnnamespace RainLoggerrnrn public class RainLoggerrn rn public delegate void WorkCompletedEventHandler(object sender);rn private delegate void WorkerEventHandler();rnrn bool isRun = true;rn string sPath = "";rnrn Dictionary dicLogs = new Dictionary();rnrn public RainLogger()rn rn sPath = AppDomain.CurrentDomain.BaseDirectory + "\\logs";rnrn if (!Directory.Exists(sPath))rn Directory.CreateDirectory(sPath); rn rnrn public void BeginLogger()rn rn //异步开始任务1rn WorkerEventHandler workerDelegate = new WorkerEventHandler(DoWork);rn workerDelegate.BeginInvoke(null, null);rn rnrn private void DoWork()rn rn tryrn rn lock (dicLogs)rn rn foreach (KeyValuePair dic in dicLogs)rn rn if (dic.Value.WLog == null)rn dic.Value.WLog = File.AppendText(sPath + "\\" + dic.Key + "_" + DateTime.Now.ToString("yyyyMMdd") + ".log");rn rn rn rn catch rnrn while (isRun)rn rn Thread.Sleep(1000);rn WriteLog();rnrn if (DateTime.Now.ToString("HHmmss") == "093809")rn rn DeleteHisFiles(sPath);rn rn rnrn rnrn private void WriteLog()rn rn lock (dicLogs)rn rn foreach (KeyValuePair dic in dicLogs)rn rnrn lock (dic.Value.Logs)rn rn tryrn rn var logs = dic.Value.Logs;rn if (logs.Count > 0)rn rn if (dic.Value.WLog == null)rn dic.Value.WLog = File.AppendText(sPath + "\\" + dic.Key + "_" + DateTime.Now.ToString("yyyyMMdd") + ".log");rnrn for (int i = 0; i < logs.Count; i++)rn rn var v = logs.Dequeue();rn dic.Value.WLog.WriteLine(v.LogDate.ToString("yyyy-MM-dd HH:mm:ss:ffffff") + ": " + v.LogType.ToString().PadRight(10) + ": " + v.LogContent);rn rnrn if (DateTime.Now.Second % 10 == 0)rn dic.Value.WLog.Flush();rn rn rn if (DateTime.Now.ToString("HHmmss") == "235959" && dic.Value.WLog != null)rn rn dic.Value.WLog.Flush();rn dic.Value.WLog.Close();rn dic.Value.WLog.Dispose();rn dic.Value.WLog = null;rn rn rn catch rn rnrn rn rn rnrn public void Stop()rn rn isRun = false;rn WriteLog();rn lock (dicLogs)rn rn foreach (KeyValuePair dic in dicLogs)rn rn if (dic.Value.WLog != null)rn rn dic.Value.WLog.Flush();rn dic.Value.WLog.Close();rn dic.Value.WLog.Dispose();rn dic.Value.WLog = null;rn rn rn rn rn rnrn public void AddContainer(string sContainerName, LogBuffer logContainer)rn rn lock (dicLogs)rn rn tryrn rn dicLogs.Add(sContainerName, logContainer);rn rn catch rn rn rnrn public void ClearContainer()rn rn lock (dicLogs)rn rn tryrn rn dicLogs.Clear();rn rn catch rn rn rnrn public void DeleteHisFiles(string dir)rn rn if (Directory.Exists(dir))rn rn foreach (string file in Directory.GetFiles(dir))rn rn tryrn rn int start = file.LastIndexOf("_") + 1;rn int end = file.LastIndexOf(".");rn if (end != -1)rn rn // 截取文件名,end - start为截取的长度rn String strName = file.Substring(start, end - start);rn DateTime logTime = DateTime.ParseExact(strName, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None);rn DateTime currentTime = DateTime.Parse(DateTime.Now.ToString());rn System.TimeSpan ts = currentTime - logTime;rn int days = ts.Days;rnrn // 删除10天之外的日志文件rn if (days > 10 && File.Exists(file))rn rn File.Delete(file);rn rn rn rn catch rn rnrn rn rnrn rn rnrnrn[/code]rnrnLogBuffer 类: (日志缓存类)rn[code=csharp]rnusing System;rnusing System.Collections.Generic;rnusing System.Linq;rnusing System.Text;rnrnusing System.Collections;rnusing System.IO;rnrnnamespace RainLoggerrnrn public enum LogTypesrn rn Normal = 0,rn Info = 1,rn Warning = 2,rn Error =3,rn rnrn public class LogInforn rn public DateTime LogDate get; set;rn public LogTypes LogType get; set; rn public string LogContent get; set;rn rnrn public class LogBufferrn rn public Queue Logs = new Queue(1024);rn public StreamWriter WLog;rnrn public void Log(LogTypes logTp, string logContent)rn rn LogInfo loginfo = new LogInfo();rn loginfo.LogDate = DateTime.Now;rn loginfo.LogType = logTp;rn loginfo.LogContent = logContent;rnrn lock (Logs)rn rn tryrn rn Logs.Enqueue(loginfo);rn rn catch rn rn rn rnrn[/code]rnrn使用:rnrn1.主线程实例化 RainLogger类, RainLogger 负责定期读取缓存,并持久化等操作:rnrnRainLogger.RainLogger rl = new RainLogger.RainLogger(); // 实例化rnrl.AddContainer("FileSystemEventLog", fa.lc); // 注册缓存类, fa.lc: Fa是你自己的类,lc是类中申明的LogBuffer对象rnrl.BeginLogger(); // 核心以异步方式运行rnrn2.日志记录rn在需要使用日志的类中实例化 LogBuffer 类:rnrnClass Farn...rnpublic LogBuffer lc = new LogBuffer(); // 实例化缓存rnlc.Log(LogTypes.Info, "日志内容"); // 记录日志rn...rnrnrn欢迎使用、提出建议!谢谢 论坛

没有更多推荐了,返回首页