【问题标题】:using stream to log information in C++使用流在 C++ 中记录信息
【发布时间】:2019-12-13 23:29:48
【问题描述】:

我有一个 C++ 类,它将消息记录到 std::ofstream。在类定义中是这样的代码:

#ifdef NDEBUG
#define FOO_LOG(msg) /* calls to log messages are no-op in release mode */
#else
std::ofstream log_stream;
#define FOO_LOG(msg) if (log_stream.is_open()) { log_stream << msg << std::endl; }
#endif

该类的构造函数会检查几项内容,并且在某些情况下会打开类似于以下内容的日志文件:

#ifndef NDEBUG
log_stream.open("output.log");
#endif

然后在代码中,它像这样调用 C 宏:

FOO_LOG("stuff=" << stuff << " in loop counter #" << xyz)

您可以将多个参数传递给FOO_LOG() 宏,这很方便。有明显的限制,例如在记录来自多个线程的消息时,但这仅用于在调试版本中进行简单的记录。

我想知道的是在 C++ 中是否有不同/更好的方法来处理 msg 参数? 有没有更简单/更干净的方法来实现类似于 FOO_LOG() 的东西在 C++ 中?

【问题讨论】:

  • 是的。类似FOO_LOG(logLevel) &lt;&lt; "stuff=" &lt;&lt; stuff &lt;&lt; " in loop counter #" &lt;&lt; xyz;
  • C++11 及更高版本,您可以使用带有参数包或可变参数宏的模板化函数
  • @S.M.将您的评论变成答案,以便人们对其发表评论。我不明白你写的东西怎么可能编译。
  • @Stéphane “类似的东西”是什么意思?您想在调用站点维护语法吗?我猜想将整个事情实现为一个名为 FOO_LOG("stuff=", stuff, " in loop counter #", xyz) 的函数模板,或者以 S.M. 的方式实现。建议可以完全删除宏并使其更清洁。

标签: c++ logging ofstream


【解决方案1】:

您可以在标头的开头使用#ifdef NDEBUG 来定义其他有用的宏,而不是在代码中到处使用#ifdef NDEBUG

对我来说FOO_LOG("stuff=" &lt;&lt; stuff &lt;&lt; " in loop counter #" &lt;&lt; xyz); 感觉有点不自然。我将不得不继续参考宏定义以查看它是如何实现的。相反,您可以定义一个宏来充当std::ostream,并像使用任何其他流一样使用它。这样您就可以执行LOG_STREAM &lt;&lt; "stuff=" &lt;&lt; stuff &lt;&lt; " in loop counter #" &lt;&lt; xyz &lt;&lt; std::endl; 之类的操作。

对于这个答案,我从this question 获得了一些灵感。

#include <fstream>

#define NDEBUG

//An ostream class that does nothing
class DummyStream : public std::ostream {
public:
    int overflow(int c) { return c; }
} dummyStream;

//Here we let NDEBUG define other macros.
#ifdef NDEBUG
    std::ofstream logStream;
    std::ostream& oLogStream(*(std::ostream*)&logStream);
    #define LOG_STREAM (logStream.is_open() ? oLogStream : dummyStream)
    #define OPEN_LOG(log) (logStream.is_open() ? logStream.close(), logStream.open(log, std::ofstream::out | std::ofstream::app) : \
                                                 logStream.open(log, std::ofstream::out | std::ofstream::app))
    #define CLOSE_LOG() (logStream.close())
#else
    #define LOG_STREAM (dummyStream)
    #define OPEN_LOG(log) //no-op
    #define CLOSE_LOG()   //no-op
#endif // NDEBUG

int main(int argc, char* argv[]) {

    //will only log if NDEBUG is defined.
    OPEN_LOG("log.txt");
    std::string stuff("stuff to log");
    for(int xyz = 0; xyz < 4; xyz++) {
        LOG_STREAM << "stuff=" << stuff << " in loop counter #" << xyz << std::endl;
    }
    CLOSE_LOG();

    //Log is not open so it will not log anything.
    stuff = "stuff to not log";
    for(int xyz = 0; xyz < 4; xyz++) {
        LOG_STREAM << "stuff=" << stuff << " in loop counter #" << xyz << std::endl;
    }

    return 0;
}

这样做的好处?

  • LOG_STREAM 的处理方式与其他任何流一样更直观。
  • OPEN_LOG(log) 将在打开新日志之前关闭已经打开的日志,当未定义 NDEBUG 时,它将什么也不做。
  • CLOSE_LOG() 将关闭一个日志,当未定义 NDEBUG 时它什么也不做。
  • 无需在任何地方输入#ifdef NDEBUG ... #endif
  • dummyStream 可以替换为 std::cout 或其他一些流。

下边?

您的代码中有这个DummyStream,当LOG_STREAM 被使用而NDEBUG 未定义时,会执行一些无操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多