//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;
}
跨平台,线程安全,超轻量的日志库
最新推荐文章于 2024-06-16 20:26:12 发布