C ++样式记录器,支持__LINE__宏和其他

时间:2015-11-14 20:09:04

标签: c++ logging operator-overloading endl

我想创建一个可以像std::cout一样使用的记录器,但我想记录一些额外的数据,如日期,时间,__LINE____func__和{{1}应该自动保存到文件中。

实施例

__FILE__

预期输出

ToolLogger log;
log << "some data" << std::endl;

解决方案不足

要做到这一点,我必须将[14.11.2015 21:10:12.344 (main.cpp) (main,14): some data 之类的宏直接放在我调用记录器的行中,否则宏将无法正常工作。我发现我可以用我的宏替换__LINE__,这样就可以做到这样的黑魔法:

std::endl

#define __FILENAME__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/') + 1 : __FILE__) #define logendl \ ((ToolLogger::fileName = __FILENAME__).empty() ? "" : "") \ << ((ToolLogger::line = __LINE__) ? "" : "") \ << ((ToolLogger::function = __func__).empty() ? "" : "") \ << std::endl 使用我的logendl类中的静态变量来保存稍后需要的ToolLogger__LINE____func__的值。所以实际上使用记录器将如下所示:

__FILE__

在课堂上我必须重载ToolLogger log; log << "some data" << logendl; 以使其工作,我需要其中两个。一个用于获取operator<<std::string等正常值,另一个用于采用int操纵器。这是我班上最重要的事情:

std::endl

问题

此解决方案的问题在于我可以通过两种方式使用记录器:

class ToolLogger
{
  public:

    // standard operator<< //
    template<typename T>
    ToolLogger& operator<< (const T& str)
    {
        out << str;
        return *this;
    }

    // operator<< for taking the std::endl manipulator //
    typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
    typedef CoutType& (*StandardEndLine)(CoutType&);
    ToolLogger& operator<<(StandardEndLine manip)
    {
        // save fileName, line and function to the file //
        // and all what is already in stringstream //
        // clear stringstream //
        return *this;
    }

    static string fileName;
    static int line;
    static string function;

  private:

    ofstream file;
    std::stringstream out;
};

string ToolLogger::fileName;
int ToolLogger::line;
string ToolLogger::function;

所以实际上我需要从我的类log << "some data" << logendl; // correct // log << "some data" << std::endl; // compiles -> wrong / 操纵器中移除operator<<,并以其他方式解决它,但是怎么做呢?我在考虑将std::endl宏中的std::endl更改为其他自定义操纵器,然后这个自定义操纵器将执行实际执行logendl的工作,但我不知道该怎么做它。我正在寻找其他解决方案,有什么建议吗?

2 个答案:

答案 0 :(得分:2)

这就是我的工作。它有点像你的问题。也就是说,不必定义endl。我所做的是从构建消息的Logger类中分离出一个LogMessage类(它只需要字符串并输出到你需要的地方)。

好处是:

  • 每个班级都很简单。

  • 非常简单的宏。我没有在下面定义宏,但它很容易做到。

  • 无需定义endl。当LogMessage类破坏

  • 时,消息以分号结束

让我知道你的想法:

#include <iostream>
#include <sstream>
#include <string>

// logger class
// this is not complete, it exists just to illustrate the LogIt function
class Logger
{
public:
    void LogIt(const std::string & s)
    {
        std::cout << s << std::endl;
    }
};

// builds a logging message; outputs it in the destructor
class LogMessage
{
public:
    // constructor
    // takes identifying info of message.  You can add log level if needed
    LogMessage(const char * file, const char * function, int line)
    {
        os << file << ": " << function << '('  << line << ") ";
    }

    // output operator
    template<typename T>
    LogMessage & operator<<(const T & t)
    {
        os << t;
        return *this;
    }

    // output message to Logger
    ~LogMessage()
     {
         Logger logger; // get logger here (perhaps it's a singleton?)
         logger.LogIt(os.str());
     }
private:
     std::ostringstream os;
};

int main()
{
// example usage
// typically this is invoked via a simple macro to reduce typing of the LogMessage constructor
LogMessage(__FILE__, __func__, __LINE__) << "this is an int " << 5;
}

答案 1 :(得分:1)

您可能拥有LoggerAt类,其中包含LoggerAt(const char*filename, int lineno)构造函数(可能是std::ostringstream的子类,等等...),然后定义

#define LOG(Out) do {LoggerAt(__FILE__,__LINE__) \
  << Out << std::endl; }while(0)

在我编写的一些C ++项目中:

void mom_inform_at(const char*fil, int lin, std::ostringstream& out)
{ out.flush(); 
  std::clog << fil << ":" << lin 
            << " INFORM: " << out.str() << std::endl ;
}

#define MOM_INFORM_AT(Fil,Lin,Output) do {      \
      std::ostringstream out_##Lin;               \
        out_##Lin << mom_outlog << Output ;       \
        mom_inform_at(Fil,Lin,out_##Lin);         \
    } while(0)

  #define MOM_INFORM_AT_BIS(Fil,Lin,Output) \
    MOM_INFORM_AT(Fil,Lin,Output)

  #define MOM_INFORM(Out)                         \
    MOM_INFORM_AT_BIS(__FILE__,__LINE__,Out)

使用类似MOM_INFORM("x=" << " point:" << pt);的内容,您可以想象通常的Point pt;示例以及std::ostream& operator << (std::ostream&out, const Point&point)函数。

请注意,要方便地使用 __FILE____LINE__,您最好使用宏。