F项目日志输出设计 郝伟 2021/03/11 [TOC]

1. 1 简介

本设计参考 log4j。 主要功能

  • 根据以上设计,提供了以下六个函数:all(arg), debug(arg), info(arg), warn(arg), error(arg), fatal(arg),每个函数可以接收任意类型的1-6个不同类型的参数。
  • 输出的信息包括时间戳、文件名、函数名、所在行号、消息类型和输出信息
  • 日志的输出等级的:
    • ALL=0:任何人都可以随意输出的信息,优先级最低;
    • DEBUG=1:以测试为目的的打印输出消息;
    • INFO=2:用于输出生产环境中一些重要的信息,这个信息与调试无关;
    • WARN=3:某些可能出问题的情况,在运行环境中会给出提示;
    • ERROR=4:程序出错,但不足矣导致程序退出时的异常信息;
    • FATAL=5:重大错误而导致程序退出的异常信息;
    • OFF=6: 不显示任何信息
  • 消息格式:[日期时间]文件路径@函数名称:行号.类型:消息1#消息1#,其中#为分隔符,通过全局变量 flogger::SEP设置
  • 级别控制通过 flogger::DEBUG_LEVEL 进行控制,只显示大于等于设定级的日志。

2. 2 使用方法

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.

3. 3 日志使用原则

  1. 严格控制日志输出数量 由于日志输出是占用性能的,且性能性别是毫秒级,所以输出的数量尽量要少,否则过多的日志输出会严重影响系统性能。
  2. 有效处理无效日志 一些已经解决问题的DEBUG输出,可以将其注释之或将其分类由DEBUG改为ALL。

