在前面所列文章的演示代码中,其实已经展示了一部分记录日志的方式。为了使用方便,在 Easylogging++ 中,通过使用宏的集合来完成日志记录。

普通日志记录

对于普通的日志记录,我们可以选择以下两种比较常用的方式:

  • LOG(LEVEL)
  • CLOG(LEVEL, logger ID)

两个宏定义的中 LEVEL 请参看《 日志库EasyLogging++学习系列(2)—— 日志级别》,而宏CLOG(CUSTOM LOG)中的 logger ID 可以参看《 日志库EasyLogging++学习系列(6)—— 日志记录器》。下面的代码简单演示了如何使用这两个宏:

[cpp] view plaincopy print?
  1. #include "easylogging++.h"
  2. INITIALIZE_EASYLOGGINGPP
  3. int main(int argc, char** argv)
  4. {
  5. /// 可以直接使用,不记录任何日志信息
  6. LOG(INFO);
  7. CLOG(INFO, "default");
  8. LOG(INFO) << "Here is very simple example.";
  9. CLOG(INFO, "default") << "Here is very simple example.";
  10. system("pause");
  11. return 0;
  12. }
#include "easylogging++.h"INITIALIZE_EASYLOGGINGPPint main(int argc, char** argv)
{/// 可以直接使用,不记录任何日志信息LOG(INFO);CLOG(INFO, "default");LOG(INFO) << "Here is very simple example.";CLOG(INFO, "default") << "Here is very simple example.";system("pause");return 0;
}

通过上面的演示代码可以发现,其实 LOG(LEVEL) 就是 CLOG(LEVEL, "default") 的缩写。不过,如果我们在包含头文件  #include "easylogging++.h" 的代码前面使用另外一个指定的 ID 来定义宏 ELPP_DEFAULT_LOGGER ,那么这个指定的 ID 就会自动地替换掉 "default" 。需要注意的是,这个指定 ID 所标识的日志记录器必须保证使用前已经被注册,否则,将无法正常使用宏 LOG(LEVEL) 来记录日志信息。下面的代码演示这个功能:

[cpp] view plaincopy print?
  1. #define ELPP_DEFAULT_LOGGER "testlog"
  2. #include "easylogging++.h"
  3. INITIALIZE_EASYLOGGINGPP
  4. int main(int argc, char** argv)
  5. {
  6. /// 使用前,注册ID为testlog的日志记录器
  7. el::Logger* newLogger = el::Loggers::getLogger("testlog");
  8. LOG(INFO) << "Here is very simple example.";
  9. system("pause");
  10. return 0;
  11. }
#define ELPP_DEFAULT_LOGGER "testlog"
#include "easylogging++.h"INITIALIZE_EASYLOGGINGPPint main(int argc, char** argv)
{/// 使用前,注册ID为testlog的日志记录器el::Logger* newLogger = el::Loggers::getLogger("testlog");LOG(INFO) << "Here is very simple example.";system("pause");return 0;
}

条件日志记录

条件日志就是只有当满足某一个条件的时候才进行日志记录,否则将忽略记录。下面是记录条件日志的两个宏定义:

  • LOG_IF(condition, LEVEL)
  • CLOG_IF(condition, LEVEL, logger ID)

上面两个宏定义中 condition 条件为真时,日志信息才被记录,在某些应用场景下这会显得十分便利,下面的代码演示了条件日志宏定义的用法:

[cpp] view plaincopy print?
  1. #include "easylogging++.h"
  2. INITIALIZE_EASYLOGGINGPP
  3. int main(int argc, char** argv)
  4. {
  5. /// 下面这三个日志,只有第一个会输出
  6. LOG_IF(1 == 1, INFO) << "1 is equal to 1";
  7. LOG_IF(1 > 2, INFO) << "1 is greater than 2";
  8. LOG_IF(1 == 2, DEBUG) << "1 is equal to 2";
  9. system("pause");
  10. return 0;
  11. }
#include "easylogging++.h"INITIALIZE_EASYLOGGINGPPint main(int argc, char** argv)
{/// 下面这三个日志,只有第一个会输出LOG_IF(1 == 1, INFO) << "1 is equal to 1";LOG_IF(1 > 2, INFO) << "1 is greater than 2";LOG_IF(1 == 2, DEBUG) << "1 is equal to 2";system("pause");return 0;
}

偶然日志记录

