在 C++ 中管理日志流以类似 cout 的表示法

发布于 2024-10-09 21:32:34 字数 796 浏览 0 评论 0原文

我有一个 C++ 类,以便为我的应用程序编写日志文件。我已经构建了该类并且它可以工作,它是这样的:

class Logger {
   std::string _filename;
public: 
   void print(std::string tobeprinted);
}

嗯,很直观的是,为了在日志文件中打印一行,对于 Logger 对象,只需执行以下操作:

Logger mylogger("myfile.log");
mylogger.print(std::string("This is a log line"));

嗯。使用方法方法与使用更好的模式(如<<)不同。是。 我想做以下事情:

Logger mylogger("myfile.log");
mylogger << "This is a log line";

仅此而已。我想我必须超载 <<运算符...但是使用这个签名(经典的)进行重载:

ostream& operator<<(ostream& output, const MyObj& o);

但是我没有ostream... 那么,我应该按如下方式操作吗?

Logger& operator<<(Logger& output, const std::string& o);

这是正确的方法吗? 谢谢

I have a class in c++ in order to write log files for an application of mine. I have already built the class and it works, it is something like this:

class Logger {
   std::string _filename;
public: 
   void print(std::string tobeprinted);
}

Well, it is intuitive that, in order to print a line in the log file, for an object of Logger, it is simply necessary to do the following:

Logger mylogger("myfile.log");
mylogger.print(std::string("This is a log line"));

Well. Using a method approach is not the same as using a much better pattern like << is.
I would like to do the following:

Logger mylogger("myfile.log");
mylogger << "This is a log line";

That's all. I suppose I must overload the << operator... But overloading using this signature (the classic one):

ostream& operator<<(ostream& output, const MyObj& o);

But I do not have a ostream...
So, should I do as follows?

Logger& operator<<(Logger& output, const std::string& o);

Is this the right way?
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小草泠泠 2024-10-16 21:32:34
class Log
{
public:

    enum Level { Debug, Error, Info };

    static ostream& GetStream() { return cout; }
    static bool IsLevelActive(Level l) { return true; }
};

#ifndef NO_LOG
#define LOG_ERROR(M)   do { if (Log::IsLevelActive(Log::Error))   (Log::GetStream() << "ERR: " << M << "\n"); } while (false)
#define LOG_INFO(M)    do { if (Log::IsLevelActive(Log::Info))    (Log::GetStream() << "INF: " << M << "\n"); } while (false)
#define LOG_WARNING(M) do { if (Log::IsLevelActive(Log::Warning)) (Log::GetStream() << "WRN: " << M << "\n"); } while (false)
#else
#define LOG_ERROR(M)
#define LOG_INFO(M)
#define LOG_WARNING(M)
#endif

struct MyObject {
    int a, b;
};

ostream& operator<<(ostream& ostr, const MyObject& obj) {
    ostr << "(a=" << obj.a << ", b=" << obj.b << ")";
    return ostr;
}

void test() {
    int v1 = 42;
    int v2 = 43;
    LOG_INFO("value1=" << v1 << ", value2=" << v2);

    MyObject o = {1, 2};
    LOG_INFO("obj=" << o);
}
class Log
{
public:

    enum Level { Debug, Error, Info };

    static ostream& GetStream() { return cout; }
    static bool IsLevelActive(Level l) { return true; }
};

#ifndef NO_LOG
#define LOG_ERROR(M)   do { if (Log::IsLevelActive(Log::Error))   (Log::GetStream() << "ERR: " << M << "\n"); } while (false)
#define LOG_INFO(M)    do { if (Log::IsLevelActive(Log::Info))    (Log::GetStream() << "INF: " << M << "\n"); } while (false)
#define LOG_WARNING(M) do { if (Log::IsLevelActive(Log::Warning)) (Log::GetStream() << "WRN: " << M << "\n"); } while (false)
#else
#define LOG_ERROR(M)
#define LOG_INFO(M)
#define LOG_WARNING(M)
#endif

struct MyObject {
    int a, b;
};

ostream& operator<<(ostream& ostr, const MyObject& obj) {
    ostr << "(a=" << obj.a << ", b=" << obj.b << ")";
    return ostr;
}

void test() {
    int v1 = 42;
    int v2 = 43;
    LOG_INFO("value1=" << v1 << ", value2=" << v2);

    MyObject o = {1, 2};
    LOG_INFO("obj=" << o);
}
苏大泽ㄣ 2024-10-16 21:32:34

为什么不简单地使 Logger 成为 std::ostream 或 std::ostringstream 的子类?那么所有这些功能都将被实现。

Why not simply make Logger a sub-class of either std::ostream or std::ostringstream? Then all that functionality will already be implemented.

是的,这是正确的方法。但你必须添加 <<您需要记录的每种数据类型的运算符重载。

Yes, this is the right way. But you'll have to add << operator overloads for every data type that you need to log.

玩物 2024-10-16 21:32:34

您并不是真的想创建全新的流,因为您需要重新定义所有流运算符。仅当您想完全更改数据转换为字符数据的方式时,才需要这样做。 (恶心)。

我发现最好的方法是创建一个类,该类将跟踪流并在销毁时将其内容发送到我选择的目的地(记录器)。这与一些宏相结合,为您提供了您正在寻找的东西:用于日志记录的流语法。

Boost 实际上有一些类可以帮助解决这个问题。查看 iostream

You don't really want to create whole new streams, as you then need to redefine all the stream operators. You'd only do that if you want to change entirely how data gets converted into character data. (Ick).

What I've found best for this is to create a class that will keep track of a stream and send its contents to a destination of my choice (the logger) when destructed. That, combined with a smattering of macros, gives you what you are looking for: stream syntax for logging.

Boost actually has some classes that help with this. Look at iostreams.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文