logger.hpp
1 
5 #pragma once
6 
7 #include <array>
8 #include <cstdint>
9 #include <iostream>
10 #include <memory>
11 #include <mutex>
12 #include <sstream>
13 #include <string>
14 #include <thread>
15 #include <unordered_map>
16 #include <utility>
17 
18 #include <rapidsmpf/config.hpp>
19 #include <rapidsmpf/utils/misc.hpp>
20 
21 namespace rapidsmpf {
22 
37 class Logger : public std::enable_shared_from_this<Logger> {
38  public:
44  enum class LOG_LEVEL : std::uint32_t {
45  NONE = 0,
46  PRINT,
47  WARN,
48  INFO,
49  DEBUG,
50  TRACE
51  };
52 
56  static constexpr std::array<char const*, 6> LOG_LEVEL_NAMES{
57  "NONE", "PRINT", "WARN", "INFO", "DEBUG", "TRACE"
58  };
59 
66  static constexpr char const* level_name(LOG_LEVEL level) {
67  auto index = static_cast<std::size_t>(level);
68  return index < LOG_LEVEL_NAMES.size() ? LOG_LEVEL_NAMES[index] : "UNKNOWN";
69  }
70 
78  [[nodiscard]] static std::shared_ptr<Logger> create(
79  LOG_LEVEL level = LOG_LEVEL::WARN, std::string name = "unknown"
80  );
81 
102  [[nodiscard]] static std::shared_ptr<Logger> from_options(config::Options options);
103 
104  virtual ~Logger() noexcept = default;
105 
106  // `Logger` is owned exclusively through `std::shared_ptr`. Use `create()`
107  // to construct instances.
108  Logger(Logger const&) = delete;
109  Logger& operator=(Logger const&) = delete;
110  Logger(Logger&&) = delete;
111  Logger& operator=(Logger&&) = delete;
112 
119  return level_;
120  }
121 
131  void set_name(std::string name);
132 
142  template <typename... Args>
143  void log(LOG_LEVEL level, Args const&... args) {
144  if (static_cast<std::uint32_t>(level_) < static_cast<std::uint32_t>(level)) {
145  return;
146  }
147  std::ostringstream ss;
148  (ss << ... << args);
149  do_log(level, std::move(ss));
150  }
151 
158  template <typename... Args>
159  void print(Args const&... args) {
160  log(LOG_LEVEL::PRINT, std::forward<Args const&>(args)...);
161  }
162 
169  template <typename... Args>
170  void warn(Args const&... args) {
171  log(LOG_LEVEL::WARN, std::forward<Args const&>(args)...);
172  }
173 
180  template <typename... Args>
181  void info(Args const&... args) {
182  log(LOG_LEVEL::INFO, std::forward<Args const&>(args)...);
183  }
184 
191  template <typename... Args>
192  void debug(Args const&... args) {
193  log(LOG_LEVEL::DEBUG, std::forward<Args const&>(args)...);
194  }
195 
202  template <typename... Args>
203  void trace(Args const&... args) {
204  log(LOG_LEVEL::TRACE, std::forward<Args const&>(args)...);
205  }
206 
207  protected:
213  Logger(LOG_LEVEL level, std::string name);
214 
220  virtual std::uint32_t get_thread_id() {
221  auto const tid = std::this_thread::get_id();
222 
223  // To avoid large IDs, we map the thread ID to an unique counter.
224  auto const [name, inserted] =
225  thread_id_names.insert({tid, thread_id_names_counter});
226  if (inserted) {
227  ++thread_id_names_counter;
228  }
229  return name->second;
230  }
231 
243  virtual void do_log(LOG_LEVEL level, std::ostringstream&& ss) {
244  std::lock_guard<std::mutex> lock(mutex_);
245  std::ostringstream full_log_msg;
246  full_log_msg << "[" << name_ << ":" << level_name(level) << ":" << get_thread_id()
247  << ":" << Clock::now() << "] " << ss.str();
248  std::cout << full_log_msg.str() << std::endl;
249  }
250 
251  private:
252  std::mutex mutex_;
253  LOG_LEVEL const level_;
254  std::string name_;
255 
258  std::uint32_t thread_id_names_counter{0};
259 
261  std::unordered_map<std::thread::id, std::uint32_t> thread_id_names;
262 };
263 
264 } // namespace rapidsmpf
A logger base class for handling different levels of log messages.
Definition: logger.hpp:37
void set_name(std::string name)
Update the name used in log message prefixes.
void warn(Args const &... args)
Logs a warning message.
Definition: logger.hpp:170
virtual void do_log(LOG_LEVEL level, std::ostringstream &&ss)
Handles the logging of a messages.
Definition: logger.hpp:243
void trace(Args const &... args)
Logs a trace message.
Definition: logger.hpp:203
static std::shared_ptr< Logger > create(LOG_LEVEL level=LOG_LEVEL::WARN, std::string name="unknown")
Create a logger.
void info(Args const &... args)
Logs an informational message.
Definition: logger.hpp:181
LOG_LEVEL
Log verbosity levels.
Definition: logger.hpp:44
@ WARN
Warning messages.
@ INFO
Informational messages.
@ PRINT
General print messages.
static std::shared_ptr< Logger > from_options(config::Options options)
Create a logger from configuration options.
void print(Args const &... args)
Logs a print message.
Definition: logger.hpp:159
Logger(LOG_LEVEL level, std::string name)
Constructs a logger.
void debug(Args const &... args)
Logs a debug message.
Definition: logger.hpp:192
virtual std::uint32_t get_thread_id()
Returns a unique thread ID for the current thread.
Definition: logger.hpp:220
static constexpr char const * level_name(LOG_LEVEL level)
Get the string name of a log level.
Definition: logger.hpp:66
void log(LOG_LEVEL level, Args const &... args)
Logs a message using the specified verbosity level.
Definition: logger.hpp:143
static constexpr std::array< char const *, 6 > LOG_LEVEL_NAMES
Log level names corresponding to the LOG_LEVEL enum.
Definition: logger.hpp:56
LOG_LEVEL verbosity_level() const
Get the verbosity level of the logger.
Definition: logger.hpp:118
Manages configuration options for RapidsMPF operations.
Definition: config.hpp:144
RAPIDS Multi-Processor interfaces.
Definition: backend.hpp:14