偶然日志可以分为以下三种常见的情况,具体使用方法请参考示例代码:

  • 每 N 次记录一次日志,对应的宏定义是:LOG_EVERY_N(n, LEVEL) 或者 CLOG_EVERY_N(n, LEVEL, logger ID)
  • 当计数达到 N 次之后,才开始记录日志,对应的宏定义是:LOG_AFTER_N(n, LEVEL)
  • 当记录次数达到 N 次之后,就不再记录日志信息,对应的宏定义是:LOG_N_TIMES(n, LEVEL)
[cpp] view plaincopy print?
  1. #include "easylogging++.h"
  2. INITIALIZE_EASYLOGGINGPP
  3. int main(int argc, char** argv)
  4. {
  5. /// 每 N 次记录一次日志
  6. for (int i = 1; i <= 200; ++i)
  7. {
  8. LOG_EVERY_N(20, INFO) << "LOG_EVERY_N i = " << i;
  9. LOG_EVERY_N(100, INFO) << "LOG_EVERY_N Current position is " << ELPP_COUNTER_POS;
  10. }
  11. /// 当计数达到 N 次之后,才开始记录日志
  12. for (int i = 1; i <= 10; ++i)
  13. {
  14. LOG_AFTER_N(6, INFO) << "LOG_AFTER_N i = " << i;
  15. }
  16. /// 当记录次数达到 N 次之后,就不再记录
  17. for (int i = 1; i < 10; ++i)
  18. {
  19. LOG_N_TIMES(6, INFO) << "LOG_N_TIMES i = " << i;
  20. }
  21. system("pause");
  22. return 0;
  23. }
#include "easylogging++.h"INITIALIZE_EASYLOGGINGPPint main(int argc, char** argv)
{/// 每 N 次记录一次日志for (int i = 1; i <= 200; ++i){LOG_EVERY_N(20, INFO) << "LOG_EVERY_N i = " << i;LOG_EVERY_N(100, INFO) << "LOG_EVERY_N Current position is " << ELPP_COUNTER_POS;}/// 当计数达到 N 次之后,才开始记录日志for (int i = 1; i <= 10; ++i) {LOG_AFTER_N(6, INFO) << "LOG_AFTER_N i = " << i;}/// 当记录次数达到 N 次之后,就不再记录for (int i = 1; i < 10; ++i) {LOG_N_TIMES(6, INFO) << "LOG_N_TIMES i = " << i;}system("pause");return 0;
}

STL容器日志记录

在前面的文章《日志库EasyLogging++学习系列(5)—— 辅助配置功能》中,已经给过示例演示了如何记录 STL 容器日志的方式。再次提示,使用 STL容器日志记录需要定义宏 ELPP_STL_LOGGING,每个容器默认最大容量是 100。下面是 Easylogging++ 支持的 STL 容器类型:

* * * *
std::vector std::list std::deque std::queue
std::stack std::priority_queue std::set std::multiset
std::pair std::bitset std::map std::multimap

下面的是 C++11 标准才支持的 STL 容器,在  Easylogging++ V9.80版本中定义相应的宏就可以使用,别忘记同样还需要定义宏 ELPP_STL_LOGGING:

Template Macro Needed
std::array ELPP_LOG_STD_ARRAY
std::unordered_map ELPP_LOG_UNORDERED_MAP
std::unordered_multimap ELPP_LOG_UNORDERED_MAP
std::unordered_set ELPP_LOG_UNORDERED_SET
std::unordered_multiset ELPP_LOG_UNORDERED_SET

系统日志记录

系统日志需要系统具有头文件 syslog.h 的支持,这个头文件在 Linux 系统下才有,也就是说Windows 系统是不支持 Easylogging++ 的系统日志功能的。因为我并没有在 linux下用过 Easylogging++,在这里只简单介绍一下。如果想要使用系统日志功能,必须先定义宏ELPP_SYSLOG 的,系统日志默认使用 ID 为 “syslog” 的日志记录器,可以用以下的宏记录日志:

  • SYSLOG(LEVEL)
  • SYSLOG_IF(Condition, LEVEL)
  • SYSLOG_EVERY_N(n, LEVEL)
  • CSYSLOG(LEVEL, loggerId)
  • CSYSLOG_IF(Condition, LEVEL, loggerId)
  • CSYSLOG_EVERY_N(n, LEVEL, loggerId)
