Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ logging to console and log-file simultaneously [closed]

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

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

Simultaneously it should write the stuff each to a derivation specific log file. I thought of a class, that can be called in the standard manner, e.g. "custom_out << "Write stuff" << std::endl;" and uses the single stream to generate two streams that one runs in console with formatting and second to a log file without formatting the name [name] in the front.

Is there a standard way of doing this? Maybe normal logger already support behaviour like this? Maybe I can derive from a std::stream somehow to accomplish this? What is the best (or at least a good) way?

like image 290
Alex Pander Avatar asked Oct 16 '22 23:10

Alex Pander


1 Answers

Here's a starter-kit for the idea I was discussing in the comments. You will need to decide what to do about errors writing to the disk file - return false, throw exception, or whatever. I edited it to return true/false. True 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's all, folks. -", 30, '-');
    std::cout << (OK ? "OK" : "So not OK") << std::endl;
}
like image 193
Jive Dadson Avatar answered Oct 21 '22 00:10

Jive Dadson