|
1 | 1 | #ifndef LOGGING_H |
2 | 2 | #define LOGGING_H |
3 | 3 |
|
4 | | -#include <cstdio> |
| 4 | +#include <iostream> |
| 5 | +#include <sstream> |
5 | 6 | #include <cstdarg> |
| 7 | +#include <memory> |
6 | 8 |
|
7 | | -namespace gpu { |
| 9 | +namespace gpu |
| 10 | +{ |
| 11 | + enum LogLevel |
| 12 | + { |
| 13 | + kNone = 0, |
| 14 | + kError = 1, |
| 15 | + kWarn = 2, |
| 16 | + kInfo = 3, |
| 17 | + kTrace = 4 |
| 18 | + }; |
8 | 19 |
|
9 | | -enum LogLevel { kError = 0, kWarn = 1, kInfo = 2, kTrace = 3 }; |
| 20 | + static const char *kLevelStr[] = {"none", "error", "warn", "info", "trace"}; |
10 | 21 |
|
11 | | -static const char *kLevelStr[] = {"error", "warn", "info", "trace"}; |
| 22 | + /** |
| 23 | + * @brief Logger struct for logging messages. |
| 24 | + * stream: The stream to log to. |
| 25 | + * level: The log level to log messages at. |
| 26 | + */ |
| 27 | + struct Logger |
| 28 | + { |
| 29 | + std::ostream &stream; |
| 30 | + int level; |
| 31 | + }; |
12 | 32 |
|
13 | | -/** |
14 | | - * @brief Logger struct for logging messages. |
15 | | - * stream: The stream to log to. |
16 | | - * buffer: A buffer to store the formatted message. |
17 | | - * level: The log level to log messages at. |
18 | | - */ |
19 | | -struct Logger { |
20 | | - FILE *stream; |
21 | | - char buffer[32768]; // TODO(avh): Expand as needed or fail gracefully. |
22 | | - int level; |
23 | | -}; |
| 33 | + template <typename T> |
| 34 | + inline std::string toString(const T &value) |
| 35 | + { |
| 36 | + std::ostringstream oss; |
| 37 | + oss << value; |
| 38 | + return oss.str(); |
| 39 | + } |
24 | 40 |
|
25 | | -#ifndef NDEBUG |
26 | 41 | /** |
27 | | - * @brief Log a message to the logger. If NDEBUG is defined in a source or as a |
| 42 | + * @brief Log a message to the logger. If NO_LOG is defined in a source or as a |
28 | 43 | * compiler flag, this is a no-op. |
29 | 44 | * |
30 | 45 | * @param logger The logger to log to. |
31 | 46 | * @param level The log level of the message. |
32 | 47 | * @param message The message to log. |
33 | 48 | */ |
34 | | -inline void LOG(Logger& logger, int level, const char *message, ...) { |
35 | | - static const char *orange = "\033[0;33m"; |
36 | | - static const char *red = "\033[0;31m"; |
37 | | - static const char *white = "\033[0;37m"; |
38 | | - static const char *gray = "\033[0;90m"; |
39 | | - static const char *reset = "\033[0m"; |
40 | | - static const char *logColors[] = {red, red, orange, gray}; |
41 | | - if (level <= logger.level) { |
42 | | - va_list(args); |
43 | | - va_start(args, message); |
44 | | - snprintf(logger.buffer, sizeof(logger.buffer), message, args); |
45 | | - // Brackets and messages are white. |
46 | | - // Log levels are red for error and warning, orange for info, and grey for trace. |
47 | | - // Then the color is reset. |
48 | | - fprintf(logger.stream, "%s[%s%s%s] ", white, logColors[level], kLevelStr[level], |
49 | | - white); |
50 | | - vfprintf(logger.stream, message, args); |
51 | | - fprintf(logger.stream, "%s\n", reset); |
52 | | - va_end(args); |
| 49 | +#ifndef NO_LOG |
| 50 | + template <typename... Args> |
| 51 | + inline void LOG(Logger &logger, int level, const char *message, ...) |
| 52 | + { |
| 53 | + static const char *orange = "\033[0;33m"; |
| 54 | + static const char *red = "\033[0;31m"; |
| 55 | + static const char *white = "\033[0;37m"; |
| 56 | + static const char *gray = "\033[0;90m"; |
| 57 | + static const char *reset = "\033[0m"; |
| 58 | + static const char *logColors[] = {red, red, orange, gray}; |
| 59 | + if (level <= logger.level) |
| 60 | + { |
| 61 | + va_list args; |
| 62 | + va_start(args, message); |
| 63 | + |
| 64 | + int size = vsnprintf(nullptr, 0, message, args) + 1; |
| 65 | + std::unique_ptr<char[]> buffer(new char[size]); |
| 66 | + |
| 67 | +#ifdef _WIN32 |
| 68 | + _vsnprintf_s(buffer.get(), size, _TRUNCATE, message, args); |
| 69 | +#else |
| 70 | + vsnprintf(buffer.get(), size, message, args); |
| 71 | +#endif |
| 72 | + |
| 73 | + // Brackets and messages are white. |
| 74 | + // Log levels are red for error and warning, orange for info, and grey for trace. |
| 75 | + // Then the color is reset. |
| 76 | + logger.stream << white << "[" << logColors[level] << kLevelStr[level] << white << "] "; |
| 77 | + logger.stream << buffer.get(); |
| 78 | + logger.stream << reset << std::endl; |
| 79 | + va_end(args); |
| 80 | + } |
53 | 81 | } |
54 | | -} |
55 | 82 | #else |
56 | | -#define LOG(logger, level, message, ...) ((void)0) |
| 83 | + template <typename... Args> |
| 84 | + inline void LOG(Logger &logger, int level, const char *message, Args... args) |
| 85 | + { |
| 86 | + (void)logger; |
| 87 | + (void)level; |
| 88 | + (void)message; |
| 89 | + (void)(std::initializer_list<int>{(static_cast<void>(args), 0)...}); |
| 90 | + } |
57 | 91 | #endif |
58 | 92 |
|
59 | | -/** |
60 | | - * @brief Default logger for logging messages to stdout at the info level. |
61 | | - * Output stream and logging level for the default logger can be globally |
62 | | - * changed on a per-program basis. |
63 | | - */ |
64 | | -static Logger kDefLog = {stdout, "", kInfo}; |
| 93 | + /** |
| 94 | + * @brief Default logger for logging messages to stdout at the info level. |
| 95 | + * Output stream and logging level for the default logger can be globally |
| 96 | + * changed on a per-program basis. |
| 97 | + */ |
| 98 | + static Logger kDefLog = {std::cout, kInfo}; |
65 | 99 |
|
66 | | -/** |
67 | | - * @brief Set the log level of the default logger. |
68 | | - * @param level The log level to set. |
69 | | - */ |
70 | | -void setLogLevel(int level) { |
71 | | - kDefLog.level = level; |
72 | | -} |
| 100 | + /** |
| 101 | + * @brief Set the log level of the default logger. |
| 102 | + * @param level The log level to set. |
| 103 | + */ |
| 104 | + static inline void setLogLevel(int level) |
| 105 | + { |
| 106 | + kDefLog.level = level; |
| 107 | + } |
73 | 108 |
|
74 | 109 | } // namespace gpu |
75 | 110 |
|
|
0 commit comments