系统日志只支持以下几个级别的日志,分别对应系统的优先级:
  • INFO (LOG_INFO)
  • DEBUG (LOG_DEBUG)
  • WARNING (LOG_WARNING)
  • ERROR (LOG_ERR)
  • FATAL (LOG_EMERG)
CHECK宏日志记录
利用CHECK宏日志可以快速地判断某个条件是否满足,当满足条件时不作记录;而不满足条件时就会记录 FATAL 级别的日志,并且会中断程序,除非你添加了标记 DisableApplicationAbortOnFatalLog ,下面是 Easylogging++ 支持的 CHECK 宏:
CHECK Name Notes + Example
CHECK(condition) Checks for condition e.g, CHECK(isLoggedIn()) << "Not logged in";
CHECK_EQ(a, b) Equality check e.g, CHECK_EQ(getId(), getLoggedOnId()) << "Invalid user logged in";
CHECK_NE(a, b) Inequality check e.g, CHECK_NE(isUserBlocked(userId), false) << "User is blocked";
CHECK_LT(a, b) Less than e.g, CHECK_LT(1, 2) << "How 1 is not less than 2";
CHECK_GT(a, b) Greater than e.g, CHECK_GT(2, 1) << "How 2 is not greater than 1?";
CHECK_LE(a, b) Less than or equal e.g, CHECK_LE(1, 1) << "1 is not equal or less than 1";
CHECK_GE(a, b) Greater than or equal e.g, CHECK_GE(1, 1) << "1 is not equal or greater than 1";
CHECK_NOTNULL(pointer) Ensures pointer is not null - if OK returns pointer e.g, explicit MyClass(Obj* obj) : m_obj(CHECK_NOT_NULL(obj)) {}
CHECK_STREQ(str1, str2) C-string equality (case-sensitive) e.g, CHECK_STREQ(argv[1], "0") << "First arg cannot be 0";
CHECK_STRNE(str1, str2) C-string inequality (case-sensitive) e.g, CHECK_STRNE(username1, username2) << "Usernames cannot be same";
CHECK_STRCASEEQ(str1, str2) C-string inequality (case-insensitive) e.g, CHECK_CASESTREQ(argv[1], "Z") << "First arg cannot be 'z' or 'Z'";
CHECK_STRCASENE(str1, str2) C-string inequality (case-insensitive) e.g,CHECK_STRCASENE(username1, username2) << "Same username not allowed";
CHECK_BOUNDS(val, min, max) Checks that val falls under the min and max range e.g,CHECK_BOUNDS(i, 0, list.size() - 1) << "Index out of bounds";

详细的用法请看演示代码,需要特别注意的是宏 CHECK_NOTNULL(pointer) 的用法:

