mirror of
https://github.com/FairRootGroup/FairLogger.git
synced 2025-10-13 00:31:12 +00:00
Logger: Allow adding custom sinks
(example in logger/loggerTest.cxx, docs in fairmq/docs/Logging.md)
This commit is contained in:
parent
a35a4f48a8
commit
a9f9030041
|
@ -69,7 +69,7 @@ class ColorOut
|
||||||
class ColoredSeverityWriter
|
class ColoredSeverityWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ColoredSeverityWriter(Logger::Severity severity)
|
ColoredSeverityWriter(Severity severity)
|
||||||
: fSeverity(severity)
|
: fSeverity(severity)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -77,40 +77,40 @@ class ColoredSeverityWriter
|
||||||
{
|
{
|
||||||
switch (w.fSeverity)
|
switch (w.fSeverity)
|
||||||
{
|
{
|
||||||
case Logger::Severity::nolog:
|
case Severity::nolog:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgDefault) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgDefault) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::fatal:
|
case Severity::fatal:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::bgRed) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::bgRed) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::error:
|
case Severity::error:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgRed) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgRed) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::warn:
|
case Severity::warn:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgYellow) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgYellow) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::state:
|
case Severity::state:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgMagenta) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgMagenta) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::info:
|
case Severity::info:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgGreen) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgGreen) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::debug:
|
case Severity::debug:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::debug1:
|
case Severity::debug1:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::debug2:
|
case Severity::debug2:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::debug3:
|
case Severity::debug3:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::debug4:
|
case Severity::debug4:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
case Logger::Severity::trace:
|
case Severity::trace:
|
||||||
return os << "\033[01;" << static_cast<int>(Color::fgCyan) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
return os << "\033[01;" << static_cast<int>(Color::fgCyan) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -120,16 +120,18 @@ class ColoredSeverityWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger::Severity fSeverity;
|
Severity fSeverity;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Logger::fColored = false;
|
bool Logger::fColored = false;
|
||||||
fstream Logger::fFileStream;
|
fstream Logger::fFileStream;
|
||||||
Logger::Verbosity Logger::fVerbosity = Logger::Verbosity::low;
|
Verbosity Logger::fVerbosity = Verbosity::low;
|
||||||
Logger::Severity Logger::fConsoleSeverity = Logger::Severity::info;
|
Severity Logger::fConsoleSeverity = Severity::info;
|
||||||
Logger::Severity Logger::fFileSeverity = Logger::Severity::nolog;
|
Severity Logger::fFileSeverity = Severity::nolog;
|
||||||
Logger::Severity Logger::fMinSeverity = Logger::Severity::info;
|
Severity Logger::fMinSeverity = Severity::info;
|
||||||
std::function<void()> Logger::fFatalCallback;
|
function<void()> Logger::fFatalCallback;
|
||||||
|
unordered_map<string, pair<Severity, function<void(const string& content, const LogMetaData& metadata)>>> Logger::fCustomSinks;
|
||||||
|
mutex Logger::fMtx;
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||||
const string Logger::fProcessName = getprogname();
|
const string Logger::fProcessName = getprogname();
|
||||||
|
@ -139,7 +141,7 @@ const string Logger::fProcessName = program_invocation_short_name;
|
||||||
const string Logger::fProcessName = "?";
|
const string Logger::fProcessName = "?";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const unordered_map<string, Logger::Verbosity> Logger::fVerbosityMap =
|
const unordered_map<string, Verbosity> Logger::fVerbosityMap =
|
||||||
{
|
{
|
||||||
{ "veryhigh", Verbosity::veryhigh },
|
{ "veryhigh", Verbosity::veryhigh },
|
||||||
{ "high", Verbosity::high },
|
{ "high", Verbosity::high },
|
||||||
|
@ -151,7 +153,7 @@ const unordered_map<string, Logger::Verbosity> Logger::fVerbosityMap =
|
||||||
{ "LOW", Verbosity::low }
|
{ "LOW", Verbosity::low }
|
||||||
};
|
};
|
||||||
|
|
||||||
const unordered_map<string, Logger::Severity> Logger::fSeverityMap =
|
const unordered_map<string, Severity> Logger::fSeverityMap =
|
||||||
{
|
{
|
||||||
{ "nolog", Severity::nolog },
|
{ "nolog", Severity::nolog },
|
||||||
{ "NOLOG", Severity::nolog },
|
{ "NOLOG", Severity::nolog },
|
||||||
|
@ -217,9 +219,20 @@ string Logger::VerbosityName(Verbosity verbosity)
|
||||||
return fVerbosityNames.at(static_cast<size_t>(verbosity));
|
return fVerbosityNames.at(static_cast<size_t>(verbosity));
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Logger(Severity severity)
|
Logger::Logger(Severity severity, const string& file, const string& line, const string& func)
|
||||||
: fCurrentSeverity(severity)
|
{
|
||||||
{}
|
chrono::time_point<chrono::system_clock> now = chrono::system_clock::now();
|
||||||
|
size_t pos = file.rfind("/");
|
||||||
|
|
||||||
|
fMetaData.timestamp = chrono::system_clock::to_time_t(now);
|
||||||
|
fMetaData.us = chrono::duration_cast<chrono::microseconds>(now.time_since_epoch()) % 1000000;
|
||||||
|
fMetaData.process_name = fProcessName;
|
||||||
|
fMetaData.file = file.substr(pos + 1);
|
||||||
|
fMetaData.line = line;
|
||||||
|
fMetaData.func = func;
|
||||||
|
fMetaData.severity_name = fSeverityNames.at(static_cast<size_t>(severity));
|
||||||
|
fMetaData.severity = severity;
|
||||||
|
}
|
||||||
|
|
||||||
void Logger::SetConsoleSeverity(const Severity severity)
|
void Logger::SetConsoleSeverity(const Severity severity)
|
||||||
{
|
{
|
||||||
|
@ -259,9 +272,36 @@ void Logger::SetFileSeverity(const string& severityStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Logger::SetCustomSeverity(const string& key, const Severity severity)
|
||||||
|
{
|
||||||
|
fCustomSinks.at(key).first = severity; // TODO: range checks
|
||||||
|
UpdateMinSeverity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetCustomSeverity(const string& key, const string& severityStr)
|
||||||
|
{
|
||||||
|
if (fSeverityMap.count(severityStr))
|
||||||
|
{
|
||||||
|
SetCustomSeverity(key, fSeverityMap.at(severityStr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(error) << "Unknown severity setting: '" << severityStr << "', setting to default 'info'.";
|
||||||
|
SetCustomSeverity(key, Severity::info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Logger::UpdateMinSeverity()
|
void Logger::UpdateMinSeverity()
|
||||||
{
|
{
|
||||||
fMinSeverity = (fConsoleSeverity <= fFileSeverity) ? fFileSeverity : fConsoleSeverity;
|
fMinSeverity = (fConsoleSeverity <= fFileSeverity) ? fFileSeverity : fConsoleSeverity;
|
||||||
|
|
||||||
|
for (auto& it : fCustomSinks)
|
||||||
|
{
|
||||||
|
if (fMinSeverity <= it.second.first)
|
||||||
|
{
|
||||||
|
fMinSeverity = it.second.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logger::Logging(Severity severity)
|
bool Logger::Logging(Severity severity)
|
||||||
|
@ -305,6 +345,7 @@ void Logger::SetConsoleColor(const bool colored)
|
||||||
|
|
||||||
void Logger::InitFileSink(const Severity severity, const string& filename, bool customizeName)
|
void Logger::InitFileSink(const Severity severity, const string& filename, bool customizeName)
|
||||||
{
|
{
|
||||||
|
lock_guard<mutex> lock(fMtx);
|
||||||
if (fFileStream.is_open())
|
if (fFileStream.is_open())
|
||||||
{
|
{
|
||||||
fFileStream.close();
|
fFileStream.close();
|
||||||
|
@ -356,6 +397,7 @@ void Logger::InitFileSink(const string& severityStr, const string& filename, boo
|
||||||
|
|
||||||
void Logger::RemoveFileSink()
|
void Logger::RemoveFileSink()
|
||||||
{
|
{
|
||||||
|
lock_guard<mutex> lock(fMtx);
|
||||||
if (fFileStream.is_open())
|
if (fFileStream.is_open())
|
||||||
{
|
{
|
||||||
fFileStream.close();
|
fFileStream.close();
|
||||||
|
@ -364,47 +406,95 @@ void Logger::RemoveFileSink()
|
||||||
|
|
||||||
bool Logger::LoggingToConsole() const
|
bool Logger::LoggingToConsole() const
|
||||||
{
|
{
|
||||||
return (fCurrentSeverity <= fConsoleSeverity &&
|
return (fMetaData.severity <= fConsoleSeverity &&
|
||||||
fCurrentSeverity > Severity::nolog) ||
|
fMetaData.severity > Severity::nolog) ||
|
||||||
fCurrentSeverity == Severity::fatal;
|
fMetaData.severity == Severity::fatal;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logger::LoggingToFile() const
|
bool Logger::LoggingToFile() const
|
||||||
{
|
{
|
||||||
return (fCurrentSeverity <= fFileSeverity &&
|
return (fMetaData.severity <= fFileSeverity &&
|
||||||
fCurrentSeverity > Severity::nolog) ||
|
fMetaData.severity > Severity::nolog) ||
|
||||||
fCurrentSeverity == Severity::fatal;
|
fMetaData.severity == Severity::fatal;
|
||||||
}
|
}
|
||||||
|
|
||||||
ostringstream& Logger::Log(const string& file, const string& line, const string& func)
|
bool Logger::LoggingCustom(const Severity severity) const
|
||||||
|
{
|
||||||
|
return (fMetaData.severity <= severity &&
|
||||||
|
fMetaData.severity > Severity::nolog) ||
|
||||||
|
fMetaData.severity == Severity::fatal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::OnFatal(function<void()> func)
|
||||||
|
{
|
||||||
|
fFatalCallback = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::AddCustomSink(const string& key, Severity severity, function<void(const string& content, const LogMetaData& metadata)> func)
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lock(fMtx);
|
||||||
|
if (fCustomSinks.count(key) == 0)
|
||||||
|
{
|
||||||
|
fCustomSinks.insert(make_pair(key, make_pair(severity, func)));
|
||||||
|
UpdateMinSeverity();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cout << "Logger::AddCustomSink: sink '" << key << "' already exists, will not add again. Remove first with Logger::RemoveCustomSink(const string& key)" << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::AddCustomSink(const string& key, const string& severityStr, function<void(const string& content, const LogMetaData& metadata)> func)
|
||||||
|
{
|
||||||
|
if (fSeverityMap.count(severityStr))
|
||||||
|
{
|
||||||
|
AddCustomSink(key, fSeverityMap.at(severityStr), func);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(error) << "Unknown severity setting: '" << severityStr << "', setting to default 'info'.";
|
||||||
|
AddCustomSink(key, Severity::info, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::RemoveCustomSink(const string& key)
|
||||||
|
{
|
||||||
|
if (fCustomSinks.count(key) > 0)
|
||||||
|
{
|
||||||
|
fCustomSinks.erase(key);
|
||||||
|
UpdateMinSeverity();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cout << "Logger::RemoveCustomSink: sink '" << key << "' doesn't exists, will not remove." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ostringstream& Logger::Log()
|
||||||
{
|
{
|
||||||
size_t pos = file.rfind("/");
|
|
||||||
auto now = chrono::system_clock::now();
|
|
||||||
auto now_c = chrono::system_clock::to_time_t(now);
|
|
||||||
auto ns = chrono::duration_cast<chrono::microseconds>(now.time_since_epoch()) % 1000000;
|
|
||||||
char tsstr[32];
|
char tsstr[32];
|
||||||
if (!strftime(tsstr, sizeof(tsstr), "%H:%M:%S", localtime(&now_c)))
|
if (!strftime(tsstr, sizeof(tsstr), "%H:%M:%S", localtime(&(fMetaData.timestamp))))
|
||||||
{
|
{
|
||||||
tsstr[0] = 'u';
|
tsstr[0] = 'u';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!fColored && LoggingToConsole()) || (fFileStream.is_open() && LoggingToFile()))
|
if ((!fColored && LoggingToConsole()) || LoggingToFile())
|
||||||
{
|
{
|
||||||
if (fVerbosity >= Verbosity::high)
|
if (fVerbosity >= Verbosity::high)
|
||||||
{
|
{
|
||||||
fBWOut << "[" << fProcessName << "]"
|
fBWOut << "[" << fMetaData.process_name << "]"
|
||||||
<< "[" << tsstr << "." << setw(6) << setfill('0') << ns.count() << "]";
|
<< "[" << tsstr << "." << setw(6) << setfill('0') << fMetaData.us.count() << "]";
|
||||||
}
|
}
|
||||||
else if (fVerbosity == Verbosity::medium)
|
else if (fVerbosity == Verbosity::medium)
|
||||||
{
|
{
|
||||||
fBWOut << "[" << tsstr << "]";
|
fBWOut << "[" << tsstr << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
fBWOut << "[" << fSeverityNames.at(static_cast<size_t>(fCurrentSeverity)) << "]";
|
fBWOut << "[" << fMetaData.severity_name << "]";
|
||||||
|
|
||||||
if (fVerbosity == Verbosity::veryhigh)
|
if (fVerbosity == Verbosity::veryhigh)
|
||||||
{
|
{
|
||||||
fBWOut << "[" << file.substr(pos + 1) << ":" << line << ":" << func << "]";
|
fBWOut << "[" << fMetaData.file << ":" << fMetaData.line << ":" << fMetaData.func << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
fBWOut << " ";
|
fBWOut << " ";
|
||||||
|
@ -414,19 +504,19 @@ ostringstream& Logger::Log(const string& file, const string& line, const string&
|
||||||
{
|
{
|
||||||
if (fVerbosity >= Verbosity::high)
|
if (fVerbosity >= Verbosity::high)
|
||||||
{
|
{
|
||||||
fColorOut << "[" << ColorOut(Color::fgBlue, fProcessName) << "]"
|
fColorOut << "[" << ColorOut(Color::fgBlue, fMetaData.process_name) << "]"
|
||||||
<< "[" << startColor(Color::fgCyan) << tsstr << "." << setw(6) << setfill('0') << ns.count() << endColor() << "]";
|
<< "[" << startColor(Color::fgCyan) << tsstr << "." << setw(6) << setfill('0') << fMetaData.us.count() << endColor() << "]";
|
||||||
}
|
}
|
||||||
else if (fVerbosity == Verbosity::medium)
|
else if (fVerbosity == Verbosity::medium)
|
||||||
{
|
{
|
||||||
fColorOut << "[" << startColor(Color::fgCyan) << tsstr << endColor() << "]";
|
fColorOut << "[" << startColor(Color::fgCyan) << tsstr << endColor() << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
fColorOut << "[" << ColoredSeverityWriter(fCurrentSeverity) << "]";
|
fColorOut << "[" << ColoredSeverityWriter(fMetaData.severity) << "]";
|
||||||
|
|
||||||
if (fVerbosity == Verbosity::veryhigh)
|
if (fVerbosity == Verbosity::veryhigh)
|
||||||
{
|
{
|
||||||
fColorOut << "[" << ColorOut(Color::fgBlue, file.substr(pos + 1)) << ":" << ColorOut(Color::fgYellow, line) << ":" << ColorOut(Color::fgBlue, func) << "]";
|
fColorOut << "[" << ColorOut(Color::fgBlue, fMetaData.file) << ":" << ColorOut(Color::fgYellow, fMetaData.line) << ":" << ColorOut(Color::fgBlue, fMetaData.func) << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
fColorOut << " ";
|
fColorOut << " ";
|
||||||
|
@ -435,13 +525,17 @@ ostringstream& Logger::Log(const string& file, const string& line, const string&
|
||||||
return fContent;
|
return fContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::OnFatal(std::function<void()> func)
|
|
||||||
{
|
|
||||||
fFatalCallback = func;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::~Logger() noexcept(false)
|
Logger::~Logger() noexcept(false)
|
||||||
{
|
{
|
||||||
|
for (auto& it : fCustomSinks)
|
||||||
|
{
|
||||||
|
if (LoggingCustom(it.second.first))
|
||||||
|
{
|
||||||
|
lock_guard<mutex> lock(fMtx);
|
||||||
|
it.second.second(fContent.str(), fMetaData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fContent << "\n"; // "\n" + flush instead of endl makes output thread safe.
|
fContent << "\n"; // "\n" + flush instead of endl makes output thread safe.
|
||||||
|
|
||||||
fBWOut << fContent.str();
|
fBWOut << fContent.str();
|
||||||
|
@ -461,13 +555,14 @@ Logger::~Logger() noexcept(false)
|
||||||
|
|
||||||
if (LoggingToFile())
|
if (LoggingToFile())
|
||||||
{
|
{
|
||||||
|
lock_guard<mutex> lock(fMtx);
|
||||||
if (fFileStream.is_open())
|
if (fFileStream.is_open())
|
||||||
{
|
{
|
||||||
fFileStream << fBWOut.str() << flush;
|
fFileStream << fBWOut.str() << flush;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fCurrentSeverity == Severity::fatal)
|
if (fMetaData.severity == Severity::fatal)
|
||||||
{
|
{
|
||||||
if (fFatalCallback)
|
if (fFatalCallback)
|
||||||
{
|
{
|
||||||
|
|
141
logger/Logger.h
141
logger/Logger.h
|
@ -18,10 +18,64 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
#include <utility> // pair
|
||||||
|
#include <time.h> // time_t
|
||||||
|
|
||||||
namespace fair
|
namespace fair
|
||||||
{
|
{
|
||||||
|
|
||||||
|
enum class Severity : int
|
||||||
|
{
|
||||||
|
nolog,
|
||||||
|
fatal,
|
||||||
|
error,
|
||||||
|
warn,
|
||||||
|
state,
|
||||||
|
info,
|
||||||
|
debug,
|
||||||
|
debug1,
|
||||||
|
debug2,
|
||||||
|
debug3,
|
||||||
|
debug4,
|
||||||
|
trace,
|
||||||
|
// backwards-compatibility:
|
||||||
|
NOLOG = nolog,
|
||||||
|
FATAL = fatal,
|
||||||
|
ERROR = error,
|
||||||
|
WARN = warn,
|
||||||
|
warning = warn,
|
||||||
|
WARNING = warn,
|
||||||
|
STATE = state,
|
||||||
|
INFO = info,
|
||||||
|
DEBUG = debug,
|
||||||
|
DEBUG1 = debug1,
|
||||||
|
DEBUG2 = debug2,
|
||||||
|
DEBUG3 = debug3,
|
||||||
|
DEBUG4 = debug4,
|
||||||
|
TRACE = trace
|
||||||
|
};
|
||||||
|
|
||||||
|
// verbosity levels:
|
||||||
|
// low: [severity] message
|
||||||
|
// medium: [HH:MM:SS][severity] message
|
||||||
|
// high: [process name][HH:MM:SS:µS][severity] message
|
||||||
|
// veryhigh: [process name][HH:MM:SS:µS][severity][file:line:function] message
|
||||||
|
enum class Verbosity : int
|
||||||
|
{
|
||||||
|
low,
|
||||||
|
medium,
|
||||||
|
high,
|
||||||
|
veryhigh,
|
||||||
|
// backwards-compatibility:
|
||||||
|
LOW = low,
|
||||||
|
MEDIUM = medium,
|
||||||
|
HIGH = high,
|
||||||
|
VERYHIGH = veryhigh
|
||||||
|
};
|
||||||
|
|
||||||
// non-std exception to avoid undesirable catches - fatal should exit in a way we want.
|
// non-std exception to avoid undesirable catches - fatal should exit in a way we want.
|
||||||
class FatalException
|
class FatalException
|
||||||
{
|
{
|
||||||
|
@ -43,59 +97,22 @@ class FatalException
|
||||||
std::string fWhat;
|
std::string fWhat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LogMetaData
|
||||||
|
{
|
||||||
|
std::time_t timestamp;
|
||||||
|
std::chrono::microseconds us;
|
||||||
|
std::string process_name;
|
||||||
|
std::string file;
|
||||||
|
std::string line;
|
||||||
|
std::string func;
|
||||||
|
std::string severity_name;
|
||||||
|
fair::Severity severity;
|
||||||
|
};
|
||||||
|
|
||||||
class Logger
|
class Logger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class Severity : int
|
Logger(Severity severity, const std::string& file, const std::string& line, const std::string& func);
|
||||||
{
|
|
||||||
nolog,
|
|
||||||
fatal,
|
|
||||||
error,
|
|
||||||
warn,
|
|
||||||
state,
|
|
||||||
info,
|
|
||||||
debug,
|
|
||||||
debug1,
|
|
||||||
debug2,
|
|
||||||
debug3,
|
|
||||||
debug4,
|
|
||||||
trace,
|
|
||||||
// backwards-compatibility:
|
|
||||||
NOLOG = nolog,
|
|
||||||
FATAL = fatal,
|
|
||||||
ERROR = error,
|
|
||||||
WARN = warn,
|
|
||||||
warning = warn,
|
|
||||||
WARNING = warn,
|
|
||||||
STATE = state,
|
|
||||||
INFO = info,
|
|
||||||
DEBUG = debug,
|
|
||||||
DEBUG1 = debug1,
|
|
||||||
DEBUG2 = debug2,
|
|
||||||
DEBUG3 = debug3,
|
|
||||||
DEBUG4 = debug4,
|
|
||||||
TRACE = trace
|
|
||||||
};
|
|
||||||
|
|
||||||
// verbosity levels:
|
|
||||||
// low: [severity] message
|
|
||||||
// medium: [HH:MM:SS][severity] message
|
|
||||||
// high: [process name][HH:MM:SS:NS][severity] message
|
|
||||||
// veryhigh: [process name][HH:MM:SS:NS][severity][file:line:function] message
|
|
||||||
enum class Verbosity : int
|
|
||||||
{
|
|
||||||
low,
|
|
||||||
medium,
|
|
||||||
high,
|
|
||||||
veryhigh,
|
|
||||||
// backwards-compatibility:
|
|
||||||
LOW = low,
|
|
||||||
MEDIUM = medium,
|
|
||||||
HIGH = high,
|
|
||||||
VERYHIGH = veryhigh
|
|
||||||
};
|
|
||||||
|
|
||||||
Logger(Severity severity);
|
|
||||||
|
|
||||||
static void SetConsoleSeverity(const Severity severity);
|
static void SetConsoleSeverity(const Severity severity);
|
||||||
static void SetConsoleSeverity(const std::string& severityStr);
|
static void SetConsoleSeverity(const std::string& severityStr);
|
||||||
|
@ -103,6 +120,9 @@ class Logger
|
||||||
static void SetFileSeverity(const Severity severity);
|
static void SetFileSeverity(const Severity severity);
|
||||||
static void SetFileSeverity(const std::string& severityStr);
|
static void SetFileSeverity(const std::string& severityStr);
|
||||||
|
|
||||||
|
static void SetCustomSeverity(const std::string& key, const Severity severity);
|
||||||
|
static void SetCustomSeverity(const std::string& key, const std::string& severityStr);
|
||||||
|
|
||||||
static bool Logging(const Severity severity);
|
static bool Logging(const Severity severity);
|
||||||
|
|
||||||
static void SetVerbosity(const Verbosity verbosity);
|
static void SetVerbosity(const Verbosity verbosity);
|
||||||
|
@ -118,19 +138,23 @@ class Logger
|
||||||
static std::string SeverityName(Severity);
|
static std::string SeverityName(Severity);
|
||||||
static std::string VerbosityName(Verbosity);
|
static std::string VerbosityName(Verbosity);
|
||||||
|
|
||||||
std::ostringstream& Log(const std::string& file, const std::string& line, const std::string& func);
|
static void OnFatal(std::function<void()> func);
|
||||||
|
|
||||||
|
static void AddCustomSink(const std::string& key, Severity severity, std::function<void(const std::string& content, const LogMetaData& metadata)> sink);
|
||||||
|
static void AddCustomSink(const std::string& key, const std::string& severityStr, std::function<void(const std::string& content, const LogMetaData& metadata)> sink);
|
||||||
|
static void RemoveCustomSink(const std::string& key);
|
||||||
|
|
||||||
|
std::ostringstream& Log();
|
||||||
|
|
||||||
static const std::unordered_map<std::string, Verbosity> fVerbosityMap;
|
static const std::unordered_map<std::string, Verbosity> fVerbosityMap;
|
||||||
static const std::unordered_map<std::string, Severity> fSeverityMap;
|
static const std::unordered_map<std::string, Severity> fSeverityMap;
|
||||||
static const std::array<std::string, 12> fSeverityNames;
|
static const std::array<std::string, 12> fSeverityNames;
|
||||||
static const std::array<std::string, 4> fVerbosityNames;
|
static const std::array<std::string, 4> fVerbosityNames;
|
||||||
|
|
||||||
static void OnFatal(std::function<void()> func);
|
|
||||||
|
|
||||||
virtual ~Logger() noexcept(false);
|
virtual ~Logger() noexcept(false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Severity fCurrentSeverity;
|
LogMetaData fMetaData;
|
||||||
|
|
||||||
std::ostringstream fContent;
|
std::ostringstream fContent;
|
||||||
std::ostringstream fColorOut;
|
std::ostringstream fColorOut;
|
||||||
|
@ -146,9 +170,12 @@ class Logger
|
||||||
static Verbosity fVerbosity;
|
static Verbosity fVerbosity;
|
||||||
|
|
||||||
static std::function<void()> fFatalCallback;
|
static std::function<void()> fFatalCallback;
|
||||||
|
static std::unordered_map<std::string, std::pair<Severity, std::function<void(const std::string& content, const LogMetaData& metadata)>>> fCustomSinks;
|
||||||
|
static std::mutex fMtx;
|
||||||
|
|
||||||
bool LoggingToConsole() const;
|
bool LoggingToConsole() const;
|
||||||
bool LoggingToFile() const;
|
bool LoggingToFile() const;
|
||||||
|
bool LoggingCustom(const Severity) const;
|
||||||
|
|
||||||
static void UpdateMinSeverity();
|
static void UpdateMinSeverity();
|
||||||
};
|
};
|
||||||
|
@ -159,13 +186,13 @@ class Logger
|
||||||
#define CONVERTTOSTRING(s) IMP_CONVERTTOSTRING(s)
|
#define CONVERTTOSTRING(s) IMP_CONVERTTOSTRING(s)
|
||||||
|
|
||||||
#define LOG(severity) \
|
#define LOG(severity) \
|
||||||
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Logger::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
|
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
|
||||||
fair::Logger(fair::Logger::Severity::severity).Log(__FILE__, CONVERTTOSTRING(__LINE__), __FUNCTION__)
|
fair::Logger(fair::Severity::severity, __FILE__, CONVERTTOSTRING(__LINE__), __FUNCTION__).Log()
|
||||||
|
|
||||||
// with custom file, line, function
|
// with custom file, line, function
|
||||||
#define LOGD(severity, file, line, function) \
|
#define LOGD(severity, file, line, function) \
|
||||||
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
|
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
|
||||||
fair::Logger(severity).Log(file, line, function)
|
fair::Logger(severity, file, line, function).Log()
|
||||||
|
|
||||||
#define LOG_IF(severity, condition) \
|
#define LOG_IF(severity, condition) \
|
||||||
for (bool fairLOggerunLikelyvariable2 = false; condition && !fairLOggerunLikelyvariable2; fairLOggerunLikelyvariable2 = true) \
|
for (bool fairLOggerunLikelyvariable2 = false; condition && !fairLOggerunLikelyvariable2; fairLOggerunLikelyvariable2 = true) \
|
||||||
|
|
|
@ -35,35 +35,35 @@ void printEverySeverity()
|
||||||
LOG(trace) << "trace message " << i++;
|
LOG(trace) << "trace message " << i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printAllVerbositiesWithSeverity(Logger::Severity sev)
|
void printAllVerbositiesWithSeverity(Severity sev)
|
||||||
{
|
{
|
||||||
Logger::SetConsoleSeverity(sev);
|
Logger::SetConsoleSeverity(sev);
|
||||||
|
|
||||||
cout << endl << ">>> testing severity '" << Logger::SeverityName(sev) << "' with 'low' verbosity..." << endl;
|
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'low' verbosity..." << endl;
|
||||||
Logger::SetVerbosity(Logger::Verbosity::low);
|
Logger::SetVerbosity(Verbosity::low);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
cout << endl << ">>> testing severity '" << Logger::SeverityName(sev) << "' with 'medium' verbosity..." << endl;
|
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'medium' verbosity..." << endl;
|
||||||
Logger::SetVerbosity(Logger::Verbosity::medium);
|
Logger::SetVerbosity(Verbosity::medium);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
cout << endl << ">>> testing severity '" << Logger::SeverityName(sev) << "' with 'high' verbosity..." << endl;
|
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'high' verbosity..." << endl;
|
||||||
Logger::SetVerbosity(Logger::Verbosity::high);
|
Logger::SetVerbosity(Verbosity::high);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
cout << endl << ">>> testing severity '" << Logger::SeverityName(sev) << "' with 'veryhigh' verbosity..." << endl;
|
cout << endl << "cout: >>> testing severity '" << Logger::SeverityName(sev) << "' with 'veryhigh' verbosity..." << endl;
|
||||||
Logger::SetVerbosity(Logger::Verbosity::veryhigh);
|
Logger::SetVerbosity(Verbosity::veryhigh);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
}
|
}
|
||||||
|
|
||||||
void silentlyPrintAllVerbositiesWithSeverity(Logger::Severity sev)
|
void silentlyPrintAllVerbositiesWithSeverity(Severity sev)
|
||||||
{
|
{
|
||||||
Logger::SetConsoleSeverity(sev);
|
Logger::SetConsoleSeverity(sev);
|
||||||
|
|
||||||
Logger::SetVerbosity(Logger::Verbosity::low);
|
Logger::SetVerbosity(Verbosity::low);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
Logger::SetVerbosity(Logger::Verbosity::medium);
|
Logger::SetVerbosity(Verbosity::medium);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
Logger::SetVerbosity(Logger::Verbosity::high);
|
Logger::SetVerbosity(Verbosity::high);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
Logger::SetVerbosity(Logger::Verbosity::veryhigh);
|
Logger::SetVerbosity(Verbosity::veryhigh);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,49 +71,49 @@ int main()
|
||||||
{
|
{
|
||||||
Logger::SetConsoleColor(true);
|
Logger::SetConsoleColor(true);
|
||||||
|
|
||||||
cout << "testing severities..." << endl;
|
cout << "cout: testing severities..." << endl;
|
||||||
|
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::trace);
|
printAllVerbositiesWithSeverity(Severity::trace);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::debug4);
|
printAllVerbositiesWithSeverity(Severity::debug4);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::debug3);
|
printAllVerbositiesWithSeverity(Severity::debug3);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::debug2);
|
printAllVerbositiesWithSeverity(Severity::debug2);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::debug1);
|
printAllVerbositiesWithSeverity(Severity::debug1);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::debug);
|
printAllVerbositiesWithSeverity(Severity::debug);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::info);
|
printAllVerbositiesWithSeverity(Severity::info);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::state);
|
printAllVerbositiesWithSeverity(Severity::state);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::warn);
|
printAllVerbositiesWithSeverity(Severity::warn);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::error);
|
printAllVerbositiesWithSeverity(Severity::error);
|
||||||
printAllVerbositiesWithSeverity(Logger::Severity::nolog);
|
printAllVerbositiesWithSeverity(Severity::nolog);
|
||||||
|
|
||||||
cout << endl;
|
cout << endl;
|
||||||
cout << "resetting severity to 'info' and verbosity to 'medium'" << endl;
|
cout << "cout: resetting severity to 'info' and verbosity to 'medium'" << endl;
|
||||||
Logger::SetConsoleSeverity(Logger::Severity::info);
|
Logger::SetConsoleSeverity(Severity::info);
|
||||||
Logger::SetVerbosity(Logger::Verbosity::medium);
|
Logger::SetVerbosity(Verbosity::medium);
|
||||||
|
|
||||||
cout << "is logging trace: " << fair::Logger::Logging(Logger::Severity::trace) << endl;
|
cout << "cout: is logging trace: " << fair::Logger::Logging(Severity::trace) << endl;
|
||||||
cout << "is logging debug4: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
cout << "cout: is logging debug4: " << fair::Logger::Logging(Severity::debug) << endl;
|
||||||
cout << "is logging debug3: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
cout << "cout: is logging debug3: " << fair::Logger::Logging(Severity::debug) << endl;
|
||||||
cout << "is logging debug2: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
cout << "cout: is logging debug2: " << fair::Logger::Logging(Severity::debug) << endl;
|
||||||
cout << "is logging debug1: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
cout << "cout: is logging debug1: " << fair::Logger::Logging(Severity::debug) << endl;
|
||||||
cout << "is logging debug: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
cout << "cout: is logging debug: " << fair::Logger::Logging(Severity::debug) << endl;
|
||||||
cout << "is logging info: " << fair::Logger::Logging(Logger::Severity::info) << endl;
|
cout << "cout: is logging info: " << fair::Logger::Logging(Severity::info) << endl;
|
||||||
cout << "is logging state: " << fair::Logger::Logging(Logger::Severity::state) << endl;
|
cout << "cout: is logging state: " << fair::Logger::Logging(Severity::state) << endl;
|
||||||
cout << "is logging warn: " << fair::Logger::Logging(Logger::Severity::warn) << endl;
|
cout << "cout: is logging warn: " << fair::Logger::Logging(Severity::warn) << endl;
|
||||||
cout << "is logging error: " << fair::Logger::Logging(Logger::Severity::error) << endl;
|
cout << "cout: is logging error: " << fair::Logger::Logging(Severity::error) << endl;
|
||||||
cout << "is logging fatal: " << fair::Logger::Logging(Logger::Severity::fatal) << endl;
|
cout << "cout: is logging fatal: " << fair::Logger::Logging(Severity::fatal) << endl;
|
||||||
cout << "is logging nolog: " << fair::Logger::Logging(Logger::Severity::nolog) << endl;
|
cout << "cout: is logging nolog: " << fair::Logger::Logging(Severity::nolog) << endl;
|
||||||
|
|
||||||
for (int i = 0; i < 1000000; ++i)
|
for (int i = 0; i < 1000000; ++i)
|
||||||
{
|
{
|
||||||
silentlyPrintAllVerbositiesWithSeverity(Logger::Severity::nolog);
|
silentlyPrintAllVerbositiesWithSeverity(Severity::nolog);
|
||||||
}
|
}
|
||||||
cout << endl;
|
cout << endl;
|
||||||
cout << "resetting severity to 'trace' and verbosity to 'veryhigh'" << endl;
|
cout << "cout: resetting severity to 'trace' and verbosity to 'veryhigh'" << endl;
|
||||||
Logger::SetConsoleSeverity(Logger::Severity::trace);
|
Logger::SetConsoleSeverity(Severity::trace);
|
||||||
Logger::SetVerbosity(Logger::Verbosity::veryhigh);
|
Logger::SetVerbosity(Verbosity::veryhigh);
|
||||||
|
|
||||||
cout << endl;
|
cout << endl;
|
||||||
cout << "testing conditional logging..." << endl;
|
cout << "cout: testing conditional logging..." << endl;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
LOG(info) << "x = " << x << " (initial)";
|
LOG(info) << "x = " << x << " (initial)";
|
||||||
LOG_IF(info, (x == 0)) << "incrementing x to " << ++x;
|
LOG_IF(info, (x == 0)) << "incrementing x to " << ++x;
|
||||||
|
@ -122,13 +122,45 @@ int main()
|
||||||
LOG(info) << "x = " << x << " (after conditional increment)";
|
LOG(info) << "x = " << x << " (after conditional increment)";
|
||||||
|
|
||||||
cout << endl;
|
cout << endl;
|
||||||
cout << "resetting severity to 'nolog'" << endl;
|
cout << "cout: resetting severity to 'nolog'" << endl;
|
||||||
Logger::SetConsoleSeverity(Logger::Severity::nolog);
|
Logger::SetConsoleSeverity(Severity::nolog);
|
||||||
|
|
||||||
cout << "----------------------------" << endl;
|
cout << "cout: ----------------------------" << endl;
|
||||||
cout << "open log file with severity 'error'" << endl;
|
cout << "cout: open log file with severity 'error'" << endl;
|
||||||
Logger::InitFileSink(Logger::Severity::error, "test_log", true);
|
Logger::InitFileSink(Severity::error, "test_log", true);
|
||||||
printEverySeverity();
|
printEverySeverity();
|
||||||
|
cout << "cout: closing log file" << endl;
|
||||||
|
Logger::RemoveFileSink();
|
||||||
|
|
||||||
|
|
||||||
|
cout << "cout: resetting severity to 'nolog'" << endl;
|
||||||
|
Logger::SetConsoleSeverity(Severity::nolog);
|
||||||
|
cout << "cout: ----------------------------" << endl;
|
||||||
|
cout << "cout: adding custom sink with error severity" << endl << endl;
|
||||||
|
|
||||||
|
Logger::AddCustomSink("CustomSink", "error", [](const string& content, const LogMetaData& metadata)
|
||||||
|
{
|
||||||
|
cout << "CustomSink: content: " << content << endl;
|
||||||
|
|
||||||
|
cout << "CustomSink: available metadata: " << endl;
|
||||||
|
cout << "CustomSink: \tstd::time_t timestamp: " << metadata.timestamp << endl;
|
||||||
|
cout << "CustomSink: \tstd::chrono::microseconds us: " << metadata.us.count() << endl;
|
||||||
|
cout << "CustomSink: \tstd::string process_name: " << metadata.process_name << endl;
|
||||||
|
cout << "CustomSink: \tstd::string file: " << metadata.file << endl;
|
||||||
|
cout << "CustomSink: \tstd::string line: " << metadata.line << endl;
|
||||||
|
cout << "CustomSink: \tstd::string func: " << metadata.func << endl;
|
||||||
|
cout << "CustomSink: \tstd::string severity_name: " << metadata.severity_name << endl;
|
||||||
|
cout << "CustomSink: \tfair::Severity severity: " << static_cast<int>(metadata.severity) << endl;
|
||||||
|
});
|
||||||
|
|
||||||
|
printEverySeverity();
|
||||||
|
|
||||||
|
cout << endl << "cout: removing custom sink with info severity" << endl;
|
||||||
|
|
||||||
|
Logger::AddCustomSink("CustomSink", Severity::error, [](const string& content, const LogMetaData& metadata){});
|
||||||
|
Logger::RemoveCustomSink("CustomSink");
|
||||||
|
Logger::RemoveCustomSink("bla");
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user