Fixposition SDK 0.0.0-heads/main-0-g90a51ff
Collection of c++ libraries and apps for use with Fixposition products
Loading...
Searching...
No Matches
logging.hpp
Go to the documentation of this file.
1/**
2 * \verbatim
3 * ___ ___
4 * \ \ / /
5 * \ \/ / Copyright (c) Fixposition AG (www.fixposition.com) and contributors
6 * / /\ \ License: see the LICENSE file
7 * /__/ \__\
8 * \endverbatim
9 *
10 * @file
11 * @brief Fixposition SDK: Logging
12 *
13 * @page FPSDK_COMMON_LOGGING Logging
14 *
15 * **API**: fpsdk_common/logging.hpp and fpsdk::common::logging
16 *
17 */
18#ifndef __FPSDK_COMMON_LOGGING_HPP__
19#define __FPSDK_COMMON_LOGGING_HPP__
20
21/* LIBC/STL */
22#include <cinttypes> // PRI.. macros, often used with formats
23#include <cstdarg>
24#include <cstdint>
25#include <sstream>
26
27/* EXTERNAL */
28
29/* PACKAGE */
30#include "string.hpp"
31#include "time.hpp"
32
33namespace fpsdk {
34namespace common {
35/**
36 * @brief Logging
37 */
38namespace logging {
39/* ****************************************************************************************************************** */
40
41/**
42 * @name Printf() style logging
43 *
44 * For example: `INFO("Hello world, the number is %d", 42);`
45 *
46 * @{
47 */
48// clang-format off
49/**
50 * @brief Print a fatal message @hideinitializer
51 */
52#define FATAL(fmt, ...) _FPSDK_LOGGING_LOG(FATAL, "Fatal: " fmt, ## __VA_ARGS__)
53/**
54 * @brief Print a error message @hideinitializer
55 */
56#define ERROR(fmt, ...) _FPSDK_LOGGING_LOG(ERROR, "Error: " fmt, ## __VA_ARGS__)
57/**
58 * @brief Print a warning message @hideinitializer
59 */
60#define WARNING(fmt, ...) _FPSDK_LOGGING_LOG(WARNING, "Warning: " fmt, ## __VA_ARGS__)
61/**
62 * @brief Print a notice message @hideinitializer
63 */
64#define NOTICE(fmt, ...) _FPSDK_LOGGING_LOG(NOTICE, fmt, ## __VA_ARGS__)
65/**
66 * @brief Print a info message @hideinitializer
67 */
68#define INFO(fmt, ...) _FPSDK_LOGGING_LOG(INFO, fmt, ## __VA_ARGS__)
69/**
70 * @brief Print a debug message @hideinitializer
71 */
72#define DEBUG(fmt, ...) _FPSDK_LOGGING_LOG(DEBUG, fmt, ## __VA_ARGS__)
73/**
74 * @brief Print a debug hexdump @hideinitializer
75 */
76#define DEBUG_HEXDUMP(data, size, prefix, fmt, ...) _FPSDK_LOGGING_HEX(DEBUG, data, size, prefix, fmt, ## __VA_ARGS__)
77#if !defined(NDEBUG) || defined(_DOXYGEN_) // Only for non-Release builds
78
79/**
80 * @brief Print a trace message (only debug builds, compiled out in release builds) @hideinitializer
81 */
82# define TRACE(fmt, ...) _FPSDK_LOGGING_LOG(TRACE, fmt, ## __VA_ARGS__)
83/**
84 * @brief Print a trace hexdump (only debug builds, compiled out in release builds) @hideinitializer
85 */
86# define TRACE_HEXDUMP(data, size, prefix, fmt, ...) _FPSDK_LOGGING_HEX(TRACE, data, size, prefix, fmt, ## __VA_ARGS__)
87#else
88# define TRACE(...) /* nothing */
89# define TRACE_HEXDUMP(...) /* nothing */
90#endif
91
92/**
93 * @brief Print a error message (throttled) @hideinitializer
94 */
95#define ERROR_THR(millis, fmt, ...) _FPSDK_LOGGING_THR(ERROR, millis, fmt, ## __VA_ARGS__)
96/**
97 * @brief Print a warning message (throttled) @hideinitializer
98 */
99#define WARNING_THR(millis, fmt, ...) _FPSDK_LOGGING_THR(WARNING, millis, fmt, ## __VA_ARGS__)
100/**
101 * @brief Print a notice message (throttled) @hideinitializer
102 */
103#define NOTICE_THR(millis, fmt, ...) _FPSDK_LOGGING_THR(NOTICE, millis, fmt, ## __VA_ARGS__)
104/**
105 * @brief Print a info message (throttled) @hideinitializer
106 */
107#define INFO_THR(millis, fmt, ...) _FPSDK_LOGGING_THR(INFO, millis, fmt, ## __VA_ARGS__)
108/**
109 * @brief Print a debug message (throttled) @hideinitializer
110 */
111#define DEBUG_THR(millis, fmt, ...) _FPSDK_LOGGING_THR(DEBUG, millis, fmt, ## __VA_ARGS__)
112// clang-format on
113///@}
114
115/**
116 * @name C++ style logging
117 *
118 * For example, `INFO_S("Hello world, the number is " << 42);`
119 *
120 * @{
121 */
122// clang-format off
123/**
124 * @brief Print a fatal message @hideinitializer
125 */
126#define FATAL_S(expr) _FPSDK_LOGGING_IF(FATAL, std::stringstream ss; ss << expr; FATAL("%s", ss.str().c_str()))
127/**
128 * @brief Print a error message @hideinitializer
129 */
130#define ERROR_S(expr) _FPSDK_LOGGING_IF(ERROR, std::stringstream ss; ss << expr; ERROR("%s", ss.str().c_str()))
131/**
132 * @brief Print a warning message @hideinitializer
133 */
134#define WARNING_S(expr) _FPSDK_LOGGING_IF(WARNING, std::stringstream ss; ss << expr; WARNING("%s", ss.str().c_str()))
135/**
136 * @brief Print a debug message @hideinitializer
137 */
138#define DEBUG_S(expr) _FPSDK_LOGGING_IF(DEBUG, std::stringstream ss; ss << expr; DEBUG("%s", ss.str().c_str()))
139/**
140 * @brief Print a notice message @hideinitializer
141 */
142#define NOTICE_S(expr) _FPSDK_LOGGING_IF(NOTIC, std::stringstream ss; ss << expr; NOTICE("%s", ss.str().c_str()))
143/**
144 * @brief Print a info message @hideinitializer
145 */
146#define INFO_S(expr) _FPSDK_LOGGING_IF(INFO, std::stringstream ss; ss << expr; INFO("%s", ss.str().c_str()))
147
148#if !defined(NDEBUG) || defined(_DOXYGEN_) // Only for non-Release builds
149/**
150 * @brief Print a trace message (only debug builds, compiled out in release builds) @hideinitializer
151 */
152# define TRACE_S(expr) _FPSDK_LOGGING_IF(TRACE, std::stringstream ss; ss << expr; TRACE("%s", ss.str().c_str()))
153#else
154# define TRACE_S(...) /* nothing */
155#endif
156// clang-format on
157///@}
158
159#if !defined(NDEBUG) || defined(_DOXYGEN_) // Only for non-Release builds
160//! Conditional compilation for non-Release builds
161# define IF_TRACE(...) __VA_ARGS__
162#else
163# define IF_TRACE(...) /* nothing */
164#endif
165// Note: for other levels use LoggingIsLevel()
166
167// ---------------------------------------------------------------------------------------------------------------------
168
169/**
170 * @brief Logging verbosity levels, default is INFO
171 *
172 * The logging levels loosely follow syslog levels (indicated in [] below, see also
173 * https://en.wikipedia.org/wiki/Syslog)
174 *
175 * Libraries (fpsdk_common, fpsdk_ros1, ...) code shall only use WARNING and DEBUG.
176 */
177enum class LoggingLevel : int
178{ // clang-format off
179 FATAL = 2, //!< [2/crit] Hard errors, critical conditions (for apps). Cannot be silenced.
180 ERROR = 3, //!< [3/err] Errors (for apps)
181 WARNING = 4, //!< [4/warning] Warnings (for libs and apps)
182 NOTICE = 5, //!< [5/notice] Significant stuff, for example headings (for apps)
183 INFO = 6, //!< [6/info] Interesting stuff, the default level (for apps)
184 DEBUG = 7, //!< [7/debug] Debugging (for libs and apps)
185 TRACE = 8, //!< [7/debug] Extra debugging, only compiled-in in non-Release builds
186}; // clang-format on
187
188LoggingLevel& operator++(LoggingLevel& level); //!< Increase verbosity (pre-increment)
189LoggingLevel& operator--(LoggingLevel& level); //!< Decrease verbosity (pre-decrement)
190LoggingLevel operator++(LoggingLevel& level, int); //!< Increase verbosity (post-increment)
191LoggingLevel operator--(LoggingLevel& level, int); //!< Decrease verbosity (post-decrement)
192
193/**
194 * @brief Stringify log level
195 *
196 * @param[in] level The logging level
197 *
198 * @returns a unique string identifying the level
199 */
200const char* LoggingLevelStr(const LoggingLevel level);
201
202/**
203 * @brief Check if given level would print
204 *
205 * @param[in] level The logging level in question
206 *
207 * @returns true if the given level would print, false otherwise
208 */
209bool LoggingIsLevel(const LoggingLevel level);
210
211/**
212 * @brief Logging "colours"
213 */
215{
216 AUTO = 0, //!< Automatic (default), use colours if stderr is an interactive terminal
217 YES, //!< Use colours (terminal escape sequences)
218 NO, //!< Do not use colours
219 JOURNAL, //!< Use systemd journal level indicators (instead of terminal colours), useful for systemd services
220};
221
222/**
223 * @brief Stringify log level
224 *
225 * @param[in] colour The logging colour
226 *
227 * @returns a unique string identifying the level
228 */
229const char* LoggingColourStr(const LoggingColour colour);
230
231/**
232 * @brief Logging timestamps
233 */
235{
236 NONE = 0, //!< No timestamps
237 RELATIVE, //!< Relative timestamps (since first logging message, sssss.sss format)
238 ABSOLUTE, //!< Absolute timestamps (local time, yyyy-mm-dd hh::mm:ss.sss format)
239};
240
241/**
242 * @brief Stringify log level
243 *
244 * @param[in] timestamps The logging timestamps
245 *
246 * @returns a unique string identifying the level
247 */
248const char* LoggingTimestampsStr(const LoggingTimestamps timestamps);
249
250struct LoggingParams; // forward declaration
251
252/**
253 * @brief Custom logging print function signature
254 */
255using LoggingPrintFunc = void (*)(const LoggingParams&, const LoggingLevel, const char*);
256
257/**
258 * @brief Logging parameters
259 */
261{
262 /**
263 * @brief Constructor
264 *
265 * @param[in] level Logging level
266 * @param[in] colour Logging colours
267 * @param[in] timestamps Logging timestamps
268 */
270 const LoggingTimestamps timestamps = LoggingTimestamps::NONE);
271 LoggingLevel level_; //!< Logging level
272 LoggingColour colour_; //!< Level colours
274 LoggingPrintFunc fn_; //!< Custom logging print function
275};
276
277/**
278 * @brief Configure logging
279 *
280 * @param[in] params Logging parameters
281 *
282 * Examples:
283 *
284 * @code{.cpp}
285 * LoggingSetParams({ LoggingLevel::DEBUG });
286 * LoggingSetParams({ LoggingLevel::DEBUG, LoggingColour::YES });
287 * LoggingSetParams({ LoggingLevel::DEBUG, LoggingColour::AUTO, LoggingTimestamps::RELATIVE });
288 * @endcode
289 *
290 * @returns a copy of the applied logging parameters
291 */
293
294/**
295 * @brief Get current logging params
296 *
297 * @returns a copy of the current logging params
298 */
300
301/**
302 * @brief Print a log message
303 *
304 * @note Use INFO(), DEBUG(), WARNING() etc. instead of this function.
305 *
306 * @param[in] level Logging level
307 * @param[in] fmt printf() style format string
308 * @param[in] ... arguments to the format string
309 */
310void LoggingPrint(const LoggingLevel level, const char* fmt, ...) PRINTF_ATTR(2);
311
312/**
313 * @brief Print a hexdump
314 *
315 * @note Typically, use DEBUG_HEXDUMP() or TRACE_HEXDUMP() instead of this function.
316 *
317 * @param[in] level Logging level
318 * @param[in] data Pointer to start of data to dump
319 * @param[in] size Size of data to dump
320 * @param[in] prefix Prefix to add to each line, can be NULL to omit
321 * @param[in] fmt printf() style format string (for a first line to print), can be NULL to omit
322 * @param[in] ... Arguments to the format string
323 */
324void LoggingHexdump(const LoggingLevel level, const uint8_t* data, const std::size_t size, const char* prefix,
325 const char* fmt, ...) PRINTF_ATTR(5);
326
327// Helper macros
328#ifndef _DOXYGEN_
329# define _FPSDK_LOGGING_LOG(_level_, _fmt_, ...) \
330 ::fpsdk::common::logging::LoggingPrint(fpsdk::common::logging::LoggingLevel::_level_, _fmt_, ##__VA_ARGS__)
331# define _FPSDK_LOGGING_HEX(_level_, _data_, _size_, _prefix_, _fmt_, ...) \
332 ::fpsdk::common::logging::LoggingHexdump( \
333 fpsdk::common::logging::LoggingLevel::_level_, _data_, _size_, _prefix_, _fmt_, ##__VA_ARGS__)
334# define _FPSDK_LOGGING_IF(_level_, _code_) \
335 if (::fpsdk::common::logging::LoggingIsLevel(fpsdk::common::logging::LoggingLevel::_level_)) { \
336 _code_; \
337 }
338# define _FPSDK_LOGGING_THR(_level_, _millis_, _fmt_, ...) \
339 do { \
340 static uint32_t __last = 0; \
341 const uint32_t __now = ::fpsdk::common::time::GetMillis(); \
342 if ((__now - __last) >= (_millis_)) { \
343 __last = __now; \
344 _level_(_fmt_, ##__VA_ARGS__); \
345 } \
346 } while (0)
347#endif // _DOXYGEN_
348
349/* ****************************************************************************************************************** */
350} // namespace logging
351} // namespace common
352} // namespace fpsdk
353#endif // __FPSDK_COMMON_LOGGING_HPP__
LoggingParams LoggingGetParams()
Get current logging params.
void(*)(const LoggingParams &, const LoggingLevel, const char *) LoggingPrintFunc
Custom logging print function signature.
Definition logging.hpp:255
LoggingParams LoggingSetParams(const LoggingParams &params)
Configure logging.
const char * LoggingLevelStr(const LoggingLevel level)
Stringify log level.
void LoggingHexdump(const LoggingLevel level, const uint8_t *data, const std::size_t size, const char *prefix, const char *fmt,...) PRINTF_ATTR(5)
Print a hexdump.
const char * LoggingTimestampsStr(const LoggingTimestamps timestamps)
Stringify log level.
bool LoggingIsLevel(const LoggingLevel level)
Check if given level would print.
LoggingLevel & operator++(LoggingLevel &level)
Increase verbosity (pre-increment)
void LoggingPrint(const LoggingLevel level, const char *fmt,...) PRINTF_ATTR(2)
Print a log message.
LoggingTimestamps
Logging timestamps.
Definition logging.hpp:235
@ ABSOLUTE
Absolute timestamps (local time, yyyy-mm-dd hh::mm:ss.sss format)
@ RELATIVE
Relative timestamps (since first logging message, sssss.sss format)
LoggingLevel
Logging verbosity levels, default is INFO.
Definition logging.hpp:178
@ WARNING
[4/warning] Warnings (for libs and apps)
@ FATAL
[2/crit] Hard errors, critical conditions (for apps). Cannot be silenced.
@ TRACE
[7/debug] Extra debugging, only compiled-in in non-Release builds
@ INFO
[6/info] Interesting stuff, the default level (for apps)
@ NOTICE
[5/notice] Significant stuff, for example headings (for apps)
@ ERROR
[3/err] Errors (for apps)
@ DEBUG
[7/debug] Debugging (for libs and apps)
const char * LoggingColourStr(const LoggingColour colour)
Stringify log level.
LoggingLevel & operator--(LoggingLevel &level)
Decrease verbosity (pre-decrement)
LoggingColour
Logging "colours".
Definition logging.hpp:215
@ JOURNAL
Use systemd journal level indicators (instead of terminal colours), useful for systemd services.
@ YES
Use colours (terminal escape sequences)
@ AUTO
Automatic (default), use colours if stderr is an interactive terminal.
Fixposition SDK.
Fixposition SDK: String utilities.
#define PRINTF_ATTR(n)
Helper macro for marking functions as taking printf() style formatting strings.
Definition string.hpp:46
LoggingColour colour_
Level colours.
Definition logging.hpp:272
LoggingLevel level_
Logging level.
Definition logging.hpp:271
LoggingParams(const LoggingLevel level=LoggingLevel::INFO, const LoggingColour colour=LoggingColour::AUTO, const LoggingTimestamps timestamps=LoggingTimestamps::NONE)
Constructor.
LoggingPrintFunc fn_
Custom logging print function.
Definition logging.hpp:274
LoggingTimestamps timestamps_
Timestamps.
Definition logging.hpp:273
Fixposition SDK: Time utilities.