从0开始Linux(45)——日志系统

欢迎来到博主的专栏:从0开始linux
博主ID:代码小豪

文章目录

    • 日志的使用方式
    • 日志源码

日志的使用方式

在较为大型的项目当中,如果发生了程序崩溃,使用gdp或者vs当中的调试模式排查报错原因有点太慢了,而且如果是系统调用出现错误的话,有可能会出现此次运行失败,下次运行就没问题的情况出现,因此一个日志系统是必不可少的,因此博主给大家设计出一个日志系统,在后续博主的文章(linux网络编程)当中,也会采取日志的方式查看运行信息,因此给大家了解一下博主的日志系统。这里不解释日志的运行原理,因为这些接口在前面的文章中都有介绍。

首先日志可以通过控制台输出的方式(即屏幕),或者文件的方式,因此我们的日志类需要定义出这两种不同的策略,这里博主选择使用宏来确定日志信息的输出方式。

#define CONVERT_CONSOLE_LOG() logmodule::logger.ConverConsoleStrategy()//向控制台输出日志
#define CONVERT_FILE_LOG() logmodule::logger.ConverFileStrategy()//向文件输出日志

首先要将该日志系统的头文件加在项目当中,后续如果我们想让日志向控制台输出日志,则使用宏CONVERT_CONSOLE_LOG(),若是向文件输出日志,则使用宏CONVERT_FILE_LOG(),如果我们选择向文件输出日志,则会在当前文件夹当中出现一个叫做log的文件夹,在文件夹当中会包含一个log.txt的文件,文件当中的内容则是日志信息。

博主设计了五个日志等级,分别是DEBUG,INFO,WARRING,ERROR,FATAL。其中DEBUG表示该日志是调试信息,INFO表示正常运行,WARRING表示运行出现了可能导致崩溃的警告,ERROR表示运行出现错误(导致运行结果出错的错误),FATAL表示运行出现了巨大的错误(导致程序崩溃的错误)

enum class loglevel{
        DEBUG=1,
        INFO,
        WARRING,
        ERROR,
        FATAL
    };
#define DEBUG logmodule::loglevel::DEBUG
#define INFO logmodule::loglevel::INFO
#define WARRING logmodule::loglevel::WARRING
#define ERROR logmodule::loglevel::ERROR
#define FATAL logmodule::loglevel::FATAL

最后博主定义了一个宏,通过这个宏可以输出日志信息。

#define LOG(LEVEL) (logmodule::logger(LEVEL,__FILE__,__LINE__))

下面是该日志系统使用的范例代码:

#include"log.hpp"

using namespace logmodule;
int main()
{
    CONVERT_FILE_LOG();//向文件输出日志
    LOG(DEBUG)<<"hello FILE";//向日志文件输出hello file
    LOG(DEBUG)<<"hello FILE";
    LOG(DEBUG)<<"hello FILE";
    LOG(DEBUG)<<"hello FILE";
    CONVERT_CONSOLE_LOG();//向控制台输出日志
    LOG(DEBUG)<<"hello world";//向控制台输出hello world
    LOG(DEBUG)<<"hello world";
    LOG(DEBUG)<<"hello world";
    LOG(DEBUG)<<"hello world";
    return 0;
}

使用方式为:LOG(日志等级)<<“日志信息”,可以使用多个<<来输出更多的信息,类似于cout的使用方式,但是要注意,endl无法用来作为换行符。

日志源码

#pragma once
#include "mutex.hpp"
#include 
#include 
#include 
#include  //c++17
#include 
#include
#include
namespace logmodule
{
    std::string defaultpath = "./log";   // 日志默认生成路径
    std::string defaultfile = "/log.txt"; // 日志默认生成文件

    enum class loglevel{
        DEBUG=1,
        INFO,
        WARRING,
        ERROR,
        FATAL
    };

    std::string currtime()//获取当前时间
    {
        char buf[1024];
        time_t timestamp=time(nullptr);
        struct tm time;
        localtime_r(&timestamp,&time);
        snprintf(buf,sizeof(buf),"%d-%d-%d %d:%d:%d",\
        time.tm_year+1900,time.tm_mon+1,time.tm_mday,\
        time.tm_hour,time.tm_min,time.tm_sec);
        return std::string(buf);
    }

    std::string leveltostring(loglevel level)
    {
        std::string str;
        switch (level)
        {
        case loglevel::DEBUG:str="DEBUG";
            break;
        case loglevel::ERROR:str="ERROR";
            break;
        case loglevel::FATAL:str="FATAL";
            break;
        case loglevel::WARRING:str="WARRING";
            break;
        case loglevel::INFO:str="INFO";
            break;
        }
        return str;
    }

    class LogStrategy // 接口类
    {
    public:
        virtual void LogStrategysync(std::string &message) = 0; // 刷新日志
        virtual ~LogStrategy(){}
    };

