使用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++ 改进打印日志记录的更多相关文章

  1. Winform开发框架之权限管理系统改进的经验总结(4)-一行代码实现表操作日志记录

    在前面介绍了几篇关于我的权限系统改进的一些经验总结,本篇继续这一系列主体,介绍如何一行代码实现重要表的操作日志记录.我们知道,在很多业务系统里面,数据是很敏感的,特别对于一些增加.修改.删除等关键的操 ...

  2. 近期业务大量突增微服务性能优化总结-3.针对 x86 云环境改进异步日志等待策略

    最近,业务增长的很迅猛,对于我们后台这块也是一个不小的挑战,这次遇到的核心业务接口的性能瓶颈,并不是单独的一个问题导致的,而是几个问题揉在一起:我们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问 ...

  3. 【改进】用Log4net建立日志记录

    上一篇随笔中只使用了普通的文件读写来进行日志的写入,正如很多朋友说的,频繁的对文件进行读写会造成很多的问题,代码缺少边界控制和操作控制,没有对资源进行管理,是非常典型的bad code. 然后经过前辈 ...

  4. jmeter 4.0版本更新说明(个人做个记录)总版本更新合集

    版本4.0 摘要 新的和值得注意的 不兼容的变化 Bug修复 改进 非功能性变化 已知问题和解决方法 谢谢 新的和值得注意的 核心改进 JMeter现在支持JAVA 9. 提供新的边界提取器元件,提供 ...

  5. 【webdriver自动化】Python数据驱动工具DDT

    一.Python数据驱动工具ddt 1.  安装 ddt pip install ddt DDT是 “Data-Driven Tests”的缩写 资料:http://ddt.readthedocs.i ...

  6. python webdriver 测试框架-行为驱动例子

    安装行为驱动模块lettuce(卷心菜)模块 pip install lettuce Successfully installed argparse-1.4.0 colorama-0.3.9 extr ...

  7. python webdriver 测试框架-数据驱动xml驱动方式

    数据驱动xml驱动的方式 存数据的xml文件:TestData.xml: <?xml version="1.0" encoding="utf-8"?> ...

  8. python webdriver 测试框架-数据驱动excel驱动的方式

    简介: 数据驱动excel驱动方式,就是数据配置在excel里面,主程序调用的时候每次用从excel里取出的数据作为参数,进行操作, 需要掌握的地方是对excel的操作,要灵活的找到目标数据 测试数据 ...

  9. python webdriver 测试框架-数据驱动json文件驱动的方式

    数据驱动json文件的方式 test_data_list.json: [ "邓肯||蒂姆", "乔丹||迈克尔", "库里||斯蒂芬", & ...

随机推荐

  1. Python3实战Spark大数据分析及调度 (网盘分享)

    Python3实战Spark大数据分析及调度 搜索QQ号直接加群获取其它学习资料:715301384 部分课程截图: 链接:https://pan.baidu.com/s/12VDmdhN4hr7yp ...

  2. mybatis拦截器实现通用权限字段添加

    实现效果 日常sql中直接使用权限字段实现权限内数据筛选,无需入参,直接使用,使用形式为:select * from crh_snp.channelinfo where short_code in ( ...

  3. android- 对话框中弹出edittext 不能调出输入法

    最近项目中用到 dialog弹出对话框功能, 弹出后输入 密码, 本以为这是一个很简单问题,但是做好发现Edittext 无法调出输入法. 解决方法,我也是百度找到的 . 记录一下,便于下次使用: f ...

  4. Winform中通过代码设置DevExpress的TextEdit的类型为Numbernic

    场景 使用DevExpress的EditText控件时,需要限制其输入类型为数字. 正常来说是窗体上拖拽一个TextEdit,然后在设计窗口点击小三角,选择Change Mask 但是如果说TextE ...

  5. 14 (OC)* UIView和UILayer

    总接来说就是如下几点: 1:每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提供.两者都有树状层级结构,layer ...

  6. PopUpWindow 的使用笔记

    最接做需求的时候,碰到了 PopUpWindow,但是也没做过多了解,就是照搬别人的代码改改逻辑.后面视觉看了之后,说让我加一些动画效果,使用起来更加舒服.可是我看别人以前也没有写,于是就开始捣鼓 P ...

  7. [C++] 头文件中的#ifndef,#define,#endif以及#pragma用法

    想必很多人都看过“头文件中用到的 #ifndef/#define/#endif 来防止该头文件被重复引用”.但是是否能理解“被重复引用”是什么意思?头文件被重复引用了,会产生什么后果?是不是所有的头文 ...

  8. C#使用Oxyplot绘制监控界面

    C#中可选的绘图工具有很多,除了Oxyplot还有DynamicDataDisplay(已经改名为InteractiveDataDisplay)等等.不过由于笔者这里存在一些环境上的特殊要求,.Net ...

  9. 自己制作一个简单的操作系统二[CherryOS]

    自己制作一个简单的操作系统二[CherryOS] 我的上一篇博客 自己制作一个简单的操作系统一[环境搭建], 详细介绍了制作所需的前期准备工作 一. 一点说明 这个操作系统只是第一步, 仅仅是开机显示 ...

  10. 性能测试瓶颈判断(LR&Windowns)

    性能测试瓶颈判断(LR&Windowns) 一.判断CPU瓶颈(Processor) 1, %processor time 如果该值持续超过95%,表明瓶颈是CPU.可以考虑增加一个处理器或换 ...