[cpp] view plaincopy print?
  1. #include "easylogging++.h"
  2. INITIALIZE_EASYLOGGINGPP
  3. int main(void)
  4. {
  5. el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);
  6. /// CHECK(condition)
  7. CHECK(1 < 2) << "CHECK(condition) example 1";      // condition为真时不记录
  8. CHECK(1 > 2) << "CHECK(condition) example 2";      // condition为假时才记录
  9. /// CHECK_EQ(a, b)
  10. CHECK_EQ(1, 1) << "CHECK_EQ(a, b) example 1";     // 满足a = b时不记录
  11. CHECK_EQ(1, 0) << "CHECK_EQ(a, b) example 3";     // 不满足a = b时记录
  12. /// CHECK_NE(a, b)
  13. CHECK_NE(1, 2) << "CHECK_NE(a, b) example 1";     // 满足a != b 时不记录
  14. CHECK_NE(1, 1) << "CHECK_NE(a, b) example 2";     // 不满足a != b 时记录
  15. /// CHECK_LT(a, b)
  16. CHECK_LT(1, 2) << "CHECK_LT(a, b) example 1";     // 满足a < b时不记录
  17. CHECK_LT(1, 1) << "CHECK_LT(a, b) example 2";     // 不满足a < b时记录
  18. /// CHECK_GT(a, b)
  19. CHECK_GT(2, 1) << "CHECK_GT(a, b) example 1";     // 满足a > b时不记录
  20. CHECK_GT(1, 1) << "CHECK_GT(a, b) example 2";     // 不满足a > b时记录
  21. /// CHECK_LE(a, b)
  22. CHECK_LE(1, 1) << "CHECK_LE(a, b) example 1";     // 满足a <= b时不记录
  23. CHECK_LE(1, 0) << "CHECK_LE(a, b) example 2";     // 不满足a <= b时记录
  24. /// CHECK_GE(a, b)
  25. CHECK_GE(1, 1) << "CHECK_GE(a, b) example 1";     // 满足a >= b时不记录
  26. CHECK_GE(1, 2) << "CHECK_GE(a, b) example 2";     // 不满足a >= b时记录
  27. /// CHECK_STREQ(str1, str2) C风格字符串区分大小写
  28. CHECK_STREQ("abc", "abc") << "CHECK_STREQ(str1, str2) example 1"; // 满足str1 = str2时不记录
  29. CHECK_STREQ("abc", "ABC") << "CHECK_STREQ(str1, str2) example 2"; // 不满足str1 = str2时记录
  30. /// CHECK_STRNE(str1, str2) C风格字符串区分大小写
  31. CHECK_STRNE("abc", "ABC") << "CHECK_STRNE(str1, str2) example 1";   // 满足str1 != str2时不记录
  32. CHECK_STRNE("abc", "abc") << "CHECK_STRNE(str1, str2) example 2";   // 不满足str1 != str2时记录
  33. /// CHECK_STRCASEEQ(str1, str2) C风格字符串不区分大小写
  34. CHECK_STRCASEEQ("abc", "ABC") << "CHECK_STRCASEEQ(str1, str2) example 1"; // 满足str1 = str2时不记录
  35. CHECK_STRCASEEQ("abc", "abd") << "CHECK_STRCASEEQ(str1, str2) example 2"; // 不满足str1 = str2时记录
  36. /// CHECK_STRCASENE(str1, str2) C风格字符串不区分大小写
  37. CHECK_STRCASENE("abc", "abd") << "CHECK_STRCASENE(str1, str2) example 1"; // 满足str1 != str2时不记录
  38. CHECK_STRCASENE("abc", "ABC") << "CHECK_STRCASENE(str1, str2) example 2"; // 不满足str1 != str2时记录
  39. /// CHECK_NOTNULL(pointer) 判断指针pointer是否为空,不为空时返回pointer
  40. int* f = nullptr;
  41. if (CHECK_NOTNULL(f))
  42. {
  43. }
  44. f = new int;
  45. if (CHECK_NOTNULL(f))
  46. {
  47. }
  48. delete f;
  49. f = nullptr;
  50. int min = 2;
  51. int max = 5;
  52. CHECK_BOUNDS(1, min, max) << "CHECK_BOUNDS(val, min, max) example 1";
  53. CHECK_BOUNDS(2, min, max) << "CHECK_BOUNDS(val, min, max) example 2";
  54. CHECK_BOUNDS(3, min, max) << "CHECK_BOUNDS(val, min, max) example 3";
  55. CHECK_BOUNDS(4, min, max) << "CHECK_BOUNDS(val, min, max) example 4";
  56. CHECK_BOUNDS(5, min, max) << "CHECK_BOUNDS(val, min, max) example 5";
  57. CHECK_BOUNDS(6, min, max) << "CHECK_BOUNDS(val, min, max) example 6";
  58. system("pause");
  59. return 0;
  60. }
