GCC Code Coverage Report


Directory: ./
File: src/iguana/services/Logger.h
Date: 2025-06-06 22:09:53
Exec Total Coverage
Lines: 26 28 92.9%
Functions: 57 168 33.9%
Branches: 39 123 31.7%

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