水平太菜,最近捣鼓这个 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. 微信小程序扫码解析小程序码

    通过微信扫小程序码,跳转到应用小程序内, 如何解析小程序码的参数呢? 一般小程序码会跳转到设置的页面,如首页, 可以直接跳转到小程序首页,然后解析小程序携带的参数,再打开某个页面. (小程序码的路径要 ...

  2. vue watch/ computed的应用(做一个简单的父子之间的传递/电话号码的搜索)

    父组件中当点击搜索的时候请求接口,然后把新的数据用 computed 传递给子组件 <van-search v-model="onSeachPhone" show-actio ...

  3. docker入门2-docker service

    docker service介绍 service是生产环境中某个image的container集合.一个service只使用一个image,但它编排这个image的运行方式,比如使用哪个端口,根据需求 ...

  4. Jmeter(二十二) - 从入门到精通 - JMeter断言 - 下篇(详解教程)

    1.简介 断言组件用来对服务器的响应数据做验证,常用的断言是响应断言,其支持正则表达式.虽然我们的通过响应断言能够完成绝大多数的结果验证工作,但是JMeter还是为我们提供了适合多个场景的断言元件,辅 ...

  5. JDBC | 第一章: 快速开始使用JDBC连接Mysql数据库?

    开始使用基于java的JDBC技术来连接mysql进行msyql数据库简单的CRUD操作 下载对应mysql驱动包 这里我创建maven项目基于maven下载 <!--mysql 驱动--> ...

  6. Android Weekly Notes Issue #428

    Android Weekly Issue #428 Kotlin Flow Retry Operator with Exponential Backoff Delay 这是讲协程Flow系列文章中的一 ...

  7. 从APP的启动说起

    iOS里面APP的启动,过程有些复杂,今天我们来抽丝剥茧,一步步探讨一下APP的启动会经历哪些过程. 首先,用户点击iPhone里面的某个APP的icon,Kernel内核会开始初始化空间并创建进程, ...

  8. VS2015+opencv3.1.0 imshow()函数出现中文乱码----问题一

    Visual Studio提供高级保存选项功能,它能指定特定代码文件的编码规范和行尾所使用的换行符.在Visual Studio 2015中,该命令没有默认显示在“文件”菜单中.用户需要手工设置,才能 ...

  9. JVM基于栈的解释器执行原理

    通过下面这段代码来解释JVM基于栈的执行原理 4. public static int add(int a, int b) { 5. int c = 0; 6. c = a + b; 7. retur ...

  10. jkd1.8 stream

    目录 Stream 创建流 通过集合创建,例如Map (常用) 通过数组方式创建 通过Stream静态方法创建 中间操作 筛选和切片 filter limit skip distinct 映射 map ...