14 bool Log::showTimestamp =
false;
15 bool Log::showLogLevel =
true;
16 bool Log::showLoggerName =
true;
17 bool Log::useShellColors =
true;
18 const int Log::end_color;
21 Log::Log(
const string& name)
22 : _name(name), _level(info) { }
25 Log::Log(
const string& name,
int level)
26 : _name(name), _level(level) { }
32 for (Log::LevelMap::const_iterator lev = defaultLevels.begin(); lev != defaultLevels.end(); ++lev) {
33 for (Log::LogMap::iterator log = existingLogs.begin(); log != existingLogs.end(); ++log) {
34 if (log->first.find(lev->first) == 0) {
35 log->second.setLevel(lev->second);
42 void Log::setLevel(
const string& name,
int level) {
43 defaultLevels[name] = level;
49 void Log::setLevels(
const LevelMap& logLevels) {
50 for (LevelMap::const_iterator lev = logLevels.begin(); lev != logLevels.end(); ++lev) {
51 defaultLevels[lev->first] = lev->second;
58 auto theLog = existingLogs.find(name);
59 if (theLog == existingLogs.end()) {
62 string tmpname = name;
63 bool triedAllParents =
false;
64 while (! triedAllParents) {
66 if (defaultLevels.find(tmpname) != defaultLevels.end()) {
67 level = defaultLevels.find(tmpname)->second;
71 if (existingLogs.find(tmpname) != existingLogs.end()) {
72 level = existingLogs.find(tmpname)->second.
getLevel();
76 size_t lastDot = tmpname.find_last_of(
".");
77 if (lastDot != string::npos) {
78 tmpname = tmpname.substr(0, lastDot);
80 triedAllParents =
true;
88 auto result = existingLogs.emplace(name,
Log(name, level));
89 theLog = result.first;
91 return theLog->second;
95 string Log::getLevelName(
int level) {
115 string Log::getColorCode(
int level) {
117 if (!Log::useShellColors)
return "";
118 const static bool IS_TTY = isatty(1);
119 if (!IS_TTY)
return "";
121 static const ColorCodes TTY_CODES = {
122 {trace,
"\033[0;36m"},
123 {debug,
"\033[0;34m"},
124 {info,
"\033[0;32m"},
125 {warn,
"\033[0;33m"},
126 {error,
"\033[0;31m"},
127 {critical,
"\033[0;31m"},
128 {end_color,
"\033[0m"}
131 return TTY_CODES.at(level);
139 if (level ==
"trace")
return trace;
140 if (level ==
"debug")
return debug;
141 if (level ==
"info")
return info;
142 if (level ==
"warn")
return warn;
143 if (level ==
"error")
return error;
144 if (level ==
"critical")
return critical;
145 SOPT_THROW(
"Couldn't create a log level from string '" + level +
"'");
149 string Log::formatMessage(
int level,
const string& message) {
151 out += getColorCode(level);
153 if (Log::showLoggerName) {
158 if (Log::showLogLevel) {
159 out += Log::getLevelName(level);
163 if (Log::showTimestamp) {
166 char* timestr = ctime(&rawtime);
172 out += getColorCode(end_color);
180 void Log::log(
int level,
const string& message) {
181 if (isActive(level)) {
183 cerr << formatMessage(level, message) <<
'\n';
185 cout << formatMessage(level, message) <<
'\n';
192 if (level > Log::warning) {
193 cerr << log.formatMessage(level,
"");
196 cout << log.formatMessage(level,
"");
200 static ostream devNull(
nullptr);
Logging system for controlled & formatted writing to stdout.
std::map< std::string, int > LevelMap
Typedef for a collection of named log levels.
bool isActive(int level) const
Will this log level produce output on this logger at the moment?
std::map< std::string, Log > LogMap
Typedef for a collection of named logs.
int getLevel() const
Get the priority level of this logger.
Level
Log priority levels.
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.
void _updateLevels(const Log::LevelMap &defaultLevels, Log::LogMap &existingLogs)