2 #include "../Common/Common.h"
4 #include "FileLogger.h"
6 // Track memory leaks on Windows to the line that new'd the memory
9 #define DEBUG_NEW new( _NORMAL_BLOCK, THIS_FILE, __LINE__ )
12 static char THIS_FILE
[] = __FILE__
;
23 #include <sys/timeb.h>
28 CFileLogger::CFileLogger(const std::string
& strFilenamePath
, eLogLevel iLogLevel
, int iOptionsMask
)
30 m_strFilenamePath
= "";
31 m_iLogLevel
= iLogLevel
;
32 m_iFunctionIndentLevel
= 0;
34 m_bFunctionLogging
= false;
37 m_bDeleteOldFile
= false;
38 m_bFunctionTiming
= false;
39 m_bOutputScreen
= false;
41 // See what options are set in our bit mask options parameter
42 if (iOptionsMask
& logFunctionEntryExit
)
43 m_bFunctionLogging
= true;
44 if (iOptionsMask
& logTimeStamp
)
46 if (iOptionsMask
& logDateStamp
)
48 if (iOptionsMask
& logDeleteOldFile
)
49 m_bDeleteOldFile
= true;
50 if (iOptionsMask
& logFunctionTiming
)
51 m_bFunctionTiming
= true;
52 if (iOptionsMask
& logOutputScreen
)
53 m_bOutputScreen
= true;
55 // On windows anyway if somebody can open up a file with CreateFile() in a different
56 // directory and cause the working directory to change. We don't want our log file
57 // moving around, so we'll find a absolute path when we are created and stick to
58 // that for the remainder of our life.
59 m_strFilenamePath
= GetFullFilenamePath(strFilenamePath
);
61 // See if we should get rid of any existing filename with our given name. This prevents having
62 // to remember to delete the file before every new debugging run.
67 fp
= fopen(m_strFilenamePath
.c_str(), "w");
77 CFileLogger::~CFileLogger()
80 if (m_bFunctionTiming
)
82 // Dump the results of our function timing logging
84 MAP_STRING_INT64::iterator map_iter
;
86 Log("%-60s%20s%10s", logNORMAL
, "Function","Ticks", "Percent");
87 Log("%-60s%20s%10s", logNORMAL
, "--------","-----", "-------");
89 __int64 iMaxTicks
= 0;
91 // First pass to count the max ticks
92 // We assume that there was a function logger on the outer most (main) program.
93 // This allows the percent reflect the relative time spent inside emedded calls.
95 for (map_iter
= m_mapFunctionTicks
.begin(); map_iter
!= m_mapFunctionTicks
.end(); map_iter
++)
97 if (map_iter
->second
> iMaxTicks
)
98 iMaxTicks
= map_iter
->second
;
101 for (map_iter
= m_mapFunctionTicks
.begin(); map_iter
!= m_mapFunctionTicks
.end(); map_iter
++)
103 std::string name
= map_iter
->first
;
104 __int64 iTicks
= map_iter
->second
;
105 Log("%-60s%20I64Ld%10.2f", logNORMAL
, name
.c_str(), iTicks
, (double) iTicks
/ (double) iMaxTicks
* (double) 100.0);
111 // Changes the filename of this logging object
112 void CFileLogger::SetFilename(const std::string
& strFilename
)
114 m_strFilenamePath
= strFilename
;
116 // See if we should get rid of any existing filename with our given name. This prevents having
117 // to remember to delete the file before every new debugging run.
118 if (m_bDeleteOldFile
)
122 fp
= fopen(m_strFilenamePath
.c_str(), "w");
131 // Logs a string to our file. eLogLevel specifies the importance of this message, we
132 // only write to the log file if it is at least as important as the level set in the
133 // constructor. Accepts printf style formatting in the first string which must be
134 // filled with the variable parameter list at the end.
135 // NOTE: Currently not thread safe!
136 void CFileLogger::Log(const char* szText
, eLogLevel iLogLevel
, ...)
140 if ((m_strFilenamePath
.length() > 0) &&
141 (m_iLogLevel
<= iLogLevel
) &&
145 fp
= fopen(m_strFilenamePath
.c_str(), "a");
147 std::string strTimeStamp
= GetTimeDateStamp();
151 std::string strIndented
= strTimeStamp
+ GetIndentedString(szText
) + "\n";
153 va_start(args
, iLogLevel
);
154 vfprintf(fp
, strIndented
.c_str(), args
);
157 // Optionally we can output message to stdout
160 va_start(args
, iLogLevel
);
161 vprintf(strIndented
.c_str(), args
);
171 // Overloaded version that takes a STL::string
172 void CFileLogger::Log(const std::string strText
, eLogLevel iLogLevel
, ...)
176 if ((m_strFilenamePath
.length() > 0) &&
177 (m_iLogLevel
<= iLogLevel
))
180 fp
= fopen(m_strFilenamePath
.c_str(), "a");
182 std::string strTimeStamp
= GetTimeDateStamp();
186 std::string strIndented
= strTimeStamp
+ GetIndentedString(strText
) + "\n";
188 va_start(args
, iLogLevel
);
189 vfprintf(fp
, strIndented
.c_str(), args
);
192 // Optionally we can output message to stdout
195 va_start(args
, iLogLevel
);
196 vprintf(strIndented
.c_str(), args
);
206 // Version that assume log level is logDEBUG
207 void CFileLogger::LogDebug(const char* szText
, ...)
209 // Note: it would be nice not to duplicate code, but the variable
210 // parameter list makes this problematic.
213 if ((m_strFilenamePath
.length() > 0) &&
214 (m_iLogLevel
== logDEBUG
) &&
218 fp
= fopen(m_strFilenamePath
.c_str(), "a");
220 std::string strTimeStamp
= GetTimeDateStamp();
224 std::string strIndented
= strTimeStamp
+ GetIndentedString(szText
) + "\n";
226 va_start(args
, szText
);
227 vfprintf(fp
, strIndented
.c_str(), args
);
230 // Optionally we can output message to stdout
233 va_start(args
, szText
);
234 vprintf(strIndented
.c_str(), args
);
244 // Version that assume log level is logNormal
245 void CFileLogger::LogNormal(const char* szText
, ...)
247 // Note: it would be nice not to duplicate code, but the variable
248 // parameter list makes this problematic.
251 if ((m_strFilenamePath
.length() > 0) &&
252 (m_iLogLevel
<= logNORMAL
) &&
256 fp
= fopen(m_strFilenamePath
.c_str(), "a");
258 std::string strTimeStamp
= GetTimeDateStamp();
262 std::string strIndented
= strTimeStamp
+ GetIndentedString(szText
) + "\n";
264 va_start(args
, szText
);
265 vfprintf(fp
, strIndented
.c_str(), args
);
268 // Optionally we can output message to stdout
271 va_start(args
, szText
);
272 vprintf(strIndented
.c_str(), args
);
282 // Version that assume log level is logCRITICAL
283 void CFileLogger::LogCritical(const char* szText
, ...)
285 // Note: it would be nice not to duplicate code, but the variable
286 // parameter list makes this problematic.
289 // Always log critical messages
290 if ((m_strFilenamePath
.length() > 0) &&
294 fp
= fopen(m_strFilenamePath
.c_str(), "a");
296 std::string strTimeStamp
= GetTimeDateStamp();
300 std::string strIndented
= strTimeStamp
+ GetIndentedString(szText
) + "\n";
302 va_start(args
, szText
);
303 vfprintf(fp
, strIndented
.c_str(), args
);
306 // Optionally we can output message to stdout
309 va_start(args
, szText
);
310 vprintf(strIndented
.c_str(), args
);
320 // Logs entry into a particular function
321 void CFileLogger::LogFunctionEntry(const std::string
& strFunctionName
)
323 if (m_bFunctionLogging
)
325 std::string strStart
= "start: ";
326 strStart
+= strFunctionName
;
327 Log(strStart
.c_str());
328 m_iFunctionIndentLevel
++;
332 // Logs exit into a particular function
333 void CFileLogger::LogFunctionExit(const std::string
& strFunctionName
)
335 if (m_bFunctionLogging
)
337 m_iFunctionIndentLevel
--;
338 std::string strEnd
= "end: ";
339 strEnd
+= strFunctionName
;
345 void CFileLogger::LogFunctionTicks(const std::string
& strFunctionName
, __int64 iTicks
)
349 iCurrent
= m_mapFunctionTicks
[strFunctionName
];
350 iCurrent
= iCurrent
+ iTicks
;
352 m_mapFunctionTicks
[strFunctionName
] = iCurrent
;
356 // Gets an indented version of the function name
357 std::string
CFileLogger::GetIndentedString(const std::string
& strText
)
359 std::string strIndented
= "";
360 for (int i
= 0; i
< m_iFunctionIndentLevel
; i
++)
362 strIndented
+= strText
;
367 bool CFileLogger::GetFunctionTiming()
369 return m_bFunctionTiming
;
372 // Utility method that converts a filename into a fully qualified
373 // path and filename on Windows. This can be used to make sure
374 // a relative filename stays pointed at the same location despite
375 // changes in the working directory.
376 std::string
CFileLogger::GetFullFilenamePath(std::string strFilename
)
381 const int MAX_PATH_LENGTH
= 1024;
385 // In Unicode, we need the parameters to GetFullPathName() in wide characters
386 wchar_t szPath
[MAX_PATH_LENGTH
];
387 wchar_t* pszFilePart
= NULL
;
388 wchar_t wstrFilenamePath
[MAX_PATH_LENGTH
];
389 char szResult
[MAX_PATH_LENGTH
];
392 for (i
= 0; i
< strFilename
.length(); i
++)
393 wstrFilenamePath
[i
] = (wchar_t) strFilename
[i
];
394 wstrFilenamePath
[i
] = '\0';
396 ::GetFullPathName(wstrFilenamePath
, MAX_PATH_LENGTH
, szPath
, &pszFilePart
);
398 while (szPath
[i
] != '\0')
400 szResult
[i
] = (char) szPath
[i
];
408 // Using normal non-unicode strings
409 char szPath
[MAX_PATH_LENGTH
];
410 char* pszFilePart
= NULL
;
412 ::GetFullPathName(strFilename
.c_str(), MAX_PATH_LENGTH
, szPath
, &pszFilePart
);
425 /////////////////////////////////////// CFunctionLogger /////////////////////////////////////////////////////////////
427 CFunctionLogger::CFunctionLogger(const std::string
& strFunctionName
, CFileLogger
* pLogger
)
431 if ((m_pLogger
!= NULL
) && (strFunctionName
.length() > 0))
433 m_strFunctionName
= strFunctionName
;
435 if (!m_pLogger
->GetFunctionTiming())
436 m_pLogger
->LogFunctionEntry(m_strFunctionName
);
444 mov iStartTicks
.int32val
.i32
[0], eax
445 mov iStartTicks
.int32val
.i32
[4], edx
447 m_iStartTicks
= iStartTicks
;
454 CFunctionLogger::~CFunctionLogger()
456 if ((m_pLogger
!= NULL
) && (m_strFunctionName
.length() > 0))
458 if (!m_pLogger
->GetFunctionTiming())
459 m_pLogger
->LogFunctionExit(m_strFunctionName
);
468 mov iEndTicks
.int32val
.i32
[0], eax
469 mov iEndTicks
.int32val
.i32
[4], edx
471 // Add our total ticks to the tracking map object in the logger object
472 m_pLogger
->LogFunctionTicks(m_strFunctionName
,
473 iEndTicks
.int64val
.i64
- m_iStartTicks
.int64val
.i64
);
480 // Update what log level this object is using
481 void CFileLogger::SetLogLevel(const eLogLevel iNewLevel
)
483 m_iLogLevel
= iNewLevel
;
486 // Update whether function entry/exit is logged
487 void CFileLogger::SetFunctionLogging(bool bFunctionLogging
)
489 m_bFunctionLogging
= bFunctionLogging
;
493 // Gets the time and/or date stamp as specified
494 // by our construction options.
495 std::string
CFileLogger::GetTimeDateStamp()
497 std::string strTimeStamp
= "";
499 if ((m_bTimeStamp
) || (m_bDateStamp
))
502 struct timeb sTimeBuffer
;
504 struct timeval sTimeBuffer
;
505 struct timezone sTimezoneBuffer
;
507 char* szTimeLine
= NULL
;
511 szTimeLine
= ctime(&(sTimeBuffer
.time
));
513 gettimeofday(&sTimeBuffer
, &sTimezoneBuffer
);
514 szTimeLine
= ctime(&(sTimeBuffer
.tv_sec
));
518 // Wed Jun 22 10:22:00 2005
519 // 0123456789012345678901234
520 if ((szTimeLine
!= NULL
) && (strlen(szTimeLine
) > 23))
524 for (int i
= 4; i
< 10; i
++)
525 strTimeStamp
+= szTimeLine
[i
];
526 for (int i
= 19; i
< 24; i
++)
527 strTimeStamp
+= szTimeLine
[i
];
534 for (int i
= 11; i
< 19; i
++)
535 strTimeStamp
+= szTimeLine
[i
];
539 sprintf(strMs
, "%d", sTimeBuffer
.millitm
);
541 sprintf(strMs
, "%d", static_cast<int>(sTimeBuffer
.tv_usec
/ 1000));
543 if (strlen(strMs
) == 1)
544 strTimeStamp
+= "00";
545 else if (strlen(strMs
) == 2)
547 strTimeStamp
+= strMs
;
550 strTimeStamp
+= "\t";