C ++同时记录到控制台和日志文件

时间:2018-02-01 11:05:07

标签: c++ logging stream

我有一个基类,例如" ProcessingThread",它有几个派生。每个派生都有一个特定的名称,例如" DerivationOne"," DerivationTwo",...现在对我来说,有一个格式化的输出到控制台打印的东西似乎很有用:

[DerivationOne]: Action X took place!
[DerivationTwo]: Action Y took place!
[DerivationTwo]: Action Z took place!

同时它应该将每个东西写入派生特定的日志文件。我想到了一个可以用标准方式调用的类,例如" custom_out<< "写东西" <<的std :: ENDL;"并使用单个流生成两个流,一个在控制台中运行格式化,另一个在日志文件中,而不在前面格式化名称[name]。

有没有一种标准的方法可以做到这一点?也许正常的记录器已经支持这样的行为?也许我可以从std :: stream派生某种方式来实现这一目标?什么是最好的(或至少是好的)?

2 个答案:

答案 0 :(得分:1)

我认为这是一个很好的问题。

在我看来,你实际上考虑了两件不同的事情:

  1. 通过自定义流重新格式化输出(前缀)
  2. 将其重定向到多个流
  3. 我不会在一个班级中同时做这两件事。我会为每个功能编写课程。

    对于第一个,我会使用一个简单的类,传递一个std::ostream引用和一个字符串(对于前缀,尽管可能有更多的概括而不仅仅是前缀)到构造函数,然后重载operator<<;

    对于第二个,我会编写一个类,可能需要两个迭代器(例如std::sort个)来获取流列表,并再次重载`operator&lt;&lt;'。

    对于你的同时做两个,我会将第二个类的对象传递给第一个类的构造函数。

答案 1 :(得分:1)

这是我在评论中讨论的想法的入门套件。您需要决定如何处理写入磁盘文件的错误 - 返回false,抛出异常等等。我编辑它以返回true / false。 True表示没有错误。正在进行中。

#include <iostream>
#include <mutex>
#include <string>
#include <fstream>
#include <string_view>
#include <iomanip>

namespace dj {

    inline bool print(std::ostream& out) {
        return !!(out << std::endl);
    }

    template<typename T>
    bool print(std::ostream& out, T&& value)
    {
        return !!(out << std::forward<T>(value) << std::endl);
    }

    template<typename First, typename ... Rest>
    bool print(std::ostream& out, First&& first, Rest&& ... rest)
    {
        return !!(out << std::forward<First>(first)) && print(out, std::forward<Rest>(rest)...);
    }

    inline std::mutex logger_mtx;

    class log_stream {
    public:
        log_stream(std::string_view str, std::ostream& ifile)
            : name(str)
            , file(ifile)
        {
            std::string s{ "[" };
            name = s + name + "] ";
        }

        template <typename... Args>
        bool operator() (Args&&... args) {
            bool OK = print(file, std::forward<Args>(args)...);
            {
                std::lock_guard<std::mutex> lck(logger_mtx);
                print(std::cout, name, std::forward<Args>(args)...);
                if (!OK) {
                    print(std::cout, name, "-- Error writing to log file. --");
                }
            }
            return OK;
        }

    private:
        std::string name;
        std::ostream& file;
    };


}
int main()
{
    std::ofstream outfile("DerivationOne.log.txt");
    dj::log_stream log("DerivationOne", outfile);

    std::ofstream outfile2; // ERROR. File not opened
    dj::log_stream log2("DerivationTwo", outfile2);

    log("Life. See ", 42, ", meaning of.");
    bool OK = 
      log2("log", std::setw(4), 2.01, " That's all, folks. -", 30, '-');
    std::cout << (OK ? "OK" : "So not OK") << std::endl;
}