13 bool Log::showTimestamp =
false;
14 bool Log::showLogLevel =
true;
15 bool Log::showLoggerName =
true;
16 bool Log::useShellColors =
true;
17 const int Log::end_color;
19 Log::Log(
const string& name) : _name(name), _level(info) {}
21 Log::Log(
const string& name,
int level) : _name(name), _level(level) {}
26 for (Log::LevelMap::const_iterator lev = defaultLevels.begin(); lev != defaultLevels.end();
28 for (Log::LogMap::iterator log = existingLogs.begin(); log != existingLogs.end(); ++log) {
29 if (log->first.find(lev->first) == 0) {
30 log->second.setLevel(lev->second);
36 void Log::setLevel(
const string& name,
int level) {
37 defaultLevels[name] = level;
42 void Log::setLevels(
const LevelMap& logLevels) {
43 for (LevelMap::const_iterator lev = logLevels.begin(); lev != logLevels.end(); ++lev) {
44 defaultLevels[lev->first] = lev->second;
50 auto theLog = existingLogs.find(name);
51 if (theLog == existingLogs.end()) {
54 string tmpname = name;
55 bool triedAllParents =
false;
56 while (!triedAllParents) {
58 if (defaultLevels.find(tmpname) != defaultLevels.end()) {
59 level = defaultLevels.find(tmpname)->second;
63 if (existingLogs.find(tmpname) != existingLogs.end()) {
64 level = existingLogs.find(tmpname)->second.
getLevel();
68 size_t lastDot = tmpname.find_last_of(
".");
69 if (lastDot != string::npos) {
70 tmpname = tmpname.substr(0, lastDot);
72 triedAllParents =
true;
80 auto result = existingLogs.emplace(name,
Log(name, level));
81 theLog = result.first;
83 return theLog->second;
86 string Log::getLevelName(
int level) {
105 string Log::getColorCode(
int level) {
107 if (!Log::useShellColors)
return "";
108 const static bool IS_TTY = isatty(1);
109 if (!IS_TTY)
return "";
111 static const ColorCodes TTY_CODES = {
112 {trace,
"\033[0;36m"}, {debug,
"\033[0;34m"}, {info,
"\033[0;32m"}, {warn,
"\033[0;33m"},
113 {error,
"\033[0;31m"}, {critical,
"\033[0;31m"}, {end_color,
"\033[0m"}
116 return TTY_CODES.at(level);
123 if (level ==
"trace")
return trace;
124 if (level ==
"debug")
return debug;
125 if (level ==
"info")
return info;
126 if (level ==
"warn")
return warn;
127 if (level ==
"error")
return error;
128 if (level ==
"critical")
return critical;
129 throw std::runtime_error(
"Couldn't create a log level from string '" + level +
"'");
132 string Log::formatMessage(
int level,
const string& message) {
134 out += getColorCode(level);
136 if (Log::showLoggerName) {
141 if (Log::showLogLevel) {
142 out += Log::getLevelName(level);
146 if (Log::showTimestamp) {
149 char* timestr = ctime(&rawtime);
155 out += getColorCode(end_color);
162 void Log::log(
int level,
const string& message) {
163 if (isActive(level)) {
165 cerr << formatMessage(level, message) <<
'\n';
167 cout << formatMessage(level, message) <<
'\n';
173 if (level > Log::warning) {
174 cerr << log.formatMessage(level,
"");
177 cout << log.formatMessage(level,
"");
181 static ostream devNull(
nullptr);
Logging system for controlled & formatted writing to stdout.
std::map< std::string, Log > LogMap
Typedef for a collection of named logs.
Level
Log priority levels.
bool isActive(int level) const
Will this log level produce output on this logger at the moment?
int getLevel() const
Get the priority level of this logger.
std::map< std::string, int > LevelMap
Typedef for a collection of named log levels.
void _updateLevels(const Log::LevelMap &defaultLevels, Log::LogMap &existingLogs)
Log & getLog()
Access method to default Log object.
ostream & operator<<(Log &log, int level)
Streaming output to a logger must have a Log::Level/int as its first argument.