log wapper类及其性能

一个log的wapper类可以用来方便地对接各种logger,但是这对logger的性能来说可能会有影响。下面测试了Linux环境下log4cplus及其wapper类的性能。

 打印100万条日志 log4cpluslog4cplus
with wapper
Linux同步logger4s4.5s
异步logger1.9s1.9s

 

由此可见,在Linux下使用该wapper类造成的性能损失为12.5%。 在Windows下使用该wapper造成的性能损失可能会非常大,当然这只是根据一些测试的推测,并没有精确的数据。

//logger.h

#ifndef _LOGGER_H_
#define _LOGGER_H_

#include <string>
#include <memory>

namespace mytest {

class ILogger {
 public:
  static const unsigned short LOG_FATAL = 5;
  static const unsigned short LOG_ERROR = 4;
  static const unsigned short LOG_WARNING = 3;
  static const unsigned short LOG_INFO = 2;
  static const unsigned short LOG_DEBUG = 1;
  static const unsigned short LOG_VERBOSE = 0;

  virtual ~ILogger() {}

  virtual void Log(int level, const char* filename, int line,
    const char* message) = 0;

};

namespace internal {

// Declare the LogFinisher class
class LogFinisher;

/// Defines the LogMessage class used to serialize the variables to be logged
class LogMessage {
 public:
  LogMessage(ILogger* logger, int level, const char* filename, int line);
  LogMessage(std::shared_ptr<ILogger> logger, int level,
    const char* filename, int line);
  ~LogMessage();

  LogMessage& operator<<(const ::std::string& value);
  LogMessage& operator<<(const char* value);
  LogMessage& operator<<(char value);
  LogMessage& operator<<(int value);
  LogMessage& operator<<(unsigned int value);
  LogMessage& operator<<(long value);
  LogMessage& operator<<(unsigned long value);
  LogMessage& operator<<(long long value);
  LogMessage& operator<<(unsigned long long value);
  LogMessage& operator<<(double value);

 private:
  friend class LogFinisher;
  void Finish();

  ILogger* logger_;
  int level_;
  const char* filename_;
  int line_;
  ::std::string message_;
};


/// Used to make the entire "LOG(BLAH) << etc." expression have a void return
/// type and print a newline after each message.
class LogFinisher {
 public:
  LogFinisher();

  void operator=(LogMessage& other);
};

} // namespace internal

} // namespace

#define MY_LOG(LOGGER, LEVEL)                            \
  mytest::internal::LogFinisher() =                          \
  mytest::internal::LogMessage(                              \
  LOGGER, LEVEL, __FILE__, __LINE__)

#endif _LOGGER_H_

 

 

//logger.cc

#include <logger.h>

#ifdef _WIN32
// MSVC has only _snprintf, not snprintf.
#define snprintf _snprintf_s
#endif

namespace mytest {

namespace internal {


LogMessage& LogMessage::operator<<(const std::string& value) {
  message_ += value;
  return *this;
}

LogMessage& LogMessage::operator<<(const char* value) {
  message_ += value;
  return *this;
}

#undef DECLARE_STREAM_OPERATOR
#define DECLARE_STREAM_OPERATOR(TYPE, FORMAT)                       \
  LogMessage& LogMessage::operator<<(TYPE value) {                  \
    /* 128 bytes should be big enough for any of the primitive */   \
    /* values which we print with this, but well use snprintf() */  \
    /* anyway to be extra safe. */                                  \
    char buffer[128];                                               \
    snprintf(buffer, sizeof(buffer), FORMAT, value);                \
    /* Guard against broken MSVC snprintf(). */                     \
    buffer[sizeof(buffer)-1] = '\0';                                \
    message_ += buffer;                                             \
    return *this;                                                   \
  }

DECLARE_STREAM_OPERATOR(char, "%c")
DECLARE_STREAM_OPERATOR(int, "%d")
DECLARE_STREAM_OPERATOR(unsigned int, "%u")
DECLARE_STREAM_OPERATOR(long, "%ld")
DECLARE_STREAM_OPERATOR(unsigned long, "%lu")
DECLARE_STREAM_OPERATOR(long long, "%lld")
DECLARE_STREAM_OPERATOR(unsigned long long, "%llu")
DECLARE_STREAM_OPERATOR(double, "%g")
#undef DECLARE_STREAM_OPERATOR

LogMessage::LogMessage(ILogger* logger, int level,
  const char* filename, int line)
  : logger_(logger), level_(level), filename_(filename), line_(line) {}
LogMessage::LogMessage(std::shared_ptr<ILogger> logger, int level,
  const char* filename, int line)
  : logger_(logger.get()), level_(level), filename_(filename), line_(line) {}
LogMessage::~LogMessage() {}

void LogMessage::Finish() {
  if(logger_)
  {
    logger_->Log(level_, filename_, line_, message_.c_str());
  }
}

LogFinisher::LogFinisher() {}

void LogFinisher::operator=(LogMessage& other) {
  other.Finish();
}

}

}

 

 

