fs/sys/fsLog.cpp

Go to the documentation of this file.
00001 /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
00002 /*                          _______      ______    ______          __      */
00003 /*  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~    / ____(_)___ / ___ /)  / ____/___  ____/ /__    */
00004 /*       [fsLog]          / /_  / / __ \\__ \|/  / /   / __ \/ __  / _ \   */
00005 /*       rev.  12        / __/ / / /_/ /__/ /   / /___/ /_/ / /_/ /  __/   */
00006 /*    29th Jan 2007     /_/   /_/ ,___/____/    \____/\____/\__,_/\___/    */
00007 /*     [x] stable              /_/ (c) 2004-7 Filip STOKLAS (FipS)         */
00008 /*  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~       http://HOLE.4FipS.com/fips_code.php          */
00009 /*                                                                         */
00010 /* This code is free for personal and commercial use. You may redistribute */
00011 /* it by any means. If you use the code for your own projects please give  */
00012 /* me credit. Please send a bug report. Don't alter or remove this header! */
00013 /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
00014 #include <fs/sys/fsLog.h>
00015 
00016 // >>> COMMON SUPPORT BLOCK (rev. 6)
00017 #if defined(FS_HAS_FSASSERT)
00018 #   include <fs/sys/fsAssert.h>
00019 #else
00020 #   include <cassert>
00021 #   if !defined(FS_ASSERT)
00022 #       define FS_ASSERT(exp) assert(exp)
00023 #   endif
00024 #   if !defined(FS_ASSERT_MSG)
00025 #       define FS_ASSERT_MSG(exp, msg) assert(exp && msg)
00026 #   endif
00027 #   if !defined(FS_VERIFY)
00028 #       define FS_VERIFY(exp) \
00029         { bool bExp = !!(exp); assert(bExp && #exp); bExp; }
00030 #   endif
00031 #   if !defined(FS_VERIFY_MSG)
00032 #       define FS_VERIFY_MSG(exp, msg) \
00033         { bool bExp = !!(exp); assert(bExp && #exp && msg); bExp; }
00034 #   endif
00035 #   if !defined(FS_STATIC_ASSERT)
00036 #       define FS_STATIC_ASSERT(exp) { char error[(exp) ? 1 : 0]; error; }
00037 #   endif
00038 #endif
00039 #if !defined(FS_VERIFY_RETURN)
00040 #   define FS_VERIFY_RETURN(exp) \
00041     if(!(exp)) { FS_ASSERT_MSG(0, #exp "<return>"); return; }
00042 #endif
00043 #if !defined(FS_VERIFY_RETURN_VAL)
00044 #   define FS_VERIFY_RETURN_VAL(exp, ret) \
00045     if(!(exp)) { FS_ASSERT_MSG(0, #exp "<returns:>" #ret); return (ret); }
00046 #endif
00047 // <<< COMMON SUPPORT BLOCK (rev. 6)
00048 
00049 #include <queue>
00050 #include <string>
00051 #include <stdarg.h> // va_list
00052 
00053 #if defined(_WIN32)
00054 #   include <windows.h> // time, debug output
00055 #else
00056 #   include <time.h> // clock
00057 #endif
00058 
00059 // provide detailed memory tracking information
00060 #if defined(FS_HAS_FSMEMMGR)
00061 #   include <fs/sys/fsMemMgr.h>
00062 #endif
00063 //---------------------------------------------------------------------------
00064 #if (_MSC_VER >= 1400) // MSVC8
00065 #   pragma warning(disable : 4996) // function was marked as deprecated
00066 #endif
00067 //---------------------------------------------------------------------------
00068 using namespace fs::sys;
00069 //---------------------------------------------------------------------------
00070 namespace fs { namespace sys {
00071 //---------------------------------------------------------------------------
00072 //--- CLASS LogImpl_t >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00073 //---------------------------------------------------------------------------
00075 
00077 class LogImpl_t : public Log_t
00078 {
00079 public:
00080 
00081     LogImpl_t(unsigned int fMode, size_t uHist, const char *pszFile);
00082     virtual ~LogImpl_t();
00083 
00084     virtual void SetTgt(Log_t *pTgt);
00085     
00086 protected:
00087 
00088     virtual void RegSrc(Log_t *pSrc, bool bReg = true);
00089     virtual void PushLn(const char *pszText, bool bMsgBrk = false);
00090     
00091 private:
00092 
00093     LogImpl_t();
00094     LogImpl_t(const LogImpl_t &);
00095     LogImpl_t & operator = (const LogImpl_t &);
00096     
00097     unsigned int m_fMode; 
00098     
00099     Log_t *m_pTgt; 
00100     typedef std::vector<Log_t *> TSrcs;
00101     TSrcs m_Srcs; 
00102             
00103     void *m_hFile; 
00104     
00105     typedef std::deque<std::string> Hist_t;
00106     Hist_t m_Hist; 
00107     size_t m_uHist; 
00108         
00109     size_t m_uWrns; 
00110     size_t m_uErrs; 
00111 };
00112 //---------------------------------------------------------------------------
00113 }} //namespace fs::sys
00114 //---------------------------------------------------------------------------
00115 LogImpl_t::LogImpl_t(unsigned int fMode, size_t uHist, const char 
00116  *pszFile):
00117 m_fMode(fMode),
00118 m_pTgt(0),
00119 m_hFile(0),
00120 m_uHist(uHist),
00121 m_uWrns(0),
00122 m_uErrs(0)
00123 {
00124     if((fMode & LOG_FILE) && pszFile)
00125         m_hFile = static_cast<FILE *>(::fopen(pszFile, "w"));
00126 }
00127 //---------------------------------------------------------------------------
00128 LogImpl_t::~LogImpl_t()
00129 {
00130     // stop being a source
00131     SetTgt(0);
00132 
00133     // disconnect from all sources
00134     while(!m_Srcs.empty())
00135         m_Srcs[0]->SetTgt(0);
00136         
00137     // log statistics
00138     char szBuf[96];
00139 
00140     ::sprintf(szBuf, "o.LOG %u warning(s), %u error(s) found.",
00141      m_uWrns, m_uErrs);
00142 
00143     PushLn(szBuf);
00144 
00145     // close resources
00146     if(m_hFile)
00147         ::fclose(static_cast<FILE *>(m_hFile));
00148 }
00149 //---------------------------------------------------------------------------
00150 void LogImpl_t::SetTgt(Log_t *pTgt)
00151 {
00152     if(pTgt == this || m_pTgt == pTgt) // do nothing
00153         return;
00154 
00155     if(m_pTgt) // brake current link
00156         m_pTgt->RegSrc(this, false);
00157 
00158     m_pTgt = pTgt;
00159     if(!m_pTgt) // no new target
00160         return;
00161 
00162     if(m_pTgt) // make a new link
00163         m_pTgt->RegSrc(this);
00164         
00165     // dump the history
00166     for(Hist_t::const_iterator it = m_Hist.begin(); it != m_Hist.end(); ++it)
00167         m_pTgt->PushLn((*it).c_str());
00168     
00169     // clear the history
00170     Hist_t().swap(m_Hist);
00171 }
00172 //---------------------------------------------------------------------------
00173 void LogImpl_t::RegSrc(Log_t *pSrc, bool bReg)
00174 {
00175     FS_ASSERT(pSrc);
00176     
00177     if(bReg)
00178         m_Srcs.push_back(pSrc);
00179     else
00180     {
00181         m_Srcs.erase(
00182          std::remove(m_Srcs.begin(), m_Srcs.end(), pSrc), m_Srcs.end()
00183         );
00184     }
00185 }
00186 //---------------------------------------------------------------------------
00187 void LogImpl_t::PushLn(const char *pszText, bool bMsgBrk)
00188 {
00189     if(bMsgBrk) // message break request
00190     {
00191         //             RUNTIME BREAK: A Message break has been invoked
00192         //                            (see 'pszText').
00193         FS_ASSERT_MSG(0, pszText); // ^^^
00194     }
00195 
00196     // scan for error / warning tag
00197     bool bWrn = pszText && ::strstr(pszText,"] !.");
00198     bool bErr = pszText && ::strstr(pszText,"] x.");
00199     
00200     if((m_fMode & LOG_RTMBRK) && (bWrn || bErr)) // notify break
00201     {
00202         //             RUNTIME BREAK: An Error / warning message has been
00203         //                            occurred (see 'pszText').
00204         FS_ASSERT_MSG(0, pszText); // ^^^
00205     }
00206 
00207     if(m_pTgt) // target is set, redirect the message
00208     {
00209         m_pTgt->PushLn(pszText);
00210         return;
00211     }
00212 
00213     // log to selected outputs
00214     if(m_fMode & LOG_HIST)
00215     {
00216         if(m_Hist.size() > m_uHist)
00217             m_Hist.pop_front();
00218 
00219         m_Hist.push_back(pszText);
00220     }
00221     if(m_hFile)
00222     {
00223         ::fputs(pszText, static_cast<FILE *>(m_hFile));
00224         ::fputs("\n", static_cast<FILE *>(m_hFile));
00225         ::fflush(static_cast<FILE *>(m_hFile));
00226     }
00227     if(m_fMode & LOG_STDOUT)
00228     {
00229         ::puts(pszText);
00230     }
00231 #if defined(_WIN32)
00232     if(m_fMode & LOG_DBGOUT)
00233     {
00234         ::OutputDebugStringA(pszText);
00235         ::OutputDebugStringA("\n");
00236     }
00237 #endif
00238 
00239     // update statistics
00240     if(bWrn) ++m_uWrns;
00241     if(bErr) ++m_uErrs;
00242 }
00243 //---------------------------------------------------------------------------
00244 //--- CLASS Log_t >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
00245 //---------------------------------------------------------------------------
00250 Log_t::Log_t(unsigned int fMode, size_t uHist, const char *pszFile):
00251 m_pImpl(new LogImpl_t(fMode, uHist, pszFile))
00252 {
00253     FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00254 }
00255 //---------------------------------------------------------------------------
00256 Log_t::Log_t():
00257 m_pImpl(0)
00258 {
00259 }
00260 //---------------------------------------------------------------------------
00261 Log_t::~Log_t()
00262 {
00263     // note that if 'm_pImpl' is 0, it means that this 'Log_t' instance is
00264     // nested in 'LogImpl_t'
00265     delete m_pImpl;
00266 }
00267 //---------------------------------------------------------------------------
00273 void Log_t::Push(const char *pszFmt, ...)
00274 {
00275     FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00276 
00277     // time stamp
00278     unsigned int uTimeMs = 0;
00279     // note that if there are multiple modules the time stamp should be
00280     // based on a common time source...
00281 
00282 #if defined(UNDER_CE)
00283 
00285     uTimeMs = ::GetTickCount();
00286     
00287 #elif defined(_WIN32)
00288 
00289     ::FILETIME tmCreation;
00290     ::FILETIME tmExit;
00291     ::FILETIME tmKernel;
00292     ::FILETIME tmUser;
00293     ::GetProcessTimes(::GetCurrentProcess(), &tmCreation, &tmExit,
00294      &tmKernel, &tmUser);
00295      
00296     ::FILETIME tmCurrent;
00297     ::GetSystemTimeAsFileTime(&tmCurrent);
00298     
00299     const __int64 nDur100NS =
00300      (static_cast<__int64>
00301      (tmCurrent.dwHighDateTime - tmCreation.dwHighDateTime) << 32) +
00302      (tmCurrent.dwLowDateTime - tmCreation.dwLowDateTime);
00303     
00304     uTimeMs = static_cast<unsigned int>(nDur100NS / 10000);
00305     
00306 #else
00307 
00309     uTimeMs = static_cast<unsigned int>
00310      (1000.0 * ::clock() / CLOCKS_PER_SEC);
00311 
00312 #endif
00313      
00314     char szBuf[1024];
00315     ::sprintf(szBuf,  "[%06u:%03u] ", uTimeMs / 1000, uTimeMs % 1000);
00316     
00317     // form the message
00318     va_list Args;
00319     va_start(Args, pszFmt);
00320     const size_t uSize = sizeof(szBuf);
00321     const size_t uCount = ::strlen(szBuf);
00323     ::_vsnprintf(szBuf + uCount, sizeof(szBuf) - uCount, pszFmt, Args);
00324     va_end(Args);
00325     
00326     // handle a truncated message (note that szBuf is never empty)
00327     szBuf[uSize - 2] = szBuf[uSize - 3] = szBuf[uSize - 4] = '.';
00328     szBuf[uSize - 1] = '\0';
00329     
00330     // truncate new-line codes
00331     for(size_t n = ::strlen(szBuf) - 1; n > 0; --n)
00332     {
00333         if(szBuf[n] == 0x0D || szBuf[n] == 0x0A)
00334             szBuf[n] = '\0';
00335         else
00336             break;
00337     }
00338     
00339     // handle 'message brake' tag
00340     bool bMsgBrk = false;
00341     size_t uLen = strlen(szBuf);
00342     if(uLen > 0 && szBuf[uLen - 1] == '@')
00343     {
00344         szBuf[uLen - 1] = '\0';
00345         bMsgBrk = true;     
00346     }
00347     
00348     // lot the line
00349     m_pImpl->PushLn(szBuf, bMsgBrk);
00350 }
00351 //---------------------------------------------------------------------------
00352 void Log_t::PushLn(const char *pszText, bool bMsgBrk)
00353 {
00354     FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00355     m_pImpl->PushLn(pszText, bMsgBrk);
00356 }
00357 //---------------------------------------------------------------------------
00360 void Log_t::SetTgt(Log_t *pTgt)
00361 {
00362     FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00363     m_pImpl->SetTgt(pTgt ? pTgt->m_pImpl : 0);
00364 }
00365 //---------------------------------------------------------------------------
00366 void Log_t::RegSrc(Log_t *pSrc, bool bReg)
00367 {
00368     FS_ASSERT_MSG(m_pImpl, "Invalid implementation pointer!");
00369     m_pImpl->RegSrc(pSrc, bReg);
00370 }
00371 //---------------------------------------------------------------------------
00372 #if defined (FS_LOG_ENABLE_MODLOG)
00373 Log_t & fs::sys::ModLog()
00374 {
00375     static Log_t Inst(
00376      FS_LOG_MODLOG_MODE,
00377      FS_LOG_MODLOG_HIST,
00378      FS_LOG_MODLOG_FILE
00379     );
00380     
00381     return Inst;
00382 }
00383 #endif
00384 //---------------------------------------------------------------------------

FipS' Code (Thu Feb 15 22:43:35 2007) - (c) Filip STOKLAS (FipS) - [ www ] [ Guest Book ]