Introduction
Back in 2001-2002, when I was working on a project that needed some Windows services to be built, I needed information on how the same service would run on Win 2K/XP, Pocket PC, and Win CE devices along with the data getting manipulated. I had written some functions that will log the required information into a text file. The function could take any number of arguments to be logged into the log file.
This article describes how to log the required information along with a date and time stamp into a predefined text file.
Using the code
There are three functions shown below, and the detailed information about each function is mentioned in the function comment block.
To use the code, replace CKishoreResearch
in this code with your project class name, or you can place these three functions in some common.h file and use them as global functions in your project.
In the .h file, declare as follows:
FILE *m_fp;
void log(LPWSTR str, ...);
void log(LPSTR str, ...);
In the .CPP file, in the class constructor, use the following code:
m_fp = NULL;
m_fp = _wfopen(L"C:\\KishoreLog.txt", L"a");
Following is the implemented code that actually does the logging functionality:
void CKishoreResearch::log(LPWSTR str, ...)
{
if (m_fp)
{
va_list arg_ptr;
va_start(arg_ptr, str);
SYSTEMTIME st;
GetLocalTime(&st);
fwprintf(m_fp, L"[%d/%d/%d - %d:%d:%d:%d]",
st.wMonth, st.wDay, st.wYear, st.wHour,
st.wMinute, st.wSecond, st.wMilliseconds);
vfwprintf(m_fp, str, arg_ptr);
fwprintf(m_fp, L"\n");
fflush(m_fp);
}
}
void CKishoreResearch::log(LPSTR str, ...)
{
if (m_fp)
{
va_list arg_ptr;
va_start(arg_ptr, str);
SYSTEMTIME st;
GetLocalTime(&st);
fprintf(m_fp, "[%d/%d/%d - %d:%d:%d:%d]", st.wMonth,
st.wDay, st.wYear, st.wHour, st.wMinute,
st.wSecond, st.wMilliseconds);
vfprintf(m_fp, str, arg_ptr);
fprintf(m_fp, "\n");
fflush(m_fp);
}
}
void CKishoreResearch::ComErrorMessageLog(_com_error &e)
{
bstr_t bstrSource(e.Source());
bstr_t bstrDescription(e.Description());
log( _T("Code = 0x%08lx\n"), e.Error());
log( _T("Code meaning = %s\n"), e.ErrorMessage());
log( _T("IErrorInfo.Source = %s\n"), (LPTSTR)bstrSource );
log( _T("IErrorInfo.Description = %s"),
(LPTSTR)bstrDescription );
}
Copy the above three functions into your code. Again, to use the code, replace the class CKishoreResearch
in the above code with your project class name. Once these three functions are copied, you can just make a call to the log(..)
function and pass the required information that needs to be logged into the text file.
Logging commonly used data types
Listed below are the examples of some commonly used data types.
For example, if you have a _bstr_t
data type variable and you want to log the value of the same using the log
function:
_bstr_t bsSelection;
log((LPTSTR)bsSelection);
To log a TCHAR
data type value:
TCHAR szSql[256];
log(szSql);
To log an int
data type value along with some user defined strings:
int nData;
log("Item Select = %d", nData);
To log multiple UINT
data type values along with some user defined strings:
UINT cbID1,cbID2;
log(L" ID1 is %d and ID2 is %d", cbID1, cbID2);
To log a TCHAR
data type value along with some user defined strings:
TCHAR *szFolderName
log("Folder: [%s]", szFolderName);
Points of interest
Apart from logging the required information, you can also use these functions in exception handling to log the reason for the exception.
Following is the code that will go in catch
block, in case of a COM exception:
catch(_com_error &e)
{
::MessageBox(NULL, (char*)e.Description(),
"Application Error", MB_OK|MB_ICONERROR);
ComErrorMessageLog(e);
CoUninitialize();
}
Following is the code that will go in the catch
block, in case of a normal exception, in MFC:
catch(CException* e)
/ Handle all other types of exceptions here.
{
TCHAR szErr[1024];
e->GetErrorMessage(szErr, 1024);
::MessageBox(NULL, (char*)szErr, "Application Error",
MB_OK|MB_ICONERROR);
log(szErr);
}
Well, the list of things on using the log
function will go on and on. So, I will stop here and let the users use the above code to log their information. :)