<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【C++】spdlog光速入門,C++logger最簡(jiǎn)單最快的庫(kù)

      參考文檔:https://spdlog.docsforge.com/master/

      spdlog簡(jiǎn)介

      Very fast, header only, C++ logging library.
      一個(gè)header-only的C++日志庫(kù),十分高效且易用。

      獲取安裝方式

      https://github.com/gabime/spdlog
      使用時(shí)只需要將git項(xiàng)目?jī)?nèi)的/include/spdlog文件夾整個(gè)放入項(xiàng)目的include目錄下即可

      使用樣例

      #include "spdlog/spdlog.h"
      
      int main() 
      {
          spdlog::info("Welcome to spdlog!");
          spdlog::error("Some error message with arg: {}", 1);
          
          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("{:<30}", "left aligned");
          
          spdlog::set_level(spdlog::level::debug); // Set global log level to debug
          spdlog::debug("This message should be displayed..");    
          
          // change log pattern
          spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
          
          // Compile time log levels
          // define SPDLOG_ACTIVE_LEVEL to desired level
          SPDLOG_TRACE("Some trace message with param {}", 42);
          SPDLOG_DEBUG("Some debug message");
      }
      

      快速入門

      幾個(gè)核心概念

      • logger:日志對(duì)象,每個(gè)日志內(nèi)包含一個(gè)sink組成的vector,每個(gè)sink可以分別設(shè)置優(yōu)先級(jí),logger本身也可設(shè)置優(yōu)先級(jí)
      • sink:直譯是水槽,實(shí)際上是引流的對(duì)象或者可以認(rèn)為是輸出目標(biāo),spdlog庫(kù)內(nèi)置了多種不同類型的logger可供選擇
      • formatter:格式化對(duì)象,絕大部分情況下spdlog默認(rèn)的格式就足夠用了,但是如果有個(gè)性化需求,可以進(jìn)行自定義格式
      • level:日志級(jí)別,不同的日志庫(kù)可能會(huì)有不同的設(shè)置,但是基本情況下都會(huì)有debug、info、warn、error等的級(jí)別劃分來處理不同的情況,具體各個(gè)級(jí)別的情況可以根據(jù)自己的實(shí)際情況選取

      邏輯關(guān)系:每個(gè)logger包含一個(gè)vector,該vector由一個(gè)或多個(gè)std::shared_ptr<sink>組成,logger的每條日志都會(huì)調(diào)用sink對(duì)象,由sink對(duì)象按照formatter的格式輸出到sink指定的地方(有可能是控制臺(tái)、文件等),接下來我們從內(nèi)到外的講解spdlog的這三個(gè)核心組件

      formatter

      formatter也即格式化對(duì)象,用于控制日志的輸出格式,spdlog自帶了默認(rèn)的formatter,一般情況下,我們無需任何修改,直接使用即可。注意,每個(gè)sink會(huì)有一個(gè)formatter

      默認(rèn)formatter

      默認(rèn)formatter的格式為:[日期時(shí)間] [logger名] [log級(jí)別] log內(nèi)容

      [2022-10-13 17:00:55.795] [service] [debug] found env XXXXXXX : true
      [2022-10-13 17:00:55.795] [func_config] [debug] kafka_brokers : localhost:9092
      [2022-10-13 17:00:55.795] [func_config] [debug] kafka_main_topic : kafka_test
      [2022-10-13 17:00:55.795] [func_config] [debug] kafka_partition_value : -1
      [2022-10-13 17:00:55.795] [service] [info] initialized
      

      自定義formatter

      如果默認(rèn)的formatter不符合需求,可以自定義formatter,具體方式如下

      • set_parrtern(pattern_string);
        • 例如:
        • 全局級(jí)別的:spdlog::set_pattern(" [%H:%M:%S %z] [thread %t] %v ");
        • 單個(gè)logger級(jí)別的:some_logger->set_parttern(">>> %H:%M:%S %z %v <<<");
        • 單個(gè)sink級(jí)別的:some_sink-> set_parttern(".. %H: %M ..");
          其中用到了%H %M這些占位符,事實(shí)上它們都是預(yù)先設(shè)定好的,想要查看所有的占位符情況,可以參考以下網(wǎng)站:
          https://spdlog.docsforge.com/v1.x/3.custom-formatting/#pattern-flags

      sink

      每個(gè)sink對(duì)應(yīng)著一個(gè)輸出目標(biāo)和輸出格式,它內(nèi)部包含一個(gè)formatter,輸出目標(biāo)可以是控制臺(tái)、文件等地方。
      所有的sink都在命名空間spdlog::sinks下,可以自行探索

      控制臺(tái)sink

      spdlog中創(chuàng)建控制臺(tái)sink非常簡(jiǎn)單,該方式創(chuàng)建的sink會(huì)輸出到命令行終端,且是彩色的(也可以選非彩色的,但是有彩色的應(yīng)該都會(huì)選彩色的吧……)。后綴的_mt代表多線程,_st代表單線程

      auto sink1 = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
      

      文件sink

      文件sink的類型有很多,這里展示幾種經(jīng)典類型

      auto sink1 = std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_file_name);//最簡(jiǎn)單的文件sink,只需要指定文件名
      
      auto sink2 = std::make_shared<spdlog::sinks::daily_file_sink_mt>(log_file_name, path, 14, 22);//每天的14點(diǎn)22分在path下創(chuàng)建新的文件
      
      auto sink3 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, 1024 * 1024 * 10, 100, false);//輪轉(zhuǎn)文件,一個(gè)文件滿了會(huì)寫到下一個(gè)文件,第二個(gè)參數(shù)是單文件大小上限,第三個(gè)參數(shù)是文件數(shù)量最大值
      

      其他sink

      ostream_sink
      syslog_sink
      ......
      也可以通過繼承base_sink創(chuàng)建子類來自定義sink,具體可以參考:
      https://spdlog.docsforge.com/v1.x/4.sinks/#implementing-your-own-sink

      sink的flush問題

      創(chuàng)建好sink后建議設(shè)置flush方式,否則可能無法立刻在file中看到logger的內(nèi)容
      以下為兩種重要的flush方式設(shè)置(直接設(shè)置全局)

      spdlog::flush_every(std::chrono::seconds(1));
      spdlog::flush_on(spdlog::level::debug);
      

      logger

      日志對(duì)象,每個(gè)logger內(nèi)包含了一個(gè)vector用于存放sink,每個(gè)sink都是相互獨(dú)立
      因此一個(gè)日志對(duì)象在輸出日志時(shí)可以同時(shí)輸出到控制臺(tái)和文件等位置

      使用默認(rèn)logger

      如果整個(gè)項(xiàng)目中只需要一個(gè)logger,spdlog提供了最為便捷的默認(rèn)logger,注意,該logger在全局公用,輸出到控制臺(tái)、多線程、彩色

      //Use the default logger (stdout, multi-threaded, colored)
      spdlog::info("Hello, {}!", "World");
      

      創(chuàng)建特定的logger

      大部分情況下默認(rèn)logger是不夠用的,因?yàn)槲覀兛赡苄枰霾煌?xiàng)目模塊各自的logger,可能需要logger輸出到文件進(jìn)行持久化,所以創(chuàng)建logger是很重要的一件事。好在創(chuàng)建logger也是非常簡(jiǎn)單的!

      方式一:直接創(chuàng)建

      與創(chuàng)建sink類似,我們可以非常便捷的創(chuàng)建logger
      由于大部分時(shí)候一個(gè)logger只會(huì)有一個(gè)sink,所以spdlog提供了創(chuàng)建logger的接口并封裝了創(chuàng)建sink的過程

      auto console = spdlog::stdout_color_mt("some_unique_name");//一個(gè)輸出到控制臺(tái)的彩色多線程logger,可以指定名字
      auto file_logger = spdlog::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);//一個(gè)輸出到指定文件的輪轉(zhuǎn)文件logger,后面的參數(shù)指定了文件的信息
      

      方式二:組合sinks方式創(chuàng)建

      有時(shí)候,單sink的logger不夠用,那么可以先創(chuàng)建sink的vector,然后使用sinks_vector創(chuàng)建logger
      以下樣例中,首先創(chuàng)建了sink的vector,然后創(chuàng)建了兩個(gè)sink并放入vector,最后使用該vector創(chuàng)建了logger,其中,set_level的過程不是必須的,register_logger一般是必須的,否則只能在創(chuàng)建logger的地方使用該logger,關(guān)于register的問題可以往下看

          std::vector<spdlog::sink_ptr> sinks;
      
          auto sink1 = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
          sink1->set_level(MyLoggers::getGlobalLevel());
          sinks.push_back(sink1);
      
          auto sink2 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, 1024 * 1024 * 10, 100, false);
          sink2->set_level(spdlog::level::debug);
          sinks.push_back(sink2);
          
          auto logger = std::make_shared<spdlog::logger>("logger_name", begin(sinks), end(sinks));
          logger->set_level(spdlog::level::debug);
          spdlog::register_logger(logger);
      

      logger的注冊(cè)與獲取

      在一個(gè)地方創(chuàng)建了logger卻只能在該處使用肯定是不好用的,所以spdlog提供了一個(gè)全局注冊(cè)和獲取logger,我們只需要在某處先創(chuàng)建logger并注冊(cè),那么后面在其他地方使用時(shí)直接獲取就可以了
      注冊(cè):spdlog::register_logger()
      獲?。簊pdlog::get()

      //上面的代碼中我們注冊(cè)了一個(gè)logger,名字是logger_name,接下來嘗試獲取
      auto logger = MyLoggers::getLogger("logger_name");
      
      

      關(guān)于注冊(cè)與獲取需要注意的事

      • 必須先創(chuàng)建注冊(cè)才能獲取,建議每個(gè)模塊的logger都在整個(gè)模塊最開始初始化時(shí)創(chuàng)建并注冊(cè)。如果在全局嘗試獲取不存在的logger,會(huì)返回空指針,如果恰好又使用空指針嘗試輸出logger,會(huì)造成整個(gè)程序的崩潰(訪問非法內(nèi)存了,segment fault)
      • 通過上述的方式一創(chuàng)建的logger是自動(dòng)注冊(cè)的,不需要手動(dòng)注冊(cè),但是方式二創(chuàng)建的logger需要手動(dòng)注冊(cè)
      • 一旦注冊(cè),全局使用,名字標(biāo)識(shí)logger,在各個(gè)模塊獲取同一個(gè)名字的logger會(huì)獲取到同一個(gè)logger的指針

      logger的使用

      獲取到一個(gè)logger之后,就可以愉快的使用它了,使用起來很簡(jiǎn)單

      logger->debug("this is a debug msg");
      logger->warn("warn!!!!");
      logger->info("hello world");
      logger->error("燙燙燙燙");
      

      logger的level設(shè)置

      logger的默認(rèn)level是info,如果處于開發(fā)環(huán)境或者生產(chǎn)環(huán)境,會(huì)只需要debug級(jí)別以上或者warn級(jí)別以上的log
      要設(shè)置logger的級(jí)別,很簡(jiǎn)單:

      logger->set_level(spdlog::level::debug);
      

      可以設(shè)置全局logger級(jí)別

      spdlog::set_level(spdlog::level::warn);
      

      可以設(shè)置sink級(jí)別的logger

      sink1->set_level(spdlog::level::info);
      

      注意:一個(gè)logger內(nèi)假如有多個(gè)sink,那么這些sink分別設(shè)置level是可以不同的,但是由于logger本身也有l(wèi)evel,所以真正使用時(shí),logger的level如果高于某個(gè)sink,會(huì)覆蓋該sink的level,所以建議此時(shí)把logger的level手動(dòng)設(shè)置為debug(默認(rèn)為info)

      樣例代碼

      以下代碼為本人對(duì)spdlog的簡(jiǎn)單使用封裝,主要功能有:

      • 一鍵初始化,根據(jù)環(huán)境變量可設(shè)置修改logger級(jí)別等
      • 一鍵創(chuàng)建雙sink的logger(控制臺(tái)和文件)
      • 一鍵獲取logger,假如logger不存在則創(chuàng)建

      頭文件

      #ifndef MY_LOGGER_H
      #define MY_LOGGER_H
      
      #include <stdlib.h>
      #include "spdlog/spdlog.h"
      #include "spdlog/sinks/stdout_color_sinks.h"
      #include "spdlog/sinks/stdout_sinks.h"
      #include "spdlog/sinks/basic_file_sink.h"
      #include "spdlog/sinks/rotating_file_sink.h"
      #include "spdlog/sinks/daily_file_sink.h"
      #include <vector>
      
      class MyLoggers
      {
      public:
          static void init();
          static spdlog::level::level_enum getGlobalLevel();
          static std::vector<spdlog::sink_ptr> createSinks(const std::string &log_file_name);
          static void createLogger(const std::string &logger_name);
          static std::shared_ptr<spdlog::logger> getLogger(const std::string &logger_name);
      
      private:
          static spdlog::level::level_enum global_level;
      };
      
      #endif
      

      源文件

      #include "my_logger.h"
      
      spdlog::level::level_enum MyLoggers::global_level = spdlog::level::info;
      
      spdlog::level::level_enum MyLoggers::getGlobalLevel()
      {
          return global_level;
      }
      
      std::vector<spdlog::sink_ptr> MyLoggers::createSinks(const std::string &log_file_name)
      {
          std::vector<spdlog::sink_ptr> sinks;
      
          auto sink1 = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
          sink1->set_level(MyLoggers::getGlobalLevel());
          sinks.push_back(sink1);
      
          auto sink2 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, 1024 * 1024 * 10, 100, false);
          sink2->set_level(spdlog::level::debug);
          sinks.push_back(sink2);
          return sinks;
      }
      
      void MyLoggers::createLogger(const std::string &logger_name)
      {
          std::string log_file_name = logger_name + "_log.txt";
          auto sinks = MyLoggers::createSinks(log_file_name);
      
          auto logger = std::make_shared<spdlog::logger>(logger_name, begin(sinks), end(sinks));
          logger->set_level(spdlog::level::debug);
          spdlog::register_logger(logger);
      }
      
      std::shared_ptr<spdlog::logger> MyLoggers::getLogger(const std::string &logger_name){
          auto logger = spdlog::get(logger_name);
          if(!logger){//looger指向?yàn)榭?        createLogger(logger_name);
              logger = spdlog::get(logger_name);
          }
          return logger;
      }
      
      
      void MyLoggers::init()
      {
          auto level = spdlog::level::debug;
          if (std::getenv("STAGE") != NULL)
          {
              std::string stage = std::getenv("STAGE");
              if (stage == "dev")
                  level = spdlog::level::debug;
          }
          MyLoggers::global_level = level;
      
          spdlog::flush_every(std::chrono::seconds(1));
          spdlog::flush_on(spdlog::level::debug);
      
          MyLoggers::createLogger("service");
      }
      
      
      posted @ 2022-10-16 21:47  縉云燒餅  閱讀(17311)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 婷婷久久综合九色综合88| 俺来也俺去啦最新在线| 国产麻豆一区二区精彩视频| 中文字幕在线视频不卡| 中文字幕午夜福利片午夜福利片97| 女同另类激情在线三区| 国产成人无码免费视频麻豆| 久久综合久中文字幕青草| 野外做受三级视频| 欧美日韩精品一区二区三区在线| 国产成人亚洲日韩欧美| 亚洲av男人电影天堂热app | 小13箩利洗澡无码视频网站| 欧美日韩精品一区二区三区高清视频| 最新午夜男女福利片视频| 成人av片无码免费网站| 天堂av色综合久久天堂| 黑人巨大无码中文字幕无码| 国产成人精品亚洲精品密奴| 99热在线观看| 中文字幕乱码熟妇五十中出 | 国产午夜亚洲精品不卡网站| 大同市| 无码专区 人妻系列 在线| 五月天天天综合精品无码| 美女无遮挡免费视频网站| 国产免费一区二区三区在线观看| 日本乱码在线看亚洲乱码| 正安县| 大香伊蕉在人线国产最新2005 | 亚洲国产精品一区二区第一页| 国产亚洲精品AA片在线爽| A级毛片免费完整视频| 日本肉体xxxx裸交| 亚洲av永久无码天堂影院| 加勒比亚洲天堂午夜中文| 国产精品中文字幕二区| 怡红院一区二区三区在线| 免费观看的av在线播放| 亚洲AV无码久久精品日韩| 亚洲免费观看一区二区三区|