Logger.h
#pragma once
#include <fstream>
#include <iostream>
#include <string>
namespace yazi{
namespace utility{
#define debug(format,...)\
Logger::getInstance()->log(Logger::DEBUG,__FILE__,__LINE__,format,##__VA_ARGS__);
#define info(format,...)\
Logger::getInstance()->log(Logger::INFO,__FILE__,__LINE__,format,##__VA_ARGS__);
#define warn(format,...)\
Logger::getInstance()->log(Logger::WARN,__FILE__,__LINE__,format,##__VA_ARGS__);
#define error(format,...)\
Logger::getInstance()->log(Logger::ERROR,__FILE__,__LINE__,format,##__VA_ARGS__);
#define fatal(format,...)\
Logger::getInstance()->log(Logger::FATAL,__FILE__,__LINE__,format,##__VA_ARGS__);
class Logger
{
public:
enum Level
{
DEBUG = 0,
INFO,
WARN,
ERROR,
FATAL,
LEVET_COUNT
};
void log(Level level,const char* file,int line,const char* format,...);
static Logger* getInstance();
void open(const std::string& filename);
void close();
void level(Level level);
void max(int bytes);
private:
Logger();
~Logger();
void rotate();
private:
std::string _fileName;
std::ofstream _out;
Level m_level;
int _max;
int _len;
static const char* _level[LEVET_COUNT];
static Logger* _instance;
};
}
}
Logger.cc
#include "Logger.h"
#include <time.h>
#include <string.h>
#include <stdexcept>
#include <stdarg.h>
using namespace yazi::utility;
const char* Logger::_level[LEVET_COUNT] = {"DEBUG","INFO","WARN","ERROR","FATAL"};
Logger* Logger::_instance = nullptr;
Logger::Logger():_max(0),_len(0),m_level(DEBUG)
{
}
void Logger::level(Level level)
{
m_level = level;
}
Logger* Logger::getInstance()
{
if(!_instance)
{
_instance = new Logger();
}
return _instance;
}
void Logger::open(const std::string& filename)
{
_out.open(filename,std::ios::app);
if(_out.fail())
{
throw std::logic_error("open file failed" + filename);
}
_fileName = filename;
_out.seekp(0,std::ios::end);
_len = _out.tellp();
}
void Logger::close()
{
_out.close();
}
void Logger::max(int bytes)
{
_max = bytes;
}
void Logger::log(Level level,const char* file,int line,const char* format,...)
{
if(m_level > level)
{
return;
}
if(_out.fail())
{
throw std::logic_error("open file failed" + _fileName);
}
time_t ticks = time(nullptr);
struct tm* ptn = localtime(&ticks);
char timestamp[32];
memset(timestamp,0,sizeof(timestamp));
strftime(timestamp,sizeof(timestamp),"[%Y-%m-%d %H:%M:%S]",ptn);
const char* fmt = "%s %s %s:%d ";
int size = snprintf(nullptr,0,fmt,timestamp,_level[level],file,line);
if(size > 0)
{
char* buffer = new char[size + 1];
snprintf(buffer,size + 1,fmt,timestamp,_level[level],file,line);
buffer[size] = 0;
_out << buffer;
_len += size;
delete buffer;
}
_out.flush();
va_list arg_ptr;
va_start(arg_ptr,format);
size = vsnprintf(nullptr,0,format,arg_ptr);
va_end(arg_ptr);
if(size > 0)
{
char* content = new char[size + 1];
va_start(arg_ptr,format);
vsnprintf(content,size + 1,format,arg_ptr);
va_end(arg_ptr);
_out << content;
_len += size;
delete content;
}
_out << "\n";
_out.flush();
if(_len >= _max && _max > 0)
{
rotate();
}
// std::cout << timestamp << std::endl;
}
void Logger::rotate()
{
close();
time_t ticks = time(nullptr);
struct tm* ptn = localtime(&ticks);
char timestamp[32];
memset(timestamp,0,sizeof(timestamp));
strftime(timestamp,sizeof(timestamp),".%Y-%m-%d_%H-%M-%S",ptn);
std::string filename = _fileName + timestamp;
if(rename(_fileName.c_str(),filename.c_str()) != 0)
{
throw std::logic_error("rename log file failed");
}
open(_fileName);
}
Logger::~Logger()
{
close();
}
main.cc
#include "utility/Logger.h"
using namespace yazi::utility;
int main()
{
Logger::getInstance()->open("./test.log");
// Logger::getInstance()->log(Logger::DEBUG,__FILE__,__LINE__,"hello %s world %d","LT",18);
Logger::getInstance()->max(200);
debug("hello world");
debug("name is %s,age is %d","jake",18);
info("info message");
warn("warn message");
error("error message");
fatal("fatal message");
return 0;
}