Main Page | Class Hierarchy | Class List | File List | Class Members

Log.h

00001 // Log.h -- Interface to a level/pattern based logging mechanism.
00002 
00003 /*
00004  * Copyright (C) 2003 Tudor Hulubei <tudor@hulubei.net>.
00005  *
00006  * This library is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as
00008  * published by the Free Software Foundation; either version 2, or (at
00009  * your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA,
00019  * 02111-1307, USA.
00020  */
00021 
00022 // $Id: Log_8h-source.html,v 1.1 2005/05/25 12:37:18 tudor Exp $
00023 
00024 #ifndef _CSP_KERNEL_Log_H
00025 #define _CSP_KERNEL_Log_H
00026 
00027 
00028 #include <vector>
00029 #include <fstream>
00030 
00031 
00032 CSP_NAMESPACE_BEGIN(csp);
00033 
00034 
00036 enum LogLevel
00037 {
00038     Info = 0, // Informational messages, versions, copyrights, etc.
00039     Error,    // Errors in the code's logic.
00040     Warning,  // Warnings about unusual conditions.
00041     Notice,   // Useful notices.
00042     Debug0,   // Debugging messages (level 0, relatively quiet).
00043     Debug1,   // Debugging messages (level 1, a bit more verbose).
00044     Debug2,   // Debugging messages (level 2, verbose).
00045     Debug,    // Debugging messages (everything).
00046     MaxLevel
00047 };
00048 
00049 // Logging preamble flags.
00050 enum LogPreambleFlags
00051 {
00052     LogProgram = 1,
00053     LogProcessId = 2,
00054     LogThreadId = 4,
00055     LogDate = 8,
00056     LogTime = 16,
00057     LogLevelName = 32,
00058     LogCategory = 64,
00059     LogIndentationLevel = 128,
00060     LogAll = 0xFFFFFFFF
00061 };
00062 
00063 
00072 class CSP_API GlobalLog
00073 {
00074   public:
00075     typedef unsigned int PreambleFlags;
00076 
00092     GlobalLog(
00093         const wstring& programName,
00094         Mutex::GlobalData& globalData,
00095         size_t maxLineLength);
00096 
00101     ~GlobalLog() { while (m_mutex.iHoldIt()) m_mutex.release();  }
00102 
00108     void registerPattern(const wstring& pattern);
00109 
00115     void unregisterPattern(const wstring& pattern);
00116 
00121     void clearPatterns()
00122     {
00123         m_patterns.clear();
00124         registerPattern(L"csp::Log");
00125     }
00126 
00132     const vector<wstring>& patterns() const { return m_patterns; }
00133 
00141     LogLevel level() const { return m_level; }
00142 
00150     void setLevel(const LogLevel level);
00151 
00159     LogLevel threshold() const { return m_threshold; }
00160 
00168     void setThreshold(const LogLevel threshold);
00169 
00177     void setPreambleFlags(const PreambleFlags preambleFlags) {
00178         m_preambleFlags = preambleFlags; }
00179 
00184     void lock() { m_mutex.acquire(); }
00185 
00191     void unlock() { m_mutex.release(); }
00192 
00199     bool isEnabled(const LogLevel level) {
00200         // Test first the condition most likely to fail.
00201         return level <= m_level && level >= 0; }
00202 
00210     bool isEnabled(const wstring& category);
00211 
00213     const wstring levelName(const LogLevel level) const;
00214 
00216     const wstring levelColor(const LogLevel level) const;
00217 
00225     void write(
00226         const wstring& category,
00227         const LogLevel level,
00228         wostringstream& wos);
00229 
00231     void setIndentationState(const bool useIndentation)
00232     {
00233         m_useIndentation = useIndentation;
00234     }
00235 
00242     void setIndentationAmount(const size_t spaces);
00243 
00252     void registerIndentationLevelPlaceholder(int& indentationLevel);
00253 
00257     void unregisterIndentationLevelPlaceholder();
00258 
00264     const int& indentationLevelPlaceholder() const;
00265 
00271     bool outputToTTY() const
00272     {
00273 #ifdef _WIN32
00274         return false;
00275 #else
00276         return isatty(2);
00277 #endif
00278     }
00279 
00280   protected:
00290     const wstring preamble(
00291         const wstring& category,
00292         const LogLevel level);
00293 
00303     void splitLine(
00304         const wstring& line,
00305         vector<wstring>& lines,
00306         wstring::size_type reserved);
00307 
00315     void splitMultiLine(const wstring& line, vector<wstring>& lines);
00316 
00325     const wstring indent(const int threadId) const;
00326 
00333     const int indentationLevel(const int threadId) const;
00334 
00345     const wstring fit(const wstring& text, const size_t limit);
00346 
00348     wstring m_programName;
00349 
00351     LogLevel m_level;
00352 
00354     LogLevel m_threshold;
00355 
00362     vector<wstring> m_patterns;
00363 
00365     vector<pair<wstring, wstring> > m_levelInfo;
00366 
00371     PreambleFlags m_preambleFlags;
00372 
00377     size_t m_maxLineLength;
00378 
00380     bool m_useIndentation;
00381 
00383     size_t m_spaces;
00384 
00386     size_t m_maxLogLevelNameLength;
00387 
00395     hash_map<int, int*> m_indentationLevels;
00396 
00398     bool m_useColors;
00399 
00404     Mutex::GlobalData& m_globalData;
00405 
00410     Mutex m_mutex;
00411 };
00412 
00413 
00414 extern CSP_API GlobalLog* g_log;
00415 
00416 
00423 class CSP_API Log
00424 {
00425   public:
00426     Log(const wstring& programName);
00427     ~Log();
00428 
00429     static void registerPattern(const wstring& pattern) {
00430         g_log->registerPattern(pattern); }
00431     static void unregisterPattern(const wstring& pattern) {
00432         g_log->unregisterPattern(pattern); }
00433     static void clearPatterns() {
00434         g_log->clearPatterns(); }
00435     static const vector<wstring>& patterns() {
00436         return g_log->patterns(); }
00437     static LogLevel level() {
00438         return g_log->level(); }
00439     static void setLevel(LogLevel level) {
00440         g_log->setLevel(level); }
00441     static LogLevel threshold() {
00442         return g_log->threshold(); }
00443     static void setThreshold(LogLevel threshold) {
00444         g_log->setThreshold(threshold); }
00445     static void setPreambleFlags(const GlobalLog::PreambleFlags flags) {
00446         g_log->setPreambleFlags(flags); }
00447     static bool isEnabled(const LogLevel level) {
00448         return g_log->isEnabled(level); }
00449     static bool isEnabled(const wstring& category) {
00450         return g_log->isEnabled(category); }
00451     static const wstring levelName(const LogLevel level) {
00452         return g_log->levelName(level); }
00453     static const wstring levelColor(const LogLevel level) {
00454         return g_log->levelColor(level); }
00455     static void write(
00456         const wstring& category,
00457         const LogLevel level,
00458         wostringstream& wos) {
00459         return g_log->write(category, level, wos); }
00460     static void setIndentationState(const bool indentation) {
00461         g_log->setIndentationState(indentation); }
00462     static void setIndentationAmount(const size_t spaces) {
00463         g_log->setIndentationAmount(spaces); }
00464     static void registerIndentationLevelPlaceholder(int& indentationLevel) {
00465         g_log->registerIndentationLevelPlaceholder(indentationLevel); }
00466     static void unregisterIndentationLevelPlaceholder() {
00467         g_log->unregisterIndentationLevelPlaceholder(); }
00468     static bool outputToTTY() {
00469         return g_log->outputToTTY(); }
00470 
00471 };
00472 
00473 
00474 // This macro is used even when optimizations are turned on.  We want
00475 // to avoid acquiring/releasing the lock for high logging levels, and
00476 // by checking the log level _outside_ of the critical region we're
00477 // trading a bit of correctness for a significant speed improvement
00478 // The worst thing that can happen is that we may end up logging when
00479 // not allowed or failing to log a few messages, if the logging level
00480 // is changed dynamically in a different thread.  Checking the logging
00481 // category is much slower and, more importantly, involves checking
00482 // data (m_patterns) whose structure can be changed in another thread,
00483 // making it unsafe to check outside the critical region.
00484 // `isEnabled(level)' checks the "level <= m_level" condition first,
00485 // making it very likely that in optimization mode, the overhead of
00486 // the LOG() macro is a simple integer comparison (well, if you're
00487 // willing to ignore the increased register pressure caused by
00488 // populating the code with these relatively large macros).
00489 #define LOG(category, level, message)\
00490 {\
00491     using namespace csp;\
00492     assert(g_log);\
00493     if (g_log->isEnabled(level))\
00494     {\
00495         g_log->lock();\
00496         if (((level) <= g_log->threshold()) || g_log->isEnabled(category))\
00497         {\
00498             std::wostringstream wos;\
00499             wos << message;\
00500             g_log->write((category), (level), wos);\
00501         }\
00502         g_log->unlock();\
00503     }\
00504 }
00505 
00506 
00507 CSP_NAMESPACE_END(csp);
00508 
00509 
00510 #endif // _CSP_KERNEL_Log_H
00511 
00512 // Local Variables:
00513 // mode: C++
00514 // End:

Generated on Wed May 25 12:21:14 2005 for csp.kdevelop by  doxygen 1.3.9.1