Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Logger update #359

Merged
merged 12 commits into from
Jan 7, 2025
16 changes: 11 additions & 5 deletions src/MarDyn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ int run_unit_tests(const Values &options, const std::vector<std::string> &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);
cniethammer marked this conversation as resolved.
Show resolved Hide resolved
#endif
Log::global_log = std::make_unique<Log::Logger>(Log::Info);

// Open scope to exclude MPI_Init() and MPI_Finalize().
// This way, all simulation objects are cleaned up before MPI finalizes.
Expand All @@ -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::Logger>(Log::Info, logfileNamePrefix);
} else {
// Print to stream (default: std::cout)
Log::global_log = std::make_unique<Log::Logger>(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<std::ostream> logfile_ptr = std::make_shared<std::ofstream>(logfile_name);
Log::global_log->set_log_stream(logfile_ptr);
}

#ifdef ENABLE_MPI
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/VectorizationTuner.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ enum MoleculeCntIncreaseTypeEnum{
both //!< both, do linear and exponential measurements, linear measurements will stop after 32 molecules.
};


#include <vector>
#include <fstream>
#include <string>
#include <vector>

#include "particleContainer/adapter/CellProcessor.h"
#include "particleContainer/adapter/FlopCounter.h"
Expand Down
33 changes: 3 additions & 30 deletions src/utils/Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,22 @@

#include "Logger.h"

#include <memory>

namespace Log {

std::unique_ptr<Logger> 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<std::ostream> os) :
cniethammer marked this conversation as resolved.
Show resolved Hide resolved
_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<std::ofstream>(_filename.c_str());
*_log_stream << std::boolalpha; // Print boolean as true/false
}

Expand Down
93 changes: 25 additions & 68 deletions src/utils/Logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,15 @@

#define USE_GETTIMEOFDAY

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <chrono>
#include <ctime>
#include <cctype>
#include <iomanip>
#include <iostream>
#include <map>
#include <ctime>
#include <string>
#include <sstream>
#include <chrono>
#include <memory>

#ifdef USE_GETTIMEOFDAY
#include <sys/time.h>
#endif
#include <string>
#include <utility>

#ifdef ENABLE_MPI
#include <mpi.h>
Expand Down Expand Up @@ -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;
Expand All @@ -96,15 +84,10 @@ class Logger {
logLevel _log_level;
logLevel _msg_log_level;
bool _do_output;
std::string _filename;
std::shared_ptr<std::ostream> _log_stream;
std::map<logLevel, std::string> 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
Expand All @@ -118,32 +101,16 @@ class Logger {
logLevelNames.insert(std::pair<logLevel, std::string>(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<std::ostream> os = std::shared_ptr<std::ostream>(&std::cout, [](void*){ /* no-op */}));

~Logger() = default;

Expand Down Expand Up @@ -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<double>(time_since_start).count() << " ";

*_log_stream << "[" << _rank << "]\t";
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -248,6 +205,10 @@ class Logger {
return _log_level;
}

void set_log_stream(std::shared_ptr<std::ostream> os) {
_log_stream = os;
}

/// switch on / off output
bool set_do_output(bool val) {
return _do_output = val;
Expand All @@ -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 */
Expand Down
Loading