使用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());
}

  

原文地址:https://www.cnblogs.com/Davirain/p/11073602.html

时间: 2024-08-30 08:24:06

使用Line Pos Info 和 Modern C++ 改进打印日志记录的相关文章

改进的日志记录类

相对之前发的日志记录来说,此类将程序记录处理与写磁盘操作分离,用户代码部分,将日志放到队列,并通知线程将日志写到文件: 1.公共类: using System;using System.IO;using System.Collections.Generic;using static System.Console;using System.Text;using System.Diagnostics; namespace LogWriter{    /// <summary>    /// 日志类

Program in Lua中图算法的改进(打印所有图路径)

在Program in Lua第二版,第11.7节中介绍了用lua写"图"数据结构的方法, 但书中提供的图的算法只能打印出第一条找到的正确路径,于是我就自己琢磨 着怎么用lua写出一个图算法打印出所有可能的路径,自己独自一个人思考了 很久,期间没有参考任何资料,完全靠"头脑暴力"把它解决了,最后思考了看看, 也不知道这到底是什么算法,完全凭借着自己认为的所谓的"退化"的概念,奇妙 的解决了这个问题,所以我把这个算法拿出来分享一下. (总觉得在哪本

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

上一篇随笔中只使用了普通的文件读写来进行日志的写入,正如很多朋友说的,频繁的对文件进行读写会造成很多的问题,代码缺少边界控制和操作控制,没有对资源进行管理,是非常典型的bad code. 然后经过前辈们的提点,今天使用了Log4net进行日志的写入,发现非常的便捷,同时也集成了对于日志的控制,减少因为日志写入而发生的一系列不该有的错误. 网上也有很多教程,在此,结合我的教训,我也厚颜无耻的贴出自己的实现步骤,欢迎前辈们指正!!! app.config配置文件,我是直接写在系统的app.confi

python webdriver 测试框架-数据驱动DDT的例子

先在cmd环境 运行 pip install ddt 安装数据驱动ddt模块  脚本: #encoding=utf-8 from selenium import webdriver import unittest,time import logging,traceback import ddt from selenium.common.exceptions import NoSuchElementException #初始化日志对象 logging.basicConfig( #日志级别 leve

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

一.Python数据驱动工具ddt 1.  安装 ddt pip install ddt DDT是 "Data-Driven Tests"的缩写 资料:http://ddt.readthedocs.io/en/latest/ 2.  DDT的使用 (1)   ddt.ddt: 装饰类,也就是继承自TestCase的类 (2)   ddt.data: 装饰测试方法.参数是一系列的值. (3)   ddt.file_data: 装饰测试方法.参数是文件名.文件可以是json 或者 yaml

数据驱动ddt 示例,数据在代码中

#coding=utf-8 from selenium import webdriver import unittest,time import logging,traceback import ddt from selenium.common.exceptions import NoSuchElementException logging.basicConfig( #日志级别 level = logging.INFO, #日志格式 #时间.代码所在文件名.代码行号.日志级别.日志信息 form

Python&amp;Selenium 数据驱动【unittest+ddt+Excel】

一.摘要 一般情况下我们为了更好的管理测试数据会选择将测试数据存储在Excel文件当中去,本节内容将展示给读者将测试数据存储在Excel文档中的案例. 二.创建存储测试数据的Excel 创建一个Excel文件TestData.xlsx,并将如下表格数据写入到Excel文件中,作为测试数据. 序号 搜索词 期望结果 1 北京 北京 2 上海 上海 3 广州 广州 三.封装解析Excel文件模块 要解析Excel文件,需要先给Python环境安装openpyxl模块,启动命令行,输入命令pip in

logging.basicConfig函数

在UI自动化应用中,经常会出错,打log就是一个很重要的环节,python的logging.basicConfig函数 真是既方便,又简单,每次粘贴到用例前,就可以打log了.  logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级.日志保存路径.日志文件回滚等. 相比print,具备如下优点:        可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息:print将所有信息都输出到标准输出中,严重影响开发者从

为企业提供存储功能的Red Hat Stratis 2.0.1发布了

导读 Red Hat的Stratis存储项目用于在Linux上提供企业存储功能,以与ZFS和Btrfs之类的产品竞争,同时在LVM和XFS之上构建,这是其2020年守护进程的首次更新. 通过Stratis,我们可以便捷的使用精简配置(thin provisioning).快照(snapshots)和基于池(pool-based )的管理和监控等高级存储功能: Stratis 2.0.1是在11月的2.0版本之后发布的,该版本带来了新的D-Bus API使用和其他改进. Stratis 2.0.1