One thing you might want in your code is to add tracing to it so that your application log file will contain entries for all function entries and exits. This is tremendously useful when debugging a running application especially when you cannot connect a debugger to it for any reason. It is also very helpful when your application behaved unexpectedly once and you can’t get to repro it while you have a debugger attached. In those cases your log file is your best friend. Assuming that your log file has all the information that you need to debug the issue. Tracing all the function calls is a big help.
You don’t want to do this:
bool SaveUserInfo(User* pUser) { log.Trace("Entering function SaveUserInfo"); Database.Connect(connectionString); Database.Update(GetUserUpdateSql(pUser)); Database.Disconnect(); log.Trace("Exiting function SaveUserInfo"); return true; }
It should be obvious that this approach is both tedious and error prone, especially with future changes. For example if we add a parameter validation such as the one given below:
bool SaveUserInfo(User* pUser) { log.Trace("Entering function SaveUserInfo"); if (nullptr == pUser) { return false; } Database.Connect(connectionString); Database.Update(GetUserUpdateSql(pUser)); Database.Disconnect(); log.Trace("Exiting function SaveUserInfo"); return true; }
Ofcourse we can fix this in multiple ways. We could add a trace just before returning from the validation failure block. Or we could add a goto towards the end of the program where we trace the function exit. Or we could just restructure the program as below:
bool SaveUserInfo(User* pUser) { log.Trace("Entering function SaveUserInfo"); bool retValue = false; if (nullptr != pUser) { Database.Connect(connectionString); Database.Update(GetUserUpdateSql(pUser)); Database.Disconnect(); retValue = true; } log.Trace("Exiting function SaveUserInfo"); return retValue; }
But you get the point, this is not a good solution.
So what is the solution. I had talked about RAII in a previous post. We could employ the same concept here. We can have an object created on the function stack frame. The constructor will trace the function entry and destructor (which is guaranteed to be invoked on function exit) can trace the function exit. The only thing the developer need to know is that a function trace object should be created on the stack and it should be the first line of the function. Here is some sample code.
class FunctionTrace { CString _functionName; public: FunctionTrace(CString functionName) { _functionName = functionName; log.TraceEnter(_functionName); } ~FunctionTrace() { log.TraceExit(_functionName); } };
Using the FunctionTrace class is trivial.
bool SaveUserInfo(User* pUser) { FunctionTrace ft("SaveUserInfo"); if (nullptr == pUser) { return false; } Database.Connect(connectionString); Database.Update(GetUserUpdateSql(pUser)); Database.Disconnect(); return true; }
As you can see, exiting from the function in the middle is not a problem anymore. The code is much more compact and clean.
One thing I would like to avoid is having to specify the name of the function myself. It is a problem because it is more typing and also because there is a chance that I would rename the function some time in the future and forget to update the string parameter to the FunctionTrace constructor. It is just too easy to miss that. The compiler will not be able to help me catch that oversight.
But the preprocessor can help. Lucky for us, Visual C++ defines a macro __FUNCTIONW__ that we can use to get the function name. One could easily write a macro that encapsulates this knowledge and makes sure that a FunctionTrace instance is created on the stack and passes the __FUNCTIONW__ to the constructor of FunctionTrace. We could even modify the trace to include the file name and line number using the __FILE__ and __LINE__ macros. Now the client code becomes much more simple.
bool SaveUserInfo(User* pUser) { // macro that creates FunctionTrace instance // on stack and passes in the name of the function. FUNCTION_TRACE(); if (nullptr == pUser) { return false; } Database.Connect(connectionString); Database.Update(GetUserUpdateSql(pUser)); Database.Disconnect(); return true; }
The FUNCTION_TRACE could be implemented like this:
#define FUNCTION_TRACE() FunctionTrace fn(__FUNCTIONW__)
If we modify FunctionTrace class to trace the line number and file name, we could pass those information from FUNCTION_TRACE as follows:
#define FUNCTION_TRACE() FunctionTrace fn(__FUNCTIONW__, __LINE__, __FILEW__)
This assumes that FunctionTrace constructor now takes two strings and an integer.
class FunctionTrace { public: FunctionTrace( LPWSTR functionName, int lineNumber, LPWSTR fileName); ~FunctionTrace(); };
Have fun tracing.