#include "easylogging++.h"INITIALIZE_EASYLOGGINGPPint main(void)
{el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);/// CHECK(condition)CHECK(1 < 2) << "CHECK(condition) example 1";      // condition为真时不记录CHECK(1 > 2) << "CHECK(condition) example 2";      // condition为假时才记录/// CHECK_EQ(a, b)CHECK_EQ(1, 1) << "CHECK_EQ(a, b) example 1";       // 满足a = b时不记录CHECK_EQ(1, 0) << "CHECK_EQ(a, b) example 3";        // 不满足a = b时记录/// CHECK_NE(a, b) CHECK_NE(1, 2) << "CHECK_NE(a, b) example 1";     // 满足a != b 时不记录CHECK_NE(1, 1) << "CHECK_NE(a, b) example 2";      // 不满足a != b 时记录/// CHECK_LT(a, b) CHECK_LT(1, 2) << "CHECK_LT(a, b) example 1";       // 满足a < b时不记录CHECK_LT(1, 1) << "CHECK_LT(a, b) example 2";      // 不满足a < b时记录/// CHECK_GT(a, b) CHECK_GT(2, 1) << "CHECK_GT(a, b) example 1";       // 满足a > b时不记录CHECK_GT(1, 1) << "CHECK_GT(a, b) example 2";      // 不满足a > b时记录/// CHECK_LE(a, b) CHECK_LE(1, 1) << "CHECK_LE(a, b) example 1";       // 满足a <= b时不记录CHECK_LE(1, 0) << "CHECK_LE(a, b) example 2";        // 不满足a <= b时记录/// CHECK_GE(a, b) CHECK_GE(1, 1) << "CHECK_GE(a, b) example 1";     // 满足a >= b时不记录CHECK_GE(1, 2) << "CHECK_GE(a, b) example 2";        // 不满足a >= b时记录/// CHECK_STREQ(str1, str2) C风格字符串区分大小写CHECK_STREQ("abc", "abc") << "CHECK_STREQ(str1, str2) example 1"; // 满足str1 = str2时不记录CHECK_STREQ("abc", "ABC") << "CHECK_STREQ(str1, str2) example 2";  // 不满足str1 = str2时记录/// CHECK_STRNE(str1, str2) C风格字符串区分大小写CHECK_STRNE("abc", "ABC") << "CHECK_STRNE(str1, str2) example 1";   // 满足str1 != str2时不记录CHECK_STRNE("abc", "abc") << "CHECK_STRNE(str1, str2) example 2";   // 不满足str1 != str2时记录/// CHECK_STRCASEEQ(str1, str2) C风格字符串不区分大小写CHECK_STRCASEEQ("abc", "ABC") << "CHECK_STRCASEEQ(str1, str2) example 1";   // 满足str1 = str2时不记录CHECK_STRCASEEQ("abc", "abd") << "CHECK_STRCASEEQ(str1, str2) example 2";  // 不满足str1 = str2时记录/// CHECK_STRCASENE(str1, str2) C风格字符串不区分大小写CHECK_STRCASENE("abc", "abd") << "CHECK_STRCASENE(str1, str2) example 1";  // 满足str1 != str2时不记录CHECK_STRCASENE("abc", "ABC") << "CHECK_STRCASENE(str1, str2) example 2"; // 不满足str1 != str2时记录/// CHECK_NOTNULL(pointer) 判断指针pointer是否为空,不为空时返回pointerint* f = nullptr;if (CHECK_NOTNULL(f)){}f = new int;if (CHECK_NOTNULL(f)){}delete f;f = nullptr;int min = 2;int max = 5;CHECK_BOUNDS(1, min, max) << "CHECK_BOUNDS(val, min, max) example 1";CHECK_BOUNDS(2, min, max) << "CHECK_BOUNDS(val, min, max) example 2";CHECK_BOUNDS(3, min, max) << "CHECK_BOUNDS(val, min, max) example 3";CHECK_BOUNDS(4, min, max) << "CHECK_BOUNDS(val, min, max) example 4";CHECK_BOUNDS(5, min, max) << "CHECK_BOUNDS(val, min, max) example 5";CHECK_BOUNDS(6, min, max) << "CHECK_BOUNDS(val, min, max) example 6";system("pause");return 0;
}

printf风格日志记录
如果编译器支持 C++11 标准的可变参数模板,那么我们可以像 printf 函数一样来记录日志,唯一和 printf 函数不一样的是,我们只需用 %v 来带代替所有的参数即可,而不需要根据变量类型来指定格式。如果想要输出 %v ,只需加上转义字符 %%v 即可。请看下面 el::Logger 类的成员函数:
  • info(const char*, const T&, const Args&...)
  • warn(const char*, const T&, const Args&...)
  • error(const char*, const T&, const Args&...)
  • debug(const char*, const T&, const Args&...)
  • fatal(const char*, const T&, const Args&...)
  • trace(const char*, const T&, const Args&...)
  • verbose(int vlevel, const char*, const T&, const Args&...)
下面的代码演示了printf风格日志记录的使用方法:

[cpp] view plaincopy print?
  1. #define  ELPP_STL_LOGGING
  2. #include "easylogging++.h"
  3. INITIALIZE_EASYLOGGINGPP
  4. int main(int argc, char** argv)
  5. {
  6. el::Logger* defaultLogger = el::Loggers::getLogger("default");
  7. std::vector<int> i;
  8. i.push_back(1);
  9. i.push_back(2);
  10. /// 记录STL容器数据
  11. defaultLogger->warn("My first ultimate log message %v %v %v", 123, 222, i);
  12. // 利用转义字符输出 % 和 %v
  13. defaultLogger->info("My first ultimate log message %% %%v %v %v", 123, 222);
  14. system("pause");
  15. return 0;
  16. }
#define  ELPP_STL_LOGGING
#include "easylogging++.h"INITIALIZE_EASYLOGGINGPPint main(int argc, char** argv)
{el::Logger* defaultLogger = el::Loggers::getLogger("default");std::vector<int> i;i.push_back(1);i.push_back(2);/// 记录STL容器数据defaultLogger->warn("My first ultimate log message %v %v %v", 123, 222, i);// 利用转义字符输出 % 和 %vdefaultLogger->info("My first ultimate log message %% %%v %v %v", 123, 222); system("pause");return 0;
}

perror风格日志记录

在C语言库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用某些库函数出错时,被调用的函数会重新设置了errno的值,而 perror() 函数就是用于将你输入的一些信息和现在的errno所对应的错误一起输出。在 Easylogging++ 中,也支持在作用上类似 perror() 函数的宏定义:

  • PLOG(LEVEL)
  • PLOG_IF(Condition, LEVEL)
  • PCHECK()
  • CPLOG(LEVEL, LoggerId)
  • CPLOG_IF(Condition, LEVEL, LoggerId)

下面的代码演示了 perror 风格日志记录的使用方式:

[cpp] view plaincopy print?
  1. #include "easylogging++.h"
  2. INITIALIZE_EASYLOGGINGPP
  3. int main(void)
  4. {
  5. el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);
  6. /// 读取一个不存在的文件,改变errno变量的值
  7. std::fstream f("a file that does not exist", std::ifstream::in);
  8. /// PLOG(LEVEL)
  9. PLOG(INFO) << "A message with plog";
  10. /// PLOG_IF(Condition, LEVEL), 条件为真时才记录
  11. PLOG_IF(true, INFO) << "A message with plog 1";
  12. PLOG_IF(false, INFO) << "A message with plog 2";
  13. /// PCHECK()  满足条件不记录,不满足才记录
  14. PCHECK(true) << "check message with plog 1";
  15. PCHECK(false) << "check message with plog 2";
  16. system("pause");
  17. return 0;
  18. }
#include "easylogging++.h"INITIALIZE_EASYLOGGINGPPint main(void)
{el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);/// 读取一个不存在的文件,改变errno变量的值std::fstream f("a file that does not exist", std::ifstream::in);/// PLOG(LEVEL)PLOG(INFO) << "A message with plog";/// PLOG_IF(Condition, LEVEL), 条件为真时才记录PLOG_IF(true, INFO) << "A message with plog 1";PLOG_IF(false, INFO) << "A message with plog 2";/// PCHECK()  满足条件不记录,不满足才记录PCHECK(true) << "check message with plog 1";PCHECK(false) << "check message with plog 2";system("pause");return 0;
}

DEBUG模式日志记录

在前面的文章《日志库EasyLogging++学习系列(2)—— 日志级别》中,简单地提到了DEBUG模式的日志记录。所谓的DEBUG模式,就是只在Debug版本的程序中才有意义,而在Release版本的程序中则没有意义。在本文以上内容所提到的全部的日志记录方式中,只要是以宏定义形式记录日志信息的,基本上都会有一个DEBUG模式对应的宏定义。在 Easylogging++ 中,所有用于DEBUG模式的宏定义都是以大写字母 D 开头的,由于DEBUG模式宏定义的使用方式和常规的宏定义使用方式都是一样的,这里不再赘述,建议有兴趣了解更多关于DEBUG模式日志详细信息的小伙伴可以亲自动手试一试。

日志库EasyLogging++学习系列(7)—— 记录方式详解相关推荐

  1. 日志库EasyLogging++学习系列(2)—— 日志级别

    在很多的C++日志库中,日志信息会根据严重性来划分级别,使用者可以设置严重性级别门阀值来控制日志的输出,即严重性级别在该门阀值以上的日志信息才进行记录.以此不同,在Easylogging++日志库中, ...

  2. 日志库EasyLogging++学习系列(5)—— 辅助配置功能

    正如前面<日志库EasyLogging++学习系列(3)-- 配置功能>文中最后提到的,在某些应用场景下,我们还需要通过其他的一些配置手段来辅助我们完成某些特殊功能,这些辅助配置手段包括设 ...

  3. 日志库EasyLogging++学习系列(10)—— 日志文件滚动

    在很多应用场合,我们是需要实现日志文件滚动的,特别是在一些长期运行的服务器程序中,如果把所有的日志都记录在一个文件之中,势必会造成日志文件越来越大.当日志内容很多的时候,万一哪天突然需要查询某个日志信 ...

  4. 日志库EasyLogging++学习系列(6)—— 日志记录器

    所有的日志都是由日志记录器完成的,日志记录器使用唯一的 ID(大小写敏感)来标识.在 Easylogging++ 中默认了三个现有的日志记录器: 默认日志记录器,其 ID 为:default 性能日志 ...

  5. 日志库EasyLogging++学习系列(3)—— 配置功能

    在前面的文章 <日志库Easylogging++学习系列(1) -- 简要介绍 >中,我们已经初步见识到了 Easylogging++ 日志库强大的配置功能.那么配置文件中各个字段的意义是 ...

  6. 日志库EasyLogging++学习系列(11)—— 共享日志库

    在前面的学习系列文章中,我们都是在单独的一个应用程序中使用 Easylogging++ 日志库.其实 Easylogging++ 日志库是可以共享给动态库.静态库以及应用程序共同使用的.在编写一些大型 ...

  7. 日志库EasyLogging++学习系列(1)—— 简要介绍

    对于有开发经验的程序员来说,记录程序执行日志是一件必不可少的事情.通过查看和分析日志信息,不仅可以有效地帮助我们调试程序,而且当程序正式发布运行之后,更是可以帮助我们快速.准确地定位问题.在现在这个开 ...

  8. 日志库EasyLogging++学习系列(4)—— 格式说明符

    在上一篇文章中,主要记录了如何使用 Easylogging++ 的配置功能,虽然已经用了很大的篇幅尽可能详细地加以记录,不过相信有些细心的小伙伴可能已经发现遗漏了些什么,请看下面两句摘自 my_log ...

  9. 日志库EasyLogging++学习系列(9)—— 性能跟踪功能

    性能跟踪是 Easylogging++ 其中一个非常显著的功能,而且使用起来也十分简单.如果在Windows平台下使用性能跟踪的话,其原理是基于 Windows API函数 GetSystemTime ...

最新文章

  1. c++ lambda函数_C++ Lambda表达式
  2. Ubuntu 启动自动登录
  3. 【java基础知识】JDK环境下载安装过程(windows环境/Linux环境)+IDEA配置
  4. 数据结构(二):线性表的使用原则以及链表的应用-稀疏矩阵的三元组表示
  5. 教你手写Java层handler机制
  6. Dreamweaver网页作业——紫罗兰永恒花园动漫价绍网页 7页,含有table表格,js表单验证还有首页视频。以及列表页。浮动布局。div+css+js
  7. 在拼多多上抢了点茅台
  8. WAITED TOO LONG FOR A ROW CACHE ENQUEUE LOCK!的分析
  9. fontTools库来检测字体文件中是否包含某字符
  10. 酒链世界为何会火起来?酒链世界是什么?
  11. 动态规划——贴纸拼词
  12. 年薪40万AI工程师必备的能力项,你达标了吗?
  13. hard resetting link----softreset failed (device not ready)----failed command: READ FPDMA QUEUED
  14. CVPR2020:Seeing Through Fog Without Seeing Fog
  15. 击鼓传花击鼓次数相同c语言,击鼓传花
  16. 纯perl语言计算文件的crc32值
  17. SAP-基于批次特定计量单位的应用-01-产品数量管理
  18. 事件抽取与事理图谱(二)
  19. Profinet远程IO控制器
  20. RISC-V+基于IMU的智能家居操作系统设计

热门文章

  1. gis 大屏_gis大屏可视化应用技术方案_gis大屏可视化应用技术_gis大屏可视化应用 - 帆软...
  2. 2020-12-22 一些有用的开源软件
  3. Linux启动redis提示 /var/run/redis_6379.pid exists, process is already running or crashed
  4. 深度学习85—[深度学习] 感知器
  5. 统计学习方法 学习笔记(十):决策树
  6. 使用jconsole监控JVM内存
  7. python+selenium自动化测试——浏览器驱动
  8. 20145204 《Java程序设计》第6周学习总结
  9. android ApiDemos学习1 主界面动态ListView显示
  10. Blueprint CSS Framework 学习笔记