• spdlog 封装为 DLL


    项目中需要快速写入巨量日志,一开始用的是boost::log,但遇到崩溃问题,程序负载大了,滚动日志时偶尔会崩溃,总是报:
    boost::filesystem_errorbad_year, bad_month 一些问题。在boost官网,和github上的 boostlog 项目 issue中窥见些端倪,说是boost::filesystem存在问题blabla
    枉我还一直很信任 boost ,还是换个日志库吧。

    github 上 spdlog 星星比 boost::log 多多了,boost::log 好像用的人挺少。

    这一换发现:相比boost::log,spdlog 速度又快,占内存又小(取决于队列长度)

    使用 spdlog1.10.0 封装的 dll

    • 使用这个dll,你的项目不用再依赖 spdlog 头文件
    • C 风格的字符串格式化语法
    • 同步/异步、滚动日志
    • 程序退出前需要调用静态方法 shutdown()
    • VS2019 编译通过
      在这里插入图片描述
    // log_spd.h
    #pragma once
    #include 
    #ifndef LOG_LIB_H
    #define LOG_LIB_H
    
    #ifdef _MSC_VER
    #define LOG_API _declspec(dllexport)
    #else
    #define LOG_API 
    #endif
    
    class SpdlogWrapper;
    
    enum class lv {
        trace,
        debug,
        info,
        warn,
        error,
        fatal
    };
    
    class LOG_API Logger
    {
    public:
        Logger();
        Logger(const std::string& file, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);
        Logger(const Logger&);
        Logger& operator=(const Logger&);
        ~Logger();
    
        // 返回一个日志对象
        static Logger createLogger(const std::string& filename, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);
    
        // 全局设置。定时写日志到文件。0 秒则不启用
        static void setFlushEverySec(int sec);
    
        // 设置日志文件
        void setFileName(const std::string&);
    
        // 设置日志前缀格式;default: [%Y-%m-%d %H:%M:%S.%e][%t][%l] %v
        void setFormat(const std::string&);
    
        // 设置日志等级,大于此等级才写入文件
        void setLevel(lv);
    
        // 设置滚动日志文件
        void setRotateFile(int size /* MB */, int count);
    
        // 设置立即写到文件的日志等级
        void setFlushOnLevel(lv);
    
        // 是否异步日志,default: true
        void setAsyncMode(bool);
    
        // 设置异步日志队列长度。默认 256。经测试,队列更长,占用内存更大,未见性能明显提升
        void setAsyncQueueSize(int);
    
        // 在调用 setXX 类函数之后,最后调用 init(); 赋值操作后,被赋值的对象需要重新 init()
        void init();
        void init(const std::string& file, lv level=lv::trace, int rotateFileSize=100 /* MB */, int rotateFileCount=5);
    
        // 格式化后的字符串最大长度: 1024
        void trace(const char* fmt, ...);
        void info(const char* fmt, ...);
        void debug(const char* fmt, ...);
        void warn(const char* fmt, ...);
        void error(const char* fmt, ...);
        void fatal(const char* fmt, ...);
    
        // 异步模式:通知缓冲, 要求写入日志文件;
        // 同步模式:立即写入日志文件
        void flush();
    
        // EXE 主程序退出前需要调用。因为 spdlog 在 windows 上存在问题关不掉程序
        // 如果是在 dll 中使用此日志库,你的 dll 需要提供接口来让 EXE 程序在退出前主动调用到此函数
        static void shutdown();
    
    private:
        SpdlogWrapper* m_logWrapper;
    };
    
    
    #endif // LOG_LIB_H
    
    
    • 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
    // log_spd.cpp
    #pragma once
    #include "log_spd.h"
    #include "log_wrapper.h"
    
    
    Logger::Logger() : m_logWrapper(nullptr)
    {
        m_logWrapper = new SpdlogWrapper(DEFAULT_FILE, lv::trace, 100, 5);
    }
    
    Logger::Logger(const std::string& file,
        lv level,
        int rotateFileSize, // MB
        int rotateFileCount) : m_logWrapper(nullptr)
    {
        m_logWrapper = new SpdlogWrapper(file, level, rotateFileSize, rotateFileCount);
    }
    
    Logger::Logger(const Logger& logger)
    {
        m_logWrapper = new SpdlogWrapper(*logger.m_logWrapper);
    }
    
    Logger& Logger::operator=(const Logger& logger)
    {
        delete m_logWrapper;
        m_logWrapper = new SpdlogWrapper(*logger.m_logWrapper);
        return *this;
    }
    
    Logger::~Logger()
    {
        delete m_logWrapper;
    }
    
    void Logger::init()
    {
        m_logWrapper->init();
    }
    
    void Logger::init(const std::string& file, lv level, int rotateFileSize, int rotateFileCount)
    {
        m_logWrapper->m_fileName = file;
        m_logWrapper->m_logLevel = level;
        m_logWrapper->m_fileSize = rotateFileSize;
        m_logWrapper->m_fileCount = rotateFileCount;
        m_logWrapper->init();
    }
    
    Logger Logger::createLogger(const std::string& filename, lv level, int rotateFileSize, int rotateFileCount)
    {
        return Logger(filename, level, rotateFileSize, rotateFileCount);
    }
    void Logger::setAsyncMode(bool enabled)
    {
        m_logWrapper->m_async = enabled;
    }
    
    void Logger::flush()
    {
        m_logWrapper->flush();
    }
    
    void Logger::setFileName(const std::string& file)
    {
        m_logWrapper->m_fileName = file;
    }
    
    void Logger::setFormat(const std::string& fmt)
    {
        m_logWrapper->m_fmt = fmt;
    }
    
    void Logger::setLevel(lv level)
    {
        m_logWrapper->m_logLevel = level;
    }
    
    void Logger::setFlushOnLevel(lv level)
    {
        m_logWrapper->m_flushOnLevel = (int)level;
    }
    
    void Logger::setFlushEverySec(int sec)
    {
        SpdlogWrapper::FlushEverySec = sec;
    }
    
    void Logger::setAsyncQueueSize(int size)
    {
        m_logWrapper->m_queueSize = size;
    }
    
    void Logger::setRotateFile(int rotateFileSize, int rotateFileCount)
    {
        m_logWrapper->m_fileSize = rotateFileSize;
        m_logWrapper->m_fileCount = rotateFileCount;
    }
    
    void Logger::shutdown()
    {
        SpdlogWrapper::shutdown();
    }
    
    void Logger::trace(const char* fmt, ...)
    {
        if (m_logWrapper->m_logLevel > lv::trace)
            return;
    
        char buff[BUFF_SIZE];
        va_list ap;
        va_start(ap, fmt);
        vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
        va_end(ap);
        m_logWrapper->write(buff, lv::trace);
    }
    
    void Logger::info(const char* fmt, ...)
    {
        if (m_logWrapper->m_logLevel > lv::info)
            return;
    
        char buff[BUFF_SIZE];
        va_list ap;
        va_start(ap, fmt);
        vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
        va_end(ap);
        m_logWrapper->write(buff, lv::info);
    }
    
    void Logger::debug(const char* fmt, ...)
    {
        if (m_logWrapper->m_logLevel > lv::debug)
            return;
    
        char buff[BUFF_SIZE];
        va_list ap;
        va_start(ap, fmt);
        vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
        va_end(ap);
        m_logWrapper->write(buff, lv::debug);
    }
    
    void Logger::warn(const char* fmt, ...)
    {
        if (m_logWrapper->m_logLevel > lv::warn)
            return;
    
        char buff[BUFF_SIZE];
        va_list ap;
        va_start(ap, fmt);
        vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
        va_end(ap);
        m_logWrapper->write(buff, lv::warn);
    }
    
    void Logger::error(const char* fmt, ...)
    {
        if (m_logWrapper->m_logLevel > lv::error)
            return;
    
        char buff[BUFF_SIZE];
        va_list ap;
        va_start(ap, fmt);
        vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
        va_end(ap);
        m_logWrapper->write(buff, lv::error);
    }
    
    void Logger::fatal(const char* fmt, ...)
    {
        if (m_logWrapper->m_logLevel > lv::fatal)
            return;
    
        char buff[BUFF_SIZE];
        va_list ap;
        va_start(ap, fmt);
        vsnprintf_s(buff, BUFF_SIZE, fmt, ap);
        va_end(ap);
        m_logWrapper->write(buff, lv::fatal);
    }
    
    • 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
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    // log_wrapper.h
    #pragma once
    #ifndef LOG_API_H
    #define LOG_API_H
    #include 
    #include "spdlog/spdlog.h"
    #include "spdlog/async.h"
    #include "spdlog/sinks/rotating_file_sink.h"
    #include "spdlog/details/thread_pool.h"
    
    static const int BUFF_SIZE = 1024;
    const std::string DEFAULT_FILE = "log.log";
    const std::string DEFAULT_FMT = "[%Y-%m-%d %H:%M:%S.%e][%t][%l] %v";
    
    class SpdlogWrapper
    {
    
    public:
        SpdlogWrapper(const std::string& file, lv level, int rotateFileSize, int rotateFileCount);
        SpdlogWrapper(const SpdlogWrapper&);
        ~SpdlogWrapper();
    
        void init();
        void write(const char* msg, lv level);
        void flush();
    
        static void shutdown();
    
        static int FlushEverySec;
        static int Id;
        static bool GlobalAttr;
    
        bool m_async;
        int m_queueSize;
        lv m_logLevel;
        int m_flushOnLevel;
        int m_fileCount;
        int m_fileSize;
        std::string m_fileName;
        std::string m_fmt;
    
    private:
        std::string m_logName;
        std::shared_ptr<spdlog::logger> m_spdLogger;
        std::shared_ptr<spdlog::details::thread_pool> m_tp;
        std::shared_ptr<spdlog::sinks::rotating_file_sink_mt> m_sink;
    
        void initGlobalAttr();
    };
    #endif //LOG_API_H
    
    
    • 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
    // log_wrapper.cpp
    #pragma once
    #include "log_spd.h"
    #include "log_wrapper.h"
    
    
    int SpdlogWrapper::Id = 0;
    int SpdlogWrapper::FlushEverySec = 3;
    bool SpdlogWrapper::GlobalAttr = false;
    SpdlogWrapper::SpdlogWrapper(const std::string& file, lv level, int rotateFileSize, int rotateFileCount)
        : m_fileCount(rotateFileCount), 
        m_fileSize(rotateFileSize), 
        m_logLevel(level), 
        m_fileName(file), 
        m_flushOnLevel(-1),
        m_fmt(DEFAULT_FMT), 
        m_logName(""), 
        m_queueSize(256),
        m_async(true)
    {
    
    }
    
    SpdlogWrapper::SpdlogWrapper(const SpdlogWrapper& log)
    {
        m_fileCount = log.m_fileCount;
        m_fileSize = log.m_fileSize;
        m_logLevel = log.m_logLevel;
        m_fileName = log.m_fileName;
        m_flushOnLevel = log.m_flushOnLevel;
        m_fmt = log.m_fmt;
        m_logName = "";
        m_queueSize = log.m_queueSize;
        m_async = log.m_async;
    
        m_spdLogger = nullptr;
        m_tp = nullptr;
        m_sink = nullptr;
    }
    
    void SpdlogWrapper::init()
    {
        if (m_spdLogger)
            spdlog::drop(m_logName);
    
        initGlobalAttr();
    
        m_logName = "__log__" + std::to_string(SpdlogWrapper::Id++);
        if (m_async) {
            m_tp = std::make_shared<spdlog::details::thread_pool>(m_queueSize, 1U);
            m_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(m_fileName, m_fileSize * 1024 * 1024, m_fileCount);
            m_spdLogger = std::make_shared<spdlog::async_logger>(m_logName, m_sink, m_tp, spdlog::async_overflow_policy::block);
            spdlog::register_logger(m_spdLogger);
        }
        else 
            m_spdLogger = spdlog::rotating_logger_mt(m_logName, m_fileName, (size_t)m_fileSize * 1024 * 1024, m_fileCount);
    
        m_spdLogger->set_pattern(m_fmt);
        m_spdLogger->set_level((spdlog::level::level_enum)m_logLevel);
    
        if (m_flushOnLevel >= 0)
            m_spdLogger->flush_on((spdlog::level::level_enum)m_flushOnLevel);
    }
    
    void SpdlogWrapper::initGlobalAttr()
    {
        if (!SpdlogWrapper::GlobalAttr) {
            spdlog::flush_every(std::chrono::seconds(SpdlogWrapper::FlushEverySec));
            SpdlogWrapper::GlobalAttr = true;
        }
    }
    
    void SpdlogWrapper::write(const char* msg, lv level)
    {
        SPDLOG_LOGGER_CALL(m_spdLogger, (spdlog::level::level_enum)level, msg);
    }
    
    void SpdlogWrapper::flush()
    {
        if (m_spdLogger)
            m_spdLogger->flush();
    }
    
    void SpdlogWrapper::shutdown()
    {
        spdlog::drop_all();
        spdlog::shutdown();
    }
    
    SpdlogWrapper::~SpdlogWrapper()
    {
        if (m_spdLogger)
            spdlog::drop(m_logName);
    }
    
    • 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
    • 90
    • 91
    • 92
    • 93
    • 94

    使用

    // main.cpp
    
    #include "log_spd.h"
    
    int main(int argc, char  *argv[])
    {
    	Logger logger, logger2;
    	// Logger logger = Logger::createLogger("mylog.log", lv::trace, 100, 5);
    	logger.setAsyncMode(false); 
    	logger.init();
    	logger.trace("Hello %s, you are the %dth visitor.", "Tony", 1);
    	logger.flush();
    	
    	logger2 = logger;
    	logger2.setAsyncMode(true);
    	logger2.setFormat("%+");
    	logger2.init("mylog.log");
    	logger2.info("blasa bad w");
    	logger2.flush();
    	
    	Logger::shutdown();
    	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

    log.log

    [2022-09-30 14:32:25.065][9532][trace] Hello Tony, you are the 1th visitor.

    mylog.log

    [2022-09-30 14:32:25.069] [__log__1] [info] [log_wrapper.cpp:75] blasa bad woa

    缺点

    • 输出日志所在的代码文件、行号不是调用封装接口的行。比如上面的 [log_wrapper.cpp:75]

    编译好的库

  • 相关阅读:
    【LeetCode454. 四数相加 II】——map型哈希表
    Ansys Zemax | 大功率激光系统的 STOP 分析1:如何使用 OpticStudio 优化光学设置
    requestAnimationFrame 和 setTimeout 的区别
    ssm计算机系统结构综合考核管理系统 毕业设计源码26480
    LabVIEW代码生成错误 61056
    【从0开始学架构】访问层架构设计
    naive-ui的n-data-table标签奇特bug记录
    Fiddler使用界面——会话栏与过滤器
    聊一聊redis奇葩数据类型与集群知识
    HC32L110(四) HC32L110的startup启动文件和ld连接脚本
  • 原文地址:https://blog.csdn.net/wn0112/article/details/127106041