lab-cosmo / librascal

A scalable and versatile library to generate representations for atomic-scale learning
https://lab-cosmo.github.io/librascal/
GNU Lesser General Public License v2.1
80 stars 20 forks source link

Implemement a small logging framework #245

Open Luthaf opened 4 years ago

Luthaf commented 4 years ago

Instead of using std::cout/std::cerr directly, we should implement a small logging framework like

#include "rascal/logging.hh"

rascal::info("starting computation");

auto foo = some_function_call();
rascal::debug("this value is now ", foo);

if (bad) {
    rascal::warning("your simulation is going to explode!");
}

This has the following benefits:

Luthaf commented 4 years ago

The API could look like this

#include <sstream>
#include <string>

namespace rascal {

/// Possible logging levels
enum class LogLevel { Debug, Info, Warn, Error };

/// Send a single log message at the given level
void log(LogLevel level, const std::string &message);

template <typename... Args> void debug(Args &&... args) {
  std::stringstream stream;
  operator<<(stream, args...);
  log(LogLevel::Debug, stream.str());
}

template <typename... Args> void info(Args &&... args) {
  std::stringstream stream;
  operator<<(stream, args...);
  log(LogLevel::Info, stream.str());
}

template <typename... Args> void warning(Args &&... args) {
  std::stringstream stream;
  operator<<(stream, args...);
  log(LogLevel::Warn, stream.str());
}

template <typename... Args> void error(Args &&... args) {
  std::stringstream stream;
  operator<<(stream, args...);
  log(LogLevel::Error, stream.str());
}

using logging_callback =
    std::function<void(LogLevel level, const std::string &message)>;

/// Send all logging messages to the given callback
void log_to(logging_callback callback);

} // namespace rascal

Here, the variadic templates allow to send warnings like rascal::warn("this value is now ", foo, " shoud be ", bar);, and rascal::log_to allows users to redirect logging messages.

felixmusil commented 4 years ago

the user can override where the logs are sent to (for example, jupyter notebook do not show the C++ stdout messages)

Not to diminish the value of such functionality but to do that in python you can use the ostream_redirect provided by pybind11 like:

with ostream_redirect():
   my_cpp_function_that_uses_cout_or_cerr()
Luthaf commented 4 years ago

Can we automatically do ostream_redirect for all calls to C++ functions, or does the user need to manually specify it for every function call?

mastricker commented 4 years ago

Just to chip in: I like the idea in general. Seems like a clean way to do this. Even add different levels of verbosity

But I also tend to agree with Felix - if we can redirect output, we can leave out one level of complexity?

I suggest we discuss this on Wednesday?

Luthaf commented 4 years ago

But I also tend to agree with Felix - if we can redirect output, we can leave out one level of complexity?

I don't know how ostream_redirect works. Can we use it to redirect output to a file? To a string? To LAMMPS logging facilities? Or does it only redirect to Python sys.stdout/sys.stderr?

mastricker commented 4 years ago

Yeah, that's what I mean - if we can. I put it in the meeting minutes.

max-veit commented 4 years ago

The real benefit of such a framework, in my view, isn't redirection (which is fairly easily done in Python) but rather logging levels, which I know I've had to implement from scratch for the gradient tester. I agree that it would be nice to simplify, centralize, and standardize this ad-hoc solution for the whole of the library.

mastricker commented 4 years ago

I do see a point, especially in logging levels. And I do not see an easy way to do that with the redirect. Let's discuss tomorrow.

felixmusil commented 4 years ago

Can we automatically do ostream_redirect for all calls to C++ functions, or does the user need to manually specify it for every function call?

ostream_redirect make the bridge between the c++ outputs with the python output so cout goes into sys.stdout and the same for cerr. Note that errors thrown in c++ are already displayed in python and without the need for ostream_redirect.