Loading

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

  

 

posted @ 2019-06-23 18:08  RainDavi  阅读(482)  评论(0编辑  收藏  举报