基于C11的简单log,支持C++的‘<<’风格和C的‘可变参数’风格

基于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;
}

运行结果:

相关推荐
青青丘比特18 分钟前
STL.string(下)
开发语言·c++
jjjxxxhhh12326 分钟前
C++ 模板是为了解决啥问题
开发语言·c++·算法
c++初学者ABC31 分钟前
GESP2级2403 小杨的日字矩阵
c++·算法
代码小将1 小时前
PTA数据结构编程题7-1最大子列和问题
数据结构·c++·笔记·学习·算法
HackKong1 小时前
高校网络安全_网络安全之道
java·网络·c++·python·学习·web安全·黑客技术
BUG制造机.1 小时前
修炼之道 ---其四
linux·c++
神经网络的应用2 小时前
C++程序设计例题——第三章程序控制结构
c++·学习·算法
zfenggo3 小时前
c/c++ 无法跳转定义
c语言·开发语言·c++
图灵猿3 小时前
【Lua之·Lua与C/C++交互·Lua CAPI访问栈操作】
c语言·c++·lua
A懿轩A3 小时前
C/C++ 数据结构与算法【树和二叉树】 树和二叉树,二叉树先中后序遍历详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·二叉树·