@@ -39,93 +39,178 @@ namespace NUClear {
3939 * Log levels are used to provide different levels of detail on a per-reactor basis.
4040 * The logging level of a reactor can be changed by setting it in the install function.
4141 */
42- enum LogLevel : uint8_t {
43- /* *
44- * Don't use this log level when emitting logs, it is for setting reactor log level from non reactor sources.
45- *
46- * Specifically when a NUClear::log is called from code that is not running in a reaction (even transitively) then
47- * the reactor_level will be set to UNKNOWN.
48- */
49- UNKNOWN,
42+ class LogLevel {
43+ public:
44+ enum Value : uint8_t {
45+ /* *
46+ * Don't use this log level when emitting logs, it is for setting reactor log level from non reactor sources.
47+ *
48+ * Specifically when a NUClear::log is called from code that is not running in a reaction (even transitively)
49+ * then the reactor_level will be set to UNKNOWN.
50+ */
51+ UNKNOWN,
52+
53+ /* *
54+ * The Trace level contains messages that are used to trace the exact flow of execution.
55+ *
56+ * This level is extremely verbose and often has a message per line of code.
57+ */
58+ TRACE,
59+
60+ /* *
61+ * Debug contains messages that represent the inputs and outputs of different computation units.
62+ *
63+ * If you have a function that performs three steps to do something then it's likely that you will have a
64+ * message for the input and output of those three steps. Additionally you would likely have messages that check
65+ * if it hit different branches.
66+ */
67+ DEBUG,
68+
69+ /* *
70+ * The info level is used to provide high level goal messages such as function start or successful completion.
71+ *
72+ * This shows when key user-facing functionality is executed and tells us that everything is working without
73+ * getting into the details.
74+ */
75+ INFO,
76+
77+ /* *
78+ * The warning level is used to notify us that everything might not be working perfectly.
79+ *
80+ * Warnings are errors or inconsistencies that aren't fatal and generally do not completely break the system.
81+ * However a warning message should require action and should point to a section of the system that needs
82+ * attention.
83+ */
84+ WARN,
85+
86+ /* *
87+ * The error level is used to report unexpected behavior.
88+
89+ * This level doesn't need to prefix a program-crashing issue but should be used to report major unexpected
90+ branches
91+ * in logic or other constraint breaking problems such as failed assertions.
92+ * All errors should require action from someone and should be addressed immediately.
93+ */
94+ ERROR,
95+
96+ /* *
97+ * Fatal is a program destroying error that needs to be addressed immediately.
98+ *
99+ * If a fatal message is sent it should point to something that should never ever happen and ideally provide as
100+ * much information as possible as to why it crashed. Fatal messages require action immediately and should
101+ * always be addressed.
102+ */
103+ FATAL
104+ };
50105
51106 /* *
52- * The Trace level contains messages that are used to trace the exact flow of execution.
107+ * Construct a LogLevel from a Value
53108 *
54- * This level is extremely verbose and often has a message per line of code.
109+ * @param value The value to construct the LogLevel from
55110 */
56- TRACE,
111+ constexpr LogLevel ( const Value& value = Value::UNKNOWN) : value(value) {};
57112
58113 /* *
59- * Debug contains messages that represent the inputs and outputs of different computation units.
114+ * Construct a LogLevel from a string
60115 *
61- * If you have a function that performs three steps to do something then it's likely that you will have a message
62- * for the input and output of those three steps.
63- * Additionally you would likely have messages that check if it hit different branches.
116+ * @param level The string to construct the LogLevel from
64117 */
65- DEBUG,
118+ LogLevel (const std::string& level)
119+ : value(level == " TRACE" ? LogLevel::TRACE
120+ : level == " DEBUG" ? LogLevel::DEBUG
121+ : level == " INFO" ? LogLevel::INFO
122+ : level == " WARN" ? LogLevel::WARN
123+ : level == " ERROR" ? LogLevel::ERROR
124+ : level == " FATAL" ? LogLevel::FATAL
125+ : LogLevel::UNKNOWN) {};
66126
67127 /* *
68- * The info level is used to provide high level goal messages such as function start or successful completion.
128+ * A call operator which will return the value of the LogLevel
129+ * This can be useful in situations where the implicit conversion operators are ambiguous.
69130 *
70- * This shows when key user-facing functionality is executed and tells us that everything is working without getting
71- * into the details.
131+ * @return The value of the LogLevel
72132 */
73- INFO,
133+ constexpr Value operator ()() const {
134+ return value;
135+ }
74136
75137 /* *
76- * The warning level is used to notify us that everything might not be working perfectly.
138+ * A conversion operator which will return the value of the LogLevel
77139 *
78- * Warnings are errors or inconsistencies that aren't fatal and generally do not completely break the system.
79- * However a warning message should require action and should point to a section of the system that needs attention.
140+ * @return The value of the LogLevel
80141 */
81- WARN,
142+ constexpr operator Value () const {
143+ return value;
144+ }
82145
83146 /* *
84- * The error level is used to report unexpected behavior.
85-
86- * This level doesn't need to prefix a program-crashing issue but should be used to report major unexpected branches
87- * in logic or other constraint breaking problems such as failed assertions.
88- * All errors should require action from someone and should be addressed immediately.
147+ * A conversion operator which will return the string representation of the LogLevel
148+ *
149+ * @return The string representation of the LogLevel
89150 */
90- ERROR,
151+ operator std::string () const {
152+ return value == LogLevel::TRACE ? " TRACE"
153+ : value == LogLevel::DEBUG ? " DEBUG"
154+ : value == LogLevel::INFO ? " INFO"
155+ : value == LogLevel::WARN ? " WARN"
156+ : value == LogLevel::ERROR ? " ERROR"
157+ : value == LogLevel::FATAL ? " FATAL"
158+ : " UNKNOWN" ;
159+ }
91160
92161 /* *
93- * Fatal is a program destroying error that needs to be addressed immediately.
162+ * Stream the LogLevel to an ostream, it will output the string representation of the LogLevel
163+ *
164+ * @param os The ostream to output to
165+ * @param level The LogLevel to output
94166 *
95- * If a fatal message is sent it should point to something that should never ever happen and ideally provide as much
96- * information as possible as to why it crashed.
97- * Fatal messages require action immediately and should always be addressed.
167+ * @return The ostream that was passed in
98168 */
99- FATAL
169+ friend std::ostream& operator <<(std::ostream& os, LogLevel level) {
170+ return os << static_cast <std::string>(level);
171+ }
172+
173+ // Operators to compare LogLevel values and LogLevel to Value
174+ // clang-format off
175+ friend constexpr bool operator <(const LogLevel& lhs, const LogLevel& rhs) { return lhs.value < rhs.value ; }
176+ friend constexpr bool operator >(const LogLevel& lhs, const LogLevel& rhs) { return lhs.value > rhs.value ; }
177+ friend constexpr bool operator <=(const LogLevel& lhs, const LogLevel& rhs) { return lhs.value <= rhs.value ; }
178+ friend constexpr bool operator >=(const LogLevel& lhs, const LogLevel& rhs) { return lhs.value >= rhs.value ; }
179+ friend constexpr bool operator ==(const LogLevel& lhs, const LogLevel& rhs) { return lhs.value == rhs.value ; }
180+ friend constexpr bool operator !=(const LogLevel& lhs, const LogLevel& rhs) { return lhs.value != rhs.value ; }
181+
182+ friend constexpr bool operator <(const LogLevel& lhs, const Value& rhs) { return lhs.value < rhs; }
183+ friend constexpr bool operator >(const LogLevel& lhs, const Value& rhs) { return lhs.value > rhs; }
184+ friend constexpr bool operator <=(const LogLevel& lhs, const Value& rhs) { return lhs.value <= rhs; }
185+ friend constexpr bool operator >=(const LogLevel& lhs, const Value& rhs) { return lhs.value >= rhs; }
186+ friend constexpr bool operator ==(const LogLevel& lhs, const Value& rhs) { return lhs.value == rhs; }
187+ friend constexpr bool operator !=(const LogLevel& lhs, const Value& rhs) { return lhs.value != rhs; }
188+ friend constexpr bool operator <(const Value& lhs, const LogLevel& rhs) { return lhs < rhs.value ; }
189+ friend constexpr bool operator >(const Value& lhs, const LogLevel& rhs) { return lhs > rhs.value ; }
190+ friend constexpr bool operator <=(const Value& lhs, const LogLevel& rhs) { return lhs <= rhs.value ; }
191+ friend constexpr bool operator >=(const Value& lhs, const LogLevel& rhs) { return lhs >= rhs.value ; }
192+ friend constexpr bool operator ==(const Value& lhs, const LogLevel& rhs) { return lhs == rhs.value ; }
193+ friend constexpr bool operator !=(const Value& lhs, const LogLevel& rhs) { return lhs != rhs.value ; }
194+
195+ friend bool operator <(const LogLevel& lhs, const std::string& rhs) { return static_cast <std::string>(lhs) < rhs; }
196+ friend bool operator >(const LogLevel& lhs, const std::string& rhs) { return static_cast <std::string>(lhs) > rhs; }
197+ friend bool operator <=(const LogLevel& lhs, const std::string& rhs) { return static_cast <std::string>(lhs) <= rhs; }
198+ friend bool operator >=(const LogLevel& lhs, const std::string& rhs) { return static_cast <std::string>(lhs) >= rhs; }
199+ friend bool operator ==(const LogLevel& lhs, const std::string& rhs) { return static_cast <std::string>(lhs) == rhs; }
200+ friend bool operator !=(const LogLevel& lhs, const std::string& rhs) { return static_cast <std::string>(lhs) != rhs; }
201+ friend bool operator <(const std::string& lhs, const LogLevel& rhs) { return lhs < static_cast <std::string>(rhs); }
202+ friend bool operator >(const std::string& lhs, const LogLevel& rhs) { return lhs > static_cast <std::string>(rhs); }
203+ friend bool operator <=(const std::string& lhs, const LogLevel& rhs) { return lhs <= static_cast <std::string>(rhs); }
204+ friend bool operator >=(const std::string& lhs, const LogLevel& rhs) { return lhs >= static_cast <std::string>(rhs); }
205+ friend bool operator ==(const std::string& lhs, const LogLevel& rhs) { return lhs == static_cast <std::string>(rhs); }
206+ friend bool operator !=(const std::string& lhs, const LogLevel& rhs) { return lhs != static_cast <std::string>(rhs); }
207+ // clang-format on
208+
209+
210+ private:
211+ // / The stored enum value
212+ Value value;
100213};
101-
102- /* *
103- * This function is used to convert a LogLevel into a string
104- *
105- * @param level the LogLevel to convert
106- *
107- * @return the string representation of the LogLevel
108- */
109- std::string to_string (const LogLevel& level);
110-
111- /* *
112- * This function is used to convert a string into a LogLevel
113- *
114- * @param level the string to convert
115- *
116- * @return the LogLevel representation of the string
117- */
118- LogLevel from_string (const std::string& level);
119-
120- /* *
121- * This function is used to convert a LogLevel into a string for printing.
122- *
123- * @param os the output stream to write to
124- * @param level the LogLevel to convert
125- * @return the output stream
126- */
127- std::ostream& operator <<(std::ostream& os, const LogLevel& level);
128-
129214} // namespace NUClear
130215
131216#endif // NUCLEAR_LOGLEVEL_HPP
0 commit comments