使用Line Pos Info 和 Modern C++ 改进打印日志记录
使用Line Pos Info 和 Modern C++ 改进打印日志记录
使用跟踪值:不管自己是多么的精通,可能仍然使用调试的主要方法之一 printf , TRaCE, outputDebugString, 等…然后扫描输出, 同时调试。
添加有关行号和日志消息来源的文件的信息是一种非常有效的方法,可以为你节省大量时间,在这篇文章将描述一个在visual Studio中特别有用的技巧,在其他IDE/编译器中有所帮助。
还将展示现在C++和C++20如何使代码更好。
常规
在调试C++代码时,将值输出到控制台或输出到窗口并扫描日志非常方便。
std::cout << "myval: " << val << endl;
可以通过添加LINE和FILE信息轻松增强此技术,这样就可以看到那条消息的来源。扫描大量日志时,这可能非常方便。
为什么会这么重要呢?就每个人来说,当我们试图查找某些日志输出的来源时,我们已经失去了很多时间。当我们看到一条消息时,我们会复制他,搜索解决方案,然后通常在滚动后终于找到了正确的代码行。那么有没有更为简便的方法呢?
将使用“标准”C++实现此代码,然后转到现代C++,最后看看C++20将会发生什么?
log4cpp 中添加需要打印的行号,文件名,函数名 (标准C++)
使用log4cpp中的Category的debug, error, info , warn 等方法输出,需要调试的信息:
root.debug(“Message”);
但最后用宏包装上面的函数:
#define logWarn(msg)\ my_logWarn(__LINE__,__FILE__,__FUNCTION__,msg)
通过logWarn(msg)使用;
上面代码调用logWarn(msg)内部调用的函数my_llogWarn。
为什么定义一个宏?当然,方便。否则,必须手动传递行号和文件名。无法在内部获取文件和行,my_logWarn 因为它始终指向实现的源代码my_logWarn而不是调用它的代码。
什么是 __ FILE __ 和 __ LINE __ ? 在vistual Studio 中,这下可以在代码中使用的预定义宏。顾名思义,他们会扩展到源代码的文件名和给定翻译单元中的确定行。要控制 __ FILE __ 宏, 可以使用编译器选项 /FC 。该选项使文件名更长(完整路径)或更短(相对于解决方案目录),请注意,/FC使用“编译并继续“时暗示。
注意, __ FILE __ 并且 __ LINE __ 也由标准制定,因此其他编译器也应该实现它。
void my_logWarn(int line,const char *filename,const char *funcName, const char *msg)
{
Mylog *log = Mylog::getInstance(); string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + std::string(filename) + " this is line: " + std::to_string(line) + " func name: " + string(funcName); log->Warn(tempMsg.c_str());
}
C++ 20
在C++20中有std::source_location
新的库类型声明如下:
struct source_location{
static constexpr source_location current () noexcept;
constexpr uint_lest32_t line() const noexcept;
constexpr uint_lest32_t column() const noexcept;
constexpr const char * filename() const noexcept;
constexpr const char *function_name() const noexcept;
}
一个基本的使用例子:
#include <iostream>
#include <string_view>
#include <experimental/source_location>
using namespace std;
using namespace std::experimental;
void log(const string_view& message,
const source_location& location = source_location::current())
{
std::cout << "info:"
<< location.file_name() << ":"
<< location.line() << " "
<< location.function_name() << " "
<< message << '\n';
}
int main()
{
log("Hello world!");
// another log
log("super extra!");
}
总结
简单介绍了增强的printf样式和日志记录
起初,使用的主要是C风格的标准代码,后来使用了现代C++进行更新,最后了使用了C++20中的source_location引入的新类型实现。
随着soure_location使我们可以跳过使用__ FILE __ 和 __ LINE __ 预定义宏,不过,日志宏(#define Log(…)) 是有帮助的,因为他可以隐藏于位置信息缺省参数。
base C++:
#pragma once #define logInfo(msg)\
my_logInfo(__LINE__,__FILE__,__FUNCTION__,msg)
#define logWarn(msg)\
my_logWarn(__LINE__,__FILE__,__FUNCTION__,msg)
#define logError(msg)\
my_logError(__LINE__,__FILE__,__FUNCTION__,msg)
#define logDebug(msg)\
my_logDebug(__LINE__,__FILE__,__FUNCTION__,msg)
#include <stdlib.h>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string; #include <log4cpp/Category.hh>
#include <log4cpp/Priority.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/RollingFileAppender.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/PatternLayout.hh> using namespace log4cpp;
class Mylog
{
public:
void Warn(const char *msg);
void Error(const char *msg);
void Debug(const char * msg);
void Info(const char * msg); static Mylog * getInstance()
{
if(_pInstance == nullptr){
_pInstance = new Mylog();
}
return _pInstance;
}
static void destory()
{ if(_pInstance)
{ Category::shutdown();
}
}
private:
Mylog():root(Category::getRoot()){
PatternLayout * ptnLayout1 = new PatternLayout();
ptnLayout1->setConversionPattern("%d [%p] %m%n");
PatternLayout * ptnLayout2 = new PatternLayout();
ptnLayout2->setConversionPattern("%d [%p] %m%n");
PatternLayout * ptnLayout3 = new PatternLayout();
ptnLayout3->setConversionPattern("%d [%p] %m%n"); OstreamAppender * ostreamAppender = new OstreamAppender("ostreamAppender",&cout);
ostreamAppender->setLayout(ptnLayout1); FileAppender *fileAppender = new FileAppender("fileAppender","davarain.log");
fileAppender->setLayout(ptnLayout2); RollingFileAppender * rollingAppender = new RollingFileAppender("rollingAppender","rollingAppender.log",5*1024,2);
rollingAppender->setLayout(ptnLayout3); root.setAppender(ostreamAppender);
root.addAppender(fileAppender);
root.addAppender(rollingAppender); root.setPriority(Priority::DEBUG);
cout << "Mylog()" << endl;
}
~Mylog()
{
cout << "~Mylog()" << endl;
}
private:
Category & root;
static Mylog * _pInstance;
}; Mylog * Mylog::_pInstance = nullptr; void Mylog::Info(const char *msg)
{
root.info(msg);
}
void Mylog::Warn(const char *msg)
{
root.warn(msg);
}
void Mylog::Debug(const char *msg)
{
root.debug(msg);
}
void Mylog::Error(const char *msg)
{
root.error(msg);
}
void my_logInfo(int line, const char *filename, const char *funcName, const char *msg)
{
Mylog *log = Mylog::getInstance();
string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + std::string(filename) + " this is line: " + std::to_string(line) + " func name: " + string(funcName);
log->Info(tempMsg.c_str());
}
void my_logError(int line,const char *filename,const char *funcName, const char *msg)
{
Mylog *log = Mylog::getInstance();
string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + std::string(filename) + " this is line: " + std::to_string(line) + " func name: " + string(funcName);
log->Error(tempMsg.c_str());
}
void my_logWarn(int line,const char *filename,const char *funcName, const char *msg)
{
Mylog *log = Mylog::getInstance();
string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + std::string(filename) \
+ " this is line: " + std::to_string(line) + " func name: " + string(funcName);
log->Warn(tempMsg.c_str());
void my_logDebug(int line, const char *filename, const char *funcName,const char *msg)
{
Mylog *log = Mylog::getInstance();
string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + std::string(filename) + " this is line: " + std::to_string(line) + " func name: " + string(funcName);
log->Debug(tempMsg.c_str());
}
C++20:
#pragma once
/*
#define logInfo(msg) \
my_logInfo(__LINE__,__FILE__,__FUNCTION__,msg)
#define logWarn(msg)\
my_logWarn(__LINE__,__FILE__,__FUNCTION__,msg)
#define logError(msg)\
my_logError(__LINE__,__FILE__,__FUNCTION__,msg)
#define logDebug(msg)\
my_logDebug(__LINE__,__FILE__,__FUNCTION__,msg)
*/
#include <stdlib.h>
#include <iostream>
#include <string>
#include <experimental/source_location>
using std::cout;
using std::endl;
using std::string;
using namespace std::experimental; #include <log4cpp/Category.hh>
#include <log4cpp/Priority.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/RollingFileAppender.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/PatternLayout.hh> using namespace log4cpp;
class Mylog
{
public:
void Warn(const char *msg);
void Error(const char *msg);
void Debug(const char * msg);
void Info(const char * msg); static Mylog * getInstance()
{
if(_pInstance == nullptr){
_pInstance = new Mylog();
}
return _pInstance;
}
static void destory()
{ if(_pInstance)
{ Category::shutdown();
}
}
private:
Mylog():root(Category::getRoot()){
PatternLayout * ptnLayout1 = new PatternLayout();
ptnLayout1->setConversionPattern("%d [%p] %m%n");
PatternLayout * ptnLayout2 = new PatternLayout();
ptnLayout2->setConversionPattern("%d [%p] %m%n");
PatternLayout * ptnLayout3 = new PatternLayout();
ptnLayout3->setConversionPattern("%d [%p] %m%n"); OstreamAppender * ostreamAppender = new OstreamAppender("ostreamAppender",&cout);
ostreamAppender->setLayout(ptnLayout1); FileAppender *fileAppender = new FileAppender("fileAppender","davarain.log");
fileAppender->setLayout(ptnLayout2); RollingFileAppender * rollingAppender = new RollingFileAppender("rollingAppender","rollingAppender.log",5*1024,2);
rollingAppender->setLayout(ptnLayout3); root.setAppender(ostreamAppender);
root.addAppender(fileAppender);
root.addAppender(rollingAppender); root.setPriority(Priority::DEBUG);
cout << "Mylog()" << endl;
}
~Mylog()
{
cout << "~Mylog()" << endl;
}
private:
Category & root;
static Mylog * _pInstance;
}; Mylog * Mylog::_pInstance = nullptr; void Mylog::Info(const char *msg)
{
root.info(msg);
}
void Mylog::Warn(const char *msg)
{
root.warn(msg);
}
void Mylog::Debug(const char *msg)
{
root.debug(msg);
}
void Mylog::Error(const char *msg)
{
root.error(msg);
}
void logInfo(const char *msg,const source_location& location= source_location::current())
{
Mylog *log = Mylog::getInstance();
string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + location.file_name() + " this is line: " + std::to_string(location.line()) + " func name: " + location.function_name();
log->Info(tempMsg.c_str());
}
void logError(const char *msg, const source_location& location = source_location::current())
{
Mylog *log = Mylog::getInstance();
string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + location.file_name() + " this is line: " + std::to_string(location.line()) + " func name: " + location.function_name();
log->Error(tempMsg.c_str());
}
void logWarn(const char *msg,const source_location& location = source_location::current())
{
Mylog *log = Mylog::getInstance();
string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + location.file_name() + " this is line: " + std::to_string(location.line()) + " func name: " + location.function_name();
log->Warn(tempMsg.c_str());
}
void logDebug(const char *msg,const source_location& location = source_location::current())
{
Mylog *log = Mylog::getInstance();
string tempMsg = msg;
tempMsg = tempMsg + " doucument name:" + location.file_name() + " this is line: " + std::to_string(location.line()) + " func name: " + location.function_name();
log->Debug(tempMsg.c_str());
}
使用Line Pos Info 和 Modern C++ 改进打印日志记录的更多相关文章
- Winform开发框架之权限管理系统改进的经验总结(4)-一行代码实现表操作日志记录
在前面介绍了几篇关于我的权限系统改进的一些经验总结,本篇继续这一系列主体,介绍如何一行代码实现重要表的操作日志记录.我们知道,在很多业务系统里面,数据是很敏感的,特别对于一些增加.修改.删除等关键的操 ...
- 近期业务大量突增微服务性能优化总结-3.针对 x86 云环境改进异步日志等待策略
最近,业务增长的很迅猛,对于我们后台这块也是一个不小的挑战,这次遇到的核心业务接口的性能瓶颈,并不是单独的一个问题导致的,而是几个问题揉在一起:我们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问 ...
- 【改进】用Log4net建立日志记录
上一篇随笔中只使用了普通的文件读写来进行日志的写入,正如很多朋友说的,频繁的对文件进行读写会造成很多的问题,代码缺少边界控制和操作控制,没有对资源进行管理,是非常典型的bad code. 然后经过前辈 ...
- jmeter 4.0版本更新说明(个人做个记录)总版本更新合集
版本4.0 摘要 新的和值得注意的 不兼容的变化 Bug修复 改进 非功能性变化 已知问题和解决方法 谢谢 新的和值得注意的 核心改进 JMeter现在支持JAVA 9. 提供新的边界提取器元件,提供 ...
- 【webdriver自动化】Python数据驱动工具DDT
一.Python数据驱动工具ddt 1. 安装 ddt pip install ddt DDT是 “Data-Driven Tests”的缩写 资料:http://ddt.readthedocs.i ...
- python webdriver 测试框架-行为驱动例子
安装行为驱动模块lettuce(卷心菜)模块 pip install lettuce Successfully installed argparse-1.4.0 colorama-0.3.9 extr ...
- python webdriver 测试框架-数据驱动xml驱动方式
数据驱动xml驱动的方式 存数据的xml文件:TestData.xml: <?xml version="1.0" encoding="utf-8"?> ...
- python webdriver 测试框架-数据驱动excel驱动的方式
简介: 数据驱动excel驱动方式,就是数据配置在excel里面,主程序调用的时候每次用从excel里取出的数据作为参数,进行操作, 需要掌握的地方是对excel的操作,要灵活的找到目标数据 测试数据 ...
- python webdriver 测试框架-数据驱动json文件驱动的方式
数据驱动json文件的方式 test_data_list.json: [ "邓肯||蒂姆", "乔丹||迈克尔", "库里||斯蒂芬", & ...
随机推荐
- 搭建自己的技术博客系列(二)把 Hexo 博客部署到 GitHub 上
1.在GitHub上建一个新仓库
- TypeScript模块系统、命名空间、声明合并
命名空间 命名空间能有效避免全局污染.在ES6引入模块之后,命名空间就较少被提及了.如果使用了全局的类库,命名空间仍是一个好的解决方案. namespace Shape{ const pi = Mat ...
- FreeSql (十三)更新数据时忽略列
var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...
- 简单说一下你对http和https的理解
http是一种超文本传输协议,传输的数据都是未加密的,也就是显示在明面上的,是现在互联网上应用最为广泛的一种网络协议,相对来说不太安全,但是所需成本很小.http一般的端口号为80. https则是具 ...
- Docker入门到实践——简单操作
1.对比传统虚拟机总结 特性 容器 虚拟机 启动 秒级 分钟级 硬盘使用 一般为MB 一般为GB 性能 接近原生 弱于 系统支持量 单机支持上千个容器 一般几十个 2.基本概念 Docker包括三个基 ...
- Vector和Arrarlist的异同;Hashtanle和HashMap的异同
Vector和ArrayList的异同 实现原理相同,功能相同,可以互用 主要区别: Vector线程安全,ArrayList重速度,轻安全,线程非安全. 长度需要增长时,Vector默认增长一倍,A ...
- Day 23 系统服务之救援模式
1.CentOS6与Centos 7启动流程 4.运行级别C6&C7 0 关机 1 单用户模式 (超级权限 必须面对实体硬件) 2 暂未使用 3 字符界面(黑框) 4 暂未使用 5 图形界面 ...
- Java程序连接数据库
/** * 了解: 利用 Driver 接口的 connect 方法获取连接 */ // 第一种实现 /** * 了解: 利用 Driver 接口的 connect 方法获取连接 */ @Test p ...
- tcp居然会数据延迟40ms被发送
tcpdump是很好的tcp分析工具,在此配合nc命令来学习tcpdump nc -l 8000 tcpdump -S -n -i lo tcp and host 127.0.0.1 and port ...
- Layer弹层(父子传值,兄弟传值)
需求:最外面列表界面点修改弹出LayerA界面,再点击LayerA界面中的选择地图坐标按钮弹出LayerB地图界面 这个过程涉及到的: 1:LayerA将坐标传给LayerB,LayerB在地图上显示 ...