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

news2024/11/15 6:51:29

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

日志仅由richlog.h单个文件实现功能,软件集成简单。

支持C++的std::cout的<<风格的日志打印,也支持C的printf风格的日志打印

日志多线程安全,采用C++11 mutex 互斥锁

日志格式如下:

[日志级别][时间戳][模块名][组件名][日志所在文件名][日志所在行号][日志所在函数名]->日志内容

日志格式、输出方式可配置,以下为配置函数

//日志输出到文件开关,默认关闭
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代码

#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

测试例子

#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;
}

运行结果:
日志测试结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2039404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Adobe PhotoShop - 制图操作

1. 排布照片 菜单 - 视图 - 对齐&#xff1a;打开后图层将会根据鼠标的移动智能对齐 菜单 - 视图 - 标尺&#xff1a;打开后在页面出现横纵标尺&#xff0c;方便图层的对齐与排列 2. 自动生成全景照 在日常处理中&#xff0c;我们常常想要将几张图片进行拼接获得一张全景图&…

Linux:文件管理,目录管理,文件系统,链接类型

1&#xff0c;文件管理 用户&#xff08;标识号&#xff1a;UID&#xff09;&#xff1a;一定资源的使用者&#xff0c;可以创建和管理文件以及访问其他用户文件。可以从属于多个群组。 用户组&#xff08;标识号&#xff1a;GID&#xff09;&#xff1a;由一定数量的对某些文件…

GlobalMapper软件安装流程

目录 一、环境准备 二、安装步骤 三、软件激活 一、环境准备 系统&#xff1a;win7操作系统 安装包下载&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1Vb4VVRFBRYawt3MT-5gYOw 提取码&#xff1a;sxdj 二、安装步骤 1、解压&#xff0c;右键global-mapper-23_1-x…

NVDLA专题5:具体模块介绍——Convolution Buffer

概述 卷积缓冲器(CBUF)是卷积流水线中的一个阶段&#xff0c;module定义在NV_NVDLA_cbuf.v&#xff0c;module信息如下&#xff1a; module NV_NVDLA_cbuf (nvdla_core_clk //|< i,nvdla_core_rstn //|< i,cdma2buf_dat_wr_addr //|< i,cdma2buf_dat_wr_…

轻松提升效率:10款工时管理软件推荐

本文将介绍以下10款工具&#xff1a;PingCode、Worktile、百宝云、华为云项目管理、Yonyou NC、云效、红圈通、Asana、7pace Timetracker、Toggl Track。 管理项目工时时&#xff0c;面对繁杂的数据和紧迫的截止日期&#xff0c;很多人都会感到压力倍增。选择一款合适的项目工时…

各大App又要出年度报告啦,看看往年的,谁家能够打动你。

还有几个月就到年终了&#xff0c;各大app都要出年度报告或者年度账单了&#xff0c;咱们先看看往年的效果&#xff0c;你觉得那家好呢&#xff1f;

阿一网络安全实践演练之查找并利用未使用的 API 端点

描述 为了解决实验室问题&#xff0c;利用一个隐藏的 API 端点购买一件 Lightweight l33t 皮夹克。您可以使用以下凭据登录您自己的账户&#xff1a;wiener:peter。 所需知识 要解决这个实验室问题&#xff0c;您需要了解以下内容&#xff1a; 如何利用错误消息构造有效的请…

凡图公益新篇章:凡图家庭教育携手舜和社区,共绘心理健康蓝图

在这个充满挑战与机遇并存的时代&#xff0c;心理健康作为衡量社会文明与进步的重要标尺&#xff0c;正日益受到社会各界的广泛关注。 正是基于这份对美好生活的共同向往与追求&#xff0c;凡图(山东)教育科技集团有限公司与济南市中区舜和社区正式签署了心理援助协议&#xf…

Linux操作系统安装

Linux操作系统安装 Linux操作系统简介VMware 虚拟机简述安装 VMware 虚拟机创建新的虚拟机 安装 Linux 操作系统&#xff08;以 CentOS 为例&#xff09;远程工具连接 Linux查看Linux的ip链接Linux操作步骤 Linux操作系统简介 Linux内核kernel最初是由芬兰人李纳斯托瓦兹&#…

基于计算机爱心小屋公益机构智慧管理(源码+论文+部署讲解等)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台的优…

Alignment

一、前置 1、我们的目的是&#xff1a;给一串声学特征&#xff0c;得出tokens的概率。 2、LAS要计算P(Y|X)&#xff0c;可以直接计算 3、training&#xff0c;就是要找到得到概率结果最大的network的参数 4、CTC、RNN-T要计算P(X|Y)依赖于要知道alignment&#xff08;下图以CT…

模型意识对比学习:摆脱训练中的一致性-容忍度困境

论文出处: ICML2023 Model-Aware Contrastive Learning: Towards Escaping Uniformity-Tolerance Dilemma in Training 什么是uniformity-tolerance困境? 温度参数 τ 的设置会影响模型性能 如果 τ 太小,模型会对训练不足的阶段施加过大的惩罚,导致难以区分潜在阳性样本,…

浙大数据结构慕课课后题(06-图3 六度空间)

题目要求&#xff1a; 输入格式: 输入第1行给出两个正整数&#xff0c;分别表示社交网络图的结点数N&#xff08;1<N≤103&#xff0c;表示人数&#xff09;、边数M&#xff08;≤33N&#xff0c;表示社交关系数&#xff09;。随后的M行对应M条边&#xff0c;每行给出一对正…

简单案例:搞定 SpringBoot 接口恶意刷新和暴力请求

​ 博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 前言 恶意刷新和暴力请求是指攻击者通过大量重复发送请求来对服务器进行攻击的行为。这些请求可能包括频繁刷新页面、提交表单、尝试登录等&#xff0c;旨在消耗服务器资源、导致服务不可用或破坏正常用户的…

WSL 忘记ubuntu的密码

文章目录 1. 以管理员身份打开 PowerShel2.输入命令 wsl.exe -d Ubuntu-20.04 --user root3.输入命令 passwd username 修改用户密码&#xff0c;username即待重置的用户的名称 1. 以管理员身份打开 PowerShel 2.输入命令 wsl.exe -d Ubuntu-20.04 --user root 注意版本号是自…

机械行业数字化生产供应链产品解决方案(一)

在机械行业数字化生产供应链产品解决方案中&#xff0c;通过全面融合物联网技术、数据分析、自动化控制系统和智能供应链管理平台&#xff0c;企业能够实现生产过程的实时监控、智能优化和高效管理&#xff0c;从而显著提升生产效率、降低运营成本&#xff0c;并增强供应链的响…

自动化基础知识

丝杆滑台 滚珠丝干设计时&#xff0c;尽量直线导轨比滚珠丝杆高一点点&#xff0c;安装时在滚珠丝杆处垫调整硅钢片。

猫头虎 分享已解决Bug || ImportError: No module named ‘django‘ 解决方案

猫头虎 分享已解决Bug || ImportError: No module named django 解决方案 摘要 &#x1f31f; 大家好&#xff01;我是你们的技术小伙伴 猫头虎&#xff0c;在日常开发中我们经常会遇到各种后端Bug&#xff0c;今天我将和大家分享一个非常常见但有时会让人头疼的Bug&#xff…

记一次:Datawhale AI夏令营-第四期-魔搭-AIGC-Task02

前言&#xff1a;上一篇我们按步骤跑了一遍Baseline也生成了8张故事图片&#xff0c;但是原理啥的都是一头雾水&#xff0c;因为是初学者&#xff0c;所以只能一点点的分析来理解消化。这篇咱们就深入的来了解一下相关的内容。根据内容自己总结理解和查询相关的一些资料。不正确…

Java基础之隐式类型转换

类型转换 基本数据类型表示范围大小排序&#xff1a; 在变量赋值及算术运算的过程中&#xff0c;经常会用到数据类型转换&#xff0c;其分为两类&#xff1a; 隐式类型转换 显式类型转换 1 隐式类型转换 情形1&#xff1a;赋值过程中&#xff0c;小数据类型值或变量可以直…