支持 __LINE__ 宏和其他宏的 C++ 风格记录器

标签 c++ logging operator-overloading endl

我想制作一个可以像std::cout一样使用的记录器,但我想记录一些额外的数据,如日期、时间、__LINE__ , __func__ ,和__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::stringint ,另一个取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<<从我的类(class)中,需要 std::endl操纵器,还有其他办法解决,但是怎么办呢?我正在考虑改变std::endllogendl宏到其他自定义操纵器,然后该自定义操纵器将执行实际执行 operator<< 的工作,但我不知道该怎么做。我正在寻找其他解决方案,有什么建议吗?

最佳答案

这就是我所做的。这有点回避你的问题。也就是说,无需定义 endl。我所做的就是从构建消息的 LogMessage 类中分离出一个 Logger 类(它只接受字符串并输出到您需要它们的任何地方)。 p>

好处是:

  • 每个类本身都非常简单。

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

  • 无需定义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;
}

关于支持 __LINE__ 宏和其他宏的 C++ 风格记录器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33712798/

相关文章:

c++ - 字符数组的长度限制

c++ - 项目库存添加/编辑/查看问题

c++ - drawToBitmap 方法将 System::Windows::Forms::Control::DrawToBitmap 转换为 System::Drawing::Rectangle

ruby-on-rails - 如何在生产日志文件中禁用 Rails 路由错误堆栈跟踪打印?

c++ - 重载 std::bitset 的移位运算符

c++ - 使用运算符/目录 : good or bad idea?

c++ - 使用自定义结构作为键类型访问 std::map 会导致奇怪的行为

logging - NXLOG日志传送中缺少消息

c++ - Operator[] 重载返回错误数据

java - 如果 App Engine 自动将 stdout & stderr 记录到 INFO & WARNING,你为什么要使用 logging.properties?