#include<iostream>
#include<string>
using namespace std;
// Generic class for tracing the function call
class functionlogging {
private:
string name;
string in{ ">>" };
string out{ "<<" };
public:
functionlogging(string x) :name(x) {
cout << in << name << endl;
}
~functionlogging(){
cout << out << name << endl;
}
};
//uses
void generic_function() {
functionlogging logger{ __func__ };
int a = 10;
int b = 100;
a += b;
}
int main() {
generic_function();
}
Many times, we do need to log when function call starts and ends for better understanding. With modern C++ concepts like __funct__/RAII
, I wrote the small class which can be used to achieve trace. With this I was able to achieve this for above "generic_function()"
.
Output
>>generic_function
<<generic_function
I wanted others opinion about the functionlogging
class and how to make it in such a way that user of this class would have to do the minimal work/code changes in his/her code base.
At present user of this class needs to create a object of this class and pass the __func__
information. Is it acceptable or in a way can it be embed inside something by which user of the class almost do not require to do anything?.
4 Answers 4
Stop doing this:
using namespace std;
see: Why is "using namespace std;" considered bad practice?
These two are not unique to the class.
string in{ ">>" };
string out{ "<<" };
May as well make them static
. Also they re never modified so make them const
.
No need to force a flush with std::endl
cout << in << name << endl;
Prefer "\n"
when you don't need a flush (also cerr or clog may be better choices of output stream).
That seems like an overly verbose and error prone way of use.
void generic_function() {
functionlogging logger{ __func__ };
You have to use up a variable and remember __func__
. Can't we get a macro in here to do all the for you? I actually need to look up to see if func is a standard macro.
Just checked the standard:
8.4.1 In general
Paragrah 8:
The function-local predefined variable __func__ is defined as if a definition of the form
static const char __func__[] = "function-name ";
So I would define the macros:
#define LOG_ENTRY_EXIT_FOR(x) functionlogging SomeLongNameThatIsNotLikelyToBeUsedInTheFunctionlogger(x)
#define LOG_ENTRY_EXIT LOG_ENTRY_EXIT_FOR(__func__)
Then usage is simply:
void generic_function() {
LOG_ENTRY_EXIT;
int a = 10;
int b = 100;
a += b;
}
The below is updated code after incorporating the suggestion in this post. This is just for easy reference for future reader.
#include<iostream>
#include<string>
// Generic class for tracing the function call
class functionlogging {
private:
std::string name;
static std::string in;
static std::string out;
public:
functionlogging(std::string x) :name(x) {
std::cout << in << name <<"\n";
}
~functionlogging(){
std::cout << out << name <<"\n";
}
};
std::string functionlogging::in{ ">>" };
std::string functionlogging::out{ "<<" };
//Define MACRO for easy use for end user.
#define LOG_ENTRY_EXIT_FOR(x) functionlogging SomeLongNameThatIsNotLikelyToBeUsedInTheFunctionlogger(x)
#define LOG_ENTRY_EXIT LOG_ENTRY_EXIT_FOR(__func__)
//uses
void generic_function() {
LOG_ENTRY_EXIT;
int a = 10;
int b = 100;
a += b;
}
int main() {
generic_function();
}
Just a minor addition. Storing (and passing) the function name in a const char*
will eliminate the costly (dynamic memory allocation) construction of a string.
Sounds great. I would recommend a little improvement to Loki Astari's answer.
By changing the way you define LOG_ENTRY_EXIT,
#if defined(DEBUG)
#define LOG_ENTRY_EXIT LOG_ENTRY_EXIT_FOR(__func__)
#else
#define LOG_ENTRY_EXIT
#endif
One will be able to compile it in or out for say release build if needed.
We use this type of tracing quite a lot in game development code.
-
\$\begingroup\$ If you're posting a comment to someone else's answer, but find it noteworthy enough to post as an answer, be sure to point out what answer you're referencing to. \$\endgroup\$Pimgd– Pimgd2016年02月26日 11:04:45 +00:00Commented Feb 26, 2016 at 11:04
-
\$\begingroup\$ I've edited your answer as an example; like this it's clearer where your contribution is coming from. When you get more reputation (50+), you'll be able to comment on other people's posts, after which you may want to write answers like this as comments instead. \$\endgroup\$Pimgd– Pimgd2016年02月26日 11:08:27 +00:00Commented Feb 26, 2016 at 11:08
#define
like withassert
, if you like that more. \$\endgroup\$