diff --git a/src/MarDyn.cpp b/src/MarDyn.cpp index 0d269c6a8d..9d56b64667 100644 --- a/src/MarDyn.cpp +++ b/src/MarDyn.cpp @@ -134,7 +134,10 @@ int run_unit_tests(const Values &options, const std::vector &args) int main(int argc, char** argv) { #ifdef ENABLE_MPI MPI_Init(&argc, &argv); + int world_rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); #endif + Log::global_log = std::make_unique(Log::Info); // Open scope to exclude MPI_Init() and MPI_Finalize(). // This way, all simulation objects are cleaned up before MPI finalizes. @@ -149,11 +152,14 @@ int main(int argc, char** argv) { if( options.is_set_by_user("logfile") ) { // Print to file std::string logfileNamePrefix(options.get("logfile")); - std::cout << "Using logfile with prefix " << logfileNamePrefix << std::endl; - Log::global_log = std::make_unique(Log::Info, logfileNamePrefix); - } else { - // Print to stream (default: std::cout) - Log::global_log = std::make_unique(Log::Info); + std::string logfile_name = logfileNamePrefix; +#ifdef ENABLE_MPI + logfile_name += "_R" + std::to_string(world_rank); +#endif + logfile_name += ".log"; + Log::global_log->info() << "Using logfile " << logfile_name << " for further log output." << std::endl; + std::shared_ptr logfile_ptr = std::make_shared(logfile_name); + Log::global_log->set_log_stream(logfile_ptr); } #ifdef ENABLE_MPI diff --git a/src/plugins/VectorizationTuner.h b/src/plugins/VectorizationTuner.h index cc5e5dabbd..908572c05c 100644 --- a/src/plugins/VectorizationTuner.h +++ b/src/plugins/VectorizationTuner.h @@ -8,9 +8,9 @@ enum MoleculeCntIncreaseTypeEnum{ both //!< both, do linear and exponential measurements, linear measurements will stop after 32 molecules. }; - -#include +#include #include +#include #include "particleContainer/adapter/CellProcessor.h" #include "particleContainer/adapter/FlopCounter.h" diff --git a/src/utils/Logger.cpp b/src/utils/Logger.cpp index 6a694fd3df..301c943920 100644 --- a/src/utils/Logger.cpp +++ b/src/utils/Logger.cpp @@ -2,49 +2,22 @@ #include "Logger.h" -#include - namespace Log { std::unique_ptr global_log; // Write to stream -Logger::Logger(logLevel level, std::ostream *os) : - _log_level(level), _msg_log_level(Log::Error), - _do_output(true), _filename(""), - // std::cout is managed globally, - // so do nothing when _log_stream goes out of scope - // --> any passed ostream other than std::cout needs to be - // deleted manually! - _log_stream(os, [](std::ostream*){/* no-op deleter */}), - logLevelNames(), _starttime(), _rank(0) -{ - init_starting_time(); - this->init_log_levels(); -#ifdef ENABLE_MPI - MPI_Comm_rank(MPI_COMM_WORLD, &_rank); -#endif - *_log_stream << std::boolalpha; // Print boolean as true/false -} - -// Write to file -Logger::Logger(logLevel level, std::string prefix) : +Logger::Logger(logLevel level, std::shared_ptr os) : _log_level(level), _msg_log_level(Log::Error), - _do_output(true), _filename(""), _log_stream(nullptr), + _do_output(true), + _log_stream(os), logLevelNames(), _starttime(), _rank(0) { init_starting_time(); this->init_log_levels(); - std::stringstream filenamestream; - filenamestream << prefix; #ifdef ENABLE_MPI MPI_Comm_rank(MPI_COMM_WORLD, &_rank); - filenamestream << "_R" << _rank; #endif - filenamestream << ".log"; - _filename = filenamestream.str(); - - _log_stream = std::make_shared(_filename.c_str()); *_log_stream << std::boolalpha; // Print boolean as true/false } diff --git a/src/utils/Logger.h b/src/utils/Logger.h index 5afa8b0b98..30df11e841 100644 --- a/src/utils/Logger.h +++ b/src/utils/Logger.h @@ -3,20 +3,15 @@ #define USE_GETTIMEOFDAY -#include -#include -#include +#include +#include +#include #include +#include #include -#include -#include -#include -#include #include - -#ifdef USE_GETTIMEOFDAY -#include -#endif +#include +#include #ifdef ENABLE_MPI #include @@ -71,14 +66,7 @@ typedef enum { /** @brief The Logger class provides a simple interface to handle log messages. * - * Provides easy interface to handle log messages. Initialize either with - * output level and stream or output level and filename or use default constructor - * values (Error, &(std::cout)). - * Note: Due to the default argument (std::cout), the passed ostream pointer - * will not be deleted automatically! Any passed ostream pointer other than - * std::cout must be deleted manually! - * With a given file basename and MPI Support each rank will create - * and write to its own file. + * The logger provides an easy way to output logging messages with various log levels. * For writing log messages use fatal(), error(), warning(), info() or debug() as * with normal streams, e.g. * > log.error() << "Wrong parameter." << std::endl; @@ -96,15 +84,10 @@ class Logger { logLevel _log_level; logLevel _msg_log_level; bool _do_output; - std::string _filename; std::shared_ptr _log_stream; std::map logLevelNames; -#ifdef USE_GETTIMEOFDAY - timeval _starttime; -#else - time_t _starttime; -#endif + std::chrono::system_clock::time_point _starttime; int _rank; /// initialize the list of log levels with the corresponding short names @@ -118,32 +101,16 @@ class Logger { logLevelNames.insert(std::pair(All, "ALL" )); } - // don't allow copy-construction - Logger(const Logger&) : _log_level(Log::Error), _msg_log_level(Log::Error), _do_output(true), - _filename(""), _log_stream(nullptr), logLevelNames(), _starttime(), _rank(0) - { } - - // don't allow assignment - Logger& operator=(const Logger&) { return *this; } - public: /** * Constructor for a logger to a stream. * * Initializes the log level, log stream and the list of log level names. * If ENABLE_MPI is enabled by default, all process perform logging output. - * Note: Due to the default argument (std::cout), the passed ostream pointer - * will not be deleted automatically! Any passed ostream pointer other than - * std::cout must be deleted manually! + * Note: The default stream used (std::cout) cannot be deleted. Therefore the + * passed shared pointer to it uses a no-op deleter function. */ - Logger(logLevel level = Log::Error, std::ostream *os = &(std::cout)); - /** - * Constructor for a logger to a file. - * - * Initializes the log level, log stream and the list of log level names. - * If ENABLE_MPI is enabled by default, all process perform logging output. - */ - Logger(logLevel level, std::string prefix); + Logger(logLevel level = Log::Error, std::shared_ptr os = std::shared_ptr(&std::cout, [](void*){ /* no-op */})); ~Logger() = default; @@ -180,22 +147,14 @@ class Logger { _msg_log_level = level; if (_msg_log_level <= _log_level && _do_output) { // Include timestamp - const auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - tm unused{}; - const auto* lt = localtime_r(&now, &unused); - //*_log_stream << ctime(&t) << " "; - std::stringstream timestampstream; - // maybe sprintf is easier here... - timestampstream << std::setfill('0') << std::setw(4) << (1900 + lt->tm_year) << std::setw(2) << (1 + lt->tm_mon) << std::setw(2) << lt->tm_mday << "T" << std::setw(2) << lt->tm_hour << std::setw(2) << lt->tm_min << std::setw(2) << lt->tm_sec; - *_log_stream << logLevelNames[level] << ":\t" << timestampstream.str() << " "; - //timestampstream.str(""); timestampstream.clear(); -#ifdef USE_GETTIMEOFDAY - timeval tod; - gettimeofday(&tod, 0); - *_log_stream << std::setw(8) << tod.tv_sec - _starttime.tv_sec + (tod.tv_usec - _starttime.tv_usec) / 1.E6 << " "; -#else - *_log_stream << t-_starttime << "\t"; -#endif + const auto now = std::chrono::system_clock::now(); + const auto time_since_start = now - _starttime; + + const auto now_time_t = std::chrono::system_clock::to_time_t(now); + std::tm now_local{}; + localtime_r(&now_time_t, &now_local); + *_log_stream << logLevelNames[level] << ":\t" << std::put_time(&now_local, "%Y-%m-%dT%H:%M:%S") << " "; + *_log_stream << std::setw(8) << std::chrono::duration(time_since_start).count() << " "; *_log_stream << "[" << _rank << "]\t"; } @@ -230,10 +189,8 @@ class Logger { } /// set log level from string logLevel set_log_level(std::string l) { - // identify the loglevel by comparing the first char of the names for (const auto& [lvl, name] : logLevelNames) { - // case-insensitive matching - if (std::toupper(name[0]) == std::toupper(l[0])) { + if (name == l) { _log_level = lvl; return _log_level; } @@ -248,6 +205,10 @@ class Logger { return _log_level; } + void set_log_stream(std::shared_ptr os) { + _log_stream = os; + } + /// switch on / off output bool set_do_output(bool val) { return _do_output = val; @@ -259,11 +220,7 @@ class Logger { /// initialize starting time void init_starting_time() { -#ifdef USE_GETTIMEOFDAY - gettimeofday(&_starttime, 0); -#else - _starttime = time(NULL); -#endif + _starttime = std::chrono::system_clock::now(); } /* methods for easy handling of output processes */