使用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. springboot使用 @EnableScheduling、@Scheduled开启定时任务

    1.在main启动项添加一个注解@EnableScheduling package com.example.springmybatis; import org.mybatis.spring.annot ...

  2. linux常用命令二

    linux常用命令一 常用指令 ls        显示文件或目录 -l           列出文件详细信息l(list) -a          列出当前目录下所有文件及目录,包括隐藏的a(all ...

  3. Hive中的数据库(Database)和表(Table)

    在前面的文章中,介绍了可以把Hive当成一个"数据库",它也具备传统数据库的数据单元,数据库(Database/Schema)和表(Table). 本文介绍一下Hive中的数据库( ...

  4. Apache Commons Collections 反序列化详细分析学习总结

    0x01.环境准备: Apache Commons Collections 3.1版本,下载链接参考: https://www.secfree.com/a/231.html jd jui地址(将jar ...

  5. Laravel 5.4 快速开发简书:

    Laravel 5.4 快速开发简书第1章 课程介绍 介绍课程的大体脉络和课程安排 第2章 Laravel 5.4介绍 本节课会带领大家介绍laravel的各个版本历史以及讨论php框架的未来发展趋势 ...

  6. 在wxml中直接写js代码(wxs)

    我们在h5开发中,很多时候要在html中写到js代码,这个很容易实现.但是在微信小程序开发中,是不能直接在wxml中写js代码的,因此就有了wxs.在wxml中用wxs代码,有以下几种方式(在小程序文 ...

  7. 新手学习FFmpeg - 调用API完成视频的读取和输出

    在写了几个avfilter之后,原本以为对ffmpeg应该算是入门了. 结果今天想对一个视频文件进行转码操作,才发现基本的视频读取,输出都搞不定. 痛定思痛,仔细研究了一下ffmpeg提供的examp ...

  8. 2018年蓝桥杯java b组第五题

    标题:快速排序 以下代码可以从数组a[]中找出第k小的元素. 它使用了类似快速排序中的分治算法,期望时间复杂度是O(N)的. 请仔细阅读分析源码,填写划线部分缺失的内容. 我在使用(a, l, r, ...

  9. Redis数据库之服务器主从配置

    目的 主要培养对分布式REDIS主从复制架构运用的能力.理解并掌握REPLICATION工作原理的同时,能独立配置Replication ,使数据库运行在主从架格上.针对主从复制架构的运用,着力掌握S ...

  10. 23种设计模式之装饰器模式(Decorator Pattern)

    装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包 ...