学习C++:使用C++11开发一个简单的log库


前言

日志对于一个项目来说是非常重要的,虽然没有日志不影响程序的运行,但是很多时候程序出bug时,首先是查看日志,然后分析定位问题出在哪里,本文将采用C++实现一个简单的log库。


1.定义

  • log文件存放
static FILE* log_file_ = nullptr;
  • 定义log等级
enum LogLevel {
  DEBUG,
  INFO,
  WARN,
  ERROR,
  FATAL
};
  • log不同等级的信息
  static char *LEVEL[] = {
    "DEBUG",
    "INFO",
    "WARN",
    "ERROR",
    "FATAL"
  };
  • log初始化和关闭函数
  bool LogInit();
  bool LogClose();
  • log类和logfatal类:
  class Log : public std::basic_ostringstream<char> {
   public:
    Log(const char* file, int line, LogLevel level);
    ~Log();

   protected:
    void LogWirte();

   private:
    const char* name_;
    int         line_;
    LogLevel    level_;
  };

  class LogFatal : public Log {
   public:
    LogFatal(const char* file, int line);
    ~LogFatal();
  };
  • 宏定义
  #define _LOG_INFO   ::dailyrecord::Log(__FILE__, __LINE__, ::dailyrecord::LogLevel::INFO)
  #define _LOG_DEBUG  ::dailyrecord::Log(__FILE__, __LINE__, ::dailyrecord::LogLevel::DEBUG)
  #define _LOG_WARN   ::dailyrecord::Log(__FILE__, __LINE__, ::dailyrecord::LogLevel::WARN)
  #define _LOG_ERROR  ::dailyrecord::Log(__FILE__, __LINE__, ::dailyrecord::LogLevel::ERROR)
  #define _LOG_FATAL  ::dailyrecord::LogFatal(__FILE__, __LINE__, ::dailyrecord::LogLevel::FATAL)

  #define LOG(level) _LOG_##level

  #ifndef likely
  #define likely(x) __builtin_expect(!!(x), 1)
  #endif

  #ifndef unlikely
  #define unlikely(x) __builtin_expect(!!(x), 0)
  #endif

2.实现

  • Init和Close
  bool LogInit() {
    //如果log_file_不为空,则先关闭
    if (log_file_ != nullptr) {
      LogClose();
    }
		
    //获取当前日期,将其作为log文件名
    time_t now_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    const int path_buffer_size = 20;
    char path[path_buffer_size];
    strftime(path, path_buffer_size, "%Y%m%d.log", localtime(&now_time));

    //以追加的方式打开文件,供log类写入日志,抛异常则返回false
    try {
      log_file_ = fopen(path, "a");
    } catch (std::exception e) {
      std::cerr << "catch exception: " << e.what() << std::endl;
      LogClose();
      return false;
    } catch (...) {
      std::cerr << "catch unknow exception" << std::endl;
      LogClose();
      return false;
    }

    return true;
  }

  bool LogClose() {
    if (log_file_ == nullptr) {
      return true;
    }
    //关闭文件,log_file_置为nullptr,抛出异常则打印信息到stderr,返回false
    try {
      fclose(log_file_);
    } catch (std::exception e) {
      std::cerr << "catch exception: " << e.what() << std::endl;
      log_file_ = nullptr;
      return false;
    } catch (...) {
      std::cerr << "catch unknow exception" << std::endl;
      log_file_ = nullptr;
      return false;
    }
    log_file_ = nullptr;
    return true;
  }
  • log类和logfatal类
  Log::Log(const char* name, int line, LogLevel level) : name_(name), line_(line), level_(level) { }

  void Log::LogWrite() {
    //获取当前时间然后格式化
    time_t now_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    const int time_buff_size = 32;
    char time_buff[time_buff_size];
    strftime(time_buff, time_buff_size, "%Y-%m-%d %H:%M:%S", localtime(&now_time));
    //写入日志文件
    fprintf(log_file_, "%s [%s] %s:%d %s\n", time_buff, LEVEL[level_], name_, line_, str().c_str());
  }

  namespace {
    //获取设置的log level
    LogLevel GetLogLevel() {
      const char* log_level = getenv("LOG_LEVEL");
      if (log_level == nullptr) {
        return LogLevel::INFO;
      }
      if (strcasecmp(log_level, "DEBUG") == 0) {
        return LogLevel::DEBUG;
      }
      if (strcasecmp(log_level, "WARN") == 0) {
        return LogLevel::WARN;
      }
      if (strcasecmp(log_level, "ERROR") == 0) {
        return LogLevel::ERROR;
      }
      if (strcasecmp(log_level, "FATAL") == 0) {
        return LogLevel::FATAL;
      }
      return LogLevel::INFO;
    }
  }

  Log::~Log() {
    static LogLevel min_level = ::dailyrecord::GetLogLevel();
    if (likely(level_ >= min_level)) {
      LogWrite();
    }
  }

  LogFatal::LogFatal(const char* file, int line) : Log(file, line, LogLevel::FATAL) { }

  LogFatal::~LogFatal() {
    LogWrite();
    abort();
  }

3.使用

#include "log.h"

int main()
{
	LogInit();
	LOG(INFO) << "test print";
	LogClose();
	
	return 0;
}

完整的代码

github地址

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值