• c++ 可变参数 log 打印函数实现


    背景

    项目需求:

    1. 要打印日志到特定模块、特定文件,并打印相应时间戳到文件中。 
    2. 日志开关,可以通过开关关闭、打开。
    3. 代码可以通过开关关闭、打开。(代码直接不进行编译)

    需求分析:

    1. 日志打印涉及可变参数,涉及log 等级,打印到模块-文件可以通过fstream实现。
    2. 日志开关,通过宏开关实现。
    3. 代码编译开关,也可以通过宏实现。

    代码实现

    log_test.h

    1. #ifndef LOG_TEST_H_
    2. #define LOG_TEST_H_
    3. #include
    4. #include
    5. namespace my_log_test {
    6. //log switch
    7. #define MY_LOG_DEBUG 1
    8. //log write to output console
    9. #define MY_LOG_OUTPUT_CONSOLE 1
    10. //log buffer size
    11. #define MY_LOG_BUFFER_SIZE 512
    12. constexpr const char* g_testDirPath { "./testDir/" };
    13. typedef enum {
    14. LOG_FATAL = 0,
    15. LOG_ERROR = 1,
    16. LOG_WARN = 2,
    17. LOG_INFO = 3,
    18. LOG_UNKNOW
    19. } MY_LOG_LEVEL;
    20. class MyLogTest {
    21. public:
    22. MyLogTest(std::string fileName, std::string moduleName = "");
    23. ~MyLogTest();
    24. static void LogPrint(MY_LOG_LEVEL level, const char* pcFunc, const int& line, const char* fmt, ...);
    25. private:
    26. std::ofstream writeOf;
    27. bool fsOpenFlag {false};
    28. }; //end of class MyLogTest
    29. //日志打印函数,可变参数。可通过宏开关,整个代码不编译
    30. #ifdef MY_LOG_DEBUG
    31. #ifndef MY_LOGERR
    32. #define MY_LOGERR(fmt, args...) MyLogTest::LogPrint(LOG_ERROR, __FUNCTION__, __LINE__, fmt, ## args)
    33. #endif
    34. #else
    35. #define MY_LOGERR(fmt, args...) ((void)0)
    36. #endif
    37. //日志打印函数,可变参数。可通过宏开关,整个代码不编译
    38. #ifdef MY_LOG_DEBUG
    39. #ifndef MY_LOGWAR
    40. #define MY_LOGWAR(fmt, args...) MyLogTest::LogPrint(LOG_WARN, __FUNCTION__, __LINE__, fmt, ## args)
    41. #endif
    42. #else
    43. #define MY_LOGWAR(fmt, args...) ((void)0)
    44. #endif
    45. //类使用宏,可通过宏开关,整个代码不编译
    46. #ifdef MY_LOG_DEBUG
    47. #ifndef DefineMyLogTest
    48. #define DefineMyLogTest(fileName, moduleName) \
    49. MyLogTest myLogTest(fileName, moduleName)
    50. #endif
    51. #else
    52. #define DefineMyLogTest(fileName, moduleName) ((void)0)
    53. #endif
    54. }//end of namespace my_log_test
    55. #endif //LOG_TEST_H_

    log_test.cpp

    1. #include
    2. #include
    3. //获取系统时间,可变参数
    4. #include
    5. #include
    6. #include
    7. #include "log_test.h"
    8. namespace my_log_test {
    9. void * BaseMyLogTest { nullptr };
    10. //获取当前系统时间
    11. void gettime(std::string *date_time)
    12. {
    13. time_t rawtime;
    14. struct tm *ptminfo;
    15. char buf[32];
    16. time(&rawtime);
    17. ptminfo = localtime(&rawtime);
    18. strftime(buf, 32, "%Y-%m-%d %H:%M:%S", ptminfo);
    19. *date_time = buf;
    20. //std::cout<<"date-time: " <
    21. }
    22. MyLogTest::MyLogTest(std::string fileName, std::string moduleName)
    23. {
    24. if( fileName.empty()) {
    25. std::string file {__FILE__};
    26. if(file.find(".cpp")) {
    27. fileName = file.substr(0, file.size()-5);
    28. }
    29. }
    30. if(!moduleName.empty()) {
    31. fileName = moduleName + "-" + fileName;
    32. }
    33. BaseMyLogTest = (void*)this;
    34. fileName = g_testDirPath + fileName;
    35. writeOf.open(fileName, std::ios::out);
    36. if(writeOf.fail()) {
    37. std::cout<<__FUNCTION__<<" open file failed: "<< fileName <
    38. fsOpenFlag = false;
    39. }else {
    40. fsOpenFlag = true;
    41. }
    42. if(fsOpenFlag) {
    43. std::string date_time {""};
    44. gettime(&date_time);
    45. std::cout<<__FUNCTION__<<" "<
    46. writeOf <<"My log test Begin date-time: "<
    47. }
    48. }
    49. MyLogTest::~MyLogTest()
    50. {
    51. if(fsOpenFlag) {
    52. writeOf.close();
    53. }
    54. }
    55. void MyLogTest::LogPrint(MY_LOG_LEVEL level, const char*pcFunc, const int& line, const char* fmt, ...)
    56. {
    57. char buffer[MY_LOG_BUFFER_SIZE];
    58. int n = sprintf(buffer, "[%s]-[%d]", pcFunc, line);
    59. va_list vap;
    60. va_start(vap, fmt);
    61. vsnprintf(buffer + n, MY_LOG_BUFFER_SIZE-n, fmt, vap);
    62. va_end(vap);
    63. std::string logLevelStr {""};
    64. switch(level) {
    65. case LOG_ERROR:
    66. logLevelStr = "Error";
    67. break;
    68. case LOG_WARN:
    69. logLevelStr = "Warn";
    70. break;
    71. default:
    72. logLevelStr = "Error";
    73. break;
    74. }
    75. std::string dt {""};
    76. gettime(&dt);
    77. #ifdef MY_LOG_OUTPUT_CONSOLE
    78. std::cout<
      " [" <"]: " <
    79. #else
    80. MyLogTest *myLogTest = (MyLogTest*)BaseMyLogTest ;
    81. myLogTest->writeOf <
      " [" <"]: " <
    82. #endif
    83. }
    84. }//end of namespace my_log_test

    main.cpp

    1. #include
    2. #include "log_test.h"
    3. using namespace my_log_test;
    4. int main(int argc, char* argv[])
    5. {
    6. std::cout<< __FUNCTION__ <<" Begin of the program!"<< std::endl;
    7. DefineMyLogTest("test_file", "test_module");
    8. std::string strErr {"string error!"};
    9. std::string strWar {"string waring!"};
    10. MY_LOGERR("my log test error: %s", strErr.c_str());
    11. MY_LOGWAR("my log test warn: %s", strWar.c_str();
    12. std::cout<< __FUNCTION__ <<" End of the program!"<< std::endl;
    13. return 0;
    14. }

    代码测试 

    当前代码在 ubuntu 系统上运行,通过下面命令进行编译。

    g++ -std=c++11 log_test.cpp main.cpp  -o test

    在当前目录创建 ”testDir“ 文件夹,执行 ./test

    即会在终端打印部分日志,并在文件 ./testDir/test_module_test_file 中写入日志,及时间戳。

  • 相关阅读:
    vue3.x中父组件添加自定义参数后,如何获取子组件$emit传递过来的参数
    React使用forward和useImperativeHandle实现父组件调用子组件
    ubuntu 22.04配置静态ip
    面试10000次依然会问的【线程池】,你还不会?
    云原生2.0时代,如何让应用拥抱云原生?
    Android 开发学习(二)
    爬取任意百度贴吧评论(可直接Copy)
    基于 idea 将 springboot 应用部署到 docker环境
    【C++深入浅出】日期类的实现
    载阿霉素PLGA-PLL-PEG纳米粒|马钱子碱mPEG-PLGA纳米粒|PLGA-PEG包裹液态PFP载紫杉醇纳米粒
  • 原文地址:https://blog.csdn.net/SHK242673/article/details/126343969