• Nx C++程序使用spdlog库进行日志存储


    1 spdlog简介

    spdlog是一个开源的日志库,在github上有。代码见这里文档这里

    C++语言的,支持Linux、windows等系统。
    csdn上也有许多介绍,这里列举两个:12

    2 使用

    2.1下载编译链接

    有多种使用方式,这里介绍下,将源代码直接链接编译的方式:代码见这里
    下载后,在Nx的QtCreator中,将Include中的代码放到代码下,然后,在pro文件中加入定义:SPDLOG_COMPILED_LIB,如下图所示。
    在这里插入图片描述

    2.2 使用的例子

    官方的一个使用的例子,这里贴出来,可以参考。
    ps:在下载文件的example文件下有。

    //
    // Copyright(c) 2015 Gabi Melman.
    // Distributed under the MIT License (http://opensource.org/licenses/MIT)
    
    // spdlog usage example
    
    #include 
    #include 
    
    void load_levels_example();
    void stdout_logger_example();
    void basic_example();
    void rotating_example();
    void daily_example();
    void async_example();
    void binary_example();
    void vector_example();
    void stopwatch_example();
    void trace_example();
    void multi_sink_example();
    void user_defined_example();
    void err_handler_example();
    void syslog_example();
    void udp_example();
    void custom_flags_example();
    void file_events_example();
    void replace_default_logger_example();
    
    #include "spdlog/spdlog.h"
    #include "spdlog/cfg/env.h"  // support for loading levels from the environment variable
    #include "spdlog/fmt/ostr.h" // support for user defined types
    
    int main(int, char *[])
    {
        // Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
        load_levels_example();
    
        spdlog::info("Welcome to spdlog version {}.{}.{}  !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);
    
        spdlog::warn("Easy padding in numbers like {:08d}", 12);
        spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
        spdlog::info("Support for floats {:03.2f}", 1.23456);
        spdlog::info("Positional args are {1} {0}..", "too", "supported");
        spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left");
    
        // Runtime log levels
        spdlog::set_level(spdlog::level::info); // Set global log level to info
        spdlog::debug("This message should not be displayed!");
        spdlog::set_level(spdlog::level::trace); // Set specific logger's log level
        spdlog::debug("This message should be displayed..");
    
        // Customize msg format for all loggers
        spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v");
        spdlog::info("This an info message with custom format");
        spdlog::set_pattern("%+"); // back to default format
        spdlog::set_level(spdlog::level::info);
    
        // Backtrace support
        // Loggers can store in a ring buffer all messages (including debug/trace) for later inspection.
        // When needed, call dump_backtrace() to see what happened:
        spdlog::enable_backtrace(10); // create ring buffer with capacity of 10  messages
        for (int i = 0; i < 100; i++)
        {
            spdlog::debug("Backtrace message {}", i); // not logged..
        }
        // e.g. if some error happened:
        spdlog::dump_backtrace(); // log them now!
    
        try
        {
            stdout_logger_example();
            basic_example();
            rotating_example();
            daily_example();
            async_example();
            binary_example();
            vector_example();
            multi_sink_example();
            user_defined_example();
            err_handler_example();
            trace_example();
            stopwatch_example();
            udp_example();
            custom_flags_example();
            file_events_example();
            replace_default_logger_example();
    
            // Flush all *registered* loggers using a worker thread every 3 seconds.
            // note: registered loggers *must* be thread safe for this to work correctly!
            spdlog::flush_every(std::chrono::seconds(3));
    
            // Apply some function on all registered loggers
            spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); });
    
            // Release all spdlog resources, and drop all loggers in the registry.
            // This is optional (only mandatory if using windows + async log).
            spdlog::shutdown();
        }
    
        // Exceptions will only be thrown upon failed logger or sink construction (not during logging).
        catch (const spdlog::spdlog_ex &ex)
        {
            std::printf("Log initialization failed: %s\n", ex.what());
            return 1;
        }
    }
    
    #include "spdlog/sinks/stdout_color_sinks.h"
    // or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
    void stdout_logger_example()
    {
        // Create color multi threaded logger.
        auto console = spdlog::stdout_color_mt("console");
        // or for stderr:
        // auto console = spdlog::stderr_color_mt("error-logger");
    }
    
    #include "spdlog/sinks/basic_file_sink.h"
    void basic_example()
    {
        // Create basic file logger (not rotated).
        auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt", true);
    }
    
    #include "spdlog/sinks/rotating_file_sink.h"
    void rotating_example()
    {
        // Create a file rotating logger with 5mb size max and 3 rotated files.
        auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
    }
    
    #include "spdlog/sinks/daily_file_sink.h"
    void daily_example()
    {
        // Create a daily logger - a new file is created every day on 2:30am.
        auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
    }
    
    #include "spdlog/cfg/env.h"
    void load_levels_example()
    {
        // Set the log level to "info" and mylogger to "trace":
        // SPDLOG_LEVEL=info,mylogger=trace && ./example
        spdlog::cfg::load_env_levels();
        // or from command line:
        // ./example SPDLOG_LEVEL=info,mylogger=trace
        // #include "spdlog/cfg/argv.h" // for loading levels from argv
        // spdlog::cfg::load_argv_levels(args, argv);
    }
    
    #include "spdlog/async.h"
    void async_example()
    {
        // Default thread pool settings can be modified *before* creating the async logger:
        // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread.
        auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
        // alternatively:
        // auto async_file = spdlog::create_async("async_file_logger", "logs/async_log.txt");
    
        for (int i = 1; i < 101; ++i)
        {
            async_file->info("Async message #{}", i);
        }
    }
    
    // Log binary data as hex.
    // Many types of std::container types can be used.
    // Iterator ranges are supported too.
    // Format flags:
    // {:X} - print in uppercase.
    // {:s} - don't separate each byte with space.
    // {:p} - don't print the position on each line start.
    // {:n} - don't split the output to lines.
    
    #include "spdlog/fmt/bin_to_hex.h"
    void binary_example()
    {
        std::vector<char> buf(80);
        for (int i = 0; i < 80; i++)
        {
            buf.push_back(static_cast<char>(i & 0xff));
        }
        spdlog::info("Binary example: {}", spdlog::to_hex(buf));
        spdlog::info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
        // more examples:
        // logger->info("uppercase: {:X}", spdlog::to_hex(buf));
        // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
        // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
        // logger->info("hexdump style: {:a}", spdlog::to_hex(buf));
        // logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20));
    }
    
    // Log a vector of numbers
    #ifndef SPDLOG_USE_STD_FORMAT
    #    include "spdlog/fmt/ranges.h"
    void vector_example()
    {
        std::vector<int> vec = {1, 2, 3};
        spdlog::info("Vector example: {}", vec);
    }
    
    #else
    void vector_example() {}
    #endif
    
    // ! DSPDLOG_USE_STD_FORMAT
    
    // Compile time log levels.
    // define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE)
    void trace_example()
    {
        // trace from default logger
        SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23);
        // debug from default logger
        SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23);
    
        // trace from logger object
        auto logger = spdlog::get("file_logger");
        SPDLOG_LOGGER_TRACE(logger, "another trace message");
    }
    
    // stopwatch example
    #include "spdlog/stopwatch.h"
    #include 
    void stopwatch_example()
    {
        spdlog::stopwatch sw;
        std::this_thread::sleep_for(std::chrono::milliseconds(123));
        spdlog::info("Stopwatch: {} seconds", sw);
    }
    
    #include "spdlog/sinks/udp_sink.h"
    void udp_example()
    {
        spdlog::sinks::udp_sink_config cfg("127.0.0.1", 11091);
        auto my_logger = spdlog::udp_logger_mt("udplog", cfg);
        my_logger->set_level(spdlog::level::debug);
        my_logger->info("hello world");
    }
    
    // A logger with multiple sinks (stdout and file) - each with a different format and log level.
    void multi_sink_example()
    {
        auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
        console_sink->set_level(spdlog::level::warn);
        console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");
    
        auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
        file_sink->set_level(spdlog::level::trace);
    
        spdlog::logger logger("multi_sink", {console_sink, file_sink});
        logger.set_level(spdlog::level::debug);
        logger.warn("this should appear in both console and file");
        logger.info("this message should not appear in the console, only in the file");
    }
    
    // User defined types logging
    struct my_type
    {
        int i = 0;
        explicit my_type(int i)
            : i(i){};
    };
    
    #ifndef SPDLOG_USE_STD_FORMAT // when using fmtlib
    template<>
    struct fmt::formatter<my_type> : fmt::formatter<std::string>
    {
        auto format(my_type my, format_context &ctx) -> decltype(ctx.out())
        {
            return format_to(ctx.out(), "[my_type i={}]", my.i);
        }
    };
    
    #else // when using std::format
    template<>
    struct std::formatter<my_type> : std::formatter<std::string>
    {
        auto format(my_type my, format_context &ctx) -> decltype(ctx.out())
        {
            return format_to(ctx.out(), "[my_type i={}]", my.i);
        }
    };
    #endif
    
    void user_defined_example()
    {
        spdlog::info("user defined type: {}", my_type(14));
    }
    
    // Custom error handler. Will be triggered on log failure.
    void err_handler_example()
    {
        // can be set globally or per logger(logger->set_error_handler(..))
        spdlog::set_error_handler([](const std::string &msg) { printf("*** Custom log error handler: %s ***\n", msg.c_str()); });
    }
    
    // syslog example (linux/osx/freebsd)
    #ifndef _WIN32
    #    include "spdlog/sinks/syslog_sink.h"
    void syslog_example()
    {
        std::string ident = "spdlog-example";
        auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
        syslog_logger->warn("This is warning that will end up in syslog.");
    }
    #endif
    
    // Android example.
    #if defined(__ANDROID__)
    #    include "spdlog/sinks/android_sink.h"
    void android_example()
    {
        std::string tag = "spdlog-android";
        auto android_logger = spdlog::android_logger_mt("android", tag);
        android_logger->critical("Use \"adb shell logcat\" to view this message.");
    }
    #endif
    
    // Log patterns can contain custom flags.
    // this will add custom flag '%*' which will be bound to a  instance
    #include "spdlog/pattern_formatter.h"
    class my_formatter_flag : public spdlog::custom_flag_formatter
    {
    public:
        void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override
        {
            std::string some_txt = "custom-flag";
            dest.append(some_txt.data(), some_txt.data() + some_txt.size());
        }
    
        std::unique_ptr<custom_flag_formatter> clone() const override
        {
            return spdlog::details::make_unique<my_formatter_flag>();
        }
    };
    
    void custom_flags_example()
    {
    
        using spdlog::details::make_unique; // for pre c++14
        auto formatter = make_unique<spdlog::pattern_formatter>();
        formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
        // set the new formatter using spdlog::set_formatter(formatter) or logger->set_formatter(formatter)
        // spdlog::set_formatter(std::move(formatter));
    }
    
    void file_events_example()
    {
        // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications
        spdlog::file_event_handlers handlers;
        handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); };
        handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) {
            spdlog::info("After opening {}", filename);
            fputs("After opening\n", fstream);
        };
        handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) {
            spdlog::info("Before closing {}", filename);
            fputs("Before closing\n", fstream);
        };
        handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); };
        auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/events-sample.txt", true, handlers);
        spdlog::logger my_logger("some_logger", file_sink);
        my_logger.info("Some log line");
    }
    
    void replace_default_logger_example()
    {
        // store the old logger so we don't break other examples.
        auto old_logger = spdlog::default_logger();
    
        auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true);
        spdlog::set_default_logger(new_logger);
        spdlog::set_level(spdlog::level::info);
        spdlog::debug("This message should not be displayed!");
        spdlog::set_level(spdlog::level::trace);
        spdlog::debug("This message should be displayed..");
    
        spdlog::set_default_logger(old_logger);
    }
    
    
    • 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
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381

    2.3 我的一个例子

        auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
        console_sink->set_level(spdlog::level::warn);
        console_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e %^%l%$] %v");
        
       //循环日志文件,每个10M,最多10个文件
        auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("logs/Log.txt", 1048576 * 10, 10);
        file_sink->set_level(spdlog::level::trace);
        file_sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e %L] %v");
    
        spdlog::logger * pLogger = new spdlog::logger("multi_sink", {console_sink, file_sink});
        pLogger->set_level(spdlog::level::debug);
    
        // Flush all *registered* loggers using a worker thread every 3 seconds.
        // note: registered loggers *must* be thread safe for this to work correctly!
        spdlog::flush_every(std::chrono::seconds(3));			//定时刷新
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2.4 关于循环日志文件

    上面的文件中有了,补充下多个文件时候的关系。
    当前写的文件为Log.txt,一旦写满后,将其更名为Log.1.txt。再新建一个Log.txt,写入
    如果新Log.txt再次满后,将Log.1.txt更名为Log.2.txt。将Log.txt更名为Log.1.txt,然后再新建一个Log.txt写入。

    2.5 关于设置日志格式

    这里有官方说明:https://github.com/gabime/spdlog/wiki/3.-Custom-formatting

    2.6 关于头文件

    这里面有很多头文件,使用不同功能需要引入不同的功能,见上面的例子吧,这点确实麻烦。

    2.7 关于输出

    保存的日志文件时,有一个刷新的机制。可以设置定时更新。如下。这里实际使用时候,除了定时外,貌似跟数据量也有关系,如果数据量少时候,也不输出!
    具体见:https://github.com/gabime/spdlog/wiki/7.-Flush-policy

    spdlog::flush_every(std::chrono::seconds(3));			//定时刷新
    
    • 1
  • 相关阅读:
    mysql配置项整理
    web前端期末大作业——基于HTML+CSS+JavaScript蓝色的远程监控设备系统后台管理界面模板
    Python Flask
    Window对象加载时的区别与倒计时
    【CNN-SVM回归预测】基于CNN-SVM实现数据回归预测附matlab代码
    自己实现 SpringMVC 底层机制 系列之-实现任务阶段 4- 完成自定义@Service 注解功能
    花椰菜的 8 大健康益处,为你一一盘点
    minio之分布式安装
    YOLOv8教程系列:五、关闭数据增强
    基于DeOldify的给黑白照片、视频上色
  • 原文地址:https://blog.csdn.net/kevinshift/article/details/128176574