4. 4 实现代码

  • flogger.h 文件 ```cpp /*
    • 【使用说明】
    • 进行日志的输出打印控制,提供了以下七个等级的日志类型(参考log4j)
    • ALL=0:任何人都可以随意输出的信息,优先级最低;
    • DEBUG=1:以测试为目的的打印输出消息;
    • INFO=2:用于输出生产环境中一些重要的信息,这个信息与调试无关;
    • WARN=3:某些可能出问题的情况,在运行环境中会给出提示;
    • ERROR=4:程序出错,但不足矣导致程序退出时的异常信息;
    • FATAL=5:重大错误而导致程序退出的异常信息;
    • OFF=6: 不显示任何信息
    • 提供了7个同名但小写的最多6个不定参数类型的函数
    • 【注意事项】
      1. 严格控制日志输出数量
    • 由于日志输出是占用性能的,且性能性别是毫秒级,所以输出的数量尽量要少,否则过多的日志输出会严重影响系统性能。
      1. 有效处理无效日志
    • 一些已经解决问题的DEBUG输出,可以将其注释之或将其分类由DEBUG改为ALL。
    • 【发布作者:郝伟】
    • 【更新记录】
    • 2021/03/11 第一次发布 **/

5. ifndef FSY_FLOGGER_H

6. define FSY_FLOGGER_H

7. include

8. include

namespace flogger{

int DEBUG_LEVEL = 0; // 调试级别 char SEP = '~'; // 输出时的分隔符

// 错误等级

9. define ALL 0

10. define DEBUG 1

11. define INFO 2

12. define WARN 3

13. define ERROR 4

14. define FATAL 5

15. define OFF 6

16. pragma execution_character_set("utf-8")

17. define INFO1(arg1) logger(INFO, FILE, FUNCTION, LINE, arg1)

18. define INFO2(arg1, arg2) logger(INFO, FILE, FUNCTION, LINE, arg1, arg2)

19. define INFO3(arg1, arg2, arg3) logger(INFO, FILE, FUNCTION, LINE, arg1, arg2, arg3)

20. define INFO4(arg1, arg2, arg3, arg4) logger(INFO, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4)

21. define INFO5(arg1, arg2, arg3, arg4, arg5) logger(INFO, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5)

22. define INFO6(arg1, arg2, arg3, arg4, arg5, arg6) logger(INFO, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5, arg6)

23. define DEBUG1(arg1) logger(DEBUG, FILE, FUNCTION, LINE, arg1)

24. define DEBUG2(arg1, arg2) logger(DEBUG, FILE, FUNCTION, LINE, arg1, arg2)

25. define DEBUG3(arg1, arg2, arg3) logger(DEBUG, FILE, FUNCTION, LINE, arg1, arg2, arg3)

26. define DEBUG4(arg1, arg2, arg3, arg4) logger(DEBUG, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4)

27. define DEBUG5(arg1, arg2, arg3, arg4, arg5) logger(DEBUG, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5)

28. define DEBUG6(arg1, arg2, arg3, arg4, arg5, arg6) logger(DEBUG, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5, arg6)

29. define ALL1(arg1) logger(ALL, FILE, FUNCTION, LINE, arg1)

30. define ALL2(arg1, arg2) logger(ALL, FILE, FUNCTION, LINE, arg1, arg2)

31. define ALL3(arg1, arg2, arg3) logger(ALL, FILE, FUNCTION, LINE, arg1, arg2, arg3)

32. define ALL4(arg1, arg2, arg3, arg4) logger(ALL, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4)

33. define ALL5(arg1, arg2, arg3, arg4, arg5) logger(ALL, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5)

34. define ALL6(arg1, arg2, arg3, arg4, arg5, arg6) logger(ALL, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5, arg6)

35. define WARN1(arg1) logger(WARN, FILE, FUNCTION, LINE, arg1)

36. define WARN2(arg1, arg2) logger(WARN, FILE, FUNCTION, LINE, arg1, arg2)

37. define WARN3(arg1, arg2, arg3) logger(WARN, FILE, FUNCTION, LINE, arg1, arg2, arg3)

38. define WARN4(arg1, arg2, arg3, arg4) logger(WARN, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4)

39. define WARN5(arg1, arg2, arg3, arg4, arg5) logger(WARN, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5)

40. define WARN6(arg1, arg2, arg3, arg4, arg5, arg6) logger(WARN, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5, arg6)

41. define ERROR1(arg1) logger(ERROR, FILE, FUNCTION, LINE, arg1)

42. define ERROR2(arg1, arg2) logger(ERROR, FILE, FUNCTION, LINE, arg1, arg2)

43. define ERROR3(arg1, arg2, arg3) logger(ERROR, FILE, FUNCTION, LINE, arg1, arg2, arg3)

44. define ERROR4(arg1, arg2, arg3, arg4) logger(ERROR, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4)

45. define ERROR5(arg1, arg2, arg3, arg4, arg5) logger(ERROR, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5)

46. define ERROR6(arg1, arg2, arg3, arg4, arg5, arg6) logger(ERROR, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5, arg6)

47. define FATAL1(arg1) logger(FATAL, FILE, FUNCTION, LINE, arg1)

48. define FATAL2(arg1, arg2) logger(FATAL, FILE, FUNCTION, LINE, arg1, arg2)

49. define FATAL3(arg1, arg2, arg3) logger(FATAL, FILE, FUNCTION, LINE, arg1, arg2, arg3)

50. define FATAL4(arg1, arg2, arg3, arg4) logger(FATAL, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4)

51. define FATAL5(arg1, arg2, arg3, arg4, arg5) logger(FATAL, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5)

52. define FATAL6(arg1, arg2, arg3, arg4, arg5, arg6) logger(FATAL, FILE, FUNCTION, LINE, arg1, arg2, arg3, arg4, arg5, arg6)

53. define GetMacro(_1, _2, _3, _4, _5, _6, NAME, ...) NAME

54. define all(...) GetMacro(VA_ARGS, ALL6, ALL5, ALL4, ALL3, ALL2, ALL1, ...)(VA_ARGS)

55. define debug(...) GetMacro(VA_ARGS, DEBUG6, DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, ...)(VA_ARGS)

56. define info(...) GetMacro(VA_ARGS, INFO6, INFO5, INFO4, INFO3, INFO2, INFO1, ...)(VA_ARGS)

57. define warn(...) GetMacro(VA_ARGS, WARN6, WARN5, WARN4, WARN3, WARN2, WARN1, ...)(VA_ARGS)

58. define error(...) GetMacro(VA_ARGS, ERROR6, ERROR5, ERROR4, ERROR3, ERROR2, ERROR1, ...)(VA_ARGS)

59. define fatal(...) GetMacro(VA_ARGS, FATAL6, FATAL5, FATAL4, FATAL3, FATAL2, FATAL1, ...)(VA_ARGS)

using namespace std;

// 参数为1个时调用此函数 template void show(const T &arg) { cout << arg << endl; }

// 参数个数大于1时使用此函数 template void show(const T &arg1, const Types &... args) { cout << arg1 << SEP; show(args...); }

// 日志记录函数, 格式为:[日期时间]文件路径@函数名称:行号.类型:消息1#消息1# template void logger(int loglevel, const char file, const char func, int lineno, const T &arg1, const Types &... args) { if(loglevel >= DEBUGLEVEL) { cout << '[' << _DATE << ' ' << __TIME << ']' << file << '@' << func << ":" << lineno << "." << log_level << ":"; show(arg1, args...); } }

}

60. endif //FSY_FLOGGER_H

# 5 参考资料 
[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 


# 其他
* 可能再利用的预编译代码
```cpp
#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

results matching ""

    No results matching ""