2 #include "../Common/Common.h"
5 #include "FileLogger.h"
7 // Track memory leaks on Windows to the line that new'd the memory
10 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
13 static char THIS_FILE
[] = __FILE__
;
19 #include <sys/timeb.h>
24 CFileLogger::CFileLogger(const std::string
& strFilenamePath
, eLogLevel iLogLevel
, int iOptionsMask
)
26 m_strFilenamePath
= "";
27 m_iLogLevel
= iLogLevel
;
28 m_iFunctionIndentLevel
= 0;
30 m_bFunctionLogging
= false;
33 m_bDeleteOldFile
= false;
34 m_bFunctionTiming
= false;
35 m_bOutputScreen
= false;
37 // See what options are set in our bit mask options parameter
38 if (iOptionsMask
& logFunctionEntryExit
)
39 m_bFunctionLogging
= true;
40 if (iOptionsMask
& logTimeStamp
)
42 if (iOptionsMask
& logDateStamp
)
44 if (iOptionsMask
& logDeleteOldFile
)
45 m_bDeleteOldFile
= true;
46 if (iOptionsMask
& logFunctionTiming
)
47 m_bFunctionTiming
= true;
48 if (iOptionsMask
& logOutputScreen
)
49 m_bOutputScreen
= true;
51 // On windows anyway if somebody can open up a file with CreateFile() in a different
52 // directory and cause the working directory to change. We don't want our log file
53 // moving around, so we'll find a absolute path when we are created and stick to
54 // that for the remainder of our life.
55 m_strFilenamePath
= GetFullFilenamePath(strFilenamePath
);
57 // See if we should get rid of any existing filename with our given name. This prevents having
58 // to remember to delete the file before every new debugging run.
63 fp
= fopen(m_strFilenamePath
.c_str(), "w");
73 CFileLogger::~CFileLogger()
76 if (m_bFunctionTiming
)
78 // Dump the results of our function timing logging
80 MAP_STRING_INT64::iterator map_iter
;
82 Log("%-60s%20s%10s", logNORMAL
, "Function","Ticks", "Percent");
83 Log("%-60s%20s%10s", logNORMAL
, "--------","-----", "-------");
85 __int64 iMaxTicks
= 0;
87 // First pass to count the max ticks
88 // We assume that there was a function logger on the outer most (main) program.
89 // This allows the percent reflect the relative time spent inside emedded calls.
91 for (map_iter
= m_mapFunctionTicks
.begin(); map_iter
!= m_mapFunctionTicks
.end(); map_iter
++)
93 if (map_iter
->second
> iMaxTicks
)
94 iMaxTicks
= map_iter
->second
;
97 for (map_iter
= m_mapFunctionTicks
.begin(); map_iter
!= m_mapFunctionTicks
.end(); map_iter
++)
99 std::string name
= map_iter
->first
;
100 __int64 iTicks
= map_iter
->second
;
101 Log("%-60s%20I64Ld%10.2f", logNORMAL
, name
.c_str(), iTicks
, (double) iTicks
/ (double) iMaxTicks
* (double) 100.0);
107 // Changes the filename of this logging object
108 void CFileLogger::SetFilename(const std::string
& strFilename
)
110 m_strFilenamePath
= strFilename
;
112 // See if we should get rid of any existing filename with our given name. This prevents having
113 // to remember to delete the file before every new debugging run.
114 if (m_bDeleteOldFile
)
118 fp
= fopen(m_strFilenamePath
.c_str(), "w");
127 // Logs a string to our file. eLogLevel specifies the importance of this message, we
128 // only write to the log file if it is at least as important as the level set in the
129 // constructor. Accepts printf style formatting in the first string which must be
130 // filled with the variable parameter list at the end.
131 // NOTE: Currently not thread safe!
132 void CFileLogger::Log(const char* szText
, eLogLevel iLogLevel
, ...)
136 if ((m_strFilenamePath
.length() > 0) &&
137 (m_iLogLevel
<= iLogLevel
) &&
141 fp
= fopen(m_strFilenamePath
.c_str(), "a");
143 std::string strTimeStamp
= GetTimeDateStamp();
147 std::string strIndented
= strTimeStamp
+ GetIndentedString(szText
) + "\n";
149 va_start(args
, iLogLevel
);
150 vfprintf(fp
, strIndented
.c_str(), args
);
153 // Optionally we can output message to stdout
156 va_start(args
, iLogLevel
);
157 vprintf(strIndented
.c_str(), args
);
167 // Overloaded version that takes a STL::string
168 void CFileLogger::Log(const std::string strText
, eLogLevel iLogLevel
, ...)
172 if ((m_strFilenamePath
.length() > 0) &&
173 (m_iLogLevel
<= iLogLevel
))
176 fp
= fopen(m_strFilenamePath
.c_str(), "a");
178 std::string strTimeStamp
= GetTimeDateStamp();
182 std::string strIndented
= strTimeStamp
+ GetIndentedString(strText
) + "\n";
184 va_start(args
, iLogLevel
);
185 vfprintf(fp
, strIndented
.c_str(), args
);
188 // Optionally we can output message to stdout
191 va_start(args
, iLogLevel
);
192 vprintf(strIndented
.c_str(), args
);
202 // Version that assume log level is logDEBUG
203 void CFileLogger::LogDebug(const char* szText
, ...)
205 // Note: it would be nice not to duplicate code, but the variable
206 // parameter list makes this problematic.
209 if ((m_strFilenamePath
.length() > 0) &&
210 (m_iLogLevel
== logDEBUG
) &&
214 fp
= fopen(m_strFilenamePath
.c_str(), "a");
216 std::string strTimeStamp
= GetTimeDateStamp();
220 std::string strIndented
= strTimeStamp
+ GetIndentedString(szText
) + "\n";
222 va_start(args
, szText
);
223 vfprintf(fp
, strIndented
.c_str(), args
);
226 // Optionally we can output message to stdout
229 va_start(args
, szText
);
230 vprintf(strIndented
.c_str(), args
);
240 // Version that assume log level is logNormal
241 void CFileLogger::LogNormal(const char* szText
, ...)
243 // Note: it would be nice not to duplicate code, but the variable
244 // parameter list makes this problematic.
247 if ((m_strFilenamePath
.length() > 0) &&
248 (m_iLogLevel
<= logNORMAL
) &&
252 fp
= fopen(m_strFilenamePath
.c_str(), "a");
254 std::string strTimeStamp
= GetTimeDateStamp();
258 std::string strIndented
= strTimeStamp
+ GetIndentedString(szText
) + "\n";
260 va_start(args
, szText
);
261 vfprintf(fp
, strIndented
.c_str(), args
);
264 // Optionally we can output message to stdout
267 va_start(args
, szText
);
268 vprintf(strIndented
.c_str(), args
);
278 // Version that assume log level is logCRITICAL
279 void CFileLogger::LogCritical(const char* szText
, ...)
281 // Note: it would be nice not to duplicate code, but the variable
282 // parameter list makes this problematic.
285 // Always log critical messages
286 if ((m_strFilenamePath
.length() > 0) &&
290 fp
= fopen(m_strFilenamePath
.c_str(), "a");
292 std::string strTimeStamp
= GetTimeDateStamp();
296 std::string strIndented
= strTimeStamp
+ GetIndentedString(szText
) + "\n";
298 va_start(args
, szText
);
299 vfprintf(fp
, strIndented
.c_str(), args
);
302 // Optionally we can output message to stdout
305 va_start(args
, szText
);
306 vprintf(strIndented
.c_str(), args
);
316 // Logs entry into a particular function
317 void CFileLogger::LogFunctionEntry(const std::string
& strFunctionName
)
319 if (m_bFunctionLogging
)
321 std::string strStart
= "start: ";
322 strStart
+= strFunctionName
;
323 Log(strStart
.c_str());
324 m_iFunctionIndentLevel
++;
328 // Logs exit into a particular function
329 void CFileLogger::LogFunctionExit(const std::string
& strFunctionName
)
331 if (m_bFunctionLogging
)
333 m_iFunctionIndentLevel
--;
334 std::string strEnd
= "end: ";
335 strEnd
+= strFunctionName
;
341 void CFileLogger::LogFunctionTicks(const std::string
& strFunctionName
, __int64 iTicks
)
345 iCurrent
= m_mapFunctionTicks
[strFunctionName
];
346 iCurrent
= iCurrent
+ iTicks
;
348 m_mapFunctionTicks
[strFunctionName
] = iCurrent
;
352 // Gets an indented version of the function name
353 std::string
CFileLogger::GetIndentedString(const std::string
& strText
)
355 std::string strIndented
= "";
356 for (int i
= 0; i
< m_iFunctionIndentLevel
; i
++)
358 strIndented
+= strText
;
363 bool CFileLogger::GetFunctionTiming()
365 return m_bFunctionTiming
;
368 // Utility method that converts a filename into a fully qualified
369 // path and filename on Windows. This can be used to make sure
370 // a relative filename stays pointed at the same location despite
371 // changes in the working directory.
372 std::string
CFileLogger::GetFullFilenamePath(std::string strFilename
)
377 const int MAX_PATH_LENGTH
= 1024;
381 // In Unicode, we need the parameters to GetFullPathName() in wide characters
382 wchar_t szPath
[MAX_PATH_LENGTH
];
383 wchar_t* pszFilePart
= NULL
;
384 wchar_t wstrFilenamePath
[MAX_PATH_LENGTH
];
385 char szResult
[MAX_PATH_LENGTH
];
388 for (i
= 0; i
< strFilename
.length(); i
++)
389 wstrFilenamePath
[i
] = (wchar_t) strFilename
[i
];
390 wstrFilenamePath
[i
] = '\0';
392 ::GetFullPathName(wstrFilenamePath
, MAX_PATH_LENGTH
, szPath
, &pszFilePart
);
394 while (szPath
[i
] != '\0')
396 szResult
[i
] = (char) szPath
[i
];
404 // Using normal non-unicode strings
405 char szPath
[MAX_PATH_LENGTH
];
406 char* pszFilePart
= NULL
;
408 ::GetFullPathName(strFilename
.c_str(), MAX_PATH_LENGTH
, szPath
, &pszFilePart
);
421 /////////////////////////////////////// CFunctionLogger /////////////////////////////////////////////////////////////
423 CFunctionLogger::CFunctionLogger(const std::string
& strFunctionName
, CFileLogger
* pLogger
)
427 if ((m_pLogger
!= NULL
) && (strFunctionName
.length() > 0))
429 m_strFunctionName
= strFunctionName
;
431 if (!m_pLogger
->GetFunctionTiming())
432 m_pLogger
->LogFunctionEntry(m_strFunctionName
);
435 QueryPerformanceCounter(&m_iStartTicks
);
442 CFunctionLogger::~CFunctionLogger()
444 if ((m_pLogger
!= NULL
) && (m_strFunctionName
.length() > 0))
446 if (!m_pLogger
->GetFunctionTiming())
447 m_pLogger
->LogFunctionExit(m_strFunctionName
);
451 LARGE_INTEGER iEndTicks
;
452 QueryPerformanceCounter(&iEndTicks
);
453 // Add our total ticks to the tracking map object in the logger object
454 m_pLogger
->LogFunctionTicks(m_strFunctionName
,
455 iEndTicks
.QuadPart
- m_iStartTicks
.QuadPart
);
461 // Update what log level this object is using
462 void CFileLogger::SetLogLevel(const eLogLevel iNewLevel
)
464 m_iLogLevel
= iNewLevel
;
467 // Update whether function entry/exit is logged
468 void CFileLogger::SetFunctionLogging(bool bFunctionLogging
)
470 m_bFunctionLogging
= bFunctionLogging
;
474 // Gets the time and/or date stamp as specified
475 // by our construction options.
476 std::string
CFileLogger::GetTimeDateStamp()
478 std::string strTimeStamp
= "";
480 if ((m_bTimeStamp
) || (m_bDateStamp
))
483 struct timeb sTimeBuffer
;
485 struct timeval sTimeBuffer
;
486 struct timezone sTimezoneBuffer
;
489 char* szTimeLine
= NULL
;
493 szTimeLine
= ctime(&(sTimeBuffer
.time
));
495 gettimeofday(&sTimeBuffer
, &sTimezoneBuffer
);
496 t
= sTimeBuffer
.tv_sec
;
497 szTimeLine
= ctime(&t
);
501 // Wed Jun 22 10:22:00 2005
502 // 0123456789012345678901234
503 if ((szTimeLine
!= NULL
) && (strlen(szTimeLine
) > 23))
507 for (int i
= 4; i
< 10; i
++)
508 strTimeStamp
+= szTimeLine
[i
];
509 for (int i
= 19; i
< 24; i
++)
510 strTimeStamp
+= szTimeLine
[i
];
517 for (int i
= 11; i
< 19; i
++)
518 strTimeStamp
+= szTimeLine
[i
];
522 sprintf(strMs
, "%d", sTimeBuffer
.millitm
);
524 sprintf(strMs
, "%d", static_cast<int>(sTimeBuffer
.tv_usec
/ 1000));
526 if (strlen(strMs
) == 1)
527 strTimeStamp
+= "00";
528 else if (strlen(strMs
) == 2)
530 strTimeStamp
+= strMs
;
533 strTimeStamp
+= "\t";