mirror of
https://github.com/FairRootGroup/FairLogger.git
synced 2025-10-13 00:31:12 +00:00
Single Logger implementation for FairLogger & FairMQLogger
This commit is contained in:
commit
58a80c7da3
25
logger/CMakeLists.txt
Normal file
25
logger/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
add_library(Logger SHARED
|
||||||
|
Logger.cxx
|
||||||
|
Logger.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(Logger
|
||||||
|
PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/logger>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(loggerTest loggerTest.cxx)
|
||||||
|
target_link_libraries(loggerTest Logger pthread)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS Logger loggerTest
|
||||||
|
EXPORT FairMQ
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES Logger.h
|
||||||
|
DESTINATION include
|
||||||
|
)
|
487
logger/Logger.cxx
Normal file
487
logger/Logger.cxx
Normal file
|
@ -0,0 +1,487 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
|
* *
|
||||||
|
* This software is distributed under the terms of the *
|
||||||
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
* copied verbatim in the file "LICENSE" *
|
||||||
|
********************************************************************************/
|
||||||
|
#include <Logger.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip> // put_time
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace fair
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class Color : int
|
||||||
|
{
|
||||||
|
fgBlack = 30,
|
||||||
|
fgRed = 31,
|
||||||
|
fgGreen = 32,
|
||||||
|
fgYellow = 33,
|
||||||
|
fgBlue = 34,
|
||||||
|
fgMagenta = 35,
|
||||||
|
fgCyan = 36,
|
||||||
|
fgWhite = 37,
|
||||||
|
fgDefault = 39,
|
||||||
|
bgRed = 41,
|
||||||
|
bgGreen = 42,
|
||||||
|
bgBlue = 44,
|
||||||
|
bgDefault = 49
|
||||||
|
};
|
||||||
|
|
||||||
|
string startColor(Color color)
|
||||||
|
{
|
||||||
|
ostringstream os;
|
||||||
|
os << "\033[01;" << static_cast<int>(color) << "m";
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
string endColor()
|
||||||
|
{
|
||||||
|
return "\033[0m";
|
||||||
|
}
|
||||||
|
|
||||||
|
class ColorOut
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ColorOut(Color color, const string& str)
|
||||||
|
: fColor(color)
|
||||||
|
, fStr(str)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend ostream& operator<<(ostream& os, const ColorOut& w)
|
||||||
|
{
|
||||||
|
return os << "\033[01;" << static_cast<int>(w.fColor) << "m" << w.fStr << "\033[0m";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Color fColor;
|
||||||
|
const string& fStr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ColoredSeverityWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ColoredSeverityWriter(Logger::Severity severity)
|
||||||
|
: fSeverity(severity)
|
||||||
|
{}
|
||||||
|
|
||||||
|
friend ostream& operator<<(ostream& os, const ColoredSeverityWriter& w)
|
||||||
|
{
|
||||||
|
switch (w.fSeverity)
|
||||||
|
{
|
||||||
|
case Logger::Severity::nolog:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgDefault) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::fatal:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::bgRed) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::error:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgRed) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::warn:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgYellow) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::state:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgMagenta) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::info:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgGreen) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::debug:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::debug1:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::debug2:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::debug3:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::debug4:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgBlue) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
case Logger::Severity::trace:
|
||||||
|
return os << "\033[01;" << static_cast<int>(Color::fgCyan) << "m" << Logger::SeverityName(w.fSeverity) << "\033[0m";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return os << "UNKNOWN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logger::Severity fSeverity;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Logger::fColored = false;
|
||||||
|
bool Logger::fCerrOnly = false;
|
||||||
|
fstream Logger::fFileStream;
|
||||||
|
Logger::Verbosity Logger::fVerbosity = Logger::Verbosity::low;
|
||||||
|
Logger::Severity Logger::fConsoleSeverity = Logger::Severity::info;
|
||||||
|
Logger::Severity Logger::fFileSeverity = Logger::Severity::nolog;
|
||||||
|
Logger::Severity Logger::fMinSeverity = Logger::Severity::info;
|
||||||
|
std::function<void()> Logger::fFatalCallback;
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||||
|
const string Logger::fProcessName = getprogname();
|
||||||
|
#elif defined(_GNU_SOURCE)
|
||||||
|
const string Logger::fProcessName = program_invocation_short_name;
|
||||||
|
#else
|
||||||
|
const string Logger::fProcessName = "?";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const unordered_map<string, Logger::Verbosity> Logger::fVerbosityMap =
|
||||||
|
{
|
||||||
|
{ "veryhigh", Verbosity::veryhigh },
|
||||||
|
{ "high", Verbosity::high },
|
||||||
|
{ "medium", Verbosity::medium },
|
||||||
|
{ "low", Verbosity::low },
|
||||||
|
{ "VERYHIGH", Verbosity::veryhigh },
|
||||||
|
{ "HIGH", Verbosity::high },
|
||||||
|
{ "MEDIUM", Verbosity::medium },
|
||||||
|
{ "LOW", Verbosity::low }
|
||||||
|
};
|
||||||
|
|
||||||
|
const unordered_map<string, Logger::Severity> Logger::fSeverityMap =
|
||||||
|
{
|
||||||
|
{ "nolog", Severity::nolog },
|
||||||
|
{ "NOLOG", Severity::nolog },
|
||||||
|
{ "error", Severity::error },
|
||||||
|
{ "ERROR", Severity::error },
|
||||||
|
{ "warn", Severity::warn },
|
||||||
|
{ "WARN", Severity::warn },
|
||||||
|
{ "warning", Severity::warning },
|
||||||
|
{ "WARNING", Severity::warning },
|
||||||
|
{ "state", Severity::state },
|
||||||
|
{ "STATE", Severity::state },
|
||||||
|
{ "info", Severity::info },
|
||||||
|
{ "INFO", Severity::info },
|
||||||
|
{ "debug", Severity::debug },
|
||||||
|
{ "DEBUG", Severity::debug },
|
||||||
|
{ "trace", Severity::trace },
|
||||||
|
{ "TRACE", Severity::trace },
|
||||||
|
{ "debug1", Severity::debug1 },
|
||||||
|
{ "DEBUG1", Severity::debug1 },
|
||||||
|
{ "debug2", Severity::debug2 },
|
||||||
|
{ "DEBUG2", Severity::debug2 },
|
||||||
|
{ "debug3", Severity::debug3 },
|
||||||
|
{ "DEBUG3", Severity::debug3 },
|
||||||
|
{ "debug4", Severity::debug4 },
|
||||||
|
{ "DEBUG4", Severity::debug4 }
|
||||||
|
};
|
||||||
|
|
||||||
|
const array<string, 12> Logger::fSeverityNames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"NOLOG",
|
||||||
|
"FATAL",
|
||||||
|
"ERROR",
|
||||||
|
"WARN",
|
||||||
|
"STATE",
|
||||||
|
"INFO",
|
||||||
|
"DEBUG",
|
||||||
|
"DEBUG1",
|
||||||
|
"DEBUG2",
|
||||||
|
"DEBUG3",
|
||||||
|
"DEBUG4",
|
||||||
|
"TRACE"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const array<string, 4> Logger::fVerbosityNames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"low",
|
||||||
|
"medium",
|
||||||
|
"high",
|
||||||
|
"veryhigh"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
string Logger::SeverityName(Severity severity)
|
||||||
|
{
|
||||||
|
return fSeverityNames.at(static_cast<size_t>(severity));
|
||||||
|
}
|
||||||
|
|
||||||
|
string Logger::VerbosityName(Verbosity verbosity)
|
||||||
|
{
|
||||||
|
return fVerbosityNames.at(static_cast<size_t>(verbosity));
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Logger(Severity severity)
|
||||||
|
: fCurrentSeverity(severity)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Logger::SetConsoleSeverity(const Severity severity)
|
||||||
|
{
|
||||||
|
fConsoleSeverity = severity;
|
||||||
|
UpdateMinSeverity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetConsoleSeverity(const string& severityStr)
|
||||||
|
{
|
||||||
|
if (fSeverityMap.count(severityStr))
|
||||||
|
{
|
||||||
|
SetConsoleSeverity(fSeverityMap.at(severityStr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(ERROR) << "Unknown severity setting: '" << severityStr << "', setting to default 'info'.";
|
||||||
|
SetConsoleSeverity(Severity::info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetFileSeverity(const Severity severity)
|
||||||
|
{
|
||||||
|
fFileSeverity = severity;
|
||||||
|
UpdateMinSeverity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetFileSeverity(const string& severityStr)
|
||||||
|
{
|
||||||
|
if (fSeverityMap.count(severityStr))
|
||||||
|
{
|
||||||
|
SetFileSeverity(fSeverityMap.at(severityStr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(error) << "Unknown severity setting: '" << severityStr << "', setting to default 'info'.";
|
||||||
|
SetFileSeverity(Severity::info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::UpdateMinSeverity()
|
||||||
|
{
|
||||||
|
fMinSeverity = (fConsoleSeverity <= fFileSeverity) ? fFileSeverity : fConsoleSeverity;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logger::Logging(Severity severity)
|
||||||
|
{
|
||||||
|
if (Severity::fatal == severity)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (severity <= fMinSeverity && severity > Severity::nolog)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetVerbosity(const Verbosity verbosity)
|
||||||
|
{
|
||||||
|
fVerbosity = verbosity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetVerbosity(const string& verbosityStr)
|
||||||
|
{
|
||||||
|
if (fVerbosityMap.count(verbosityStr))
|
||||||
|
{
|
||||||
|
fVerbosity = fVerbosityMap.at(verbosityStr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(error) << "Unknown verbosity setting: '" << verbosityStr << "', setting to default 'low'.";
|
||||||
|
fVerbosity = Verbosity::low;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetConsoleColor(const bool colored)
|
||||||
|
{
|
||||||
|
fColored = colored;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::InitFileSink(const Severity severity, const string& filename, bool customizeName)
|
||||||
|
{
|
||||||
|
if (fFileStream.is_open())
|
||||||
|
{
|
||||||
|
fFileStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
string fullName = filename;
|
||||||
|
|
||||||
|
if (customizeName)
|
||||||
|
{
|
||||||
|
// TODO: customize file name
|
||||||
|
auto now = chrono::system_clock::to_time_t(chrono::system_clock::now());
|
||||||
|
stringstream ss;
|
||||||
|
ss << "_" << put_time(localtime(&now), "%Y-%m-%d_%H_%M_%S") << ".log";
|
||||||
|
fullName += ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
fFileStream.open(fullName, fstream::out | fstream::app);
|
||||||
|
|
||||||
|
if (fFileStream.is_open())
|
||||||
|
{
|
||||||
|
fFileSeverity = severity;
|
||||||
|
UpdateMinSeverity();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cout << "Error opening file: " << fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::InitFileSink(const string& severityStr, const string& filename, bool customizeName)
|
||||||
|
{
|
||||||
|
if (fSeverityMap.count(severityStr))
|
||||||
|
{
|
||||||
|
InitFileSink(fSeverityMap.at(severityStr), filename, customizeName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(error) << "Unknown severity setting: '" << severityStr << "', setting to default 'info'.";
|
||||||
|
InitFileSink(Severity::info, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::RemoveFileSink()
|
||||||
|
{
|
||||||
|
if (fFileStream.is_open())
|
||||||
|
{
|
||||||
|
fFileStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logger::LoggingToConsole() const
|
||||||
|
{
|
||||||
|
return (fCurrentSeverity <= fConsoleSeverity &&
|
||||||
|
fCurrentSeverity > Severity::nolog) ||
|
||||||
|
fCurrentSeverity == Severity::fatal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logger::LoggingToFile() const
|
||||||
|
{
|
||||||
|
return (fCurrentSeverity <= fFileSeverity &&
|
||||||
|
fCurrentSeverity > Severity::nolog) ||
|
||||||
|
fCurrentSeverity == Severity::fatal;
|
||||||
|
}
|
||||||
|
|
||||||
|
ostringstream& Logger::Log(const string& file, const string& line, const string& func)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
if ((!fColored && LoggingToConsole()) || (fFileStream.is_open() && LoggingToFile()))
|
||||||
|
{
|
||||||
|
if (fVerbosity >= Verbosity::high)
|
||||||
|
{
|
||||||
|
fBWOut << "[" << fProcessName << "]"
|
||||||
|
<< "[" << put_time(localtime(&now_c), "%H:%M:%S") << "." << setw(6) << setfill('0') << ns.count() << "]";
|
||||||
|
}
|
||||||
|
else if (fVerbosity == Verbosity::medium)
|
||||||
|
{
|
||||||
|
fBWOut << "[" << put_time(localtime(&now_c), "%H:%M:%S") << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
fBWOut << "[" << fSeverityNames.at(static_cast<size_t>(fCurrentSeverity)) << "]";
|
||||||
|
|
||||||
|
if (fVerbosity == Verbosity::veryhigh)
|
||||||
|
{
|
||||||
|
fBWOut << "[" << file.substr(pos + 1) << ":" << line << ":" << func << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
fBWOut << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fColored && (LoggingToConsole()))
|
||||||
|
{
|
||||||
|
if (fVerbosity >= Verbosity::high)
|
||||||
|
{
|
||||||
|
fColorOut << "[" << ColorOut(Color::fgBlue, fProcessName) << "]"
|
||||||
|
<< "[" << startColor(Color::fgCyan) << put_time(localtime(&now_c), "%H:%M:%S") << "." << setw(6) << setfill('0') << ns.count() << endColor() << "]";
|
||||||
|
}
|
||||||
|
else if (fVerbosity == Verbosity::medium)
|
||||||
|
{
|
||||||
|
fColorOut << "[" << startColor(Color::fgCyan) << put_time(localtime(&now_c), "%H:%M:%S") << endColor() << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
fColorOut << "[" << ColoredSeverityWriter(fCurrentSeverity) << "]";
|
||||||
|
|
||||||
|
if (fVerbosity == Verbosity::veryhigh)
|
||||||
|
{
|
||||||
|
fColorOut << "[" << ColorOut(Color::fgBlue, file.substr(pos + 1)) << ":" << ColorOut(Color::fgYellow, line) << ":" << ColorOut(Color::fgBlue, func) << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
fColorOut << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return fContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::OnFatal(std::function<void()> func)
|
||||||
|
{
|
||||||
|
fFatalCallback = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::SetCerrOnly(bool cerrOnly)
|
||||||
|
{
|
||||||
|
fCerrOnly = cerrOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::~Logger() noexcept(false)
|
||||||
|
{
|
||||||
|
fContent << "\n"; // "\n" + flush instead of endl makes output thread safe.
|
||||||
|
|
||||||
|
fBWOut << fContent.str();
|
||||||
|
|
||||||
|
if (LoggingToConsole())
|
||||||
|
{
|
||||||
|
if (fColored)
|
||||||
|
{
|
||||||
|
fColorOut << fContent.str();
|
||||||
|
if (fCurrentSeverity == Severity::fatal || fCurrentSeverity == Severity::error || fCerrOnly)
|
||||||
|
{
|
||||||
|
cerr << fColorOut.str() << flush;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cout << fColorOut.str() << flush;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fCurrentSeverity == Severity::fatal || fCurrentSeverity == Severity::error || fCerrOnly)
|
||||||
|
{
|
||||||
|
cerr << fBWOut.str() << flush;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cout << fBWOut.str() << flush;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LoggingToFile())
|
||||||
|
{
|
||||||
|
if (fFileStream.is_open())
|
||||||
|
{
|
||||||
|
fFileStream << fBWOut.str() << flush;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fCurrentSeverity == Severity::fatal)
|
||||||
|
{
|
||||||
|
if (fFatalCallback)
|
||||||
|
{
|
||||||
|
fFatalCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fair
|
177
logger/Logger.h
Normal file
177
logger/Logger.h
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
|
* *
|
||||||
|
* This software is distributed under the terms of the *
|
||||||
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
* copied verbatim in the file "LICENSE" *
|
||||||
|
********************************************************************************/
|
||||||
|
#ifndef FAIR_LOGGER_H
|
||||||
|
#define FAIR_LOGGER_H
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#undef DEBUG
|
||||||
|
#warning "The symbol 'DEBUG' is used in FairRoot Logger. undefining..."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace fair
|
||||||
|
{
|
||||||
|
|
||||||
|
// non-std exception to avoid undesirable catches - fatal should exit in a way we want.
|
||||||
|
class FatalException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FatalException()
|
||||||
|
: fWhat()
|
||||||
|
{}
|
||||||
|
|
||||||
|
FatalException(std::string what)
|
||||||
|
: fWhat(what)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string What()
|
||||||
|
{
|
||||||
|
return fWhat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string fWhat;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
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: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 std::string& severityStr);
|
||||||
|
|
||||||
|
static void SetFileSeverity(const Severity severity);
|
||||||
|
static void SetFileSeverity(const std::string& severityStr);
|
||||||
|
|
||||||
|
static bool Logging(const Severity severity);
|
||||||
|
|
||||||
|
static void SetVerbosity(const Verbosity verbosity);
|
||||||
|
static void SetVerbosity(const std::string& verbosityStr);
|
||||||
|
|
||||||
|
static void SetConsoleColor(const bool colored = true);
|
||||||
|
|
||||||
|
static void InitFileSink(const Severity severity, const std::string& filename, bool customizeName = true);
|
||||||
|
static void InitFileSink(const std::string& severityStr, const std::string& filename, bool customizeName = true);
|
||||||
|
|
||||||
|
static void RemoveFileSink();
|
||||||
|
|
||||||
|
static std::string SeverityName(Severity);
|
||||||
|
static std::string VerbosityName(Verbosity);
|
||||||
|
|
||||||
|
std::ostringstream& Log(const std::string& file, const std::string& line, const std::string& func);
|
||||||
|
|
||||||
|
static const std::unordered_map<std::string, Verbosity> fVerbosityMap;
|
||||||
|
static const std::unordered_map<std::string, Severity> fSeverityMap;
|
||||||
|
static const std::array<std::string, 12> fSeverityNames;
|
||||||
|
static const std::array<std::string, 4> fVerbosityNames;
|
||||||
|
|
||||||
|
static void OnFatal(std::function<void()> func);
|
||||||
|
|
||||||
|
static void SetCerrOnly(bool cerrOnly);
|
||||||
|
|
||||||
|
virtual ~Logger() noexcept(false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Severity fCurrentSeverity;
|
||||||
|
|
||||||
|
std::ostringstream fContent;
|
||||||
|
std::ostringstream fColorOut;
|
||||||
|
std::ostringstream fBWOut;
|
||||||
|
static const std::string fProcessName;
|
||||||
|
static bool fColored;
|
||||||
|
static bool fCerrOnly;
|
||||||
|
static std::fstream fFileStream;
|
||||||
|
|
||||||
|
static Severity fConsoleSeverity;
|
||||||
|
static Severity fFileSeverity;
|
||||||
|
static Severity fMinSeverity;
|
||||||
|
|
||||||
|
static Verbosity fVerbosity;
|
||||||
|
|
||||||
|
static std::function<void()> fFatalCallback;
|
||||||
|
|
||||||
|
bool LoggingToConsole() const;
|
||||||
|
bool LoggingToFile() const;
|
||||||
|
|
||||||
|
static void UpdateMinSeverity();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace fair
|
||||||
|
|
||||||
|
#define IMP_CONVERTTOSTRING(s) # s
|
||||||
|
#define CONVERTTOSTRING(s) IMP_CONVERTTOSTRING(s)
|
||||||
|
|
||||||
|
#define LOG(severity) \
|
||||||
|
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(fair::Logger::Severity::severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
|
||||||
|
fair::Logger(fair::Logger::Severity::severity).Log(__FILE__, CONVERTTOSTRING(__LINE__), __FUNCTION__)
|
||||||
|
|
||||||
|
// with custom file, line, function
|
||||||
|
#define LOGD(severity, file, line, function) \
|
||||||
|
for (bool fairLOggerunLikelyvariable = false; fair::Logger::Logging(severity) && !fairLOggerunLikelyvariable; fairLOggerunLikelyvariable = true) \
|
||||||
|
fair::Logger(severity).Log(file, line, function)
|
||||||
|
|
||||||
|
#define LOG_IF(severity, condition) \
|
||||||
|
for (bool fairLOggerunLikelyvariable2 = false; condition && !fairLOggerunLikelyvariable2; fairLOggerunLikelyvariable2 = true) \
|
||||||
|
LOG(severity)
|
||||||
|
|
||||||
|
#endif // FAIR_LOGGER_H
|
134
logger/loggerTest.cxx
Normal file
134
logger/loggerTest.cxx
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
|
* *
|
||||||
|
* This software is distributed under the terms of the *
|
||||||
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
* copied verbatim in the file "LICENSE" *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
// WARNING : pragma commands to hide boost warning
|
||||||
|
// TODO : remove these pragma commands when boost will fix this issue in future release
|
||||||
|
|
||||||
|
#include <Logger.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace fair;
|
||||||
|
|
||||||
|
void printEverySeverity()
|
||||||
|
{
|
||||||
|
static int i = 1;
|
||||||
|
|
||||||
|
LOG(nolog) << "nolog message " << i++;
|
||||||
|
LOG(error) << "error message " << i++;
|
||||||
|
LOG(warn) << "warning message " << i++;
|
||||||
|
LOG(state) << "state message " << i++;
|
||||||
|
LOG(info) << "info message " << i++;
|
||||||
|
LOG(debug) << "debug message " << i++;
|
||||||
|
LOG(debug1) << "debug1 message " << i++;
|
||||||
|
LOG(debug2) << "debug2 message " << i++;
|
||||||
|
LOG(debug3) << "debug3 message " << i++;
|
||||||
|
LOG(debug4) << "debug4 message " << i++;
|
||||||
|
LOG(trace) << "trace message " << i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printAllVerbositiesWithSeverity(Logger::Severity sev)
|
||||||
|
{
|
||||||
|
Logger::SetConsoleSeverity(sev);
|
||||||
|
|
||||||
|
cout << endl << ">>> testing severity '" << Logger::SeverityName(sev) << "' with 'low' verbosity..." << endl;
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::low);
|
||||||
|
printEverySeverity();
|
||||||
|
cout << endl << ">>> testing severity '" << Logger::SeverityName(sev) << "' with 'medium' verbosity..." << endl;
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::medium);
|
||||||
|
printEverySeverity();
|
||||||
|
cout << endl << ">>> testing severity '" << Logger::SeverityName(sev) << "' with 'high' verbosity..." << endl;
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::high);
|
||||||
|
printEverySeverity();
|
||||||
|
cout << endl << ">>> testing severity '" << Logger::SeverityName(sev) << "' with 'veryhigh' verbosity..." << endl;
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::veryhigh);
|
||||||
|
printEverySeverity();
|
||||||
|
}
|
||||||
|
|
||||||
|
void silentlyPrintAllVerbositiesWithSeverity(Logger::Severity sev)
|
||||||
|
{
|
||||||
|
Logger::SetConsoleSeverity(sev);
|
||||||
|
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::low);
|
||||||
|
printEverySeverity();
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::medium);
|
||||||
|
printEverySeverity();
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::high);
|
||||||
|
printEverySeverity();
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::veryhigh);
|
||||||
|
printEverySeverity();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Logger::SetConsoleColor(true);
|
||||||
|
|
||||||
|
cout << "testing severities..." << endl;
|
||||||
|
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::trace);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::debug4);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::debug3);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::debug2);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::debug1);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::debug);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::info);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::state);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::warn);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::error);
|
||||||
|
printAllVerbositiesWithSeverity(Logger::Severity::nolog);
|
||||||
|
|
||||||
|
cout << endl;
|
||||||
|
cout << "resetting severity to 'info' and verbosity to 'medium'" << endl;
|
||||||
|
Logger::SetConsoleSeverity(Logger::Severity::info);
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::medium);
|
||||||
|
|
||||||
|
cout << "is logging trace: " << fair::Logger::Logging(Logger::Severity::trace) << endl;
|
||||||
|
cout << "is logging debug4: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
||||||
|
cout << "is logging debug3: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
||||||
|
cout << "is logging debug2: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
||||||
|
cout << "is logging debug1: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
||||||
|
cout << "is logging debug: " << fair::Logger::Logging(Logger::Severity::debug) << endl;
|
||||||
|
cout << "is logging info: " << fair::Logger::Logging(Logger::Severity::info) << endl;
|
||||||
|
cout << "is logging state: " << fair::Logger::Logging(Logger::Severity::state) << endl;
|
||||||
|
cout << "is logging warn: " << fair::Logger::Logging(Logger::Severity::warn) << endl;
|
||||||
|
cout << "is logging error: " << fair::Logger::Logging(Logger::Severity::error) << endl;
|
||||||
|
cout << "is logging fatal: " << fair::Logger::Logging(Logger::Severity::fatal) << endl;
|
||||||
|
cout << "is logging nolog: " << fair::Logger::Logging(Logger::Severity::nolog) << endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
{
|
||||||
|
silentlyPrintAllVerbositiesWithSeverity(Logger::Severity::nolog);
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
|
cout << "resetting severity to 'trace' and verbosity to 'veryhigh'" << endl;
|
||||||
|
Logger::SetConsoleSeverity(Logger::Severity::trace);
|
||||||
|
Logger::SetVerbosity(Logger::Verbosity::veryhigh);
|
||||||
|
|
||||||
|
cout << endl;
|
||||||
|
cout << "testing conditional logging..." << endl;
|
||||||
|
int x = 0;
|
||||||
|
LOG(info) << "x = " << x << " (initial)";
|
||||||
|
LOG_IF(info, (x == 0)) << "incrementing x to " << ++x;
|
||||||
|
LOG(info) << "x = " << x << " (after increment)";
|
||||||
|
LOG_IF(info, (x == 0)) << "this should not be printed and x not incremented: " << ++x;
|
||||||
|
LOG(info) << "x = " << x << " (after conditional increment)";
|
||||||
|
|
||||||
|
cout << endl;
|
||||||
|
cout << "resetting severity to 'nolog'" << endl;
|
||||||
|
Logger::SetConsoleSeverity(Logger::Severity::nolog);
|
||||||
|
|
||||||
|
cout << "----------------------------" << endl;
|
||||||
|
cout << "open log file with severity 'error'" << endl;
|
||||||
|
Logger::InitFileSink(Logger::Severity::error, "test_log", true);
|
||||||
|
printEverySeverity();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user