//main.cc
#include <string>
#include <iostream>
#include <logger.h>
#include <boost/property_tree/ini_parser.hpp>
#include <log4cplus/logger.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>

using namespace mytest;

int ReadFile(const char* file_path, std::vector<char>* o_data) {
  std::ifstream in (file_path, std::ios::binary);
  if (!in.good ()) {
    return -1;
  }

  in.seekg(0, std::ifstream::end);
  size_t size = (size_t) in.tellg ();
  in.seekg(0, std::ifstream::beg);
  o_data->resize (size);
  in.read(&(*o_data)[0], size);
  if (in.gcount() != size) {
    return -1;
  }

  return 0;
}

class Log4cplusLogger : public ILogger {
 public:
  Log4cplusLogger(const std::string& logger_name) {
    logger_ = log4cplus::Logger::getInstance(logger_name);
  }
  virtual ~Log4cplusLogger() {
    // nothing
  }

  virtual void Log(int level, const char* filename, int line,
    const char* message) {
    switch (level) {
    case ILogger::LOG_FATAL:
      logger_.log(log4cplus::FATAL_LOG_LEVEL, message, filename, line);
      break;

    case ILogger::LOG_ERROR:
      logger_.log(log4cplus::ERROR_LOG_LEVEL, message, filename, line);
      break;

    case ILogger::LOG_WARNING:
      logger_.log(log4cplus::WARN_LOG_LEVEL, message, filename, line);
      break;

    case ILogger::LOG_INFO:
      logger_.log(log4cplus::INFO_LOG_LEVEL, message, filename, line);
      break;

    case ILogger::LOG_DEBUG:
      logger_.log(log4cplus::DEBUG_LOG_LEVEL, message, filename, line);
      break;

    case ILogger::LOG_VERBOSE:
      logger_.log(log4cplus::TRACE_LOG_LEVEL, message, filename, line);
      break;

    default:
      break;
    }
  }

 private:
  log4cplus::Logger logger_;
};


int main(int argc, char* argv[])
{
    if (argc < 2) {
      std::cout << "Please specify path of the confuguration file." << std::endl;
      return 0;
    }

    std::string config_path(argv[1]);
    std::string log_config;
    std::vector<char> data;
    int res = ReadFile(config_path.c_str(), &data);
    if (0 != res) {
      std::cout << "Read ini file failed!" << std::endl;
      return -1;
    }

    std::string config_str(&data[0], data.size());
    std::stringstream css(config_str);
    boost::property_tree::ptree pt;
    boost::property_tree::read_ini(css, pt);

    std::stringstream ss;
    boost::property_tree::write_ini(ss, pt.get_child("log4cplus"));

    log4cplus::initialize();
    log4cplus::PropertyConfigurator pc(ss);
    pc.configure();

    std::shared_ptr<ILogger> logger;
    logger.reset(new Log4cplusLogger("global"));
    logger.reset();

    for(int i=0; i<1000000; ++i)
    {
      MY_LOG(logger, ILogger::LOG_INFO) << "logging test " << i;
    }

    return 0;
}

Makefile:

main:
        g++ -std=c++11 -Wall -O3 -L/home/wqf/usr/lib/boost_1_67_0/lib/ -lboost_system -lboost_filesystem -lboost_locale -lboost_date_time -llog4cplus main.cc logger.cc  -o main

 

配置文件同上一篇文章https://blog.csdn.net/wqfhenanxc/article/details/88892996

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值