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

背景

项目需求:

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

需求分析:

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

代码实现

log_test.h

#ifndef LOG_TEST_H_
#define LOG_TEST_H_
#include <string>
#include <fstream>

namespace my_log_test {
//log switch
#define MY_LOG_DEBUG 1

//log write to output console
#define MY_LOG_OUTPUT_CONSOLE 1

//log buffer size
#define MY_LOG_BUFFER_SIZE 512

constexpr const char* g_testDirPath { "./testDir/" };

typedef enum {
  LOG_FATAL = 0,
  LOG_ERROR = 1,
  LOG_WARN  = 2,
  LOG_INFO  = 3,
  LOG_UNKNOW
} MY_LOG_LEVEL;

class MyLogTest {
public:
  MyLogTest(std::string fileName, std::string moduleName = "");
  ~MyLogTest();

  static void LogPrint(MY_LOG_LEVEL level, const char* pcFunc, const int& line, const char* fmt, ...);
private:
  std::ofstream writeOf;
  bool fsOpenFlag {false};
}; //end of class MyLogTest

//日志打印函数,可变参数。可通过宏开关,整个代码不编译
#ifdef MY_LOG_DEBUG
#ifndef MY_LOGERR
#define MY_LOGERR(fmt, args...) MyLogTest::LogPrint(LOG_ERROR, __FUNCTION__, __LINE__, fmt, ## args)
#endif
#else
#define MY_LOGERR(fmt, args...)  ((void)0)
#endif

//日志打印函数,可变参数。可通过宏开关,整个代码不编译
#ifdef MY_LOG_DEBUG
#ifndef MY_LOGWAR
#define MY_LOGWAR(fmt, args...) MyLogTest::LogPrint(LOG_WARN, __FUNCTION__, __LINE__, fmt, ## args)
#endif
#else
#define MY_LOGWAR(fmt, args...)  ((void)0)
#endif


//类使用宏,可通过宏开关,整个代码不编译
#ifdef MY_LOG_DEBUG
#ifndef DefineMyLogTest
#define DefineMyLogTest(fileName, moduleName) \
MyLogTest myLogTest(fileName, moduleName)
#endif
#else
#define DefineMyLogTest(fileName, moduleName) ((void)0)
#endif

}//end of namespace my_log_test

#endif //LOG_TEST_H_

log_test.cpp

#include <iostream>
#include <fstream>

//获取系统时间,可变参数
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#include "log_test.h"

namespace my_log_test {
void * BaseMyLogTest { nullptr };

//获取当前系统时间
void gettime(std::string *date_time)
{
  time_t rawtime;
  struct tm *ptminfo;
  char buf[32];

  time(&rawtime);
  ptminfo = localtime(&rawtime);
  strftime(buf, 32, "%Y-%m-%d %H:%M:%S", ptminfo);
  *date_time = buf;
  //std::cout<<"date-time: " <<buf<<std::endl;
}

MyLogTest::MyLogTest(std::string fileName, std::string moduleName)
{
  if( fileName.empty()) {
    std::string file {__FILE__};
    if(file.find(".cpp")) {
      fileName = file.substr(0, file.size()-5);
    }
  }

  if(!moduleName.empty()) {
    fileName = moduleName + "-" + fileName;
  }

  BaseMyLogTest = (void*)this;

  fileName = g_testDirPath + fileName;
  writeOf.open(fileName, std::ios::out);
  if(writeOf.fail()) {
    std::cout<<__FUNCTION__<<" open file failed: "<< fileName <<std::endl;
    fsOpenFlag = false; 
  }else {
    fsOpenFlag = true;
  }
  
  if(fsOpenFlag) {
    std::string date_time {""};
    gettime(&date_time);
    std::cout<<__FUNCTION__<<" "<<date_time << std::endl;

    writeOf <<"My log test Begin date-time: "<<date_time<<std::endl;
  }
}

MyLogTest::~MyLogTest()
{
  if(fsOpenFlag) {
    writeOf.close();
  }
}

void MyLogTest::LogPrint(MY_LOG_LEVEL level, const char*pcFunc, const int& line, const char* fmt, ...)
{
  char buffer[MY_LOG_BUFFER_SIZE];
  int n = sprintf(buffer, "[%s]-[%d]", pcFunc, line);

  va_list vap;
  va_start(vap, fmt);
  vsnprintf(buffer + n, MY_LOG_BUFFER_SIZE-n, fmt, vap);
  va_end(vap);

  std::string logLevelStr {""};
  switch(level) {
    case LOG_ERROR:
      logLevelStr = "Error";
      break;
    case LOG_WARN:
      logLevelStr = "Warn";
      break;
    default:
      logLevelStr = "Error";
      break;
  }
  std::string dt {""};
  gettime(&dt);

  #ifdef MY_LOG_OUTPUT_CONSOLE
  std::cout<<dt <<" [" <<logLevelStr << "]: " <<buffer << std::endl;

  #else
  MyLogTest *myLogTest = (MyLogTest*)BaseMyLogTest ;
  myLogTest->writeOf  <<dt <<" [" <<logLevelStr << "]: " <<buffer << std::endl;
  #endif
}
}//end of namespace my_log_test

main.cpp

#include <iostream>
#include "log_test.h"

using namespace my_log_test;

int main(int argc, char* argv[])
{
  std::cout<< __FUNCTION__ <<" Begin of the program!"<< std::endl;
  
  DefineMyLogTest("test_file", "test_module");
  std::string strErr {"string error!"};
  std::string strWar {"string waring!"};
  
  MY_LOGERR("my log test error: %s", strErr.c_str());
  MY_LOGWAR("my log test warn: %s", strWar.c_str();

  std::cout<< __FUNCTION__ <<" End of the program!"<< std::endl;
  return 0;
}

代码测试 

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值