Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

__func__ and logging

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.

like image 344
qrikko Avatar asked Jan 02 '13 09:01

qrikko


2 Answers

#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.

like image 20
Karthik T Avatar answered Sep 25 '22 09:09

Karthik T


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.

like image 132
Matthieu M. Avatar answered Sep 21 '22 09:09

Matthieu M.