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?
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With