Logging.cc
Go to the documentation of this file.
00001 #include "Rivet/Tools/Logging.hh" 00002 #include <ctime> 00003 #include <unistd.h> 00004 using namespace std; 00005 00006 namespace Rivet { 00007 00008 00009 Log::LogMap Log::existingLogs; 00010 Log::LevelMap Log::defaultLevels; 00011 Log::ColorCodes Log::colorCodes; 00012 string Log::endColorCode; 00013 bool Log::showTimestamp = false; 00014 bool Log::showLogLevel = true; 00015 bool Log::showLoggerName = true; 00016 bool Log::useShellColors = true; 00017 00018 00019 Log::Log(const string& name) 00020 : _name(name), _level(INFO), _nostream(new ostream(0)) { } 00021 00022 00023 Log::Log(const string& name, int level) 00024 : _name(name), _level(level), _nostream(new ostream(0)) { } 00025 00026 00027 /// @todo Add single static setLevel 00028 void _updateLevels(const Log::LevelMap& defaultLevels, Log::LogMap& existingLogs) { 00029 /// @todo Check ordering - "Foo" should come before "Foo.Bar" 00030 for (Log::LevelMap::const_iterator lev = defaultLevels.begin(); lev != defaultLevels.end(); ++lev) { 00031 for (Log::LogMap::iterator log = existingLogs.begin(); log != existingLogs.end(); ++log) { 00032 if (log->first.find(lev->first) == 0) { 00033 log->second->setLevel(lev->second); 00034 } 00035 } 00036 } 00037 } 00038 00039 00040 void Log::setLevel(const string& name, int level) { 00041 defaultLevels[name] = level; 00042 //cout << name << " -> " << level << endl; 00043 _updateLevels(defaultLevels, existingLogs); 00044 } 00045 00046 00047 void Log::setLevels(const LevelMap& logLevels) { 00048 for (LevelMap::const_iterator lev = logLevels.begin(); lev != logLevels.end(); ++lev) { 00049 defaultLevels[lev->first] = lev->second; 00050 } 00051 _updateLevels(defaultLevels, existingLogs); 00052 } 00053 00054 00055 Log& Log::getLog(const string& name) { 00056 if (existingLogs.find(name) == existingLogs.end()) { 00057 int level = INFO; 00058 // Try running through all parent classes to find an existing level 00059 string tmpname = name; 00060 bool triedAllParents = false; 00061 while (! triedAllParents) { 00062 // Is there a default level? 00063 if (defaultLevels.find(tmpname) != defaultLevels.end()) { 00064 level = defaultLevels.find(tmpname)->second; 00065 break; 00066 } 00067 // Is there already such a logger? (NB. tmpname != name) 00068 if (existingLogs.find(tmpname) != existingLogs.end()) { 00069 level = existingLogs.find(tmpname)->second->getLevel(); 00070 break; 00071 } 00072 // Crop the string back to the next parent level 00073 size_t lastDot = tmpname.find_last_of("."); 00074 if (lastDot != string::npos) { 00075 tmpname = tmpname.substr(0, lastDot); 00076 } else { 00077 triedAllParents = true; 00078 } 00079 } 00080 // for (LevelMap::const_iterator l = defaultLevels.begin(); l != defaultLevels.end(); ++l) { 00081 // 00082 // } 00083 existingLogs[name] = new Log(name, level); 00084 } 00085 return *existingLogs[name]; 00086 } 00087 00088 00089 string Log::getLevelName(int level) { 00090 /// @todo Do the map::upper_limit thing to find nearest level... 00091 switch(level) { 00092 case TRACE: 00093 return "TRACE"; 00094 case DEBUG: 00095 return "DEBUG"; 00096 case INFO: 00097 return "INFO"; 00098 case WARN: 00099 return "WARN"; 00100 case ERROR: 00101 return "ERROR"; 00102 default: 00103 return ""; 00104 } 00105 //throw Error("Enum value was not a valid log level. How did that happen?"); 00106 } 00107 00108 00109 string Log::getColorCode(int level) { 00110 if (!Log::useShellColors) return ""; 00111 // If the codes haven't been initialized, do so now. 00112 if (Log::colorCodes.empty()) { 00113 // If stdout is a valid tty, try to use the appropriate codes. 00114 if (isatty(1)) { 00115 /// @todo Test for VT100 compliance? 00116 Log::colorCodes[TRACE] = "\033[0;36m"; 00117 Log::colorCodes[DEBUG] = "\033[0;34m"; 00118 Log::colorCodes[INFO] = "\033[0;32m"; 00119 Log::colorCodes[WARN] = "\033[0;33m"; 00120 Log::colorCodes[ERROR] = "\033[0;31m"; 00121 Log::endColorCode = "\033[0m"; 00122 } else { 00123 Log::colorCodes[TRACE] = ""; 00124 Log::colorCodes[DEBUG] = ""; 00125 Log::colorCodes[INFO] = ""; 00126 Log::colorCodes[WARN] = ""; 00127 Log::colorCodes[ERROR] = ""; 00128 } 00129 } 00130 // Return the appropriate code from the colour map. 00131 /// @todo Do the map::upper_limit thing to find nearest level... 00132 return colorCodes[level]; 00133 } 00134 00135 00136 Log::Level Log::getLevelFromName(const string& level) { 00137 if (level == "TRACE") return TRACE; 00138 if (level == "DEBUG") return DEBUG; 00139 if (level == "INFO") return INFO; 00140 if (level == "WARN") return WARN; 00141 if (level == "ERROR") return ERROR; 00142 throw Error("Couldn't create a log level from string '" + level + "'"); 00143 } 00144 00145 00146 string Log::formatMessage(int level, const string& message) { 00147 string out; 00148 if (Log::useShellColors) { 00149 out += getColorCode(level); 00150 } 00151 00152 if (Log::showLoggerName) { 00153 out += getName(); 00154 out += ": "; 00155 } 00156 00157 if (Log::showLogLevel) { 00158 out += Log::getLevelName(level); 00159 out += " "; 00160 } 00161 00162 if (Log::showTimestamp) { 00163 time_t rawtime; 00164 time(&rawtime); 00165 char* timestr = ctime(&rawtime); 00166 timestr[24] = ' '; 00167 out += timestr; 00168 out += " "; 00169 } 00170 00171 if (Log::useShellColors) { 00172 out += endColorCode; 00173 } 00174 00175 out += " "; 00176 out += message; 00177 00178 return out; 00179 } 00180 00181 00182 void Log::log(int level, const string& message) { 00183 if (isActive(level)) { 00184 cout << formatMessage(level, message) << endl; 00185 } 00186 } 00187 00188 00189 ostream& operator<<(Log& log, int level) { 00190 if (log.isActive(level)) { 00191 cout << log.formatMessage(level, ""); 00192 return cout; 00193 } else { 00194 return *(log._nostream); 00195 } 00196 } 00197 00198 } Generated on Tue Sep 30 2014 19:45:45 for The Rivet MC analysis system by ![]() |