使用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: [ "邓肯||蒂姆", "乔丹||迈克尔", "库里||斯蒂芬", & ...
随机推荐
- Maven工程读取properties文件过程
1.创建需要读取的properties文件 2.在xml文件中加载配置文件 <!-- 加载配置文件 --> <context:property-placeholder locatio ...
- nginx部署成功却没有办法访问
1.首要想到的问题是防火墙没关 注意:因为centos7.0默认不是使用iptables方式管理,而是firewalld方式.CentOS6.0防火墙用iptables管理. 2.解决: ①首先查看防 ...
- android 端缓存清理的实现
首先关于缓存清理,网上已经有太多的工具类,但是遗憾的是,基本上都不完善,或者说根本就不能用,而项目中又要求实现这个烂东西(其实这玩意真没一点屁用,毕竟第三方清理/杀毒软件都带这么一个功能),但是只好硬 ...
- springmvc 事务控制与数据库隔离级别
springmvc 事物传播与数据库隔离控制 http://www.cnblogs.com/yangy608/archive/2011/06/29/2093478.html 一.Propagation ...
- JWT简明介绍
JSON Web Token一种数据格式,用来表示Token.具有可扩展.防篡改.能够在URL中安全传输的特性,已经形成标准,定义在rfc7519. JSON Web Token (JWT) is a ...
- 三句话告诉你break、return、continue!
break:终止循环执行循环体下面的代码 return:终止循环并且退出循环所在的方法 continue:终止当前循环,进行下一次循环
- NLP舞动之中文分词浅析(一)
一.简介 针对现有中文分词在垂直领域应用时,存在准确率不高的问题,本文对其进行了简要分析,对中文分词面临的分词歧义及未登录词等难点进行了介绍,最后对当前中文分词实现的算法原理(基于词表. ...
- MySQL设计表规范
规范总结 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用 MySQL 保留关键字[设计表后逐一排查] 所有表必须使用 Innodb 存储引擎,数据库和表的字符集统一使用 ...
- pip安装Mysql-python报错EnvironmentError: mysql_config not found
如下图,安装Mysql-python报错EnvironmentError: mysql_config not found 经过验证,可通过以下方式解决: 从官网下载mysql安装,成功之后输入PATH ...
- 浅谈HDFS(一)
产生背景及定义 HDFS:分布式文件系统,用于存储文件,主要特点在于其分布式,即有很多服务器联合起来实现其功能,集群中的服务器各有各的角色 随着数据量越来越大,一个操作系统存不下所有的数据,那么就分配 ...