    class ConsoleLogStrategy : public LogStrategy // 继承接口类,向控制台输出日志
    {
    public:
        void LogStrategysync(std::string &message)
        {
            mutexmodule::lockgroud lock(_mutex);
            std::cerr << message << std::endl;
        }
        ~ConsoleLogStrategy()
        {
        }

    private:
        mutexmodule::mutex _mutex;
    };

    class FileLogStrategy : public LogStrategy // 继承接口类,向文件输出日志
    {
    public:
        FileLogStrategy() : _filename(defaultfile), _filepath(defaultpath)
        {
            mutexmodule::lockgroud lock(_mutex);
            if (std::filesystem::exists(_filepath))
                return;
            try
            {
                std::filesystem::create_directory(_filepath);
            }
            catch (std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << std::endl;
            }
        }
        FileLogStrategy(const std::string &filepath, std::string &filename) : _filename(filename), _filepath(filepath)
        {
            mutexmodule::lockgroud lock(_mutex);
            if (std::filesystem::exists(_filepath))
                return;
            try
            {
                std::filesystem::create_directory(_filepath);
            }
            catch (std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << std::endl;
            }
        }
        void LogStrategysync(std::string &message)
        {
            mutexmodule::lockgroud lock(_mutex);
            std::string file = _filepath + _filename;
            std::ofstream out(file.c_str(), std::ofstream::app);
            out << message << '\n';
            out.close();
        }

    private:
        std::string _filepath;
        std::string _filename;
        mutexmodule::mutex _mutex;
    };

    class Logger
    {
    public:
        Logger(){
            _strategy=std::make_shared<ConsoleLogStrategy>();//默认策略是是使用控制台输出日志信息
        }
        void ConverConsoleStrategy(){
            _strategy=std::make_shared<ConsoleLogStrategy>();
        }
        void ConverFileStrategy(std::string filepath,std::string filename){
            _strategy=std::make_shared<FileLogStrategy>(filepath,filename);
        }
        void ConverFileStrategy(){
            _strategy=std::make_shared<FileLogStrategy>();
        }
        //日志信息封装成类
        class LogMessage
        {
        public:
            LogMessage(loglevel level,std::string filename,int line,Logger& log)//构造出message的大部分固定内容
            :_time(currtime())
            ,_level(level)
            ,_pid(::getpid())
            ,_filename(filename)
            ,_line(line)
            ,_log(log)
            {
                std::stringstream ss;
                ss<<'['<<_time<<"] ["<<leveltostring(_level)<<"] ["<<_pid<<"] ["<<_filename<<"] ["<<_line<<"] -";
                message=ss.str();
            }

            template<class T>
            LogMessage& operator<<(const T& data)
            {
                std::stringstream ss;
                ss<<data;
                message+=ss.str();
                return *this;
            }

            ~LogMessage(){
                _log._strategy->LogStrategysync(message);
            }
        private:
            std::string _time;//当前时间
            loglevel _level;
            pid_t _pid;
            std::string _filename;
            int _line;
            std::string message;
            Logger& _log;
        };

        LogMessage operator()(loglevel level,std::string filename,int line)
        {
            return LogMessage(level,filename,line,*this);
        }
        ~Logger()=default;
    private:
        std::shared_ptr<LogStrategy> _strategy;
    };

    Logger logger;
}
#define LOG(LEVEL) (logmodule::logger(LEVEL,__FILE__,__LINE__))
#define CONVERT_CONSOLE_LOG() logmodule::logger.ConverConsoleStrategy()
#define CONVERT_FILE_LOG() logmodule::logger.ConverFileStrategy()
#define DEBUG logmodule::loglevel::DEBUG
#define INFO logmodule::loglevel::INFO
#define WARRING logmodule::loglevel::WARRING
#define ERROR logmodule::loglevel::ERROR
#define FATAL logmodule::loglevel::FATAL

这里的mutex类是博主自己封装的互斥锁库,大家可以使用c++里面的mutex类对象来替换,或者也引用博主自己封装的mutex.hpp库,源码如下:

#pragma once
#include
#include

namespace mutexmodule
{
    class mutex
    {
    public:
        mutex(){
            pthread_mutex_init(&_mutex,nullptr);
        }
        void lock()
        {
            pthread_mutex_lock(&_mutex);
        }
        pthread_mutex_t* addr()
        {
            return &_mutex;
        }
        void unlock()
        {
            pthread_mutex_unlock(&_mutex);
        }
        ~mutex(){
            pthread_mutex_destroy(&_mutex);
        }
    private:
        pthread_mutex_t _mutex;
    };

    class lockgroud
    {
    public:
        lockgroud(mutex& lock):_mutex(lock){
            _mutex.lock();
        }
        ~lockgroud(){
            _mutex.unlock();
            // std::cout<<"开锁成功"<
        }
    private:
        mutex& _mutex;
    };
}

你可能感兴趣的:(从0开始linux,linux,前端,运维,c++)