使用流在C++中记录信息

using stream to log information in C++

本文关键字:记录 信息 C++      更新时间:2023-10-16

我有一个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参数?有没有更简单/更干净的方法来实现类似于C++FOO_LOG()的东西?

与其在代码中随处#ifdef NDEBUG,不如在标头的开头有一个#ifdef NDEBUG来定义其他有用的宏。

对我来说FOO_LOG("stuff=" << stuff << " in loop counter #" << xyz);感觉有点不自然。我将不得不不断参考宏定义以查看它是如何实现的。相反,您可以定义一个宏以充当std::ostream,并像使用任何其他流一样使用它。这样你就可以做一些事情,比如LOG_STREAM << "stuff=" << stuff << " in loop counter #" << xyz << std::endl;.

对于这个答案,我从这个问题中得到了一些启发。

#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,它只存在于您的代码中,并且在未定义NDEBUG时使用LOG_STREAM时会执行一些无操作。