Line | Branch | Exec | Source |
---|---|---|---|
1 | #pragma once | ||
2 | |||
3 | // workaround https://github.com/fmtlib/fmt/issues/4133 | ||
4 | #ifdef __clang__ | ||
5 | #pragma clang diagnostic push | ||
6 | #pragma clang diagnostic ignored "-Wshift-overflow" | ||
7 | #else | ||
8 | #pragma GCC diagnostic push | ||
9 | #pragma GCC diagnostic ignored "-Wstringop-overflow" | ||
10 | #endif | ||
11 | #include <fmt/color.h> | ||
12 | #include <fmt/format.h> | ||
13 | #include <fmt/ranges.h> | ||
14 | #ifdef __clang__ | ||
15 | #pragma clang diagnostic pop | ||
16 | #else | ||
17 | #pragma GCC diagnostic pop | ||
18 | #endif | ||
19 | |||
20 | #include <functional> | ||
21 | #include <unordered_map> | ||
22 | |||
23 | namespace iguana { | ||
24 | |||
25 | /// @brief Simple logger service | ||
26 | /// | ||
27 | /// - Each algorithm instance should own a `Logger` instance | ||
28 | /// - The user may control the log level of each `Logger`, thus the log level of each algorithm | ||
29 | /// - Errors and warnings print to `stderr`, whereas all other levels print to `stdout` | ||
30 | class Logger | ||
31 | { | ||
32 | |||
33 | friend class Object; | ||
34 | |||
35 | public: | ||
36 | |||
37 | /// These are the available log levels, from lowest to highest: | ||
38 | /// - `trace`: the most verbose level, used for fine-grained printouts for each event | ||
39 | /// - `debug`: less verbose printout, expected to be less frequent than `trace` | ||
40 | /// - `info`: the least verbose printout; this is the default level | ||
41 | /// - `quiet`: use this level to only allow warnings and errors, silencing all other printouts | ||
42 | /// - `warn`: an issue that may or may not be critical | ||
43 | /// - `error`: an issue that is likely critical | ||
44 | /// - `silent`: use this level to silence **all** printouts (use it at your own risk!) | ||
45 | enum Level { | ||
46 | trace, | ||
47 | debug, | ||
48 | info, | ||
49 | quiet, | ||
50 | warn, | ||
51 | error, | ||
52 | silent | ||
53 | }; | ||
54 | |||
55 | /// The default log level | ||
56 | static Level const DEFAULT_LEVEL = info; | ||
57 | |||
58 | /// @param name the name of this logger instance, which will be include in all of its printouts | ||
59 | /// @param lev the log level | ||
60 | /// @param enable_style if true, certain printouts will be styled with color and emphasis | ||
61 | Logger(std::string_view name = "log", Level const lev = DEFAULT_LEVEL, bool const enable_style = true); | ||
62 | 189 | ~Logger() {} | |
63 | |||
64 | /// Set the log level to this level. Log messages with a lower level will not be printed. | ||
65 | /// @see `Logger::Level` for available levels. | ||
66 | /// @param lev the log level name | ||
67 | void SetLevel(std::string_view lev); | ||
68 | |||
69 | /// Set the log level to this level. Log messages with a lower level will not be printed. | ||
70 | /// @see `Logger::Level` for available levels. | ||
71 | /// @param lev the log level | ||
72 | void SetLevel(Level const lev); | ||
73 | |||
74 | /// Get the current log level | ||
75 | /// @returns the log level | ||
76 | Level GetLevel(); | ||
77 | |||
78 | /// Enable styled log printouts, with color and emphasis | ||
79 | void EnableStyle(); | ||
80 | |||
81 | /// Disable styled log printout color and emphasis | ||
82 | void DisableStyle(); | ||
83 | |||
84 | /// Generate a header for a printout | ||
85 | /// @param message the header message | ||
86 | /// @param width the width of the header in number of characters | ||
87 | /// @returns the header string | ||
88 | static std::string Header(std::string_view message, int const width = 50); | ||
89 | |||
90 | /// Printout a log message at the `trace` level @see `Logger::Print` for more details | ||
91 | template <typename... VALUES> | ||
92 |
2/4✓ Branch 0 taken 16570 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1665 times.
✗ Branch 3 not taken.
|
43680 | void Trace(std::string_view message, const VALUES... vals) const { Print(trace, message, vals...); } |
93 | /// Printout a log message at the `debug` level @see `Logger::Print` for more details | ||
94 | template <typename... VALUES> | ||
95 |
1/2✓ Branch 0 taken 385 times.
✗ Branch 1 not taken.
|
69677 | void Debug(std::string_view message, const VALUES... vals) const { Print(debug, message, vals...); } |
96 | /// Printout a log message at the `info` level @see `Logger::Print` for more details | ||
97 | template <typename... VALUES> | ||
98 |
4/20✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
14 | void Info(std::string_view message, const VALUES... vals) const { Print(info, message, vals...); } |
99 | /// Printout a log message at the `warn` level @see `Logger::Print` for more details | ||
100 | template <typename... VALUES> | ||
101 |
1/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
14 | void Warn(std::string_view message, const VALUES... vals) const { Print(warn, message, vals...); } |
102 | /// Printout a log message at the `error` level @see `Logger::Print` for more details | ||
103 | template <typename... VALUES> | ||
104 |
2/28✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
|
26 | void Error(std::string_view message, const VALUES... vals) const { Print(error, message, vals...); } |
105 | |||
106 | /// Printout a log message at the specified level. The message will only print if `lev` is at least as high as the current level of | ||
107 | /// this `Logger` instance, as set by `Logger::SetLevel`. | ||
108 | /// @param lev the log level for this message | ||
109 | /// @param message the message to print; this may be a format string, as in `fmt::format` | ||
110 | /// @param vals values for the format string `message` | ||
111 | template <typename... VALUES> | ||
112 | 96622 | void Print(Level const lev, std::string_view message, const VALUES... vals) const | |
113 | { | ||
114 |
2/2✓ Branch 0 taken 931 times.
✓ Branch 1 taken 95691 times.
|
96622 | if(lev >= m_level) { |
115 |
1/2✓ Branch 0 taken 931 times.
✗ Branch 1 not taken.
|
931 | if(auto it{m_level_names.find(lev)}; it != m_level_names.end()) { |
116 | std::function<std::string(std::string)> style = [](std::string s) | ||
117 | 18 | { return fmt::format("[{}]", s); }; | |
118 |
2/2✓ Branch 0 taken 922 times.
✓ Branch 1 taken 9 times.
|
931 | if(m_enable_style) { |
119 |
3/3✓ Branch 0 taken 7 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 888 times.
|
922 | switch(lev) { |
120 | 7 | case warn: | |
121 | 21 | style = [](std::string s) | |
122 | 14 | { return fmt::format("[{}]", fmt::styled(s, fmt::emphasis::bold | fmt::fg(fmt::terminal_color::magenta))); }; | |
123 | 7 | break; | |
124 | 27 | case error: | |
125 | 81 | style = [](std::string s) | |
126 | 54 | { return fmt::format("[{}]", fmt::styled(s, fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red))); }; | |
127 | 27 | break; | |
128 | 888 | default: | |
129 | 2664 | style = [](std::string s) | |
130 | 1776 | { return fmt::format("[{}]", fmt::styled(s, fmt::emphasis::bold)); }; | |
131 | } | ||
132 | } | ||
133 |
3/4✓ Branch 0 taken 36 times.
✓ Branch 1 taken 895 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
|
1818 | fmt::print( |
134 | lev >= warn ? stderr : stdout, | ||
135 |
3/6✓ Branch 0 taken 931 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 929 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
3724 | fmt::runtime(fmt::format("{} {} {}\n", style(it->second), style(m_name), message)), |
136 | vals...); | ||
137 | } | ||
138 | else { | ||
139 | ✗ | Warn("Logger::Print called with unknown log level '{}'; printing as error instead", static_cast<int>(lev)); // FIXME: static_cast -> fmt::underlying, but needs new version of fmt | |
140 | ✗ | Error(message, vals...); | |
141 | } | ||
142 | } | ||
143 | 96620 | } | |
144 | |||
145 | private: | ||
146 | |||
147 | /// The name of this logger, which is included in all printouts | ||
148 | std::string m_name; | ||
149 | |||
150 | /// The current log level for this instance | ||
151 | Level m_level; | ||
152 | |||
153 | /// Association of the log level to its name | ||
154 | std::unordered_map<Level, std::string> m_level_names; | ||
155 | |||
156 | /// If true, style the printouts | ||
157 | bool m_enable_style; | ||
158 | }; | ||
159 | } | ||
160 |