C++实现简易log日志系统

1.log日志的作用

在软件开发周期中,不管是前台还是后台,系统一般会采用一个持久化的日志系统来记录运行情况。

在代码中嵌入log代码信息,主要记录下列信息:

(1)记录系统运行异常信息。

(2)记录系统运行状态信息。

(3)记录系统运行性能指标。

通过对上述信息分析和诊断,我们能采取正确的手段来提高系统质量和系统性能。由此可见log日志在系统中的重要地位和存在的必要性。

2.log日志的类型与级别

 

2.1日志的类型

主要分三大类:

安全类信息:记录系统边界交互行为和信息;

业务类信息:记录系统内部业务处理行为和信息;

性能类信息:记录系统硬件对业务处理的支撑能力。

2.2日志的类型

一般分五级:

ERROR(错误):此信息输出后,主体系统核心模块不能正常工作,需要修复才能正常工作。

WARN(警告):此信息输出后,系统一般模块存在问题,不影响系统运行。

INFO(通知):此信息输出后,主要是记录系统运行状态等关联信息。

DEBUG(调试):最细粒度的输出,除却上面各种情况后,你希望输出的相关信息,都可以在这里输出。

TRACE(跟踪):最细粒度的输出,除却上面各种情况后,你希望输出的相关信息,都可以在这里输出。

在本文实现的简单日志系统中不包括DEBUG和TRACE。DEBUG在编码过程中进行,TRACE不太需要。

2.3常见的开源log工具

         C/C++实现的开源log常见有:C++版的log4j 的log4cplus、快速的 C++ 日志库——spdlog、纯C日志函数库 ——zlog、C++日志框架——GoogleGlog等。

其中开源log工具log4cplus在项目中的使用较为常见,具体用法和源码请参考网络的资源,不再赘述。

3.自实现log工具

主要针对ERROR(错误)、WARN(警告)和INFO(通知)这三种日志类型实现了如下的C++简易log工具。由源文件(logger.cpp)和头文件(logger.h)组成。源码如下。

logger.h文件:

/*
 *\logger.h
 *\brief 日记模块
 */

#ifndef  __logger__
#define  __logger__

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstdlib>
#include <stdint.h>

///
/// \brief 日志文件的类型
///
typedef enum log_rank {
   INFO,
   WARNING,
   ERROR,
   FATAL
}log_rank_t;

///
/// \brief 初始化日志文件
/// \param info_log_filename 信息文件的名字
/// \param warn_log_filename 警告文件的名字
/// \param error_log_filename 错误文件的名字
void initLogger(const std::string&info_log_filename,
                const std::string&warn_log_filename,
                const std::string&error_log_filename);

///
/// \brief 日志系统类
///
class Logger {
   friend void initLogger(const std::string& info_log_filename,
                           conststd::string& warn_log_filename,
                           conststd::string& erro_log_filename);

public:
         //构造函数
   Logger(log_rank_t log_rank) : m_log_rank(log_rank) {};

   ~Logger();
   ///
   /// \brief 写入日志信息之前先写入的源代码文件名, 行号, 函数名
   /// \param log_rank 日志的等级
   /// \param line 日志发生的行号
   /// \param function 日志发生的函数
   static std::ostream& start(log_rank_t log_rank,
                               const int32line,
                               conststd::string& function);

private:
   ///
   /// \brief 根据等级获取相应的日志输出流
   ///
   static std::ostream& getStream(log_rank_t log_rank);

   static std::ofstream m_info_log_file;                   ///< 信息日子的输出流
   static std::ofstream m_warn_log_file;                  ///< 警告信息的输出流
   static std::ofstream m_error_log_file;                  ///< 错误信息的输出流
   log_rank_t m_log_rank;                             ///< 日志的信息的等级
};

///
/// \brief 根据不同等级进行用不同的输出流进行读写
///
#define LOG(log_rank)   Logger(log_rank).start(log_rank, __LINE__,__FUNCTION__)

///
/// \brief 利用日记进行检查的各种宏
///
#define CHECK(a)                                               if(!(a)) {                                                     LOG(ERROR) << " CHECK failed " << endl                                 << #a << "= " << (a) << endl;                 abort();                                               }
#define CHECK_NOTNULL(a)                                       if( NULL == (a)) {                                             LOG(ERROR) << " CHECK_NOTNULL failed "                                 << #a << "== NULL " << endl;                  abort();                                                }

#define CHECK_NULL(a)                                          if( NULL != (a)) {                                             LOG(ERROR) << " CHECK_NULL failed " << endl                            << #a << "!= NULL " << endl;                  abort();                                                }

