在 Qt的源码与Protobuf 的代码中,看到相同的简单消息(日志)输出的类实现,基本思路是使用宏定义,重载临时类对象,调用类方法或者通过析构函数自动调用输出方法,实现消息输出。这里以 Protobuf 的LogMessage 类为例,简单描述实现方法。

类定义很简单,主要是构造函数、重载的 operator<< 操作符、Finish方法。构造函数传入日志等级、文件名及行号,为输出用。重载的 << 操作符为了流式输出。在后边实现了个私有的  Finish 方法,该方法简单粗暴,就是调用输出函数,如果是 Fatal 等级输出,还会抛出异常或者 abort。其定义如下:

enum LogLevel {
LOGLEVEL_INFO, // Informational. This is never actually used by
// libprotobuf.
LOGLEVEL_WARNING, // Warns about issues that, although not technically a
// problem now, could cause problems in the future. For
// example, a // warning will be printed when parsing a
// message that is near the message size limit.
LOGLEVEL_ERROR, // An error occurred which should never happen during
// normal use.
LOGLEVEL_FATAL, // An error occurred from which the library cannot
// recover. This usually indicates a programming error
// in the code which calls the library, especially when
// compiled in debug mode.
}; class LIBPROTOBUF_EXPORT LogMessage {
public:
LogMessage(LogLevel level, const char* filename, int line);
~LogMessage(); LogMessage& operator<<(const std::string& value);
LogMessage& operator<<(const char* value);
LogMessage& operator<<(char value);
LogMessage& operator<<(int value);
LogMessage& operator<<(uint value);
LogMessage& operator<<(long value);
LogMessage& operator<<(unsigned long value);
LogMessage& operator<<(long long value);
LogMessage& operator<<(unsigned long long value);
LogMessage& operator<<(double value);
LogMessage& operator<<(void* value);
LogMessage& operator<<(const StringPiece& value);
LogMessage& operator<<(const ::google::protobuf::util::Status& status);
LogMessage& operator<<(const uint128& value); private:
friend class LogFinisher;
void Finish(); LogLevel level_;
const char* filename_;
int line_;
std::string message_;
};

同时实现了一个 LogFinisher 类,只重载了 operator= 操作符,该方法只是调用 LogMessage 的 Finish 方法。

 class LIBPROTOBUF_EXPORT LogFinisher {
public:
void operator=(LogMessage& other) {
other.Finish();
}
};

再者实现方便使用的宏定义,定义如下所示。主要为 GOOGLE_LOG 宏,该宏构造 LogMessage 临时对象,调用 LogFinisher 的 operator= 方法,实现消息输出。在Qt 的代码中,并没有实现类似  LogFinisher 的类,直接构造了MessageLog 临时对象,在对象析构时调用输出函数,临时对象生命周期会在构造完执行析构,执行消息输出。以下宏定义中还定义了 GOOGLE_LOG_IF ,即条件为 true 时,什么都不做 (void)0,为 false时调用 GOOGLE_LOG。

 #define GOOGLE_LOG(LEVEL)                                                 \
