C ++ logging to the console and log file at the same time

I have a base class, for example. "ProcessingThread", which has several derivations. Each pin has a specific name, for example. "DerivationOne", "DerivationTwo", ... Now it seems to me useful to have formatted output to the console that prints something like:

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

At the same time, he must write each material to a specific derivation log file. I was thinking of a class that can be called in a standard way, for example. "custom_out <" Write stuff "<std :: endl;" and uses one thread to generate two threads, one that runs in the formatting console, and the second into the log file without formatting the name [name] in front.

Is there a standard way to do this? Maybe the regular logger already supports this behavior? Maybe I can come from std :: stream somehow to do this? What is the best (or at least good) way?

+4
source share
2 answers

Here is the starter kit for the idea that I discussed in the comments. You will need to decide what to do with the errors written to the disk file - return false, exclude throw, or something else. I edited it to return true / false. Truth means no error. Work in progress.

#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 all, folks. -", 30, '-');
    std::cout << (OK ? "OK" : "So not OK") << std::endl;
}
+1
source

I think this is a great question.

In fact, in my opinion, you are considering two different things:

  • Reformatting the output (prefix) with a custom stream

. .

-, , std::ostream ( , , , , ) , operator<<;

, , , (, std::sort) , `operator < < '.

, , .

+1

Source: https://habr.com/ru/post/1693027/


All Articles