Hermes
logging.h
Go to the documentation of this file.
1 
32 #ifndef HERMES_LOG_LOGGING_H
33 #define HERMES_LOG_LOGGING_H
34 
35 #include <hermes/common/str.h>
39 #include <cstdarg>
40 #include <chrono>
41 #include <cstring>
42 
43 namespace hermes {
44 
47 enum class logging_options {
48  none = 0x00,
49  info = 0x01,
50  warn = 0x02,
51  error = 0x04,
52  critical = 0x08,
53  location = 0x10,
54  time = 0x10,
55  abbreviate = 0x20,
56  use_colors = 0x40,
57  full_path_location = 0x80,
58  callback_only = 0x100
59 };
60 
61 HERMES_ENABLE_BITMASK_OPERATORS(logging_options);
62 
64 class Log {
65 public:
67  struct Location {
68  const char *file_name;
69  int line;
70  const char *function_name;
71  };
72 
79  template<typename ...Ts>
80  HERMES_DEVICE_CALLABLE static inline void logMessage(logging_options message_options, const char *fmt,
81  Location location,
82  Ts &&...args) {
83 #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ > 0
84  printf(fmt);
85 #else
86  // merge options_
87  message_options = options_ | message_options;
88  bool use_colors = HERMES_MASK_BIT(message_options, logging_options::use_colors);
89  u8 color, label_color;
90  configFrom(message_options, color, label_color);
91  // label
92  Str s;
93  if (use_colors)
94  s += ConsoleColors::color(color);
95  s += label(message_options);
96  // location
97  if (HERMES_MASK_BIT(message_options, logging_options::location))
98  s += Str::format("[{}][{}][{}] ",
99  processPath(message_options, abbreviate(message_options, location.file_name)), location.line,
100  abbreviate(message_options, location.function_name));
101  // message
102  if (use_colors)
103  s += ConsoleColors::color(label_color);
104  s += Str::format(fmt, std::forward<Ts>(args)...);
105  if (use_colors)
107  if (log_callback)
108  log_callback(s, message_options);
109  if (HERMES_MASK_BIT(message_options, logging_options::callback_only))
110  return;
111  printf("%s\n", s.c_str());
112 #endif
113  }
119  template<typename ...Ts>
120  HERMES_DEVICE_CALLABLE static inline void logMessage(logging_options message_options, const char *fmt, Ts &&...args) {
121 #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ > 0
122  printf(fmt);
123 #else
124  // merge options_
125  message_options = options_ | message_options;
126  bool use_colors = HERMES_MASK_BIT(message_options, logging_options::use_colors);
127  u8 color, label_color;
128  configFrom(message_options, color, label_color);
129  // label
130  Str s;
131  if (use_colors)
132  s += ConsoleColors::color(color);
133  s += label(message_options);
134  // message
135  if (use_colors)
136  s += ConsoleColors::color(label_color);
137  s += Str::format(fmt, std::forward<Ts>(args)...);
138  if (use_colors)
140  if (log_callback)
141  log_callback(s, message_options);
142  if (HERMES_MASK_BIT(message_options, logging_options::callback_only))
143  return;
144  printf("%s\n", s.c_str());
145 #endif
146  }
151  template<typename ...Ts>
152  HERMES_DEVICE_CALLABLE static inline void info(const char *fmt, Ts &&...args) {
153 #if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ > 0))
154  printf(fmt, std::forward<Ts>(args)...);
155 #else
156  auto message_options = options_ | logging_options::info;
157  bool use_colors = HERMES_MASK_BIT(message_options, logging_options::use_colors);
158  Str s;
159  if (use_colors)
161  s += label(message_options);
162  if (use_colors)
164  s += Str::format(fmt, std::forward<Ts>(args)...);
165  if (use_colors)
167  if (info_callback)
168  info_callback(s);
169  else
170  printf("%s\n", s.c_str());
171 #endif
172  }
177  template<typename ...Ts>
178  HERMES_DEVICE_CALLABLE static inline void warn(const char *fmt, Ts &&...args) {
179 #if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ > 0))
180  printf(fmt, std::forward<Ts>(args)...);
181 #else
182  auto message_options = options_ | logging_options::warn;
183  bool use_colors = HERMES_MASK_BIT(message_options, logging_options::use_colors);
184  Str s;
185  if (use_colors)
187  s += label(message_options);
188  if (use_colors)
190  s += Str::format(fmt, std::forward<Ts>(args)...);
191  if (use_colors)
193  if (warn_callback)
194  warn_callback(s);
195  else
196  printf("%s\n", s.c_str());
197 #endif
198  }
203  template<typename ...Ts>
204  static HERMES_DEVICE_CALLABLE inline void error(const char *fmt, Ts &&...args) {
205 #if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ > 0))
206  printf(fmt, std::forward<Ts>(args)...);
207 #else
208  auto message_options = options_ | logging_options::error;
209  bool use_colors = HERMES_MASK_BIT(message_options, logging_options::use_colors);
210  Str s;
211  if (use_colors)
213  s += label(message_options);
214  if (use_colors)
216  s += Str::format(fmt, std::forward<Ts>(args)...);
217  if (use_colors)
219  if (error_callback)
220  error_callback(s);
221  else
222  printf("%s\n", s.c_str());
223 #endif
224  }
229  template<typename ...Ts>
230  HERMES_DEVICE_CALLABLE static inline void critical(const std::string &fmt, Ts &&...args) {
231 #if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ > 0))
232  printf("[%s][%d][%s] CRITICAL\n", std::forward<Ts>(args)...);
233 #else
234  auto message_options = options_ | logging_options::critical;
235  bool use_colors = HERMES_MASK_BIT(message_options, logging_options::use_colors);
236  Str s;
237  if (use_colors)
239  s += label(message_options);
240  if (use_colors)
242  s += Str::format(fmt, std::forward<Ts>(args)...);
243  if (use_colors)
245  if (critical_callback)
247  else
248  printf("%s\n", s.c_str());
249 #endif
250  }
253  static inline void addOptions(logging_options options_to_add) {
254  options_ = options_ | options_to_add;
255  }
258  static inline void removeOptions(logging_options options_to_remove) {
259  options_ = options_ & ~options_to_remove;
260  }
261 
262  static u8 info_color;
263  static u8 warn_color;
264  static u8 error_color;
266 
271 
272  static size_t abbreviation_size;
273 
274  static std::function<void(const Str &, logging_options)> log_callback;
275  static std::function<void(const Str &)> info_callback;
276  static std::function<void(const Str &)> warn_callback;
277  static std::function<void(const Str &)> error_callback;
278  static std::function<void(const Str &)> critical_callback;
279 
280 private:
281 
282  static inline Str label(const logging_options &message_options) {
283  const std::chrono::time_point<std::chrono::system_clock> now =
284  std::chrono::system_clock::now();
285  const std::time_t t_c = std::chrono::system_clock::to_time_t(now);
286  Str s;
287  s += std::put_time(std::localtime(&t_c), "[%F %T]");
288  if (HERMES_MASK_BIT(message_options, logging_options::info))
289  s += " [info] ";
290  else if (HERMES_MASK_BIT(message_options, logging_options::warn))
291  s += " [warn] ";
292  else if (HERMES_MASK_BIT(message_options, logging_options::error))
293  s += " [error] ";
294  else if (HERMES_MASK_BIT(message_options, logging_options::critical))
295  s += " [critical] ";
296  return s;
297  }
298 
299  static inline void configFrom(const logging_options &message_options,
300  u8 &label_color,
301  u8 &color) {
302  if (HERMES_MASK_BIT(message_options, logging_options::info)) {
303  color = info_color;
304  label_color = info_label_color;
305  } else if (HERMES_MASK_BIT(message_options, logging_options::warn)) {
306  color = warn_color;
307  label_color = warn_label_color;
308  } else if (HERMES_MASK_BIT(message_options, logging_options::error)) {
309  color = error_color;
310  label_color = error_label_color;
311  } else if (HERMES_MASK_BIT(message_options, logging_options::critical)) {
312  color = critical_color;
313  label_color = critical_label_color;
314  }
315  }
316 
317  static inline Str abbreviate(logging_options message_options, const char *str) {
318  Str s;
319  if (HERMES_MASK_BIT(message_options, logging_options::abbreviate)) {
320  size_t l = std::strlen(str);
321  if (l > abbreviation_size + 3) {
322  s += "...";
323  s += &str[l - abbreviation_size];
324  return s;
325  }
326  }
327  return s + str;
328  }
329 
330  static inline Str processPath(logging_options options, const hermes::Path &path) {
331  if (!HERMES_MASK_BIT(options, logging_options::full_path_location))
332  return path.name();
333  return path.fullName();
334  }
335 
336  static logging_options options_;
337 };
338 
339 }
340 
341 // *********************************************************************************************************************
342 // LOGGING
343 // *********************************************************************************************************************
344 #ifndef INFO_ENABLED
345 #define INFO_ENABLED
346 #endif
347 
348 #ifdef INFO_ENABLED
349 
350 #ifndef HERMES_PING
352 #define HERMES_PING hermes::Log::info("[{}][{}][{}]", __FILE__, __LINE__, __FUNCTION__);
353 #endif
354 
355 #ifndef HERMES_LOG
363 #define HERMES_LOG(FMT, ...) hermes::Log::logMessage(hermes::logging_options::info, FMT, \
364  hermes::Log::Location{__FILE__, __LINE__, __FUNCTION__} __VA_OPT__(,) __VA_ARGS__)
365 #endif
373 #ifndef HERMES_LOG_WARNING
374 #define HERMES_LOG_WARNING(FMT, ...) hermes::Log::logMessage(hermes::logging_options::warn, FMT, \
375  hermes::Log::Location{__FILE__, __LINE__, __FUNCTION__} __VA_OPT__(,) __VA_ARGS__)
376 #endif
384 #ifndef HERMES_LOG_ERROR
385 #define HERMES_LOG_ERROR(FMT, ...) hermes::Log::logMessage(hermes::logging_options::error, FMT, \
386  hermes::Log::Location{__FILE__, __LINE__, __FUNCTION__} __VA_OPT__(,) __VA_ARGS__)
387 #endif
395 #ifndef HERMES_LOG_CRITICAL
396 #define HERMES_LOG_CRITICAL(FMT, ...) hermes::Log::logMessage(hermes::logging_options::critical, FMT, \
397  hermes::Log::Location{__FILE__, __LINE__, __FUNCTION__} __VA_OPT__(,) __VA_ARGS__)
398 #endif
399 
400 #ifndef HERMES_LOG_VARIABLE
404 #define HERMES_LOG_VARIABLE(A) hermes::Log::logMessage(hermes::logging_options::info, "{} = {}", \
405  hermes::Log::Location{__FILE__, __LINE__, __FUNCTION__}, #A, A)
406 #endif
407 
408 #ifndef HERMES_LOG_ARRAY
412 #define HERMES_LOG_ARRAY(A) \
413  HERMES_LOG("values of \"{}\":", #A); \
414  for(const auto& hermes_log_array_element : A) \
415  HERMES_LOG(" {}", hermes_log_array_element)
416 #endif
421 template<typename T>
422 static inline void hermes_log_variables_r(std::stringstream &s, const T &first) {
423  s << first << "\n";
424 }
431 template<typename T, typename ...Args>
432 static inline void hermes_log_variables_r(std::stringstream &s, const T &first, Args &&...rest) {
433  s << first << " | ";
434  if constexpr(sizeof ...(rest) > 0)
435  hermes_log_variables_r(s, std::forward<Args>(rest) ...);
436 }
441 template<class... Args>
442 static inline std::string hermes_log_variables(Args &&... args) {
443  std::stringstream s;
444  if constexpr(sizeof...(args) > 0) {
445  hermes_log_variables_r(s, std::forward<Args>(args) ...);
446  return s.str();
447  }
448  return "";
449 }
450 
451 #ifndef HERMES_LOG_VARIABLES
455 #define HERMES_LOG_VARIABLES(...) \
456  hermes::Log::info("[{}][{}][{}]: {}", __FILE__, __LINE__, __FUNCTION__, hermes_log_variables(__VA_ARGS__))
457 #endif
458 
459 #ifndef HERMES_C_LOG
467 #define HERMES_C_LOG(FMT, ...) \
468 fprintf(stdout, "[%s][%d][%s]: ", __FILE__, __LINE__, __FUNCTION__); \
469 fprintf(stdout, FMT __VA_OPT__(,) __VA_ARGS__); \
470 fprintf(stdout, "\n")
471 #endif
472 #ifndef HERMES_C_LOG_ERROR
480 #define HERMES_C_LOG_ERROR(FMT, ...) \
481 fprintf(stderr, "[%s][%d][%s]: ", __FILE__, __LINE__, __FUNCTION__); \
482 fprintf(stderr, FMT __VA_OPT__(,) __VA_ARGS__); \
483 fprintf(stderr, "\n")
484 #endif
485 #ifndef HERMES_C_DEVICE_LOG
493 #define HERMES_C_DEVICE_LOG(FMT, ...) \
494 printf("[%s][%d][%s]: ", __FILE__, __LINE__, __FUNCTION__); \
495 printf(FMT __VA_OPT__(,) __VA_ARGS__); \
496 printf("\n")
497 #endif
498 #ifndef HERMES_C_DEVICE_ERROR
506 #define HERMES_C_DEVICE_ERROR(FMT, ...) \
507 printf("[%s][%d][%s]: ", __FILE__, __LINE__, __FUNCTION__); \
508 printf(FMT __VA_OPT__(,) __VA_ARGS__); \
509 printf("\n")
510 #endif
511 
512 #else
513 
514 #define HERMES_PING
515 #define HERMES_LOG
516 #define HERMES_LOG_VARIABLE
517 
518 #endif
519 
520 #endif //HERMES_LOG_LOGGING_H
521 
Support of bitwise operations for compatible enum classes.
#define HERMES_MASK_BIT(MASK, BIT)
Tests if enum class value is enabled.
Definition: bitmask_operators.h:84
#define HERMES_ENABLE_BITMASK_OPERATORS(x)
Adds bitwise operation support to a given enum class.
Definition: bitmask_operators.h:58
static std::string color(u8 color_number)
Get 88/256 color code.
Definition: console_colors.h:99
static char reset[5]
"\e[0m"
Definition: console_colors.h:53
Static class that manages logging messages.
Definition: logging.h:64
static u8 info_color
info stream messages color
Definition: logging.h:262
static void removeOptions(logging_options options_to_remove)
Disables logging options.
Definition: logging.h:258
static HERMES_DEVICE_CALLABLE void critical(const std::string &fmt, Ts &&...args)
Logs into critical stream.
Definition: logging.h:230
static HERMES_DEVICE_CALLABLE void warn(const char *fmt, Ts &&...args)
Logs into warn stream.
Definition: logging.h:178
static std::function< void(const Str &)> info_callback
info stream redirection callback
Definition: logging.h:275
static size_t abbreviation_size
size after abbreviation (in characters)
Definition: logging.h:272
static u8 critical_color
critical stream messages color
Definition: logging.h:265
static u8 critical_label_color
critical stream label color
Definition: logging.h:270
static HERMES_DEVICE_CALLABLE void logMessage(logging_options message_options, const char *fmt, Location location, Ts &&...args)
Logs a formatted message with code location information.
Definition: logging.h:80
static u8 warn_label_color
warn stream label color
Definition: logging.h:268
static u8 warn_color
warn stream messages color
Definition: logging.h:263
static HERMES_DEVICE_CALLABLE void error(const char *fmt, Ts &&...args)
Logs into error stream.
Definition: logging.h:204
static HERMES_DEVICE_CALLABLE void logMessage(logging_options message_options, const char *fmt, Ts &&...args)
Logs a formatted message.
Definition: logging.h:120
static u8 error_label_color
error stream label color
Definition: logging.h:269
static u8 info_label_color
info stream label color
Definition: logging.h:267
static std::function< void(const Str &)> critical_callback
critical stream redirection callback
Definition: logging.h:278
static u8 error_color
error stream messages color
Definition: logging.h:264
static HERMES_DEVICE_CALLABLE void info(const char *fmt, Ts &&...args)
Logs into info stream.
Definition: logging.h:152
static std::function< void(const Str &)> warn_callback
warn stream redirection callback
Definition: logging.h:276
static std::function< void(const Str &, logging_options)> log_callback
redirection callback
Definition: logging.h:274
static std::function< void(const Str &)> error_callback
error stream redirection callback
Definition: logging.h:277
static void addOptions(logging_options options_to_add)
Enables logging options.
Definition: logging.h:253
Representation of a directory/file in the filesystem.
Definition: file_system.h:48
const std::string & fullName() const
Gets this full path string.
Definition: file_system.cpp:143
std::string name() const
Gets last folder/file name.
Definition: file_system.cpp:139
String class and set of string functions.
Definition: str.h:53
const char * c_str() const
Get const char* pointer.
Definition: str.h:384
static std::string format(const std::string &fmt, Ts &&... args)
Definition: str.h:170
Set of 256-terminal supported color codes.
Filesystem utils.
@ none
default behaviour
#define HERMES_DEVICE_CALLABLE
Specifies that the function can be called from both host and device sides.
Definition: defs.h:45
uint8_t u8
8 bit size unsigned integer type
Definition: defs.h:86
logging_options
Options for logging output.
Definition: logging.h:47
@ callback_only
redirect output to callback only
@ time
logs message time point
@ warn
logs into warning stream
@ full_path_location
output full path locations
@ critical
logs into critical stream
@ abbreviate
abbreviate long paths
@ info
logs into info stream
@ error
logs into error stream
@ location
logs code location
@ use_colors
output colored messages
String utils.
Holds information about log code location.
Definition: logging.h:67
int line
file line number
Definition: logging.h:69
const char * function_name
scope name
Definition: logging.h:70
const char * file_name
file path
Definition: logging.h:68