::google::protobuf::internal::LogFinisher() = \
::google::protobuf::internal::LogMessage( \
::google::protobuf::LOGLEVEL_##LEVEL, __FILE__, __LINE__)
#define GOOGLE_LOG_IF(LEVEL, CONDITION) \
!(CONDITION) ? (void) : GOOGLE_LOG(LEVEL) #define GOOGLE_CHECK(EXPRESSION) \
GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
#define GOOGLE_CHECK_OK(A) GOOGLE_CHECK(::google::protobuf::internal::IsOk(A))
#define GOOGLE_CHECK_EQ(A, B) GOOGLE_CHECK((A) == (B))
#define GOOGLE_CHECK_NE(A, B) GOOGLE_CHECK((A) != (B))
#define GOOGLE_CHECK_LT(A, B) GOOGLE_CHECK((A) < (B))
#define GOOGLE_CHECK_LE(A, B) GOOGLE_CHECK((A) <= (B))
#define GOOGLE_CHECK_GT(A, B) GOOGLE_CHECK((A) > (B))
#define GOOGLE_CHECK_GE(A, B) GOOGLE_CHECK((A) >= (B))

通过以上实现,则可以在代码中使用以下形式进行消息输出或者断言。第一行直接输出 "Hello sunshy",额,sunshy 是寡人姓名拼音的简拼,第二行在var0 和 var1 不相等时输出后边的消息,同时抛异常或者abort,相等时则 do nothing

 GOOGLE_LOG(INFO)<< "Hello " <<"sunshy\n";
GOOGLE_CHECK_EQ(var0, var1)<<" var0 not equal var\n";

最新工作的事心有不畅,随便写写,以遣胸怀

C++ Simple Message/Logging Class的更多相关文章

  1. Recommended Settings for Tracing and Message Logging

    https://docs.microsoft.com/en-us/dotnet/framework/wcf/diagnostics/tracing/recommended-settings-for-t ...

  2. Python自动化运维之9、模块之sys、os、hashlib、random、time&datetime、logging、subprocess

    python模块 用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需 ...

  3. Taxonomy of class loader problems encountered when using Jakarta Commons Logging(转)

    Acknowledgments I would like to thank Jacob Kjome for reviewing early drafts of this document. His c ...

  4. python标准库-日志logging

    1.模块级别 先看一下logging模块的日志级别特点,共分6个等级. 可以手工设置当前日志的默认等级(warn),当日志输出的等级高于默认等级时,日志输出到屏幕,否则不输出. #!/usr/bin/ ...

  5. python之配置logging的几种方式

    作为开发者,我们可以通过以下3中方式来配置logging: 1)使用Python代码显式的创建loggers, handlers和formatters并分别调用它们的配置函数: 2)创建一个日志配置文 ...

  6. 以打印日志为荣之logging模块详细使用

    啄木鸟社区里的Pythonic八荣八耻有一条: 以打印日志为荣 , 以单步跟踪为耻; 很多程序都有记录日志的需求,并且日志中包含的信息既有正常的程序访问日志,还可能有错误.警告等信息输出,python ...

  7. python3之xml&ConfigParser&hashlib&Subprocess&logging模块

    1.xml模块 XML 指可扩展标记语言(eXtensible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言. XML 被设计用来传输和存储 ...

  8. Python之配置日志的几种方式(logging模块)

    原文:https://blog.csdn.net/WZ18810463869/article/details/81147167 作为开发者,我们可以通过以下3种方式来配置logging: 1)使用Py ...

  9. python模块之logging模块

    1. 低配版 # 指定显示信息格式 import logging logging.basicConfig( level=20, # 设置显示或写入的起始级别 format="%(asctim ...

随机推荐

  1. AT2534 港湾設備 (Port Facility)

    洛谷 先膜一下Iscream巨巨 首先我们可以把题目转化为线段覆盖,如果两条线段相交(不算某一条完全在另一条里面的情况),那么这两条线段代表的集装箱就不能放到同一个栈里,我们在它们之间连一条边.如果图 ...

  2. python中用代码实现99乘法表

    第一种:使用for遍历循环嵌套 ,): ,x+): print("%s*%s=%s" % (y,x,x*y),end=" ") print("&quo ...

  3. GoAhead4.1.0 开发总结三(GoAction+Ajax实现局部数据交互)

    环境 官方文档:https://www.embedthis.com/goahead/doc/ 源码下载: goahead-4.1.0-src.tgz 系统平台:Ubuntu 12.04.4 gcc v ...

  4. Centos 搭建Mysql-Proxy 读写分离

    Mysql 读写分离 主:192.168.153.130 从:193.168.153.131 Mysql-Proxy:193.168.153.132 这里省略mysql主从同步,如果有需要,请查看:M ...

  5. pyinstaller模块

    应用场景: 1 把一些python脚本推广到更多机器上运行,但无法保证他们都有安装python解释器,所以,打包可以免去这一障碍 win: 安装: 在cmd中运行pip install pyinsta ...

  6. selenium之webdriverAPI接口详解

    1. 浏览器操作 driver.maximize_window() #最大化窗口driver.execute_script('window.scrollTo(0,0);') #滚动窗口到最上面driv ...

  7. 洛谷 P4585 [FJOI2015]火星商店问题

    (勿看,仅作笔记) bzoj权限题... https://www.luogu.org/problemnew/show/P4585 对于特殊商品,直接可持久化trie处理一下即可 剩下的,想了一段时间c ...

  8. Codeforces Round #295 (Div. 2) B. Two Buttons

    B. Two Buttons time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  9. curry柯里化函数实现

    curry柯里化函数实现 参考文章: 一行写出javascript函数式编程中的curry 感谢作者分享 第一步: 缓存原始函数的参数个数 function curry(fn) { var limit ...

  10. JavaScript--字符串常用方法总结

    JavaScript--字符串常用方法总结 举例模板: var str = "what are you " var str1 = "sss" var txt = ...