Let's suppose that we have several levels of logging: trace, debug, info, error. I was wondering if there is a way to write the following code:
enum log_level = {trace, debug, info, error};
log_level global_log_level = info;
void log(log_level level, string& message){
if (level >= global_log_level){
std::cout << message << std::endl;
}
}
string create_message(){
...
}
log_level level = debug;
log (level, create_message());
without create_message being called if level is smaller that global_severity_level. Indeed, create_message can be quite long, and no matter what it creates a string. If there are a lot of "debug" logs, those ones can become a substantial overhead when running in non-debug mode.
I know it is possible to do so if the function "log" is a macro, calling create_message() only if severity > minimal_severity; but isn't there another way to do this without macros?
EDIT
In the above, I didn't specify create_message, because it could be anything, in particular:
log(level, "Created object " + my_object.getName());
In this case, is there a way to write log such that the full string is not created, in a relatively transparent way for the programmer calling log?
Many thanks
Similar to @sftrabbit, but as suggested by @ipc.
Use a template to avoid the std::function machinery, and the compiler may be able to inline this and thus it hopefully will end up being faster.
template< typename F >
void log(log_level level, F message_creator){
if (level >= global_log_level){
std::cout << message_creator() << std::endl;
}
}
There are several alternatives. An interesting one is to pass create_message
as a std::function<std::string()>
and call it from within log
:
void log(log_level level, std::function<std::string()> message_creator){
if (level >= global_log_level){
std::cout << message_creator() << std::endl;
}
}
Then you would call it like so:
log(level, create_message);
This can work with arbitrary expressions as arguments if you wrap them in a lambda:
log(level, [&](){ return "Created object " + my_object.getName(); });
If you really don't want to argument to be evaluated at all (as you've described in the comments), then you'll need to check the level outside of the call:
if (level >= global_log_level) {
log(level, create_message());
}
@sftrabbit answer is prefered. But just if you dont want to change log(), you can call it:
log (level, (level >= global_log_level)? create_message() : "");
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