基于C11的简单log,支持C++的'<<'风格和C的'可变参数'风格
日志仅由richlog.h单个文件实现功能,软件集成简单。
支持C++的std::cout的<<风格的日志打印,也支持C的printf风格的日志打印
日志多线程安全,采用C++11 mutex 互斥锁
日志格式如下:
shell
[日志级别][时间戳][模块名][组件名][日志所在文件名][日志所在行号][日志所在函数名]->日志内容
日志格式、输出方式可配置,以下为配置函数
C++
//日志输出到文件开关,默认关闭
static void set_output_to_file(bool to_file)
//日志输出到终端开关,默认打开
static void set_output_to_console(bool to_console)
//日志打印时间戳开关,默认打开
static void set_print_timestamp(bool log_timestamp)
//设置日志打印模块名,默认为空
static void set_modulename(std::string name)
//设置日志打印组件名,默认为空
static void set_componentname(std::string name)
//日志级别开关,默认打开
static void set_print_log_level(bool log_level)
//日志所在文件名开关,默认打开
static void set_print_filename(bool log_level)
//日志所在行号开关,默认打开
static void set_print_linenum(bool plinenum)
//日志所在函数名,默认打开
static void set_print_funcname(bool pfuncname)
//设置日志输出的文件名,默认为空
static void set_output_to_filename(std::string filename)
richlog.h代码
c++
#ifndef _RICHLOGS_H
#define _RICHLOGS_H
#include <cstring>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
#include <thread>
#include <mutex>
#define CXXLOG_FILENAME(x) (strrchr((x),'/')?strrchr((x),'/')+1:(x))
#define C11LOG_ERROR CPP_LOG::RichLogs(CPP_LOG::ERROR,CXXLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__)
#define C11LOG_WARN CPP_LOG::RichLogs(CPP_LOG::WARN,CXXLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__)
#define C11LOG_INFO CPP_LOG::RichLogs(CPP_LOG::INFO,CXXLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__)
#define C11LOG_DEBUG CPP_LOG::RichLogs(CPP_LOG::DEBUG,CXXLOG_FILENAME(__FILE__),__LINE__,__FUNCTION__)
namespace CPP_LOG
{
enum LOG_LEVEL{ERROR,WARN,INFO,DEBUG};
class RichLogs
{
public:
RichLogs(LOG_LEVEL log_level,std::string filename,unsigned int line_num,std::string func_name)
{
m_has_endl=false;
if(m_print_log_level)
{
switch(log_level)
{
case ERROR:
m_log_data<<"[ERROR]";
break;
case WARN:
m_log_data<<"[ WARN]";
break;
case INFO:
m_log_data<<"[ INFO]";
break;
case DEBUG:
m_log_data<<"[DEBUG]";
break;
}
}
if(m_print_timestamp)
{
m_log_data<<"["<<getNowTime().count()<<"]";
}
if(m_module_name!="")
{
m_log_data<<"["<<m_module_name<<"]";
}
if(m_component_name!="")
{
m_log_data<<"["<<m_component_name<<"]";
}
if(m_print_filename)
{
m_log_data<<"["<<filename<<"]";
}
if(m_print_linenum)
{
m_log_data<<"["<<line_num<<"]";
}
if(m_print_funcname)
{
m_log_data<<"["<<func_name<<"]";
}
m_log_data<<"->";
}
~RichLogs()
{
if(!m_has_endl)
{
m_log_data<<std::endl;
}
if(m_output_to_file)
{
if(m_output_to_filename!="")
{
std::ofstream outputFile;
outputFile.open(m_output_to_filename,std::ios::app);
if (outputFile.is_open())
{
std::lock_guard<std::mutex> lock(m_log_mutex);
outputFile<<m_log_data.str();
outputFile.flush();
}
outputFile.close();
}
}
if(m_output_to_console)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
std::cout<<m_log_data.str();
}
}
RichLogs& operator<<(std::ostream&(*p)(std::ostream&))
{
m_has_endl=true;
m_log_data<<std::endl;
return *this;
}
template<typename T>
RichLogs& operator<<(const T& logdata)
{
m_has_endl=false;
m_log_data<<logdata;
return *this;
}
// 泛型
template <typename... Args>
RichLogs& operator()(const char *pformat, Args... args)
{
int total_len = std::snprintf(nullptr, 0, pformat, args...);
if (0 >= total_len)
{
return *this;
}
total_len++;
char *log_str_out = nullptr;
log_str_out = new(std::nothrow) char[total_len];
if (NULL == log_str_out || nullptr == log_str_out)
{
return *this;
}
std::snprintf(log_str_out, total_len, pformat, args...);
if(log_str_out[total_len-2]=='\n')
{
m_has_endl=true;
}
else
{
m_has_endl=false;
}
std::string str(log_str_out);
delete log_str_out;
log_str_out = nullptr;
m_log_data<<str;
return *this;
}
static void set_output_to_file(bool to_file)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_output_to_file=to_file;
}
static void set_output_to_console(bool to_console)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_output_to_console=to_console;
}
static void set_print_timestamp(bool log_timestamp)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_print_timestamp=log_timestamp;
}
static void set_modulename(std::string name)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_module_name=name;
}
static void set_componentname(std::string name)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_component_name=name;
}
static void set_print_log_level(bool log_level)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_print_log_level=log_level;
}
static void set_print_filename(bool log_level)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_print_log_level=log_level;
}
static void set_print_linenum(bool plinenum)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_print_linenum=plinenum;
}
static void set_print_funcname(bool pfuncname)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_print_funcname=pfuncname;
}
static void set_output_to_filename(std::string filename)
{
std::lock_guard<std::mutex> lock(m_log_mutex);
m_output_to_filename=filename;
}
private:
bool m_has_endl;
std::stringstream m_log_data;
static std::mutex m_log_mutex;
static bool m_output_to_file;
static bool m_output_to_console;
static bool m_print_log_level;
static bool m_print_timestamp;
static std::string m_module_name;
static std::string m_component_name;
static bool m_print_filename;
static bool m_print_linenum;
static bool m_print_funcname;
static std::string m_output_to_filename;
std::chrono::milliseconds getNowTime()
{
std::chrono::system_clock::time_point now_time = std::chrono::system_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(now_time.time_since_epoch());
}
};
std::mutex RichLogs::m_log_mutex;
bool RichLogs::m_output_to_file=false;
bool RichLogs::m_output_to_console=true;
bool RichLogs::m_print_log_level=true;
bool RichLogs::m_print_timestamp=true;
std::string RichLogs::m_module_name="";
std::string RichLogs::m_component_name="";
bool RichLogs::m_print_filename=true;
bool RichLogs::m_print_linenum=true;
bool RichLogs::m_print_funcname=true;
std::string RichLogs::m_output_to_filename="";
}
#endif //C11LOG_C11LOG_H
测试例子
C++
#include <iostream>
#include "richlog.h"
using namespace std;
int main()
{
CPP_LOG::RichLogs::set_modulename("test123");
CPP_LOG::RichLogs::set_componentname("sdfghjk");
CPP_LOG::RichLogs::set_output_to_file(true);
CPP_LOG::RichLogs::set_output_to_filename("test4444.log");
for(int i=0;i<100;i++)
{
C11LOG_INFO<<"123456 "<<" sdfsdfgfdgjghjsegwdsfbrsntbrsb"<<"54332gfdsbrrbfdxbw4353vsw";
C11LOG_DEBUG<<"123456 "<<1234<<" "<<345.6<<" sdsafdsv ewtertyui"<<'c'<<'l';
C11LOG_WARN<<"123456 "<<1234<<" "<<345.6<<" sdsafdsv ewtertyui"<<'c'<<'l';
C11LOG_ERROR<<"123456 "<<1234<<" "<<345.6<<" sdsafdsv ewtertyui"<<'c'<<'l';
C11LOG_INFO("%d-%f-%s-%c\n",1234,345.234,"kkkkkkk",'e');
C11LOG_DEBUG("%d-%f-%s-%c\n",1234,345.234,"kkkkkkk",'e');
C11LOG_WARN("%d-%f-%s-%c",1234,345.234,"kkkkkkk",'e');
C11LOG_ERROR("%d-%f-%s-%c",1234,345.234,"kkkkkkk",'e');
}
return 0;
}
运行结果: