水平太菜,最近捣鼓这个 log,折腾了好一会。由于之前都是用 std::cout,不能满足同时输出到屏与文件的目的,故经过一番搜索,在stackoverflow 找到了答案,现总结如下:

  1. 头文件 logger.hpp, 代码如下:
#ifndef __LOGGER
#define __LOGGER #include <iostream>
#include <fstream>
#include <sstream>
#include <mutex>
#include <ctime> #include <syslog.h> typedef enum
{
EMERG = LOG_EMERG, /* system is unusable */
ALERT = LOG_ALERT, /* action must be taken immediately */
CRIT = LOG_CRIT, /* critical conditions */
ERROR = LOG_ERR, /* error conditions */
WARNING = LOG_WARNING, /* warning conditions */
NOTICE = LOG_NOTICE, /* normal but significant condition */
INFO = LOG_INFO, /* informational */
DEBUG = LOG_DEBUG /* debug-level messages */
} Severity; static std::string severity_str[] = {
[EMERG] = "EMERG", /* system is unusable */
[ALERT] = "ALERT", /* action must be taken immediately */
[CRIT] = "CRIT", /* critical conditions */
[ERROR] = "ERROR", /* error conditions */
[WARNING] = "WARNING", /* warning conditions */
[NOTICE] = "NOTICE,", /* normal but significant condition */
[INFO] = "INFO", /* informational */
[DEBUG] = "DEBUG", /* debug-level messages */
}; class Logger
{
private:
Logger() {} ~Logger() {} /* forbide copy */
Logger &operator=(const Logger &) = delete;
Logger(const Logger &) = delete; private:
static Severity m_log_level; /* only show log that with level
not higher than m_log_level */
static bool m_sync_syslog; /* sync log to syslog ? */
static bool m_sync_stdout; /* sync log to stdout */
static bool m_sync_file; /* sync log to file */
static std::string m_logfile; /* file to save log */
static Severity m_severity;
static std::string m_filename;
static int m_line;
static std::string m_funcname;
std::stringstream ss;
std::mutex m_lk; public:
static Logger &Instance(Severity s = Severity::INFO,
const char *f = "", int l = 0,
const char *fc = "")
{
static Logger instance_; instance_.m_severity = s;
instance_.m_filename = f;
instance_.m_line = l;
instance_.m_funcname = fc;
return instance_;
} static void Init(bool sync_flag, const char *logfile)
{
m_sync_file = sync_flag;
m_logfile = logfile;
} static void Init(bool sync_stdout, bool sync_file, bool sync_syslog)
{
m_sync_file = sync_file;
m_sync_stdout = sync_stdout;
m_sync_syslog = sync_syslog;
} static void Init(const char *label = "LOGGER",
Severity s = Severity::INFO,
bool sync_syslog = false)
{
m_log_level = s;
if (sync_syslog)
{
m_sync_syslog = true;
openlog(label, LOG_CONS | LOG_NDELAY, LOG_USER | LOG_LOCAL1);
}
} Logger &operator<<(const char *t)
{
std::lock_guard<std::mutex> _lk(m_lk);
ss << t;
return *this;
} template <typename T>
Logger &operator<<(const T &t)
{
std::lock_guard<std::mutex> _lk(m_lk);
ss << t;
return *this;
} Logger &operator<<(std::ostream &(*os)(std::ostream &))
{
dump_line();
return *this;
} void dump_line()
{
std::lock_guard<std::mutex> _lk(m_lk);
time_t rawtime;
char now[80]; time(&rawtime);
struct tm *tt = localtime(&rawtime); strftime(now, 80, "%Y-%m-%d %H:%M:%S", tt); std::string obuf = "";
if (!m_filename.empty())
{
obuf += "[" + m_filename + ":" +
std::to_string(m_line) + " " +
m_funcname + "]";
} obuf += "[" + std::string(now) + "][" +
severity_str[static_cast<int>(m_severity)] + "] "; obuf += ss.str(); if (m_log_level >= m_severity)
{
/* syslog */
if (m_sync_syslog)
syslog(LOG_USER | m_severity, "%s", obuf.c_str()); /* stdout/stderr */
if (m_sync_stdout)
std::cerr << obuf << std::endl; if (m_sync_file)
{
std::ofstream fout(m_logfile, std::ios::app);
fout.write(obuf.c_str(), obuf.length());
fout.close();
}
} ss.str("");
m_funcname = "";
m_filename = "";
m_line = 0;
} template <typename T>
void operator()(T t)
{
ss << t;
dump_line();
} template <typename T, typename... Args>
void operator()(const T &t, const Args &... args)
{
ss << t;
(*this)(args...);
}
}; #define ENDL std::endl #ifndef NDEBUG
#define LOG(v) Logger::Instance(v, __FILE__, __LINE__, __func__)
#define LOGI Logger::Instance(Severity::INFO, __FILE__, __LINE__, __func__)
#define LOGV Logger::Instance(Severity::NOTICE, __FILE__, __LINE__, __func__)
#define LOGD Logger::Instance(Severity::DEBUG, __FILE__, __LINE__, __func__)
#define LOGW Logger::Instance(Severity::WARNING, __FILE__, __LINE__, __func__)
#define LOGE Logger::Instance(Severity::ERROR, __FILE__, __LINE__, __func__) #define LOGFI(a, v...) Logger::Instance(Severity::INFO, __FILE__, __LINE__, __func__)(a, ##v)
#define LOGFV(a, v...) Logger::Instance(Severity::NOTICE, __FILE__, __LINE__, __func__)(a, ##v)
#define LOGFD(a, v...) Logger::Instance(Severity::DEBUG, __FILE__, __LINE__, __func__)(a, ##v)
#define LOGFW(a, v...) Logger::Instance(Severity::WARNING, __FILE__, __LINE__, __func__)(a, ##v)
#define LOGFE(a, v...) Logger::Instance(Severity::ERROR, __FILE__, __LINE__, __func__)(a, ##v) #else
#define LOG(v) Logger::Instance(v)
#define LOGI Logger::Instance()
#define LOGV Logger::Instance()
#define LOGD Logger::Instance()
#define LOGW Logger::Instance()
#define LOGE Logger::Instance() #define LOGFI(a, v...) Logger::Instance()(a, ##v)
#define LOGFV(a, v...) Logger::Instance()(a, ##v)
#define LOGFD(a, v...) Logger::Instance()(a, ##v)
#define LOGFW(a, v...) Logger::Instance()(a, ##v)
#define LOGFE(a, v...) Logger::Instance()(a, ##v)
#endif // NDEBUG #define LINE LOGI << __FILE__ << __LINE__ << ENDL
#endif //__LOGGER

cpp 源码文件

#include "logger.h"

Severity Logger::m_log_level = Severity::INFO; /* only show log that with level
not higher than m_log_level */
bool Logger::m_sync_syslog = false; /* sync log to syslog ? */
bool Logger::m_sync_stdout = true; /* sync log to stdout */
bool Logger::m_sync_file = false; /* sync log to file */
std::string Logger::m_logfile;
Severity Logger::m_severity = Severity::INFO;
std::string Logger::m_filename;
int Logger::m_line;
std::string Logger::m_funcname;

头文件提供了5个宏,实现了5种log级别。目前没有加入色彩显示功能。如果定义了 DEBUG_MODE 宏,会有文件,行号等信息。

  1. 使用
#include "logger.h"

using namespace LOGGER;

int main()
{
Logger::Init(Severity::DEBUG, "./log.log");
LOG(Severity::ERROR) << "Severity error" << std::endl;
LOGI << "INFO LOG" << std::endl;
LOGV << "VERBOSE LOG" << std::endl;
LOGD << "DEBUG LOG" << std::endl;
LOGW << "WARNNING LOG" << std::endl;
LOGE << "ERROR LOG" << std::endl; LOGFI ("INFO LOG");
LOGFV ("VERBOSE LOG");
LOGFD ("DEBUG LOG");
LOGFW ("WARNNING LOG");
LOGFE ("ERROR LOG"); return 0;
}

mini logger for c++的更多相关文章

  1. X2E车载数据记录仪

            随着智能驾驶及网联技术深入应用,汽车中传输的数据量与日俱增,包括多种总线数据.视频数据.雷达数据.定位数据等等.据悉,高级别智能驾驶汽车中每秒传输的总线数据就达到G比特级别.而从产品开 ...

  2. Ubuntu下LimeSDR Mini使用说明

    本文内容.开发板及配件仅限用于学校或科研院所开展科研实验! 淘宝店铺名称:开源SDR实验室 LimeSDR链接:https://item.taobao.com/item.htm?spm=a230r.1 ...

  3. 让MacBook识别noppoo mini 84

    让MacBook识别noppoo mini 84 noppoo默认是没有mac驱动的,需要下载一个IOUSBHIDDriverDescriptorOverride否则无法noppoo的键位是识别错误的 ...

  4. ABP源码分析八:Logger集成

    ABP使用Castle日志记录工具,并且可以使用不同的日志类库,比如:Log4Net, NLog, Serilog... 等等.对于所有的日志类库,Castle提供了一个通用的接口来实现,我们可以很方 ...

  5. org.apache.log4j.Logger详解

    org.apache.log4j.Logger 详解 1. 概述 1.1. 背景 在应用程序中添加日志记录总的来说基于三个目的 :监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工 ...

  6. Java程序日志:java.util.logging.Logger类

    一.Logger 的级别 比log4j的级别详细,全部定义在java.util.logging.Level里面.各级别按降序排列如下:SEVERE(最高值)WARNINGINFOCONFIGFINEF ...

  7. 中大东校小米路由器mini实现inode上网,ipv6 wifi【中大】【东校】【inode】【ipv6】

    还有不到4个月就要毕业了,前几天半夜没事捣鼓小米路由没想到竟然实现了wifi的ipv6. 正好又安利了同学一台小米路由mini,从刷机到inode到ipv6全搞了一遍. 这里将教程写出来,服务学弟妹. ...

  8. [LeetCode] Logger Rate Limiter 记录速率限制器

    Design a logger system that receive stream of messages along with its timestamps, each message shoul ...

  9. .Net Core Logger 实现log写入本地文件系统

    .net core 自带一个基础的logger框架Microsoft.Extensions.Logging. 微软默认实现了Microsoft.Extensions.Logging.Console.d ...

随机推荐

  1. Golang并发编程基础

    硬件 内存 作为并发编程一个基础硬件知识储备,首先要说的就是内存了,总的来说在绝大多数情况下把内存的并发增删改查模型搞清楚了其他的基本上也是异曲同工之妙. 内存芯片--即我们所知道的内存颗粒,是一堆M ...

  2. Java算法之根据二叉树不同遍历结果重建二叉树

    二叉树的遍历方式一般包括前序遍历.中序遍历以及后序遍历: 前序遍历:根结点 | 左子树 | 右子树 中序遍历:左子树 | 根结点 | 右子树 后序遍历:左子树 | 右子树 | 根结点 二叉树遍历的性质 ...

  3. python元组的概念与基本操作

    元组与列表类似,关于元组同样需要做如下三点: A.概念 1.元组通过英文状态下的圆括号构成“()”.其存放元素与列表一样,可以是不通的数值类型,也可以是不通的数据结构. 2.元组仍然是一种序列,所以几 ...

  4. Java高级特性———Java注解

    什么是注解(Annotation)? 注解是放在Java源码的类.方法.字段.参数上的一种标签,在Java SE 5.0版本中开始引入.注解同class和interface一样,也属于一种类型. 如何 ...

  5. 前端Web APIS

    day01 - Web APIs 学习目标: 能够通过ID来获取元素能够通过标签名来获取元素能够通过class来获取元素能够通过选择器来获取元素能够获取body和html元素能够给元素注册事件能够修改 ...

  6. 力扣Leetcode 461. 汉明距离

    给你一个数组 arr ,请你将每个元素用它右边最大的元素替换,如果是最后一个元素,用 -1 替换. 完成所有替换操作后,请你返回这个数组. 示例: 输入:arr = [17,18,5,4,6,1] 输 ...

  7. 无法创建新虚拟机: 无法打开配置文件“F:\BigData\vm12\centos01\centos01.vmx”: 拒绝访问。

    退出,右键vmware选择以管理员身份运行即可.

  8. 新手oracle重启、监听

    有一次遇到了记录下. #su到oracle用户下 [root@localhost ~]# su - oracle  #重启数据库:[oracle@localhost ~]$ sqlplus /nolo ...

  9. 你可能不了解的java枚举

    枚举在java里也算个老生长谈的内容了,每当遇到一组需要类举的数据时我们都会自然而然地使用枚举类型: public enum Color { RED, GREEN, BLUE, YELLOW; pub ...

  10. 【小白学PyTorch】5 torchvision预训练模型与数据集全览

    文章来自:微信公众号[机器学习炼丹术].一个ai专业研究生的个人学习分享公众号 文章目录: 目录 torchvision 1 torchvision.datssets 2 torchvision.mo ...