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