I am implementing a log handler in C++, and it works good and all, however there is one thing which I would find usable and that is where the logger got the output from.
I guess this isn't really a big issue, but I stumbled on the __func__
identifier, which basically will keep the function name of the current function.
So I have a static function in my Log class called Write
, it takes a log level, and a vary list. So I would call it as such:
Log::Write(LOG_DEBUG, "this is an integer: %d", 10);
and it will print:
2013-01-02 => 10:12:01.366 [DEBUG]: this is an integer: 10
However I was thinking that it could be useful to also have the caller in the message, to produce something like this:
2013... => 10:12:... (functionName) [DEBUG]: blah
So what I can do (of course) is to add the __func__
as a parameter to Log::Write
, however that would mean that any time I call Log::Write
I need to also send __func__
which will always be the same and I feel like it should be possible to do it without explicitly saying so.
So what I want is the functionality which would be provided with:
Log::Write(LOG_DEBUG, __func__, "message");
without needing to explicitly type out func every time.
I don't know if this really is possible, the best bet I've got is that there is some way to dereference the caller inside of the function Write
, it doesn't seem likely that I can just "infer" a parameter like that. But worth asking at least and maybe I can see what options there are.
Thanks.
#define WRITE_LOG(X,...) Log::Write(LOG_DEBUG, __func__, (X),__VA_ARGS__);
Use this macro to write logs instead of the function, and it will automatically add the func parameter. As Mat mentions, this is the typical way, I cant think of any way to avoid macros in this case.
This is usually done with macros, along with the filename __FILE__
and line number __LINE__
.
void Log::Write(Level l,
char const* function,
char const* file,
int line,
char const* format,
...);
is wrapped into a macro:
#define LOG(Level_, Format_, ...) \
Log::Write(Level_, __func__, __FILE__, __LINE__, Format_, __VA_ARGS__);
Note that you may want to "save" some computing by having a check for whether to log at that level or not:
// suppose availability of "bool Log::Enabled(Level l)"
#define LOG(Level_, Format_, ...) \
while (Log::Enabled(Level_)) { \
Log::Write(Level_, __func__, __FILE__, __LINE__, Format_, __VA_ARGS__); \
break; \
}
The use of a while
instead of if
is to avoid the dangling else issue.
Note: you may wish to investigate the use of streams for logging. The issue with printf
style is that it is not composable. With streams, you can overload std::ostream& operator<<(std::ostream&, X const&)
for any X
and then only write once a method to dump its content in the logs.
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