#define CHECK_EQ(a, b)                                         if(!((a) == (b))) {                                            LOG(ERROR) << " CHECK_EQ failed "  << endl                             << #a << "= " << (a) << endl                              << #b << "= " << (b) << endl;                 abort();                                                }

#define CHECK_NE(a, b)                                         if(!((a) != (b))) {                                            LOG(ERROR) << " CHECK_NE failed " << endl                              << #a << "= " << (a) << endl                              << #b << "= " << (b) << endl;                 abort();                                                }

#define CHECK_LT(a, b)                                         if(!((a) < (b))) {                                             LOG(ERROR) << " CHECK_LT failed "                                      << #a << "= " << (a) << endl                              << #b << "= " << (b) << endl;                 abort();                                                }

#define CHECK_GT(a, b)                                         if(!((a) > (b))) {                                             LOG(ERROR) << " CHECK_GT failed "  << endl                            << #a <<" = " << (a) << endl                               << #b << "= " << (b) << endl;                 abort();                                                }

#define CHECK_LE(a, b)                                         if(!((a) <= (b))) {                                            LOG(ERROR) << " CHECK_LE failed "  << endl                             << #a << "= " << (a) << endl                              << #b << "= " << (b) << endl;                 abort();                                                }

#define CHECK_GE(a, b)                                         if(!((a) >= (b))) {                                            LOG(ERROR) << " CHECK_GE failed "  << endl                             << #a << " = "<< (a) << endl                               << #b << "= " << (b) << endl;                 abort();                                                }

#define CHECK_DOUBLE_EQ(a, b)                                  do {                                                           CHECK_LE((a), (b)+0.000000000000001L);                     CHECK_GE((a), (b)-0.000000000000001L);                  }while (0)

#endif

logger.cpp文件源码:

#include "logger.h"
#include <cstdlib>
#include <ctime>

std::ofstream Logger::m_error_log_file;
std::ofstream Logger::m_info_log_file;
std::ofstream Logger::m_warn_log_file;

void initLogger(const std::string&info_log_filename,
                const std::string&warn_log_filename,
               const std::string&error_log_filename){
   Logger::m_info_log_file.open(info_log_filename.c_str());
   Logger::m_warn_log_file.open(warn_log_filename.c_str());
   Logger::m_error_log_file.open(error_log_filename.c_str());
}

std::ostream& Logger::getStream(log_rank_tlog_rank){
   return (INFO == log_rank) ?
                (m_info_log_file.is_open() ?m_info_log_file : std::cout) :
                (WARNING == log_rank ?
                    (m_warn_log_file.is_open()? m_warn_log_file : std::cerr) :
                    (m_error_log_file.is_open()? m_error_log_file : std::cerr));
}

std::ostream& Logger::start(log_rank_tlog_rank,
                            const int32 line,
                            const std::string&function) {
   time_t tm;
   time(&tm);
   char time_string[128];
   ctime_r(&tm, time_string);
   return getStream(log_rank) << time_string
                               << "function (" << function << ")"
                               << "line " << line
                               <<std::flush;
}

Logger::~Logger(){
   getStream(m_log_rank) << std::endl << std::flush;

   if (FATAL == m_log_rank) {
       m_info_log_file.close();
       m_info_log_file.close();
       m_info_log_file.close();
       abort();
    }
}

使用方法如下:

第一步,通过给定三个日志文件的路径,调用初始化函数initLogger进行日志文件的创建。

第二步,在需要插入日志的地方调用LOG(TYPE)<<”yourinfo”;即可。your info表示你要输入到日志文件中的信息。

以WARN日志为例,输出的信息大致如下:

Sun Jul  5 09:49:48 2015

function (getNextTask) line 75 no task to berun

Sun Jul  5 09:49:53 2015

function (getNextTask) line 75 no task to berun

Sun Jul  5 09:49:58 2015

function (getNextTask) line 75 no task to berun

Sun Jul  5 09:50:03 2015

function (getNextTask) line 75 no task to berun

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-11 16:52:25

C++实现简易log日志系统的相关文章

使用 SLF4J + LogBack 构建日志系统(转)

转载自:http://www.cnblogs.com/mailingfeng/p/3499436.html 上次我们讨论了如何选择一个好的开源日志系统方案,其中的结论是:使用 SLF4J + LogBack 是一个很好的选择.这篇文章就来讲讲如何快速地搭建起这套日志系统. 一.简介 LogBack是一个日志框架,它与Log4j可以说是同出一源,都出自Ceki Gülcü之手.(log4j的原型是早前由Ceki Gülcü贡献给Apache基金会的) LogBack.Slf4j.Log4j 之间的

