• C++项目实战——基于多设计模式下的同步&异步日志系统-⑫-日志宏&全局接口设计(代理模式)


    专栏导读

    🌸作者简介:花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。

    🌸专栏简介:本文收录于 C++项目——基于多设计模式下的同步与异步日志系统

    🌸相关专栏推荐:C语言初阶系列C语言进阶系列 C++系列数据结构与算法Linux

    在这里插入图片描述

    日志宏&全局接口设计

    本章我们将完成提供全局接口&宏函数,对日志系统接口进行使用便捷性优化(避免用户自己创建单例)。

    设计思想:

    • 提供获取指定日志器的全局接口(避免用户自己操作单例对象);
    • 使用宏函数对日志器的接口进行代理(代理模式);
    • 提供宏函数,直接通过默认日志器进行日志的标准输出打印(省去获取日志器的操作);
    #ifndef __MY_LOG__
    #define __MY_LOG__
    #include "logger.hpp"
    
    namespace LOG
    {
        // 1.提供获取指定日志器的全局接口(避免用户自己操作单例对象)
        Logger::ptr getLogger(const std::string &name)
        {
            return LOG::LoggerManager::getInstance().getLogger(name);
        }
        Logger::ptr rootLogger()
        {
            return LOG::LoggerManager::getInstance().rootLogger();
        }
    
        // 2.实用宏函数对日志器的接口进行代理(代理模式)
        #define debug(fmt, ...) debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
        #define info(fmt, ...) info(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
        #define warn(fmt, ...) warn(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
        #define error(fmt, ...) error(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
        #define fatal(fmt, ...) fatal(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
    
        // 3.提供宏函数,直接通过默认日志器进行日志的标准输出打印
        #define DEBUG(fmt, ...) LOG::rootLogger()->debug(fmt, ##__VA_ARGS__)
        #define INFO(fmt, ...) LOG::rootLogger()->info(fmt, ##__VA_ARGS__)
        #define WARN(fmt, ...) LOG::rootLogger()->warn(fmt, ##__VA_ARGS__)
        #define ERROR(fmt, ...) LOG::rootLogger()->error(fmt, ##__VA_ARGS__)
        #define FATAL(fmt, ...) LOG::rootLogger()->fatal(fmt, ##__VA_ARGS__)
    
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    全局接口测试

    测试代码

    void log_test()
    {
        DEBUG("%s", "测试日志");
        INFO("%s", "测试日志");
        WARN("%s", "测试日志");
        ERROR("%s", "测试日志");
        FATAL("%s", "测试日志");
    
        size_t count = 0;
        while(count < 300000)
        {
            FATAL("测试日志-%d", count++);
        }
    }
    int main()
    {
    	log_test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    项目目录结构整理

    在这里插入图片描述

    示例代码

    // example/test.cc
    #include "../logs/log.h"
    #include 
    
    void log_test(const std::string& name)
    {
        INFO("%s", "测试开始");
        LOG::Logger::ptr logger = LOG::LoggerManager::getInstance().getLogger("async_logger");
        logger->debug(__FILE__, __LINE__, "%s", "测试日志");
        logger->info(__FILE__, __LINE__, "%s", "测试日志");
        logger->warn(__FILE__, __LINE__, "%s", "测试日志");
        logger->error(__FILE__, __LINE__, "%s", "测试日志");
        logger->fatal(__FILE__, __LINE__, "%s", "测试日志");
        INFO("%s", "测试完毕");
    }
    int main()
    {
        std::unique_ptr<LOG::LoggerBuilder> builder(new LOG::GlobalLoggerBuilder());
        builder->buildLoggerName("async_logger");
        builder->buildLoggerLevel(LOG::LogLevel::value::WARN);
        builder->buildFormatter("[%c][%f:%l]%m%n");
        builder->buildLoggerType(LOG::LoggerType::LOGGER_ASYNC);
        builder->buildSink<LOG::FileSink>("./logfile/async.log");
        builder->buildSink<LOG::StdOutSink>();
        builder->buildSink<LOG::RollBySizeSink>("./logfile/roll-async-by-size", 1024 * 1024);
        builder->build();
        log_test("async_logger");
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    拓展示例代码

    // extent/test.cc
    #include "../logs/log.h"
    #include 
    
    enum class TimeGap
    {
        GAP_SECOND,
        GAP_MINUTE,
        GAP_HOUR,
        GAP_DAY
    };
    class RollByTimeSink : public LOG::LogSink
    {
    public:
        // 构造时传入文件名,并打开文件,将操作句柄管理起来
        RollByTimeSink(const std::string &basename, TimeGap gap_type) : _basename(basename)
        {
            switch(gap_type)
            {
            case TimeGap::GAP_SECOND: _gap_size = 1; break;
            case TimeGap::GAP_MINUTE: _gap_size = 60; break;
            case TimeGap::GAP_HOUR: _gap_size = 3600; break;
            case TimeGap::GAP_DAY: _gap_size = 3600 * 24; break;
            }
            _cur_gap = _gap_size == 1? LOG::util::Date::getTime() : LOG::util::Date::getTime() % _gap_size; // 获取当前是第几个时间段
            std::string filename = createNewFile();
            LOG::util::File::createDirectory(LOG::util::File::path(filename));
            _ofs.open(filename, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }
    
        // 将日志消息写入到标准输出,判断当前时间是否是当前文件的时间段,不是则切换文件
        void log(const char* data, size_t len)
        {
            time_t cur = LOG::util::Date::getTime();
            if((cur % _gap_size) != _cur_gap)
            {
                _ofs.close();
                std::string filename = createNewFile();
                _ofs.open(filename, std::ios::binary | std::ios::app);
                assert(_ofs.is_open());
            }
            _ofs.write(data, len);
            assert(_ofs.good());
        }
    private:
        std::string createNewFile()
        {
            time_t t = LOG::util::Date::getTime();
            struct tm lt;
            localtime_r(&t, &lt);
            std::stringstream filename;
            filename << _basename;
            filename << lt.tm_year + 1900;
            filename << lt.tm_mon + 1;
            filename << lt.tm_mday;
            filename << lt.tm_hour;
            filename << lt.tm_min;
            filename << lt.tm_sec;
            filename << "-";
            filename << ".log";
            return filename.str();
        }
    private:
        std::string _basename;
        size_t _gap_size; // 时间段的大小
        int _cur_gap; // 当前是第几个时间段
        std::ofstream _ofs;
    };
    
    int main()
    {
        std::unique_ptr<LOG::LoggerBuilder> builder(new LOG::GlobalLoggerBuilder());
        builder->buildLoggerName("async_logger");
        builder->buildLoggerLevel(LOG::LogLevel::value::WARN);
        builder->buildFormatter("[%c][%f:%l]%m%n");
        builder->buildLoggerType(LOG::LoggerType::LOGGER_ASYNC);
        builder->buildSink<LOG::FileSink>("./logfile/async.log");
        builder->buildSink<LOG::StdOutSink>();
        builder->buildSink<RollByTimeSink>("./logfile/roll-async-by-time", TimeGap::GAP_SECOND);
        LOG::Logger::ptr logger = builder->build();
        size_t cur = LOG::util::Date::getTime();
        while(LOG::util::Date::getTime() < cur + 5)
        {
            logger->fatal("这是一条测试日志");
        }
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    在这里插入图片描述

  • 相关阅读:
    (WebFlux)004、WebFilter踩坑记录
    微服务框架
    webpack--加载器(loader)
    设计模式:02观察者模式--labview实现
    C++ 虚函数表原理和类的内存分布
    计算机毕业设计springboot+vue基本微信小程序的学生健康管理小程序
    【51单片机】51单片机概述(学习笔记)
    【MySQL】Error Code: 1153 - Got a packet bigger than ‘max_allowed_packet‘ bytes
    内部振荡器、无源晶振、有源晶振有什么区别?
    转行软件测试,薪资10K | 真正明智的人,懂得脚踏实地 ...
  • 原文地址:https://blog.csdn.net/gllll_yu/article/details/133861109