完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
|
|
相关推荐
1个回答
|
|
最近整理代码,看到了公司的关于日志方面的代码,收获比较大,所以整理一下spdlog库的使用说明。
本文主要是以下几个方面的整理,参考的主要依据就是 官方例程,位于github的 exampleexample.cpp 1. 日志等级的划分以及和日志等级相关的几个函数 日志分成了以下的这几个等级,具体的等级就是其中的含义 ,最严重的的时间就是 critical 级别 ,最不严重的是trace /* spdlog::level::trace */ /* spdlog::level::debug */ /* spdlog::level::info */ /* spdlog::level::warn */ /* spdlog::level::err */ /* spdlog::level::critical */ /* spdlog::level::off */ 实际的使用中可以使用这种方法直接的输出日志 spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); //[2021-04-07 22:46:35.840] [info] Welcome to spdlog version 1.8.5 ! 在开发中还会 去使用 m_logger->info(“xxxxxxxxxxxxxxx”) 这种形式进行输出,添加上指针主要是方便将不同的日志输出到不同的位置,例如将m_log1对应的内容 输出到文件1 ; m_log2的内容输出到文件2; 1.1 spdlog::set_level(spdlog::level::trace) 这个函数主要是设置日志的输出等级,在调试阶段我们希望输出较多的调试信息,而当程序稳定之后我们只需要输出少量的重要的信息,如报错等。 这个时候就需要设置日志的输出等级。 spdlog::set_level就是设置输出等级的函数。 1.2 logger->flush_on(spdlog::level::err); 遇到错误及以上级别会立马将缓存的buffer写到文件中,底层调用是std::fflush(_fd) 2. 日志的字符格式介绍 因为在spdlog 大量的使用了模板函数所以函数的使用很灵活 所有的格式的参数都可以使用 {} 来替代。 2.1 打乱参数的顺序 括号内的变量可以分为两部分 如果只填入一个数字的话 则代表参数的序号 spdlog::info("Positional args are {1} {0}..", "too", "supported"); //[2021-04-07 23:49:24.916] [info] Positional args are supported too.. 上面的例子中参数的顺序是按照括号内的序号去取的。 2.2 格式化的数字输出 和printf类似,spdlog也支持格式化的字符输出。 spdlog::warn("Easy padding in numbers like {:08d}", 12); // [2021-04-07 23:49:24.916] [warning] Easy padding in numbers like 00000012 spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); // [2021-04-07 23:49:24.916] [critical] Support for int: 42; hex: 2a; oct: 52; bin: 101010 spdlog::info("Support for floats {1:06.4f}", 1.23456,9.8754321); // [2021-04-07 23:49:24.916] [info] Support for floats 9.8754 spdlog::info("Positional args are {1} {0}..", "too", "supported"); // [2021-04-07 23:49:24.916] [info] Positional args are supported too.. spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left"); // [2021-04-07 23:49:24.916] [info] right aligned, left aligned 2.3 去掉日志的时间的方法 觉得日志的时间打印太占用存储空间? ,可以这样去掉日志的时间打印 m_log->set_pattern("%v"); 1 2.4 记录16进制数字的一些方法 以下 来自官方的 readme 文件 // many types of std::container // 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. // {:a} - show ASCII if :n is not set. #include "spdlog/fmt/bin_to_hex.h" void binary_example() { auto console = spdlog::get("console"); std::array console->info("Binary example: {}", spdlog::to_hex(buf)); console->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)); } 2.5 关于时间,线程等的输出格式 这里网上的大佬写的非常好 https://blog.csdn.net/shizheng163/article/details/79418190 1 除了上面大佬的总结之外,我还找到了关于格式解析的代码段,大家可以直接看代码得出格式的意思! // 代码取自 includespdlogpattern_formatter-inl.h 约 1100 行的位置 switch (flag) { case ('+'): // default formatter formatters_.push_back(details::make_unique break; case 'n': // logger name formatters_.push_back(details::make_unique break; case 'l': // level formatters_.push_back(details::make_unique break; case 'L': // short level formatters_.push_back(details::make_unique break; case ('t'): // thread id formatters_.push_back(details::make_unique break; case ('v'): // the message text formatters_.push_back(details::make_unique break; case ('a'): // weekday formatters_.push_back(details::make_unique break; case ('A'): // short weekday formatters_.push_back(details::make_unique break; case ('b'): case ('h'): // month formatters_.push_back(details::make_unique break; case ('B'): // short month formatters_.push_back(details::make_unique break; case ('c'): // datetime formatters_.push_back(details::make_unique break; case ('C'): // year 2 digits formatters_.push_back(details::make_unique break; case ('Y'): // year 4 digits formatters_.push_back(details::make_unique break; case ('D'): case ('x'): // datetime MM/DD/YY formatters_.push_back(details::make_unique break; case ('m'): // month 1-12 formatters_.push_back(details::make_unique break; case ('d'): // day of month 1-31 formatters_.push_back(details::make_unique break; case ('H'): // hours 24 formatters_.push_back(details::make_unique break; case ('I'): // hours 12 formatters_.push_back(details::make_unique break; case ('M'): // minutes formatters_.push_back(details::make_unique break; case ('S'): // seconds formatters_.push_back(details::make_unique break; case ('e'): // milliseconds formatters_.push_back(details::make_unique break; case ('f'): // microseconds formatters_.push_back(details::make_unique break; case ('F'): // nanoseconds formatters_.push_back(details::make_unique break; case ('E'): // seconds since epoch formatters_.push_back(details::make_unique break; case ('p'): // am/pm formatters_.push_back(details::make_unique break; case ('r'): // 12 hour clock 02:55:02 pm formatters_.push_back(details::make_unique break; case ('R'): // 24-hour HH:MM time formatters_.push_back(details::make_unique break; case ('T'): case ('X'): // ISO 8601 time format (HH:MM:SS) formatters_.push_back(details::make_unique break; case ('z'): // timezone formatters_.push_back(details::make_unique break; case ('P'): // pid formatters_.push_back(details::make_unique break; case ('^'): // color range start formatters_.push_back(details::make_unique break; case ('$'): // color range end formatters_.push_back(details::make_unique break; case ('@'): // source location (filename:filenumber) formatters_.push_back(details::make_unique break; case ('s'): // short source filename - without directory name formatters_.push_back(details::make_unique break; case ('g'): // full source filename formatters_.push_back(details::make_unique break; case ('#'): // source line number formatters_.push_back(details::make_unique break; case ('!'): // source funcname formatters_.push_back(details::make_unique break; case ('%'): // % char formatters_.push_back(details::make_unique break; case ('u'): // elapsed time since last log message in nanos formatters_.push_back(details::make_unique break; case ('i'): // elapsed time since last log message in micros formatters_.push_back(details::make_unique break; case ('o'): // elapsed time since last log message in millis formatters_.push_back(details::make_unique break; case ('O'): // elapsed time since last log message in seconds formatters_.push_back(details::make_unique break; 3. 日志的输出形式 文件/打印/远程打印 解决了前面的日志生成的格式的问题,接下来分析一下日志的去向的问题。 spdlog提供了多种的日志去向,为了兼容不同的平台又分别的实现了不同平台下的日志去向,但是这些大致是分成了这几类 直接打印本地控制台 打印到远程控制台 写入文件的 自定义类型 ( 你完全可以照着 标准的格式自己定义你的日志要输出到哪里!!!) 对于第一类的打印到控制台是最简单的一种,最直接的就是使用printf 这种函数去实现,spdlog 还为我们实现了彩色打印,也就是打印信息中附带了控制台的颜色信息,可以控制打印出来的字符的颜色! 他们对应的实现类也就是 includespdlogsinksstdout_color_sinks.h # 彩色的打印输出 includespdlogsinksstdout_sinks.h # 无色的打印输出 对于第二类,spdlog 主要提供了一个tcp的客户端的例子,可以将本地的日志写到远程的tcp 客户端 他的实现是 includespdlogsinkstcp_sink.h # 注意 老版本没有这个文件,笔者是 1.8.5 版本的 对于第三类写文件的这一类,实现的就更加的多样化。 ① 最简单粗暴的就是直接写一个日志文件,不限制大小。这种的缺陷很大,但是也不失简单。 # includespdlogsinksbasic_file_sink.h ② 滚动文件式,设定一个文件最大的大小以及最多的文件数量,系统就可以自动的去写文件,如果文件大小超出了设定的最大的单个文件的大小,就会将当前文件重命名,然后另起一个文件继续写日志。 //includespdlogsinksrotating_file_sink.h // Rotate files: // log.txt -> log.1.txt // log.1.txt -> log.2.txt // log.2.txt -> log.3.txt // log.3.txt -> delete ③ 就是定时的写文件,然后以时间命名。根据周期又分为 每天更新,每小时更新 # includespdlogsinksdaily_file_sink.h # Generator of daily log file names in format basename.YYYY-MM-DD.ext # includespdlogsinkshourly_file_sink.h # Generator of Hourly log file names in format basename.YYYY-MM-DD-HH.ext ④ 最后简单记录一下自定义的日志类型,项目中用到了这个日志库,但是我们希望项目的产品能作为TCP的服务端,当我们的调试器连接到产品上的时候,产品会将实时的日志打印到调试器(电脑上位机)上。 其实 主要就是需要去实现一下 _sink_it() 和 _flush()函数,这里就不去细说了。 4 .日志的多输出 有一些情况下,我希望日志不但显示在控制台 还去写入文件,这个时候就有必要去使用日志的多重输出的功能。 这在默认的demo 里面有提到 // spdlogexampleexample.cpp // 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 console_sink->set_level(spdlog::level::warn); console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); auto file_sink = std::make_shared 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"); } 更多的使用技巧我也需要去学习。 |
|
|
|
只有小组成员才能发言,加入小组>>
914 浏览 0 评论
1224 浏览 1 评论
2592 浏览 5 评论
2927 浏览 9 评论
移植了freeRTOS到STMf103之后显示没有定义的原因?
2788 浏览 6 评论
keil5中manage run-time environment怎么是灰色,不可以操作吗?
1306浏览 3评论
240浏览 2评论
513浏览 2评论
421浏览 2评论
M0518 PWM的电压输出只有2V左右,没有3.3V是怎么回事?
498浏览 1评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-2-14 07:00 , Processed in 0.959837 second(s), Total 77, Slave 58 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191