跨平台,线程安全,超轻量的日志库

//as_log.h
//No make, only one file, copy and use!
//enjoy it!

#ifndef _AS_LOG_H_
#define _AS_LOG_H_
#include <cstdlib>
#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <errno.h>

using namespace std;


//日志级别,默认支持  错误,信息,调试 三类
const unsigned char AS_LOG_ERR = 0;
const unsigned char AS_LOG_INFO = 1;
const unsigned char AS_LOG_DBG = 2;

//锁, 在线程环境下需要派生一个具体的锁, as_log_init日志初始化的时候传锁对象指针参数
class Lockable
{
public:
       virtual ~Lockable(){}
       virtual void Lock()=0;
       virtual void UnLock()=0;
};

//自动锁, 代码更方便简洁
class LockGuard
{
public:
       LockGuard(Lockable *p){m_lock = p; if(m_lock){m_lock->Lock();}}
       ~LockGuard(){if(m_lock){m_lock->UnLock();}}
private:
        Lockable *m_lock;
};

//日志类
class as_log
{
public:
    as_log()
    {
            m_log_level = AS_LOG_DBG;
            m_fplog = stdout;
            m_day = 0;
            m_lock = 0;
    }
    ~as_log()
    {
      LockGuard g(m_lock);
      if(m_fplog){fclose(m_fplog); m_fplog = 0;}
    }

    //初始化:日志保存路径,支持<=level的日志级别,目录分隔符,锁对象指针
    int init(const char *path, unsigned char level, char sep = '/', Lockable *lock=0)
    {
        m_lock = lock;
        LockGuard g(m_lock);
        m_log_level =level;
        if(path){m_log_path = path;}
        if(m_log_path.empty())
        {
                m_log_path = ".";
                m_log_path.push_back(sep);
        }
        if(m_log_path[m_log_path.size()-1] != sep)
        {
                m_log_path.push_back(sep);
        }
        m_fplog = 0;
        return open();
    }
    //写日志:级别, 格式,参数
    int log(unsigned int level, const char *fmt,...)
    {
        if(level > m_log_level){return 0;}
        const char *level_str_err = "ERR";
        const char *level_str_dbg = "DBG";
        const char *level_str_info = "INF";
        const char *level_str = "LOG";
        switch(level)
        {
        case AS_LOG_ERR:
                level_str = level_str_err;
                break;
        case AS_LOG_DBG:
                level_str = level_str_dbg;
                break;
        case AS_LOG_INFO:
                level_str = level_str_info;
                break;
        }
        struct tm t;
        time_t n = time(NULL);
        t = *localtime(&n);
        //localtime_r(&n, &t);

        LockGuard g(m_lock);
        if(t.tm_mday != m_day)
        {
                open();
        }
        fprintf(m_fplog, "[%s:%04d%02d%02d %02d%02d%02d] ", level_str,
                1900+t.tm_year, 1+t.tm_mon, t.tm_mday, t.tm_hour,t.tm_min, t.tm_sec);
        va_list ap;
        va_start(ap, fmt);
        vfprintf(m_fplog, fmt, ap);
        va_end(ap);
        return 0;
    }

   //立即将数据所写入磁盘
    void flush()
    {
        LockGuard g(m_lock);
        if(m_fplog){fflush(m_fplog);}
    }
private:
        //打开日志文件
        int open()
        {
        LockGuard g(m_lock);
        if(m_fplog == stdout){return 0;}
        if(m_fplog)
        {
                fclose(m_fplog);
                m_fplog = 0;
        }
        struct tm t;
        time_t n = time(NULL);
        t = *localtime(&n);
        //localtime_r(&n, &t);
        char file[1024];
        sprintf(file, "%s%04d%02d%02d.log", m_log_path.c_str(), 1900+t.tm_year, 1+t.tm_mon, t.tm_mday);
        m_fplog = fopen(file, "a");
        if(!m_fplog)
        {
                fprintf(stderr,"open log:%s failed. errno=%d\n", file,errno);
                m_fplog = stdout;
                return -1;
        }
        else
        {
        }
        m_day = t.tm_mday;
        return 0;
    }

    Lockable *m_lock;   //锁对象指针
    string m_log_path;  //日志保存路径
    unsigned char m_log_level;  //日志级别
    FILE *m_fplog;       //日志文件
    int m_day;            //当前时间的天,用于检查是否要换文件了。 一天写一个文件。
};


//单例模板
template <class T>
class Singleton
{
public:
static inline T& instance()
{
static T _instance;
return _instance;
}

private:
Singleton(void);
~Singleton(void);
Singleton(const Singleton<T>&);
Singleton<T>& operator= (const Singleton<T> &);
};

typedef Singleton<as_log> LogSingleton;   //日志单体

inline void as_log_flush(){LogSingleton::instance().flush();}  //不解释
//unix,linux 环境下的初始化
inline int as_log_init_unx(const char *path,int level,Lockable *lock=0){ return LogSingleton::instance().init(path,level,'/',lock);}
//windows环境下的初始化
inline int as_log_init_win32(const char *path,int level,Lockable *lock=0){ return LogSingleton::instance().init(path,level,'\\',lock);}

//如果编译器比较规范,应该可以自动识别环境
#ifdef WIN32
inline int as_log_init(const char *path,int level,Lockable *lock=0){ return as_log_init_win32(path,level,lock);}
#else
inline int as_log_init(const char *path,int level,Lockable *lock=0){ return as_log_init_unx(path,level,lock);}
#endif

//写错误日志
#define as_log_err(fmt,args...) LogSingleton::instance().log(AS_LOG_ERR,fmt,##args)
//写信息日志
#define as_log_info(fmt,args...) LogSingleton::instance().log(AS_LOG_INFO,fmt,##args)
//写调试日志
#define as_log_dbg(fmt,args...) LogSingleton::instance().log(AS_LOG_DBG,fmt,##args)

#endif



//test.cpp  测试用例
#include "as_log.h"
int main(int argc, char *argv[])
{
    as_log_init(".",AS_LOG_DBG);
    as_log_dbg("test dbg\n");
    as_log_flush();
    return EXIT_SUCCESS;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值