1、BaseLog类。
.h
class BaseLog
{
public:
BaseLog(const char* _pfile_name);
virtual ~BaseLog();
//写入日志
void write_log(const string& str_log);
void flush();
void change_path(const std::string& _str_path);
void change_log_file(const string& filename);
protected:
void init_trace_file();
const char* get_fullexepath(std::string& _str_path) const;
bool create_tracedir(const char* _pdir, const char* _pparent) const;
string get_log_name(bool cur_flag = false);
private:
BaseLog& operator = (const BaseLog& _other);
BaseLog(const BaseLog& _other);
protected:
ofstream m_of_file;
string m_file_path;
string m_filename;
string rename_filename;
int32_t m_line_count;
int32_t m_file_count;
int32_t day_;
bool wait_flush_;
};
.cpp
////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <time.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "base_os.h"
#include "gettimeofday.h"
#include "base_log_thread.h"
#include "base_log.h"
#include "date_time.h"
#include "base_timer_value.h"
#define _MAX_LOGLINE 250000
#define MAX_PATH 1024
const char* title_str[] = {
"[fatal]",
"[error]",
"[warning]",
"[info]",
"[debug]"
};
const char* get_time_str(char *date_str)
{
struct tm tm_now;
struct timeval tv;
gettimeofday(&tv, NULL);
time_t now = tv.tv_sec;
#ifdef WIN32
::localtime_s(&tm_now, &now);
#else
::localtime_r(&now, &tm_now);
#endif
sprintf(date_str, "%04d-%02d-%02d %02d:%02d:%02d.%3ld", tm_now.tm_year + 1900, tm_now.tm_mon + 1, tm_now.tm_mday,
tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv.tv_usec /1000);
return date_str;
}
BaseLog::BaseLog(const char *_pfile_name) :m_line_count(0), m_file_count(0), wait_flush_(false)
{
string str_exepath;
#ifdef WIN32
create_tracedir("\\log", get_fullexepath(str_exepath));
#else
create_tracedir("/log", get_fullexepath(str_exepath));
#endif
char buffer[MAX_PATH]= {0};
#ifdef WIN32
char *path = _getcwd(buffer, MAX_PATH);
#else
char* path = getcwd(buffer, MAX_PATH);
#endif
m_filename = _pfile_name;
m_file_path = buffer;
#ifdef WIN32
m_file_path += "\\log\\";
#else
m_file_path += "/log/";
#endif
rename_filename = "";
day_ = DateTime::GetNow().GetDay();
init_trace_file();
}
BaseLog::~BaseLog()
{
if (m_of_file.is_open())
{
m_of_file.flush();
m_of_file.close();
}
}
string BaseLog::get_log_name(bool cur_flag)
{
string final_file_name = m_filename;
if(!cur_flag)
{
final_file_name += "-";
char date[20] = {0};
sprintf(date, "%d-%d", DateTime::GetNow().GetMonth() + 1, DateTime::GetNow().GetDay());
final_file_name += date;
}
final_file_name +=".log";
return final_file_name;
}
void BaseLog::write_log(const string& str_log)
{
if (m_of_file.is_open())
{
m_line_count ++;
if (m_line_count > _MAX_LOGLINE || day_ != DateTime::GetNow().GetDay()) //过了晚上12点,换文件
{
this->flush();
init_trace_file();
day_ = DateTime::GetNow().GetDay();
}
char info[64] = {0};
m_of_file << get_time_str(info);
m_of_file << str_log;
wait_flush_ = true;
}
}
void BaseLog::flush()
{
if(m_of_file.is_open() && wait_flush_)
{
m_of_file.flush();
wait_flush_ = false;
}
}
void BaseLog::init_trace_file()
{
char newFile[1024] = {0};
string rename_path = m_file_path + get_log_name();
sprintf(newFile, "%s.%d", rename_path.data(), m_file_count++);
if (m_of_file.is_open())
{
m_of_file.close();
}
string str_logfile_path = m_file_path + get_log_name(true);
if(m_line_count > _MAX_LOGLINE || day_ != DateTime::GetNow().GetDay()) //文件满,清空文件
{
rename(str_logfile_path.data(), rename_filename.c_str());
m_of_file.open(str_logfile_path.c_str(), std::ios_base::trunc|std::ios_base::out);
}
else //刚开始,直接追加到后面
{
m_of_file.open(str_logfile_path.c_str(), std::ios_base::app|std::ios_base::out);
}
rename_filename = newFile;
m_line_count = 0;
}
const char* BaseLog::get_fullexepath(string& _str_path) const
{
char buffer[MAX_PATH]= {0};
#ifdef WIN32
char *path = _getcwd(buffer, MAX_PATH);
#else
char* path = getcwd(buffer, MAX_PATH);
#endif
_str_path = path;
return _str_path.c_str();
}
bool BaseLog::create_tracedir(const char* _pdir, const char* _pparent) const
{
if (_pparent == NULL || strlen(_pparent) == 0)
return false;
string str_dir = _pparent;
str_dir += _pdir;
#ifdef WIN32
_mkdir(str_dir.c_str());
#else
mkdir(str_dir.c_str(), S_IRWXU);
#endif
return true;
}
void BaseLog::change_path(const std::string& _str_path)
{
if (m_of_file.is_open())
m_of_file.close();
m_file_path = _str_path;
#ifdef WIN32
m_file_path += "\\";
#else
m_file_path += "/";
#endif
init_trace_file();
}
void BaseLog::change_log_file(const string& filename)
{
if (m_of_file.is_open())
m_of_file.close();
m_filename = filename;
init_trace_file();
}
3、成员函数解析。
3.1、const char* get_time_str(char* date_str);
获取当前的时间 ,获取的时间格式:。
3.2、const char* get_fullexepath(string& _str_path);
获取当前exe所在目录。
3.3、bool create_tracedir(const char* _pdir,const char* _pprent) const;
在当前父目录下在新创建一个名为_pdir的文件夹。
3.4、string get_log_name(bool cur_flag);
返回日志文件的带后缀的日志文件的名族。依据cur_flag的值,来决定是否加时间标志。
3.5、构造函数。
<1>、在当前exe文件所在目录下,新建一个名为log的日志文件夹;
<2>、初始化各个成员变量。
<3>、打开日志追踪文件。并记录下下次需要切换文件时,被切换的文件需要改的名字。待下次切换文件时,首先将被切换的文件改成之前一次切换文件时记录下的需要改的名字,再根据条件决定是否切换文件。
2、BaseLogManager日志管理索引类。
.h
//日志管理和索引
typedef vector<BaseLog*> BaseLogVector;
class BaseLogManager
{
public:
BaseLogManager();
~BaseLogManager();
int32_t create_base_log(const char* _pfile_name);
BaseLog* get_log_handler(int32_t log_index);
void flush();
private:
BaseLogVector m_log_vector;
uint64_t flush_ts_;
};
.cpp
BaseLogManager::BaseLogManager()
{
flush_ts_ = CBaseTimeValue::get_time_value().msec();
}
BaseLogManager::~BaseLogManager()
{
//释放文件
for(size_t i = 0; i < m_log_vector.size(); ++ i)
{
delete m_log_vector[i];
}
}
int32_t BaseLogManager::create_base_log(const char *pfile_name)
{
int32_t index = -1;
BaseLog *file_log = new BaseLog(pfile_name);
index = m_log_vector.size();
m_log_vector.push_back(file_log);
return index;
}
BaseLog* BaseLogManager::get_log_handler(int32_t index)
{
if(index < 0 || index > m_log_vector.size())
return NULL;
else
return m_log_vector[index];
}
void BaseLogManager::flush()
{
uint64_t cur_ts = CBaseTimeValue::get_time_value().msec();
if(cur_ts > flush_ts_ + 200)
{
for(int32_t i = 0; i < m_log_vector.size(); ++i)
m_log_vector[i]->flush();
flush_ts_ = cur_ts;
}
}
3、基础日志流接口类。
.h
//日志流
class BaseLogStreamInterface
{
public:
enum TRACE_LEVEL
{
fatal = 0,
error = 1,
warning = 2,
general = 3,
debug = 4,
};
public:
BaseLogStreamInterface(){}
virtual ~BaseLogStreamInterface(){}
virtual std::ostream& dump_trace(int32_t _level) = 0;
virtual std::ostream& get_ostream() = 0;
virtual void put_log(int32_t level) = 0;
bool is_enable_trace(int32_t level) const { return (level <= m_level); }
void set_trace_level(int32_t level) { m_level = level; }
protected:
int32_t m_level;
public:
BaseThreadMutex mutex_;
};
.cpp
4、BaseLogStream基础日志流与SingleLogStream单日志流。
.h
class BaseLogStream : public BaseLogStreamInterface
{
public:
BaseLogStream(const char* pfile_name, int32_t level);
~BaseLogStream();
public:
std::ostream& dump_trace(int32_t _level);
std::ostream& get_ostream();
void put_log(int32_t level);
//这个模式下不能改变路径
void change_path(const std::string& path){}
private:
int32_t m_log_index;
std::string m_strFileName;
ostringstream m_strm;
};
class SingleLogStream : public BaseLogStreamInterface,
public BaseLog
{
public:
SingleLogStream(const char* pfile_name, int32_t level);
~SingleLogStream();
public:
std::ostream& dump_trace(int32_t _level);
std::ostream& get_ostream();
void put_log(int32_t level);
};
.cpp
BaseLogStream::BaseLogStream(const char* pfile_name, int32_t level)
{
m_level = level;
m_log_index = LOG_INSTANCE()->create_base_log(pfile_name);
m_strFileName = pfile_name;
}
BaseLogStream::~BaseLogStream()
{
}
ostream& BaseLogStream::dump_trace(int32_t _level)
{
if(_level > 0 && _level < 5)
{
m_strm << title_str[_level] << "\t";
}
return m_strm;
}
std::ostream& BaseLogStream::get_ostream()
{
return m_strm;
}
void BaseLogStream::put_log(int32_t level)
{
//写入LOG线程
LogInfoData* data = LOGPOOL.pop_obj();
if(data != NULL)
{
data->index = m_log_index;
data->level = level;
data->str_log = m_strm.str();
LOG_THREAD_INSTANCE()->put_log(data);
m_strm.str("");
}
}
/////////////////////////////////////////////////////////////////////////////////////////
SingleLogStream::SingleLogStream(const char* pfile_name, int32_t level) : BaseLog(pfile_name)
{
m_level = level;
}
SingleLogStream::~SingleLogStream()
{
}
std::ostream& SingleLogStream::dump_trace(int32_t _level)
{
if(_level > 0 && _level < 5)
{
write_log(title_str[_level]);
m_of_file << "\t";
}
return m_of_file;
}
std::ostream& SingleLogStream::get_ostream()
{
return m_of_file;
}
void SingleLogStream::put_log(int32_t level)
{
flush();
}
//to do