F项目日志输出设计
郝伟 2021/03/11
本设计参考 log4j。
主要功能
[日期时间]文件路径@函数名称:行号.类型:消息1#消息1#,其中#为分隔符,通过全局变量 flogger::SEP设置flogger::DEBUG_LEVEL 进行控制,只显示大于等于设定级的日志。flogger库的使用示例代码如下所示:
#include "flogger.h" using namespace flogger; void test(){ all('a', 123, "this is all function."); info("Terminal", "192.168.1.254", 66534, "OK"); info("Terminal", "192.168.1.254", 66534, "OK", 'c'); error("out of index", 1234); warn("this class is time taken."); fatal("the current thread is forced to shutdown."); } int main(int argc, char **argv) { DEBUG_LEVEL=ALL; SEP='_'; info("hello"); info("Network: Done.", "192.168.1.0:8080", 29343); all(123); test(); return 0; }
输出结果为:
C:\Users\hwaus\CLionProjects\hello\cmake-build-debug\hello.exe [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@main:17.2:hello [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@main:18.2:Network: Done._192.168.1.0:8080_29343 [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@main:19.0:123 [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@test:6.0:a_123_this is all function. [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@test:7.2:Terminal_192.168.1.254_66534_OK [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@test:8.2:Terminal_192.168.1.254_66534_OK_c [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@test:9.4:out of index_1234 [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@test:10.3:this class is time taken. [Mar 11 2021 09:48:19]C:\Users\hwaus\CLionProjects\hello\main.cpp@test:11.5:the current thread is forced to shutdown.
flogger.h 文件/*************************************************************** * 【使用说明】 * 进行日志的输出打印控制,提供了以下七个等级的日志类型(参考log4j) * ALL=0:任何人都可以随意输出的信息,优先级最低; * DEBUG=1:以测试为目的的打印输出消息; * INFO=2:用于输出生产环境中一些重要的信息,这个信息与调试无关; * WARN=3:某些可能出问题的情况,在运行环境中会给出提示; * ERROR=4:程序出错,但不足矣导致程序退出时的异常信息; * FATAL=5:重大错误而导致程序退出的异常信息; * OFF=6: 不显示任何信息 * 提供了7个同名但小写的最多6个不定参数类型的函数 * 【注意事项】 * 1. 严格控制日志输出数量 * 由于日志输出是占用性能的,且性能性别是毫秒级,所以输出的数量尽量要少,否则过多的日志输出会严重影响系统性能。 * 2. 有效处理无效日志 * 一些已经解决问题的DEBUG输出,可以将其注释之或将其分类由DEBUG改为ALL。 * 【发布作者:郝伟】 * 【更新记录】 * 2021/03/11 第一次发布 ****************************************************************/ #ifndef FSY_FLOGGER_H #define FSY_FLOGGER_H #include <iostream> #include <stdio.h> namespace flogger{ int DEBUG_LEVEL = 0; // 调试级别 char SEP = '~'; // 输出时的分隔符 // 错误等级 #define ALL 0 #define DEBUG 1 #define INFO 2 #define WARN 3 #define ERROR 4 #define FATAL 5 #define OFF 6 #pragma execution_character_set("utf-8") #define INFO1(arg1) logger(INFO, __FILE__, __FUNCTION__, __LINE__, arg1) #define INFO2(arg1, arg2) logger(INFO, __FILE__, __FUNCTION__, __LINE__, arg1, arg2) #define INFO3(arg1, arg2, arg3) logger(INFO, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3) #define INFO4(arg1, arg2, arg3, arg4) logger(INFO, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4) #define INFO5(arg1, arg2, arg3, arg4, arg5) logger(INFO, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5) #define INFO6(arg1, arg2, arg3, arg4, arg5, arg6) logger(INFO, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5, arg6) #define DEBUG1(arg1) logger(DEBUG, __FILE__, __FUNCTION__, __LINE__, arg1) #define DEBUG2(arg1, arg2) logger(DEBUG, __FILE__, __FUNCTION__, __LINE__, arg1, arg2) #define DEBUG3(arg1, arg2, arg3) logger(DEBUG, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3) #define DEBUG4(arg1, arg2, arg3, arg4) logger(DEBUG, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4) #define DEBUG5(arg1, arg2, arg3, arg4, arg5) logger(DEBUG, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5) #define DEBUG6(arg1, arg2, arg3, arg4, arg5, arg6) logger(DEBUG, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5, arg6) #define ALL1(arg1) logger(ALL, __FILE__, __FUNCTION__, __LINE__, arg1) #define ALL2(arg1, arg2) logger(ALL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2) #define ALL3(arg1, arg2, arg3) logger(ALL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3) #define ALL4(arg1, arg2, arg3, arg4) logger(ALL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4) #define ALL5(arg1, arg2, arg3, arg4, arg5) logger(ALL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5) #define ALL6(arg1, arg2, arg3, arg4, arg5, arg6) logger(ALL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5, arg6) #define WARN1(arg1) logger(WARN, __FILE__, __FUNCTION__, __LINE__, arg1) #define WARN2(arg1, arg2) logger(WARN, __FILE__, __FUNCTION__, __LINE__, arg1, arg2) #define WARN3(arg1, arg2, arg3) logger(WARN, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3) #define WARN4(arg1, arg2, arg3, arg4) logger(WARN, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4) #define WARN5(arg1, arg2, arg3, arg4, arg5) logger(WARN, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5) #define WARN6(arg1, arg2, arg3, arg4, arg5, arg6) logger(WARN, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5, arg6) #define ERROR1(arg1) logger(ERROR, __FILE__, __FUNCTION__, __LINE__, arg1) #define ERROR2(arg1, arg2) logger(ERROR, __FILE__, __FUNCTION__, __LINE__, arg1, arg2) #define ERROR3(arg1, arg2, arg3) logger(ERROR, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3) #define ERROR4(arg1, arg2, arg3, arg4) logger(ERROR, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4) #define ERROR5(arg1, arg2, arg3, arg4, arg5) logger(ERROR, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5) #define ERROR6(arg1, arg2, arg3, arg4, arg5, arg6) logger(ERROR, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5, arg6) #define FATAL1(arg1) logger(FATAL, __FILE__, __FUNCTION__, __LINE__, arg1) #define FATAL2(arg1, arg2) logger(FATAL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2) #define FATAL3(arg1, arg2, arg3) logger(FATAL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3) #define FATAL4(arg1, arg2, arg3, arg4) logger(FATAL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4) #define FATAL5(arg1, arg2, arg3, arg4, arg5) logger(FATAL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5) #define FATAL6(arg1, arg2, arg3, arg4, arg5, arg6) logger(FATAL, __FILE__, __FUNCTION__, __LINE__, arg1, arg2, arg3, arg4, arg5, arg6) #define GetMacro(_1, _2, _3, _4, _5, _6, NAME, ...) NAME #define all(...) GetMacro(__VA_ARGS__, ALL6, ALL5, ALL4, ALL3, ALL2, ALL1, ...)(__VA_ARGS__) #define debug(...) GetMacro(__VA_ARGS__, DEBUG6, DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, ...)(__VA_ARGS__) #define info(...) GetMacro(__VA_ARGS__, INFO6, INFO5, INFO4, INFO3, INFO2, INFO1, ...)(__VA_ARGS__) #define warn(...) GetMacro(__VA_ARGS__, WARN6, WARN5, WARN4, WARN3, WARN2, WARN1, ...)(__VA_ARGS__) #define error(...) GetMacro(__VA_ARGS__, ERROR6, ERROR5, ERROR4, ERROR3, ERROR2, ERROR1, ...)(__VA_ARGS__) #define fatal(...) GetMacro(__VA_ARGS__, FATAL6, FATAL5, FATAL4, FATAL3, FATAL2, FATAL1, ...)(__VA_ARGS__) using namespace std; // 参数为1个时调用此函数 template<typename T> void show(const T &arg) { cout << arg << endl; } // 参数个数大于1时使用此函数 template<typename T, typename ... Types> void show(const T &arg1, const Types &... args) { cout << arg1 << SEP; show(args...); } // 日志记录函数, 格式为:[日期时间]文件路径@函数名称:行号.类型:消息1#消息1# template<typename T, typename ... Types> void logger(int log_level, const char* file, const char* func, int lineno, const T &arg1, const Types &... args) { if(log_level >= DEBUG_LEVEL) { cout << '[' << __DATE__ << ' ' << __TIME__ << ']' << file << '@' << func << ":" << lineno << "." << log_level << ":"; show(arg1, args...); } } } #endif //FSY_FLOGGER_H
[1] C++11 - New features - Variadic templates, http://www.cplusplus.com/articles/EhvU7k9E/
[2] What's New in the C++11 Standard Template Library?, https://www.quantstart.com/articles/Whats-New-in-the-C11-Standard-Template-Library/
[3] logger with file name, line and time stamp, https://stackoverflow.com/questions/15134727/logger-with-file-name-line-and-time-stamp
[4] C语言重载宏函数的小技巧, https://blog.csdn.net/lmhuanying1012/article/details/78715351
#if DEBUG_LEVEL==FATAL #define fatal(...) GetMacro(__VA_ARGS__, FATAL6, FATAL5, FATAL4, FATAL3, FATAL2, FATAL1, ...)(__VA_ARGS__) #elif DEBUG_LEVEL==ERROR #define error(...) GetMacro(__VA_ARGS__, ERROR6, ERROR5, ERROR4, ERROR3, ERROR2, ERROR1, ...)(__VA_ARGS__) #define fatal(...) GetMacro(__VA_ARGS__, FATAL6, FATAL5, FATAL4, FATAL3, FATAL2, FATAL1, ...)(__VA_ARGS__) #elif DEBUG_LEVEL==WARN #define warn(...) GetMacro(__VA_ARGS__, WARN6, WARN5, WARN4, WARN3, WARN2, WARN1, ...)(__VA_ARGS__) #define error(...) GetMacro(__VA_ARGS__, ERROR6, ERROR5, ERROR4, ERROR3, ERROR2, ERROR1, ...)(__VA_ARGS__) #define fatal(...) GetMacro(__VA_ARGS__, FATAL6, FATAL5, FATAL4, FATAL3, FATAL2, FATAL1, ...)(__VA_ARGS__) #elif DEBUG_LEVEL==INFO #define all(...) GetMacro(__VA_ARGS__, ALL6, ALL5, ALL4, ALL3, ALL2, ALL1, ...)(__VA_ARGS__) #define info(...) GetMacro(__VA_ARGS__, INFO6, INFO5, INFO4, INFO3, INFO2, INFO1, ...)(__VA_ARGS__) #define warn(...) GetMacro(__VA_ARGS__, WARN6, WARN5, WARN4, WARN3, WARN2, WARN1, ...)(__VA_ARGS__) #define error(...) GetMacro(__VA_ARGS__, ERROR6, ERROR5, ERROR4, ERROR3, ERROR2, ERROR1, ...)(__VA_ARGS__) #define fatal(...) GetMacro(__VA_ARGS__, FATAL6, FATAL5, FATAL4, FATAL3, FATAL2, FATAL1, ...)(__VA_ARGS__) #elif DEBUG_LEVEL==DEBUG #define all(...) GetMacro(__VA_ARGS__, ALL6, ALL5, ALL4, ALL3, ALL2, ALL1, ...)(__VA_ARGS__) #define debug(...) GetMacro(__VA_ARGS__, DEBUG6, DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, ...)(__VA_ARGS__) #define info(...) GetMacro(__VA_ARGS__, INFO6, INFO5, INFO4, INFO3, INFO2, INFO1, ...)(__VA_ARGS__) #define warn(...) GetMacro(__VA_ARGS__, WARN6, WARN5, WARN4, WARN3, WARN2, WARN1, ...)(__VA_ARGS__) #define error(...) GetMacro(__VA_ARGS__, ERROR6, ERROR5, ERROR4, ERROR3, ERROR2, ERROR1, ...)(__VA_ARGS__) #define fatal(...) GetMacro(__VA_ARGS__, FATAL6, FATAL5, FATAL4, FATAL3, FATAL2, FATAL1, ...)(__VA_ARGS__) #elif DEBUG_LEVEL==ALL #define all(...) GetMacro(__VA_ARGS__, ALL6, ALL5, ALL4, ALL3, ALL2, ALL1, ...)(__VA_ARGS__) #define debug(...) GetMacro(__VA_ARGS__, DEBUG6, DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, ...)(__VA_ARGS__) #define info(...) GetMacro(__VA_ARGS__, INFO6, INFO5, INFO4, INFO3, INFO2, INFO1, ...)(__VA_ARGS__) #define warn(...) GetMacro(__VA_ARGS__, WARN6, WARN5, WARN4, WARN3, WARN2, WARN1, ...)(__VA_ARGS__) #define error(...) GetMacro(__VA_ARGS__, ERROR6, ERROR5, ERROR4, ERROR3, ERROR2, ERROR1, ...)(__VA_ARGS__) #define fatal(...) GetMacro(__VA_ARGS__, FATAL6, FATAL5, FATAL4, FATAL3, FATAL2, FATAL1, ...)(__VA_ARGS__) #endif