My question may be open to interpretation cause I`m not sure about a specific error I've encountered. So I'll appreciate any idea or even solution.
I'm working on my custom Logger class, based on this repo.
I've made many changes, including adding overloaded operator+
to assemble/push incoming log_txt
into std::map (K - thread_id, V - string_log)
.
So:
operator()
- add time and status to the std::map;operator+
- MUST assemble all text and values and push resulting string
into std::map;operator<<
- release log at once to avoid text conflicts between logs from other threads.log(LOG_WARN) << "thread ONE : " + to_string(1111) + " val\n";
///> Will work but than i have to implement all possible types cast...
///> I'm trying to keep the code easy to read.
log(LOG_WARN) << "thread ONE : " + 1111 + " val\n";
///> Won't work --> error: invalid operands of types ‘const char*’ and ‘const char [6]’ to binary ‘operator+’
///> comment: "thread ONE : " + 1111 - const char* and + "val\n" - const char[6]
My overloaded operator+
as func-member of the Logger class:
template <typename T>
Logger& Logger::operator+(const T& s){
lock_guard<mutex> lock(_mutex);
if (auto search = _th_streams.find(this_thread::get_id()); search != _th_streams.end()){
stringstream ss;
ss << s;
search->second.append(ss.str());
return *this;
}
return *this;
}
I'm sure, my operator+
implementation may be far from ideal but I'm curious is it possible to solve the error by editing only my operator+
?
Overload ooperator+ or to_string()
Because of operator precedence, you'll need to adjust something in the requirements.
I would go for
log(LOG_WARN) << "thread ONE : " << 1111 << " val";
which is recognizable by most C++ programmers.
I would rewrite the requirements so that
operator()
- Acquires, in a thread-safe manner, a reference to the std::string
in the std::map
that is unique for this thread and adds time and status to it.operator<<
- Appends to the std::string
above.The additional measures could be to send the log entry to a central logger. In my example I just add \n
to mark the end of this logging entry.
std::map
is here only locked while fetching the std::string
from it. Logging to the individual std::string
s in the map can then be done without locking.operator()
returns a proxy object (expr
) that keeps a reference to the std::string
in the std::map
class Logger {
struct expr {
~expr() {
// the end of the full logging expression
th_stream += '\n';
}
template <class T>
expr& operator<<(const T& s) {
std::ostringstream ss;
ss << s;
th_stream.append(ss.str());
return *this;
}
std::string& th_stream;
};
public:
expr operator()(loglevel level) {
std::string& th_stream = [&]() -> std::string& {
std::lock_guard<std::mutex> lock(_mutex);
return _th_streams[std::this_thread::get_id()];
}();
th_stream += std::string("TIMESTAMP ") + std::to_string(level) + ' ';
return {th_stream};
}
private:
std::mutex _mutex;
std::map<std::thread::id, std::string> _th_streams;
};