使用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. .Net基础篇_学习笔记_第七天_Continue关键字的用法

    Continue: 立即结束本次循环,判断循环条件: 如果成立,则进行下一次循环,否则退出循环. Continue和break的区别: 遇到break,循环不继续. 遇到continue,本次循环也不 ...

  2. Redis集群增加节点和删除节点

    本文主要是承接上一篇文章Redis集群的离线安装成功以后,我们如何进行给集群增加新的主从节点(集群扩容)以及如何从集群中删除节点(集群缩容),也就是集群的伸缩,集群伸缩的原理是控制虚拟槽和数据在节点之 ...

  3. HTML 框架导航

    初次学习HTML,在www.w3school.com.cn看到了框架导航,上面的例子没有看懂所以搜了一下相应的问题,最后弄懂了怎么实现同一界面下的框架导航. 首先是www.w3school.com.c ...

  4. Centos第一次使用配置IP地址

    1.vim /etc/sysconfig/network-scripts/ifcfg-eth0   修改默认配置文件 TYPE=Ethernet BOOTPROTO=static #静态 可修改为[n ...

  5. c++异常处理函数

    注意: throw 抛出异常,catch 捕获异常,try 尝试捕获异常 catch 中的参数类型要和throw 抛出的数据类型一致 try{    //可能抛出异常的语句}catch (异常类型1) ...

  6. 自己动手实现springboot配置(非)中心

    好久没写博客了,这段时间主要是各种充电,因为前面写的一些东西,可能大家不太感兴趣或者是嫌弃没啥技术含量,所以这次特意下了一番功夫.这篇博客其实我花了周末整整两天写好了第一个版本,已经开源出去了,同样是 ...

  7. ES6中的迭代器、Generator函数以及Generator函数的异步操作

    最近在写RN相关的东西,其中涉及到了redux-saga ,saga的实现原理就是ES6中的Generator函数,而Generator函数又和迭代器有着密不可分的关系.所以本篇博客先学习总结了ite ...

  8. Widget 中的 State 解析

    StatefulWidget 应对有交互.需要动态变化视觉效果的场景 StatelessWidget 则用于处理静态的.无状态的视图展示 那么,StatelessWidget 是否有存在的必要?Sta ...

  9. Vue.js+vue-element搭建属于自己的后台管理模板:Vue.js快速入门(二)

    Vue.js+vue-element搭建属于自己的后台管理模板:Vue.js快速入门(二) 前言 上篇文章对Vue.js有了初步理解,接下来我们把Vue.js基础语法快速的过一遍,先混个脸熟留个印象就 ...

  10. 浅谈JavaScript的闭包原理

    在一般的教程里,都谈到子作用域可以访问到父级作用域,进而访问到父级作用域中的变量,具体是如何实现的,就不得不提及到函数堆栈和执行上下文. 举个例子,一个简单的闭包:   首先,我们可以知道,examp ...