43#include "fileHandler.hpp"
64 : m_buffer(bufferSize + 1),
65 m_nProcesses(nProcesses), m_rank(rank),
66 m_consoleEnabled(false), m_console(&std::cout),
67 m_fileEnabled(false), m_file(nullptr),
68 m_settings(std::make_shared<
Settings>())
71 char *bufferBegin = &m_buffer.front();
72 setp(bufferBegin, bufferBegin + m_buffer.size() - 1);
81 if (m_nProcesses > 1) {
82 int nDigits =
static_cast<int>(std::ceil(log10(m_nProcesses)));
83 std::ostringstream convert;
84 convert << std::setw(nDigits) << m_rank;
85 m_rankPrefix =
"#" + convert.str();
91 m_settings->context =
"";
92 m_settings->indentation = 0;
93 m_settings->consoleTimestampEnabled =
false;
94 m_settings->fileTimestampEnabled =
false;
136LoggerBuffer::int_type LoggerBuffer::overflow(int_type character)
138 if (character != traits_type::eof()) {
143 assert(std::less_equal<char *>()(pptr(), epptr()));
153 return traits_type::eof();
161int LoggerBuffer::sync()
176 const char *bufferBegin = pbase();
177 const char *bufferEnd = pptr();
178 if (bufferBegin == bufferEnd) {
183 static const std::string EMPTY_STRING =
"";
185 const char *lineBegin =
nullptr;
186 const char *lineEnd = bufferBegin;
187 while (lineEnd != bufferEnd) {
190 for (lineEnd = lineBegin; lineEnd != bufferEnd; ++lineEnd) {
191 if (*lineEnd ==
'\n') {
198 bool terminateLine =
false;
199 if (terminate && (lineEnd == bufferEnd)) {
200 if (bufferBegin == bufferEnd) {
201 terminateLine =
true;
202 }
else if (*(bufferEnd - 1) !=
'\n') {
203 terminateLine =
true;
208 std::string timestamp;
209 if (m_settings->consoleTimestampEnabled || m_settings->fileTimestampEnabled) {
210 timestamp = getTimestamp();
214 if (m_console && m_consoleEnabled) {
215 const std::string *consoleTimestamp;
216 if (m_settings->consoleTimestampEnabled) {
217 consoleTimestamp = ×tamp;
219 consoleTimestamp = &EMPTY_STRING;
222 int status = flushLine(*m_console, lineBegin, lineEnd, *consoleTimestamp, terminateLine);
229 if (m_file && m_fileEnabled && m_file->is_open()) {
230 const std::string *fileTimestamp;
231 if (m_settings->fileTimestampEnabled) {
232 fileTimestamp = ×tamp;
234 fileTimestamp = &EMPTY_STRING;
237 int status = flushLine(*m_file, lineBegin, lineEnd, *fileTimestamp, terminateLine);
245 pbump(
static_cast<int>(bufferBegin - bufferEnd));
263int LoggerBuffer::flushLine(std::ostream &stream,
const char *begin,
const char *end,
264 const std::string ×tamp,
bool terminate)
266 if (!timestamp.empty()) {
267 stream <<
"[" + timestamp +
"] ";
268 if ((stream.rdstate() & std::ifstream::failbit) != 0) {
273 if (!m_rankPrefix.empty()) {
274 stream << m_rankPrefix <<
" :: ";
275 if ((stream.rdstate() & std::ifstream::failbit) != 0) {
280 if (!m_settings->context.empty()) {
281 stream << m_settings->context +
" :: ";
282 if ((stream.rdstate() & std::ifstream::failbit) != 0) {
287 for (
int i = 0; i < m_settings->indentation; ++i) {
289 if ((stream.rdstate() & std::ifstream::failbit) != 0) {
294 stream.write(begin, end - begin);
295 if ((stream.rdstate() & std::ifstream::failbit) != 0) {
301 if ((stream.rdstate() & std::ifstream::failbit) != 0) {
316 if (m_consoleEnabled == enabled) {
322 m_consoleEnabled = enabled;
358 if (m_fileEnabled == enabled) {
364 m_fileEnabled = enabled;
396 return m_settings.get();
406 if (settings.get() == m_settings.get()) {
412 m_settings = settings;
418std::string LoggerBuffer::getTimestamp()
const
420 static const std::string TIMESTAMP_FORMAT =
"%Y-%m-%d %H:%M:%S";
422 auto currentClock = std::chrono::system_clock::now();
423 std::time_t currentTime = std::chrono::system_clock::to_time_t(currentClock);
425 auto seconds = std::chrono::duration_cast<std::chrono::seconds>(currentClock.time_since_epoch());
426 auto millisecs = std::chrono::duration_cast<std::chrono::milliseconds>(currentClock.time_since_epoch() - seconds);
427 std::array<char, 11> millisecsBuffer;
428 std::snprintf(millisecsBuffer.data(), millisecsBuffer.size(),
"%03u",
static_cast<unsigned int>(millisecs.count()));
430 std::string timestamp;
431 timestamp.resize(23);
432 std::strftime(×tamp[0], timestamp.size(), TIMESTAMP_FORMAT.c_str(), localtime(¤tTime));
434 timestamp[20] = millisecsBuffer[0];
435 timestamp[21] = millisecsBuffer[1];
436 timestamp[22] = millisecsBuffer[2];
456Logger::Logger(
const std::string &name,
const std::shared_ptr<LoggerBuffer> &buffer)
457 : std::ios(nullptr), std::ostream(nullptr),
459 m_buffer(buffer), m_bufferSettings(std::make_shared<LoggerBuffer::Settings>()),
460 m_defaultSeverity(log::LEVEL_INFO), m_defaultVisibility(log::VISIBILITY_MASTER),
461 m_consoleDisabledThreshold(log::LEVEL_NOTSET), m_consoleVerbosityThreshold(log::LEVEL_INFO),
462 m_fileDisabledThreshold(log::LEVEL_NOTSET), m_fileVerbosityThreshold(log::LEVEL_INFO)
465 basic_ios<char>::rdbuf(m_buffer.get());
468 m_bufferSettings->context =
"";
469 m_bufferSettings->indentation = 0;
470 m_bufferSettings->consoleTimestampEnabled =
false;
471 m_bufferSettings->fileTimestampEnabled =
true;
516 m_consoleDisabledThreshold = level;
538 m_fileDisabledThreshold = level;
549 assert(severity != log::Level::LEVEL_NOTSET);
550 m_defaultSeverity = severity;
560 return m_defaultSeverity;
591 assert(visibility != log::VISIBILITY_NOTSET);
592 m_defaultVisibility = visibility;
602 return m_defaultVisibility;
661 return m_bufferSettings->consoleTimestampEnabled;
671 if (m_bufferSettings->consoleTimestampEnabled == enabled) {
675 m_buffer->flush(
true);
677 m_bufferSettings->consoleTimestampEnabled = enabled;
692 m_consoleVerbosityThreshold = threshold;
701void Logger::enableBufferStreams(
log::Level severity, log::Visibility visibility)
704 bool isConsoleEnabled =
true;
705 if (severity <= m_consoleDisabledThreshold) {
706 isConsoleEnabled =
false;
707 }
else if (visibility == log::VISIBILITY_MASTER && (m_buffer->getRank() != 0)) {
708 isConsoleEnabled =
false;
710 isConsoleEnabled = (severity >= m_consoleVerbosityThreshold);
712 m_buffer->setConsoleEnabled(isConsoleEnabled);
715 bool isFileEnabled =
true;
716 if (severity <= m_fileDisabledThreshold) {
717 isFileEnabled =
false;
718 }
else if (visibility == log::VISIBILITY_MASTER && (m_buffer->getRank() != 0)) {
719 isFileEnabled =
false;
721 isFileEnabled = (severity >= m_fileVerbosityThreshold);
723 m_buffer->setFileEnabled(isFileEnabled);
737 return m_consoleVerbosityThreshold;
748 return m_bufferSettings->fileTimestampEnabled;
758 if (m_bufferSettings->fileTimestampEnabled == enabled) {
762 m_buffer->flush(
true);
764 m_bufferSettings->fileTimestampEnabled = enabled;
779 m_fileVerbosityThreshold = threshold;
791 return m_fileVerbosityThreshold;
801 if (m_bufferSettings->context == context) {
805 m_buffer->flush(
true);
807 m_bufferSettings->context = context;
817 return m_bufferSettings->context;
831 m_buffer->flush(
true);
833 m_bufferSettings->indentation += delta;
843 return m_bufferSettings->indentation;
874 print(line +
'\n', severity);
885 print(line +
'\n', visibility);
897 print(line +
'\n', severity, visibility);
956std::unique_ptr<LoggerManager> LoggerManager::m_manager =
nullptr;
961std::string LoggerManager::BITPIT_LOG_NAME =
"bitpit";
966std::string LoggerManager::BITPIT_LOG_DIRECTORY =
".";
971LoggerManager::LoggerManager()
972 : m_defaultName(BITPIT_LOG_NAME), m_defaultDirectory(BITPIT_LOG_DIRECTORY),
973 m_mode(
log::MODE_SEPARATE)
984 std::vector<std::string> loggerNames;
985 loggerNames.reserve(m_loggers.size());
986 for (
const auto &entry : m_loggers) {
987 loggerNames.push_back(entry.first);
991 for (
const std::string &name : loggerNames) {
1004 m_manager = std::unique_ptr<LoggerManager>(
new LoggerManager());
1027 return cout(m_defaultName, defaultSeverity, defaultVisibility);
1052 if (m_loggers.count(name) == 0) {
1057 if (name == m_defaultName) {
1058 _create(name,
false, m_defaultDirectory, 1, 0);
1060 create(name,
false, m_defaultDirectory, 1, 0);
1064 Logger &logger = *(m_loggers.at(name));
1067 if (defaultSeverity != log::Level::LEVEL_NOTSET) {
1071 if (defaultVisibility != log::VISIBILITY_NOTSET) {
1093 return critical(m_defaultName, defaultVisibility);
1114 return cout(name, log::Level::LEVEL_CRITICAL, defaultVisibility);
1131 return error(m_defaultName, defaultVisibility);
1152 return cout(name, log::Level::LEVEL_ERROR, defaultVisibility);
1169 return warning(m_defaultName, defaultVisibility);
1190 return cout(name, log::Level::LEVEL_WARNING, defaultVisibility);
1207 return info(m_defaultName, defaultVisibility);
1228 return cout(name, log::Level::LEVEL_INFO, defaultVisibility);
1245 return debug(m_defaultName, defaultVisibility);
1266 return cout(name, log::Level::LEVEL_DEBUG, defaultVisibility);
1278 int nProcesses,
int rank)
1280 initialize(mode, m_defaultName, reset, m_defaultDirectory, nProcesses, rank);
1293 int nProcesses,
int rank)
1295 initialize(mode, m_defaultName, reset, directory, nProcesses, rank);
1309 const std::string &directory,
1310 int nProcesses,
int rank)
1313 log::cout().
println(
"Logger initialization has to be called before creating the loggers.");
1321 m_defaultName = name;
1322 m_defaultDirectory = directory;
1325 _create(m_defaultName, reset, directory, nProcesses, rank);
1337 int nProcesses,
int rank)
1339 create(name, reset, m_defaultDirectory, nProcesses, rank);
1352 const std::string &directory,
1353 int nProcesses,
int rank)
1359 m_loggerUsers[name]++;
1361 cout(name) <<
"Detected an attemp to create the logger \"" << name <<
"\" twice" << std::endl;
1362 cout(name) <<
"The previously created logger will be used." << std::endl;
1364 }
else if (name == m_defaultName) {
1365 cout(m_defaultName) <<
"Detected an attemp to overwrite the default logger" << std::endl;
1366 cout(m_defaultName) <<
"The name of the default logger is \"" << name <<
"\"" << std::endl;
1368 }
else if (name ==
"") {
1369 cout() <<
"Detected an attemp to create a logger with an empty name" << std::endl;
1374 if (m_mode == log::MODE_SEPARATE) {
1375 _create(name, reset, directory, nProcesses, rank);
1378 _create(name, defaultLogger.m_buffer);
1400 int &nUsers = m_loggerUsers[name];
1404 if (nUsers == 0 || force) {
1406 m_loggers.erase(name);
1407 m_loggerUsers.erase(name);
1410 if (m_fileStreams.count(name) > 0) {
1412 std::ofstream &fileStream = *(m_fileStreams.at(name));
1416 m_fileStreams.erase(name);
1433 return (m_loggers.count(name) != 0);
1448 return (m_loggers.size() > 0);
1468 cout().
println(
"The policy has to be set before creating the loggers.");
1495void LoggerManager::_create(
const std::string &name,
bool reset,
1496 const std::string &directory,
1497 int nProcesses,
int rank)
1505 if (nProcesses > 1) {
1509 std::string filePath = fileHandler.
getPath();
1512 std::ios_base::openmode fileMode;
1514 fileMode = std::ofstream::out;
1516 fileMode = std::ofstream::app;
1519 m_fileStreams[name] = std::unique_ptr<std::ofstream>(
new std::ofstream());
1520 std::ofstream &fileStream = *(m_fileStreams.at(name));
1521 fileStream.rdbuf()->pubsetbuf(0, 0);
1522 fileStream.open(filePath, fileMode);
1525 std::ostream &consoleStream = std::cout;
1528 std::shared_ptr<LoggerBuffer> buffer = std::make_shared<LoggerBuffer>(nProcesses, rank, 256);
1529 buffer->setFileStream(&fileStream);
1530 buffer->setConsoleStream(&consoleStream);
1533 _create(name, buffer);
1542void LoggerManager::_create(
const std::string &name, std::shared_ptr<LoggerBuffer> &buffer)
1544 m_loggers[name] = std::unique_ptr<Logger>(
new Logger(name, buffer));
1545 m_loggerUsers[name] = 1;
1560 for (
auto &entry : m_loggers) {
1561 entry.second->setVerbosities(threshold);
1576 for (
auto &entry : m_loggers) {
1577 entry.second->setConsoleVerbosity(threshold);
1592 for (
auto &entry : m_loggers) {
1593 entry.second->setFileVerbosity(threshold);
1604 return m_defaultName;
1614 return m_defaultDirectory;
Creates file names and checks status.
std::string getPath() const
void setParallel(bool p_)
void setDirectory(const std::string &d_)
void setName(const std::string &n_)
void setAppendix(const std::string &a_)
std::ofstream & getFileStream()
LoggerBuffer(int nProcesses, int rank, std::size_t bufferSize=256)
void setFileEnabled(bool enabled)
void setSettings(const std::shared_ptr< Settings > &settings)
int getProcessCount() const
const Settings * getSettings() const
void setFileStream(std::ofstream *file)
void setConsoleEnabled(bool enabled)
std::ostream & getConsoleStream()
int flush(bool terminate)
void setConsoleStream(std::ostream *console)
void create(const std::string &name, bool reset=false, int nProcesses=1, int rank=0)
bool setMode(log::Mode mode)
bool exists(const std::string &name) const
Logger & debug(log::Visibility visibility=log::VISIBILITY_NOTSET)
bool destroy(const std::string &name, bool force=false)
void setVerbosities(log::Level threshold)
Logger & critical(log::Visibility visibility=log::VISIBILITY_NOTSET)
std::string getDefaultDirectory() const
log::Mode getMode() const
Logger & cout(log::Level defualtSeverity=log::Level::LEVEL_NOTSET, log::Visibility defualtVisibility=log::VISIBILITY_NOTSET)
Logger & warning(log::Visibility visibility=log::VISIBILITY_NOTSET)
static LoggerManager & manager()
Logger & error(log::Visibility visibility=log::VISIBILITY_NOTSET)
void setFileVerbosity(log::Level threshold)
std::string getDefaultName() const
Logger & info(log::Visibility visibility=log::VISIBILITY_NOTSET)
bool isInitialized() const
void setConsoleVerbosity(log::Level threshold)
void initialize(log::Mode mode, bool reset, int nProcesses, int rank)
void setDefaultVisibility(log::Visibility visibility)
void setDefaultSeverity(log::Level severity)
void setVerbosities(log::Level threshold)
void setConsoleTimestampEnabled(bool enabled)
void setFileVerbosity(log::Level threshold)
log::Level getDefaultSeverity()
void setConsoleVerbosity(log::Level threshold)
void setPriority(log::Priority priority)
bool isConsoleTimestampEnabled() const
void disable(log::Level=log::Level::LEVEL_CRITICAL)
log::Visibility getDefaultVisibility()
log::Level getFileVerbosity()
void setIndentation(int delta)
void disableConsole(log::Level=log::Level::LEVEL_CRITICAL)
bool isFileTimestampEnabled() const
void setVisibility(log::Visibility visibility)
void setFileTimestampEnabled(bool enabled)
void println(const std::string &message)
void disableFile(log::Level=log::Level::LEVEL_CRITICAL)
std::string getName() const
void print(const std::string &message)
void setContext(const std::string &context)
void setTimestampEnabled(bool enabled)
log::Level getConsoleVerbosity()
log::Visibility getVisibility()
log::Priority getPriority()
The namespace 'log' contains routines for interacting with the message logger.
LoggerManipulator< log::Level > defaultSeverity(const log::Level &severity)
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
LoggerManipulator< log::Visibility > defaultVisibility(const log::Visibility &visibility)
LoggerManipulator< log::Level > verbosities(const log::Level &threshold)
Logger & setPriority(Logger &logger, const log::Priority &priority)
LoggerManipulator< log::Visibility > visibility(const log::Visibility &visibility)
Logger & critical(log::Visibility defaultVisibility)
Logger & disable(Logger &logger, const log::Level &level)
LoggerManipulator< log::Level > consoleVerbosity(const log::Level &threshold)
Logger & setDefaultSeverity(Logger &logger, const log::Level &severity)
LoggerManipulator< log::Priority > priority(const log::Priority &priority)
Logger & error(log::Visibility defaultVisibility)
Logger & warning(log::Visibility defaultVisibility)
LoggerManipulator< log::Level > fileVerbosity(const log::Level &threshold)
Logger & debug(log::Visibility defaultVisibility)
LoggerManipulator< int > indent(int delta)
Logger & setFileVerbosity(Logger &logger, const log::Level &threshold)
Logger & setVisibility(Logger &logger, const log::Visibility &visibility)
Logger & info(log::Visibility defaultVisibility)
Logger & disableConsole(Logger &logger, const log::Level &level)
Logger & setDefaultVisibility(Logger &logger, const log::Visibility &visibility)
LoggerManager & manager()
Logger & setVerbosities(Logger &logger, const log::Level &threshold)
Logger & setIndentation(Logger &logger, const int &delta)
LoggerManipulator< std::string > context(const std::string &context)
Logger & disableFile(Logger &logger, const log::Level &level)
Logger & setConsoleVerbosity(Logger &logger, const log::Level &threshold)
Logger & setContext(Logger &logger, const std::string &context)