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) { } 00021 00022 00023 Log::Log(const string& name, int level) 00024 : _name(name), _level(level) { } 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 auto theLog = existingLogs.find(name); 00057 if (theLog == existingLogs.end()) { 00058 int level = INFO; 00059 // Try running through all parent classes to find an existing level 00060 string tmpname = name; 00061 bool triedAllParents = false; 00062 while (! triedAllParents) { 00063 // Is there a default level? 00064 if (defaultLevels.find(tmpname) != defaultLevels.end()) { 00065 level = defaultLevels.find(tmpname)->second; 00066 break; 00067 } 00068 // Is there already such a logger? (NB. tmpname != name in later iterations) 00069 if (existingLogs.find(tmpname) != existingLogs.end()) { 00070 level = existingLogs.find(tmpname)->second.getLevel(); 00071 break; 00072 } 00073 // Crop the string back to the next parent level 00074 size_t lastDot = tmpname.find_last_of("."); 00075 if (lastDot != string::npos) { 00076 tmpname = tmpname.substr(0, lastDot); 00077 } else { 00078 triedAllParents = true; 00079 } 00080 } 00081 // for (LevelMap::const_iterator l = defaultLevels.begin(); l != defaultLevels.end(); ++l) { 00082 // 00083 // } 00084 00085 // emplace returns pair<iterator,bool> 00086 auto result = existingLogs.emplace(name, Log(name, level)); 00087 theLog = result.first; 00088 } 00089 return theLog->second; 00090 } 00091 00092 00093 string Log::getLevelName(int level) { 00094 /// @todo Do the map::upper_limit thing to find nearest level... 00095 switch(level) { 00096 case TRACE: 00097 return "TRACE"; 00098 case DEBUG: 00099 return "DEBUG"; 00100 case INFO: 00101 return "INFO"; 00102 case WARN: 00103 return "WARN"; 00104 case ERROR: 00105 return "ERROR"; 00106 default: 00107 return ""; 00108 } 00109 //throw Error("Enum value was not a valid log level. How did that happen?"); 00110 } 00111 00112 00113 string Log::getColorCode(int level) { 00114 if (!Log::useShellColors) return ""; 00115 // If the codes haven't been initialized, do so now. 00116 if (Log::colorCodes.empty()) { 00117 // If stdout is a valid tty, try to use the appropriate codes. 00118 if (isatty(1)) { 00119 /// @todo Test for VT100 compliance? 00120 Log::colorCodes[TRACE] = "\033[0;36m"; 00121 Log::colorCodes[DEBUG] = "\033[0;34m"; 00122 Log::colorCodes[INFO] = "\033[0;32m"; 00123 Log::colorCodes[WARN] = "\033[0;33m"; 00124 Log::colorCodes[ERROR] = "\033[0;31m"; 00125 Log::endColorCode = "\033[0m"; 00126 } else { 00127 Log::colorCodes[TRACE] = ""; 00128 Log::colorCodes[DEBUG] = ""; 00129 Log::colorCodes[INFO] = ""; 00130 Log::colorCodes[WARN] = ""; 00131 Log::colorCodes[ERROR] = ""; 00132 } 00133 } 00134 // Return the appropriate code from the colour map. 00135 /// @todo Do the map::upper_limit thing to find nearest level... 00136 return colorCodes[level]; 00137 } 00138 00139 00140 Log::Level Log::getLevelFromName(const string& level) { 00141 if (level == "TRACE") return TRACE; 00142 if (level == "DEBUG") return DEBUG; 00143 if (level == "INFO") return INFO; 00144 if (level == "WARN") return WARN; 00145 if (level == "ERROR") return ERROR; 00146 throw Error("Couldn't create a log level from string '" + level + "'"); 00147 } 00148 00149 00150 string Log::formatMessage(int level, const string& message) { 00151 string out; 00152 if (Log::useShellColors) { 00153 out += getColorCode(level); 00154 } 00155 00156 if (Log::showLoggerName) { 00157 out += getName(); 00158 out += ": "; 00159 } 00160 00161 if (Log::showLogLevel) { 00162 out += Log::getLevelName(level); 00163 out += " "; 00164 } 00165 00166 if (Log::showTimestamp) { 00167 time_t rawtime; 00168 time(&rawtime); 00169 char* timestr = ctime(&rawtime); 00170 timestr[24] = ' '; 00171 out += timestr; 00172 out += " "; 00173 } 00174 00175 if (Log::useShellColors) { 00176 out += endColorCode; 00177 } 00178 00179 out += " "; 00180 out += message; 00181 00182 return out; 00183 } 00184 00185 00186 void Log::log(int level, const string& message) { 00187 if (isActive(level)) { 00188 cout << formatMessage(level, message) << endl; 00189 } 00190 } 00191 00192 00193 ostream& operator<<(Log& log, int level) { 00194 if (log.isActive(level)) { 00195 cout << log.formatMessage(level, ""); 00196 return cout; 00197 } else { 00198 static ostream devNull(nullptr); 00199 return devNull; 00200 } 00201 } 00202 00203 } Generated on Tue Dec 13 2016 16:32:38 for The Rivet MC analysis system by ![]() |