GCC Code Coverage Report


Directory: ./
File: src/iguana/services/Logger.h
Date: 2025-01-05 09:03:17
Exec Total Coverage
Lines: 26 28 92.9%
Functions: 57 167 34.1%
Branches: 24 83 28.9%

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