You could avoid the construction of the std::string by directly operating on the stream:
std::ostream& operator << (std::ostream& os, LogLevel level)
{
switch(level)
{
case critical: os << "CRITICAL"; break;
...
}
return os;
}
or, if you dislike overloading operators, a similar function void add_prefix(std::ostream& os, LogLevel level).
2.
We could actually base the whole logger on overloading << instead of macros and std::strings, providing a syntax like:
log(LogLevel::debug) << "here's some debug integer: " << some_integer << std::endl;
Advantages:
common C++ syntax.
messages become almost no-ops if a higher logging level is selected.
Disadvantage:
more templates -> Slightly higher compilation times.
Suggestions from @ahehn-nv -
1.
2.