Consider the following code:
void Foo() {
......
LOG_ERROR("I'm error 1") // call 1
.....
LOG_ERROR("I'm error 2") // call 2
.....
}
LOG_ERROR()
is a macro. LOG_ERROR()
should print string identifying it
in code, while the assumption is that code can change, but A::Foo()
will remain unchanged. The identifier should retain while code
changes.
This can be solved by adding error code as argument to LOG_ERROR()
,
but we want to remove from the programmer the burden to manage error
codes.
Using __LINE__
is not an answer, since Foo()
can move from build to
build.
Therefore I thought about identifying LOG_ERROR()
relative to start of
Foo()
:
__FILE__
) + function name (__FUNCTION__
) +
line number of LOG_ERROR()
relative to Foo()
start.__FILE__
) + function name (__FUNCTION__
) +
LOG_ERROR()
call number in Foo()
.The solution should be work with VC++ 2008 and g++ 4.1.1 at least.
One proposed solution (link text) is:
#define ENABLE_LOG_ERROR static const int LOG_ERROR_start_line = __LINE__
#define LOG_ERROR(s) cerr << "error #" << (__LINE__ - LOG_ERROR_start_line) \
<< " in " << __func__ << ": " << s << endl
void Foo() {
ENABLE_LOG_ERROR;
//...
LOG_ERROR("error 1");
int i;
LOG_ERROR("error 2");
}
This will force user to write ENABLE_LOG_ERROR
in start of each function containing
LOG_ERROR()
and there're many such functions.
Is there other way to accomplish the task?
This solution is non-standard, but both MSVC and GCC support __COUNTER__
, which is incremented every time it is invoked.
#define LOG_ERROR(s) cerr << "error #" << (__COUNTER__) << " in " \
<< __func__ << ": " << s << endl
Note that __COUNTER__
will be reset in each compilation unit, and ONLY in each compilation unit. So if Foo()
has 7 LOG_ERROR()
macros, in a later function Bar()
the value of __COUNTER__
will be 7 for the first use of LOG_ERROR()
.
While the question is about ways to generate unique line identifiers within a function for logging purposes, I'm going to take a step back and look at the actual problem to be solved: How to generate log output which can easily identify the source code line without putting the burden on the writer of the code.
Let's assume you are embedding a unique build version in each release of your program (which is a good idea in general). Let's also assume you are using a source code control mechanism which keeps the history of your source code (which is also a very good idea to be doing anyway) and which can present you with the source as it was for any requested build version of the program.
If those assumptions hold true, then a solution is to have your program write it's current version into the log file. Then each individual logging entry can simply record the line number via __LINE__
.
Thus, when someone needs to use the log: they can look at the version number in the log, grab the corresponding source from the source code control repository, and use the line numbers from the log to go to the proper source lines. This puts a bit more burden on the person using the log output. However, if logged code depends on or is influenced by other code which could change from version to version, then the historical state of the source code might be required anyway.
Furthermore, a benefit of working this way is that it removes to need to assume that any given function will remain unchanged, as was originally part of the question. So this method has a much broader application.
As far as implementation goes, you could either log the program version when the program starts up or you could make the logging macro include it in each entry.
If the program version is normally stored somewhere not easily accessible in normal source code, then you could create a pre-build step which would extract the version and write it into a simple version.h file as a #define or const string. Then the logging code or macro could automatically use that to always output the current version of the program.
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