SpringBoot 日志系统

日志框架 开发一个大型系统的简易步骤: system.out.println("..") 将关键的数据在控制台输出 框架记录系统的一些运行时的信息,---日志框架. 牛逼的功能---异步模式,自动归档等等... 进一步发展,卸掉旧得框架,并且修改之前的API, JDBC 数据库驱动,JDC 数据库驱动: 写一个统一的接口层: 日志门面,(日志的一个抽象层) 给项目导入具体的日志实现,之前的框架都是实现的抽象层 主流的日志框架 JUL.JCL.Jboss-logging.logback.

【Yii系列】错误处理和日志系统

缘起 跟随上一章的脚步,上一章中,我们主要讲解了在用户发起请求,解析请求,服务器反馈请求以及session的一些知识点,这过程中,难免会遇到一些问题,比方说数据库查询失败,用户输入导致脚本出错,网络问题等等突发情况,对于突发情况,做过软件的一般都知道,会有错误处理和日志去记录下这个过程,同样的,Yii也提供了类似的功能帮助我们去抓住错误,记录错误,并且对相应错误做出对应处理. 错误处理 Yii 内置了一个error handler错误处理器. 所有非致命PHP错误(如,警告,提示)会转换成可获取

DNS的视图功能以及日志系统

实验环境:RHEL5.8 32Bit DNS的视图功能以及日志系统详解 DNS的主配置文件中的allow-recursion参数用来定义能够和DNS服务器进行递归的客户端来源,allow-query参数用来定义允许到DNS服务器上面发起查询请求的客户端,allow-transfer参数用来定义允许和DNS服务器进行区域传送的客户端,区域传送主要有两种方式,axfr和ixfr,使用dig命令也可以模拟实现区域传送: 如果我们的DNS服务器允许进行递归.发起查询请求以及进行区域传送的客户端比较多的话

Linux上的日志系统

Syslog Syslog-ng 日志系统:syslogd() A: B: D: syslog服务: syslogd:系统,非内核产生的信息 klogd:内核,专门负责记录内科产生的日志 kernel –物理终端(dev/console)--/var/log/dmesg 日志需求滚动(日志切割): messages message.1  message.2 /sbin/init /var/log/messages,系统保准错误日志,非内核产生引导信息:各子系统产生的信息: /var/log/ma

日志系统之基于flume收集docker容器日志

最近我在日志收集的功能中加入了对docker容器日志的支持.这篇文章简单谈谈策略选择和处理方式. 关于docker的容器日志 docker 我就不多说了,这两年火得发烫.最近我也正在把日志系统的一些组件往docker里部署.很显然,组件跑在容器里之后很多东西都会受到容器的制约,比如日志文件就是其中之一. 当一个组件部署到docker中时,你可以通过如下命令在标准输出流(命令行)中查看这个组件的日志: docker logs ${containerName} 日志形如: 但这种方式并不能让你实时获

atitit. 日志系统的原则and设计and最佳实践(1)-----原理理论总结.

atitit. 日志系统的原则and设计and最佳实践总结. 1. 日志系统是一种不可或缺的单元测试,跟踪调试工具 1 2. 日志系统框架通常应当包括如下基本特性 1 1. 所输出的日志拥有自己的分类. 2 2. 日志按照某种标准分成不同级别. 2 3. 支持多线程. 2 4. 稳定性. 2 3. 一个理想的日志模式 2 4. 判断指定的方法是否被调用了 3 5. 给方法的输入输出加上日志通过Aop 3 6. 日志易读,易解析  对日志感兴趣的可以分为两类: 3 7. 输出日志使用的性能 3 8

MySQL日志系统

body { font-family: Helvetica, arial, sans-serif; font-size: 14px; line-height: 1.6; padding-top: 10px; padding-bottom: 10px; background-color: white; padding: 30px } body>*:first-child { margin-top: 0 !important } body>*:last-child { margin-bottom:

使用Slf4j集成Log4j2构建项目日志系统的完美解决方案

一.背景 最近因为公司项目性能需要,我们考虑把以前基于的log4j的日志系统重构成基于Slf4j和log4j2的日志系统,因为,使用slf4j可以很好的保证我们的日志系统具有良好的兼容性,兼容当前常见几种日志系统,而使用log4j2而不是log4j是因为Log4j 1.x 在高并发情况下出现死锁导致cpu使用率异常飙升,而Log4j2.0基于LMAX Disruptor的异步日志在多线程环境下性能会远远优于Log4j 1.x和logback(官方数据是10倍以上). 关于slf4j的原理以及优点