librnr  1.14.5
RoadNarrows Robotics Common Library 1
log.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 /*! \file
3  *
4  * \brief Logger declarations.
5  *
6  * Logging supports error and diagnostics (debugging) reports to stderr or a
7  * specified file. Logging reporting is filtered by a simple threshold level.
8  *
9  * The logging facilities are designed to support independent logging
10  * capabilities through namespaceing. Copy log.h and log.c to user application
11  * source tree and compile with LOGNS uniquely defined.
12  *
13  * \par The Defined Loggging Thresholds
14  * Define | Threshold | Description
15  * ------ | ----- | -----------
16  * \ref LOGGING_NA | -1 | Logging is not compiled into the application.<br> See \ref LOG_GET_THRESHOLD() to test level including this level.
17  * \ref LOG_LEVEL_OFF | 0 | Logging is turned off.
18  * \ref LOG_LEVEL_ERROR | 1 | Log only warnings and errors.
19  * \ref LOG_LEVEL_DIAG1 | 2 | Log errors plus level 1 diagnostics.
20  * \ref LOG_LEVEL_DIAG2 | 3 | Log errors plus level 1-2 diagnostics.
21  * \ref LOG_LEVEL_DIAG3 | 4 | Log errors plus level 1-3 diagnostics.
22  * \ref LOG_LEVEL_DIAG4 | 5 | Log errors plus level 1-4 diagnostics.
23  * \ref LOG_LEVEL_DIAG5 | 6 | Log errors plus level 1-5 diagnostics.
24  * \b User \b Defined | \h_ge 7 | User defined loggging levels.
25  *
26  * \par Coding Common Logging Macros
27  * Macro | Threshold | Description
28  * ----- | ----- | -----------
29  * \ref LOGWARN() | 1 | Log warning message.
30  * \ref LOGERROR() | 1 | Log error message.
31  * \ref LOGSYSERROR() | 1 | Log system error message.<br>The _errno_ and associaed string will also be logged.
32  * \ref LOGDIAG1() | 2 | Log level 1 diagnostic message.
33  * ~ | ~ | ~
34  * \ref LOGDIAG5() | 6 | Log level 5 diagnostic message.
35  * \ref LOG_GET_THRESHOLD() | - | Get current logging level.
36  * \ref LOG_SET_THRESHOLD() | - | Set current logging level.
37  * \ref LOGFUNCNAME | - | Calling function or method name.
38  *
39  * \par Special Make Defines
40  * <dl>
41  * <dt> \b LOG </dt>
42  * <dd>If defined, complile logging into an application.\n
43  * Default: not defined.</dd>
44  * <dt> \ref LOGNS </dt>
45  * <dd>Log namespace string. All external identifiers will be
46  * prefixed by \ref LOGNS<<em>id</em>>. This is usefull, for example, if
47  * a program uses logging and is also linked with a library
48  * that also uses logging.\n
49  * Default: <emptystring> </dd>
50  * <dt> \ref LOGMOD </dt>
51  * <dd>If defined, all logging output will be prefaced with this string.\n
52  * Default: \ref LOGNS </dd>
53  * <dt> \ref LOG_LEVEL_DFT </dt>
54  * <dd>Initial default logging threshold level.\n
55  * Default: 0 (off)</dd>
56  * </dl>
57  *
58  * \sa
59  * Page \ref example_log under "Related Pages" for an example usage of logging.
60  *
61  * \todo
62  * Define log class concepts whereby logging can be filtered by threshold and
63  * class.\n
64  * LogClassSet(...), LogClassClear(), LogClassAdd(...), LogClassDel(...)\n
65  * Class maps to a bit in a bitmap. All logging macros check loglevel and
66  * class bit.\n
67  * Reserved names: '_all_', '_none_', '_common_' (default)
68  *
69  * \pkgsynopsis
70  * RoadNarrows Robotics Common Library 1
71  *
72  * \pkgcomponent{Library}
73  * librnr
74  *
75  * \pkgfile{include/rnr/log.h}
76  *
77  * \author Robin Knight (robin.knight@roadnarrows.com)
78  *
79  * \pkgcopyright{2005-2018,RoadNarrows LLC.,http://www.roadnarrows.com}
80  *
81  * \license{MIT}
82  *
83  * \EulaBegin
84  * See the README and EULA files for any copyright and licensing information.
85  * \EulaEnd
86  */
87 ////////////////////////////////////////////////////////////////////////////////
88 
89 #ifndef _RNR_LOG_H
90 #define _RNR_LOG_H
91 
92 #include <stdio.h>
93 #include <stdarg.h>
94 #include <errno.h>
95 #include <string.h>
96 #include <ctype.h>
97 
98 #include "rnr/rnrconfig.h"
99 
101 
102 //
103 // Usefull macro utilities
104 //
105 #define CONCAT_(x, y) x ## y ///< build concatenation operator
106 #define CONCAT(x, y) CONCAT_(x, y) ///< now concatenate
107 #define MKSTR_(x) #x ///< build token into string operator
108 #define MKSTR(x) MKSTR_(x) ///< now make string literal
109 
110 //
111 // Logging Entity's Namespace
112 //
113 #ifndef LOGNS
114 
115 #undef LOGNS_DEF ///< default logging namespace
116 #define LOGNS ///< default namespace preface token
117 #define LOGNS_NAME "" ///< default namespace string name
118 #undef LOGNS_PREFACE ///< default logging preface string
119 
120 #else // user defined namespace
121 
122 #define LOGNS_DEF ///< separate logging namespace
123 #define LOGNS_NAME MKSTR(LOGNS) ///< namespace string name
124 #define LOGNS_PREFACE LOGNS_NAME ///< logging preface string
125 
126 #endif // LOGNS
127 
128 #define LOGNS_PUT(id) CONCAT(LOGNS, id) ///< put identifier into namespace
129 
130 //
131 // Loggging module name
132 //
133 #ifdef LOGMOD
134 #define LOG_PREFACE_TEXT LOGMOD ": " ///< user logging preface
135 #elif defined(LOGNS_PREFACE)
136 #define LOG_PREFACE_TEXT LOGNS_PREFACE ": " ///< namespace logging preface
137 #else
138 #define LOGMOD ///< default logging module name
139 #define LOG_PREFACE_TEXT "" ///< no logging preface
140 #endif // LOGMOD
141 
142 
143 //
144 // Global Names in namespace
145 //
146 #define LOG_VAR_THRESHOLD LOGNS_PUT(LogThresholdLevel)
147  ///< current threshold variable name
148 
149 #define LOG_SET_THRESHOLD LOGNS_PUT(LogSetThresholdLevel)
150  ///< set threshold function name
151 
152 #define LOG_GET_THRESHOLD LOGNS_PUT(LogGetThresholdLevel)
153  ///< get threshold function name
154 
155 #define LOG_VAR_COLOR_EN LOGNS_PUT(LogColorEnable)
156  ///< logging in color is [not] enabled
157 
158 #define LOG_SET_LOGFILE LogSetLogFile
159  ///< set output log file function name
160 #define LOG_GET_LOGFILE LogGetLogFile
161  ///< get output log file function name
162 #define LOG_SET_COLOR_ENABLE LogSetColorEnable
163  ///< enable/disable logging in color func name
164 #define LOG_SET_TIMESTAMP_ENABLE LogSetTimestampEnable
165  ///< enable/disable logging timestamps func name
166 #define LOG_ATTACH_LOGFP LogAttachLogFp
167  ///< attach file pointer as logging out stream
168 #define LOG_GET_LOGFP LogGetLogFp
169  ///< get current logging out stream file pointer
170 #define LOGGER LogPrintf
171  ///< logger function name
172 #define LOGGER_CALL LogCallPrintf
173  ///< logger of "function call" function name
174 
175 //
176 // Log Levels (levels >6 are user defined)
177 //
178 #define LOGGING_NA -1 ///< logging not available (not compiled)
179 #define LOG_LEVEL_OFF 0 ///< turn off all non-error logging
180 #define LOG_LEVEL_ERROR 1 ///< errors
181 #define LOG_LEVEL_DIAG1 2 ///< diagnostic level 1
182 #define LOG_LEVEL_DIAG2 3 ///< diagnostic level 2
183 #define LOG_LEVEL_DIAG3 4 ///< diagnostic level 3
184 #define LOG_LEVEL_DIAG4 5 ///< diagnostic level 4
185 #define LOG_LEVEL_DIAG5 6 ///< diagnostic level 5
186 #ifndef LOG_LEVEL_DFT
187 #define LOG_LEVEL_DFT 0 ///< default log level is off
188 #endif
189 
190 /*!
191  * \brief Test if given level is logable at current threshold.
192  *
193  * \param level Level to test.
194  */
195 #define LOGABLE(level) ((level) <= LOG_VAR_THRESHOLD)
196 
197 /*!
198  * \brief Test if logging in color.
199  */
200 #define LOG_IN_COLOR() (LOG_VAR_COLOR_EN)
201 
202 /*!
203  * \brief Test if logging includes timestamps.
204  */
205 #define LOG_WITH_TIMESTAMP() (LOG_VAR_TIMESTAMP_EN)
206 
207 //
208 // Log Filenames and Pointers
209 //
210 #define LOG_FILENAME_STDERR "stderr" ///< 'stderr' log filename
211 #define LOG_FILENAME_STDOUT "stdout" ///< 'stdout' log filename
212 #define LOG_FILENAME_DFT LOG_FILENAME_STDERR ///< default log filename
213 #define LOG_FP_DFT stderr ///< default log out stream
214 
215 //
216 // Other Logging Options
217 //
218 #define LOG_COLOR_EN_DFT true ///< default is to log in color
219 #define LOG_TIMESTAMP_EN_DFT true ///< default is to include timestamps
220 
221 //
222 // Log function name formatters (must keep literal)
223 // Note: Might be protability issues with this macro.
224 //
225 #define LOGFUNCNAME __func__ ///< function name
226 
227 //
228 // Log Colors. Colors are expressed in ANSI escape code sequences.
229 //
230 #define LOG_COLOR_PRE "\033[" ///< color escape sequence prefix
231 #define LOG_COLOR_POST "\033[0m" ///< color escape sequence postfix
232 #define LOG_COLOR_RED "0;31m" ///< normal red
233 #define LOG_COLOR_GREEN "0;32m" ///< normal green
234 #define LOG_COLOR_YELLOW "0;33m" ///< normal yellow
235 #define LOG_COLOR_BLUE "0;34m" ///< normal blue
236 #define LOG_COLOR_MAGENTA "0;35m" ///< normal magenta
237 #define LOG_COLOR_CYAN "0;36m" ///< normal cyan
238 #define LOG_COLOR_LIGHT_RED "1;31m" ///< light red
239 #define LOG_COLOR_LIGHT_GREEN "1;32m" ///< light green
240 #define LOG_COLOR_LIGHT_YELLOW "1;33m" ///< light yellow
241 #define LOG_COLOR_LIGHT_BLUE "1;34m" ///< light blue
242 #define LOG_COLOR_LIGHT_MAGENTA "1;35m" ///< light magenta
243 #define LOG_COLOR_LIGHT_CYAN "1;36m" ///< light cyan
244 
245 #define LOG_COLOR_ERROR LOG_COLOR_PRE LOG_COLOR_RED ///< error color
246 #define LOG_COLOR_WARN LOG_COLOR_PRE LOG_COLOR_YELLOW ///< warning color
247 #define LOG_COLOR_DIAG LOG_COLOR_PRE LOG_COLOR_GREEN ///< diagnostics color
248 
249 #ifdef LOGMOD_COLOR
250 #define LOG_PREFACE LOG_COLOR_PRE LOGMOD_COLOR LOG_PREFACE_TEXT LOG_COLOR_POST
251  ///< loging preface string
252 #else
253 #define LOG_PREFACE LOG_PREFACE_TEXT ///< loging preface string
254 #endif
255 
256 #define LOG_PREFACE_PLAIN LOG_PREFACE_TEXT ///< loging preface with no color
257 
258 
259 //-----------------------------------------------------------------------------
260 // Logging Diagnostics and Error Argument Macros
261 //-----------------------------------------------------------------------------
262 
263 /*!
264  * \brief Standard diagnostic logging output arguments with compiled color.
265  * \param level Loggging level.
266  * \param fmt Optional specifics format string.
267  * \param ... Optional specific variable arguments for fmt.
268  */
269 #define LOGARGS_DIAG(level, fmt, ...) \
270  LOG_PREFACE LOG_COLOR_DIAG "Diag%d: %s[%d] " LOG_COLOR_POST fmt, \
271  (level-1), __FILE__, __LINE__, ##__VA_ARGS__
272 
273 /*!
274  * \brief Standard diagnostic logging output arguments in plain text.
275  * \param level Loggging level.
276  * \param fmt Optional specifics format string.
277  * \param ... Optional specific variable arguments for fmt.
278  */
279 #define LOGARGS_DIAG_PLAIN(level, fmt, ...) \
280  LOG_PREFACE_PLAIN "Diag%d: %s[%d] " fmt, \
281  (level-1), __FILE__, __LINE__, ##__VA_ARGS__
282 
283 /*!
284  * \brief Standard warning logging output arguments with compiled color.
285  * \param fmt Optional specifics format string.
286  * \param ... Optional specific variable arguments for fmt.
287  */
288 #define LOGARGS_WARN(fmt, ...) \
289  LOG_PREFACE LOG_COLOR_WARN "Warning: %s[%d] " LOG_COLOR_POST fmt, \
290  __FILE__, __LINE__, ##__VA_ARGS__
291 
292 /*!
293  * \brief Standard warning logging output arguments in plain text.
294  * \param fmt Optional specifics format string.
295  * \param ... Optional specific variable arguments for fmt.
296  */
297 #define LOGARGS_WARN_PLAIN(fmt, ...) \
298  LOG_PREFACE_PLAIN "Warning: %s[%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__
299 
300 /*!
301  * \brief Standard error logging output arguments with compiled color.
302  * \param fmt Optional specifics format string.
303  * \param ... Optional specific variable arguments for fmt.
304  */
305 #define LOGARGS_ERR(fmt, ...) \
306  LOG_PREFACE LOG_COLOR_ERROR "Error: %s[%d] " LOG_COLOR_POST fmt, \
307  __FILE__, __LINE__, ##__VA_ARGS__
308 
309 /*!
310  * \brief Standard error logging output arguments in plain text.
311  * \param fmt Optional specifics format string.
312  * \param ... Optional specific variable arguments for fmt.
313  */
314 #define LOGARGS_ERR_PLAIN(fmt, ...) \
315  LOG_PREFACE_PLAIN "Error: %s[%d] " fmt, __FILE__, __LINE__, ##__VA_ARGS__
316 
317 /*!
318  * \brief Standard system error logging output arguments with compiled color.
319  * \param fmt Optional specifics format string.
320  * \param ... Optional specific variable arguments for fmt.
321  */
322 #define LOGARGS_SYSERR(fmt, ...) \
323  LOG_PREFACE LOG_COLOR_ERROR "Error: %s[%d] " LOG_COLOR_POST "%s(errno=%d): " \
324  fmt, __FILE__, __LINE__, strerror(errno), errno, ##__VA_ARGS__
325 
326 /*!
327  * \brief Standard system error logging output arguments with compiled color.
328  * \param fmt Optional specifics format string.
329  * \param ... Optional specific variable arguments for fmt.
330  */
331 #define LOGARGS_SYSERR_PLAIN(fmt, ...) \
332  LOG_PREFACE_PLAIN "Error: %s[%d] " "%s(errno=%d): " fmt, \
333  __FILE__, __LINE__, strerror(errno), errno, ##__VA_ARGS__
334 
335 
336 //-----------------------------------------------------------------------------
337 // Logging Diagnostics and Error Macros
338 // See http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros
339 //-----------------------------------------------------------------------------
340 #ifdef LOG
341 
342 /*!
343  * \brief Standard Diagnostic logging.
344  * \param level Loggging level.
345  * \param fmt Optional specifics format string.
346  * \param ... Optional specific variable arguments for fmt.
347  */
348 #define LOGDIAG(level, fmt, ...) \
349  do \
350  { \
351  if( LOGABLE(level) ) \
352  { \
353  if( LOG_IN_COLOR() ) \
354  { \
355  LOGGER(LOGARGS_DIAG(level, fmt), ##__VA_ARGS__); \
356  } \
357  else \
358  { \
359  LOGGER(LOGARGS_DIAG_PLAIN(level, fmt), ##__VA_ARGS__); \
360  } \
361  } \
362  } while(0)
363 
364 /*!
365  * \brief Standard User Diagnostic logging.
366  * \param level Loggging user level.
367  * \param fmt Optional specifics format string.
368  * \param ... Optional specific variable arguments for fmt.
369  * \sa LOGDIAG()
370  */
371 #define LOGUSER(level, fmt, ...) \
372  LOGDIAG(level+LOG_LEVEL_DIAG3+1, fmt, ##__VA_ARGS__)
373 
374 /*!
375  * \brief Standard Diagnostic Level 5 logging.
376  * \param fmt Optional specifics format string.
377  * \param ... Optional specific variable arguments for fmt.
378  */
379 #define LOGDIAG5(fmt, ...) LOGDIAG(LOG_LEVEL_DIAG5, fmt, ##__VA_ARGS__)
380 
381 /*!
382  * \brief Standard Diagnostic Level 4 logging.
383  * \param fmt Optional specifics format string.
384  * \param ... Optional specific variable arguments for fmt.
385  */
386 #define LOGDIAG4(fmt, ...) LOGDIAG(LOG_LEVEL_DIAG4, fmt, ##__VA_ARGS__)
387 
388 /*!
389  * \brief Standard Diagnostic Level 3 logging.
390  * \param fmt Optional specifics format string.
391  * \param ... Optional specific variable arguments for fmt.
392  */
393 #define LOGDIAG3(fmt, ...) LOGDIAG(LOG_LEVEL_DIAG3, fmt, ##__VA_ARGS__)
394 
395 /*!
396  * \brief Standard Diagnostic Level 2 logging.
397  * \param fmt Optional specifics format string.
398  * \param ... Optional specific variable arguments for fmt.
399  */
400 #define LOGDIAG2(fmt, ...) LOGDIAG(LOG_LEVEL_DIAG2, fmt, ##__VA_ARGS__)
401 
402 /*!
403  * \brief Standard Diagnostic Level 1 logging.
404  * \param fmt Optional specifics format string.
405  * \param ... Optional specific variable arguments for fmt.
406  */
407 #define LOGDIAG1(fmt, ...) LOGDIAG(LOG_LEVEL_DIAG1, fmt, ##__VA_ARGS__)
408 
409 /*!
410  * \brief Standard Diagnostic function call tracing.
411  * \param level Loggging level.
412  * \param ... Optional argument_format,argument pairs.
413  */
414 #define LOGDIAGCALL(level, ...) \
415  do \
416  { \
417  if( LOGABLE(level) ) \
418  { \
419  if( LOG_IN_COLOR() ) \
420  { \
421  LOGGER_CALL(LOG_PREFACE, level, __FILE__, __LINE__, \
422  LOGFUNCNAME, ##__VA_ARGS__, NULL, 0); \
423  } \
424  else \
425  { \
426  LOGGER_CALL(LOG_PREFACE_PLAIN, level, __FILE__, __LINE__, \
427  LOGFUNCNAME, ##__VA_ARGS__, NULL, 0); \
428  } \
429  } \
430  } while(0)
431 
432 /*!
433  * \brief Standard Diagnostic Level 5 function call tracing.
434  * \param ... Optional argument_format,argument pairs.
435  */
436 #define LOGDIAG5CALL(...) LOGDIAGCALL(LOG_LEVEL_DIAG5, ##__VA_ARGS__)
437 
438 /*!
439  * \brief Standard Diagnostic Level 4 function call tracing.
440  * \param ... Optional argument_format,argument pairs.
441  */
442 #define LOGDIAG4CALL(...) LOGDIAGCALL(LOG_LEVEL_DIAG4, ##__VA_ARGS__)
443 
444 /*!
445  * \brief Standard Diagnostic Level 3 function call tracing.
446  * \param ... Optional argument_format,argument pairs.
447  */
448 #define LOGDIAG3CALL(...) LOGDIAGCALL(LOG_LEVEL_DIAG3, ##__VA_ARGS__)
449 
450 /*!
451  * \brief Standard Diagnostic Level 2 function call tracing.
452  * \param ... Optional argument_format,argument pairs.
453  */
454 #define LOGDIAG2CALL(...) LOGDIAGCALL(LOG_LEVEL_DIAG2, ##__VA_ARGS__)
455 
456 /*!
457  * \brief Standard Diagnostic Level 1 function call tracing.
458  * \param ... Optional argument_format,argument pairs.
459  */
460 #define LOGDIAG1CALL(...) LOGDIAGCALL(LOG_LEVEL_DIAG1, ##__VA_ARGS__)
461 
462 /*!
463  * \brief Standard Warning logging.
464  * \param fmt Optional specifics format string.
465  * \param ... Optional specific variable arguments for fmt.
466  */
467 #define LOGWARN(fmt, ...) \
468  do \
469  { \
470  if( LOGABLE(LOG_LEVEL_ERROR) ) \
471  { \
472  if( LOG_IN_COLOR() ) \
473  { \
474  LOGGER(LOGARGS_WARN(fmt), ##__VA_ARGS__); \
475  } \
476  else \
477  { \
478  LOGGER(LOGARGS_WARN_PLAIN(fmt), ##__VA_ARGS__); \
479  } \
480  } \
481  } while(0)
482 
483 /*!
484  * \brief Standard Error logging.
485  * \param fmt Optional specifics format string.
486  * \param ... Optional specific variable arguments for fmt.
487  */
488 #define LOGERROR(fmt, ...) \
489  do \
490  { \
491  if( LOGABLE(LOG_LEVEL_ERROR) ) \
492  { \
493  if( LOG_IN_COLOR() ) \
494  { \
495  LOGGER(LOGARGS_ERR(fmt), ##__VA_ARGS__); \
496  } \
497  else \
498  { \
499  LOGGER(LOGARGS_ERR_PLAIN(fmt), ##__VA_ARGS__); \
500  } \
501  } \
502  } while(0)
503 
504 /*!
505  * \brief Standard System Error logging.
506  * \param fmt Optional specifics format string.
507  * \param ... Optional specific variable arguments for fmt.
508  */
509 #define LOGSYSERROR(fmt, ...) \
510  do \
511  { \
512  if( LOGABLE(LOG_LEVEL_ERROR) ) \
513  { \
514  int errsave = errno; \
515  if( LOG_IN_COLOR() ) \
516  { \
517  LOGGER(LOGARGS_SYSERR(fmt), ##__VA_ARGS__); \
518  } \
519  else \
520  { \
521  LOGGER(LOGARGS_SYSERR_PLAIN(fmt), ##__VA_ARGS__); \
522  } \
523  errno = errsave; \
524  } \
525  } while(0)
526 
527 #else // do not compile logging
528 
529 #define LOGDIAG(...)
530 #define LOGUSER(...)
531 #define LOGDIAG5(...)
532 #define LOGDIAG4(...)
533 #define LOGDIAG3(...)
534 #define LOGDIAG2(...)
535 #define LOGDIAG1(...)
536 #define LOGDIAG5CALL(...)
537 #define LOGDIAG4CALL(...)
538 #define LOGDIAG3CALL(...)
539 #define LOGDIAG2CALL(...)
540 #define LOGDIAG1CALL(...)
541 #define LOGWARN(...)
542 #define LOGERROR(...)
543 #define LOGSYSERROR(...)
544 
545 #endif // LOG
546 
547 
548 //-----------------------------------------------------------------------------
549 // Helper Formatters
550 //-----------------------------------------------------------------------------
551 
552 //
553 // Helper formaters
554 //
555 #define _VARFMT(var, fmt) #var "=" fmt ///< log Variable Format.
556 #define _TF(b) ((b)? "true": "false") ///< boolean to string format
557 #define _CHARFMT(var) (isprint(var)? #var "='%c'": #var "=0x%02x")
558  ///< char format string
559 
560 /*!
561  * \brief Family of 2-tuple ("<varname>=<fmt>", <var>) variable logging
562  * formatters.
563  *
564  * The \p _T*() macros are used to create a format string, variable pair of the
565  * form: "<varname>=<fmt>",<var>
566  *
567  * \param var Variable identifier.
568  * \param fmt Format string to print variable.
569  *
570  * \note Intended use are calls to the LOGDIAGxCALL() macros,
571  * although can be used anywhere, although only once per each LOGDIAGx(),
572  * LOGERROR(), or LOGSYSERROR() call.
573  *
574  * \sa _VARFMT() for a more general varaible formatter.
575  */
576 #define _TFMT(var, fmt) #var "=" fmt, var ///< raw Format,Variable Pair
577 #define _TSTR(var) _TFMT(var, "\"%s\"") ///< string variable
578 #define _TLONG(var) _TFMT(var, "%ld") ///< long int (decimal)
579 #define _TULONG(var) _TFMT(var, "%lu") ///< unsigned long int (decimal)
580 #define _THEX(var) _TFMT(var, "0x%x") ///< int (hex)
581 #define _TINT(var) _TFMT(var, "%d") ///< int (decimal)
582 #define _TUINT(var) _TFMT(var, "%u") ///< unsigned int (decimal)
583 #define _TSHORT(var) _TFMT(var, "%hd") ///< short int (decimal)
584 #define _TUSHORT(var) _TFMT(var, "%hu") ///< unsigned short (decimal)
585 #define _TFLOAT(var) _TFMT(var, "%f") ///< float
586 #define _TPTR(var) _TFMT(var, "%p") ///< pointer
587 #define _TBOOL(var) _VARFMT(var, "%s"), _TF(var) ///< boolean
588 #define _TCHAR(var) _CHARFMT(var), var ///< character
589 #define _TVEC(var, i, fmt) #var "[%d]=" fmt, i, var[i] ///< vector variable
590 #define _TVEC_UINT(var, i) _TVEC(var, i, "%u") ///< unsigned vector variable
592 
593 /*!
594  * function name w/ parens
595  */
596 #define LFF "%s()", LOGFUNCNAME
598 /*!
599  * \brief Log formatter for function with arguments.
600  *
601  * Format: function(var=val, ...)
602  *
603  * \param fmt Format string to print function arguments.
604  * \param ... Arguments to fmt string.
605  */
606 #define LFF_ARGS(fmt, ...) \
607  "%s(" fmt "%s", LOGFUNCNAME, ##__VA_ARGS__, ")"
608 
609 /*!
610  * \brief Log formatter for function with a bad argument.
611  *
612  * Format: function(var=val): errmsg
613  *
614  * \param var Variable identifier.
615  * \param fmt Format string to print function argument.
616  * \param postfmt Format string to print after function string.
617  * \param ... Arguments to postfmt string
618  */
619 #define LFF_BADARG(var, fmt, postfmt, ...) \
620  "%s(" #var "=" fmt "): " postfmt, LOGFUNCNAME, var, ##__VA_ARGS__
621 
622 /*!
623  * \brief Log formatter for function with a bad vector argument.
624  *
625  * Format: function(var[i]=val): errmsg
626  *
627  * \param var Vector variable identifier.
628  * \param i Variable index.
629  * \param fmt Format string to print function argument.
630  * \param postfmt Format string to print after function string.
631  * \param ... Arguments to postfmt string
632  */
633 #define LFF_BADARG_VEC(var, i, fmt, postfmt, ...) \
634  "%s(" #var "[%d]=" fmt "): " postfmt, LOGFUNCNAME, i, var[i], ##__VA_ARGS__
635 
636 
637 //-----------------------------------------------------------------------------
638 // Data Validation Helpers
639 //-----------------------------------------------------------------------------
640 
641 /*!
642  * \brief Checks validity of pointer.
643  *
644  * If null then log error and return from the embedding function with given
645  * (optional) error return code.
646  *
647  * \param p Pointer that should not be NULL.
648  * \param ... Error return code (optional).
649  */
650 #define CHKPTR(p, ...) \
651  do \
652  { \
653  if( (p) == NULL ) \
654  { \
655  LOGERROR(_TPTR(p)); return __VA_ARGS__; \
656  } \
657  } while(0)
658 
659 /*!
660  * \brief Checks validity of value against the given validation expression.
661  *
662  * The \p CHKEXPR*() macros are used validate a value against an expression.
663  * If the expression evaluates to false, then log an error message
664  * and return from the embedding functin with the given (optional)
665  * error return code.
666  *
667  * \param val Value identifier to check.
668  * \param expr Validation expression to evaluate.
669  * \param valfmt Value format string to use on error.
670  * \param ... Error return code (optional).
671  */
672 #define CHKEXPR(val, expr, valfmt, ...) \
673  do \
674  { \
675  if( !(expr) ) \
676  { \
677  LOGERROR(_VARFMT(val, valfmt) ": failed check: %s", val, #expr); \
678  return __VA_ARGS__; \
679  } \
680  } while(0)
681 
682 //
683 // Family of macro data validators.
684 //
685 
686 /*! \brief check integer */
687 #define CHKEXPR_INT(val, expr, ...) CHKEXPR(val, expr, "%d", ##__VA_ARGS__)
689 /*! \brief check string */
690 #define CHKEXPR_STR(val, expr, ...) CHKEXPR(val, expr, "'%s'", ##__VA_ARGS__)
692 /*! \brief check long integer */
693 #define CHKEXPR_LONG(val, expr, ...) CHKEXPR(val, expr, "%ld", ##__VA_ARGS__)
695 /*! \brief check unsigned long integer */
696 #define CHKEXPR_ULONG(val, expr, ...) CHKEXPR(val, expr, "%lu", ##__VA_ARGS__)
698 /*! \brief check integer hex */
699 #define CHKEXPR_HEX(val, expr, ...) CHKEXPR(val, expr, "0x%x", ##__VA_ARGS__)
701 /*! \brief check unsigned integer */
702 #define CHKEXPR_UINT(val, expr, ...) CHKEXPR(val, expr, "%u", ##__VA_ARGS__)
704 /*! \brief check short integer */
705 #define CHKEXPR_SHORT(val, expr, ...) CHKEXPR(val, expr, "%hd",## __VA_ARGS__)
707 /*! \brief check unsigned short integer */
708 #define CHKEXPR_USHORT(val, expr, ...) CHKEXPR(val, expr, "%hu", ##__VA_ARGS__)
710 /*! \brief check pointer */
711 #define CHKEXPR_PTR(val, expr, ...) CHKEXPR(val, expr, "%p", ##__VA_ARGS__)
713 
714 //
715 // Data
716 //
717 
718 // Log threshold level (log iff level <= threshold)
719 #ifdef LOG
720 extern int LOG_VAR_THRESHOLD; ///< current logging threshold variable
721 extern bool_t LOG_VAR_COLOR_EN; ///< color logging is [not] enabled
722 #endif // LOG
723 
724 
725 //-----------------------------------------------------------------------------
726 // Namespace C Definitions
727 //-----------------------------------------------------------------------------
728 
729 /*!
730  * \brief If logging is defined is a different logging name space, then
731  * LOGNS_DEF must be included into the application or library.
732  */
733 #if defined(LOGNS_DEF)
734  #if defined(LOG)
735  #define LOGNS_DEF_BLOCK \
736 extern "C" { \
737  int LOG_VAR_THRESHOLD = LOG_LEVEL_OFF; \
738  int LOG_SET_THRESHOLD(int nLevel) \
739  { \
740  LOG_VAR_THRESHOLD = nLevel; \
741  if( LOG_VAR_THRESHOLD >= LOG_LEVEL_DIAG1 ) \
742  { \
743  LOGGER(LOGARGS_DIAG(2, "Logging level set to %d", LOG_VAR_THRESHOLD)); \
744  } \
745  return LOG_VAR_THRESHOLD; \
746  } \
747  int LOG_GET_THRESHOLD() \
748  { \
749  return LOG_VAR_THRESHOLD; \
750  } \
751 }
752  #else
753  #define LOGNS_DEF_BLOCK \
754 extern "C" { \
755  int LOG_VAR_THRESHOLD = LOG_LEVEL_NA; \
756  int LOG_SET_THRESHOLD(int nLevel)
757  { \
758  return LOG_VAR_THRESHOLD; \
759  } \
760  int LOG_GET_THRESHOLD() \
761  { \
762  return LOG_VAR_THRESHOLD; \
763  } \
764 }
765  #endif
766 #else
767  #define LOGNS_DEF_BLOCK
768 #endif
769 
770 
771 //-----------------------------------------------------------------------------
772 // Prototypes
773 //-----------------------------------------------------------------------------
774 
775 //
776 // <namespace>LogSetThresholdLevel()
777 // Set new logging threshold level. Always compile for blind sets.
778 //
779 extern int LOG_SET_THRESHOLD(int nLevel);
780 
781 //
782 // <namespace>LogGetThresholdLevel()
783 // Get current logging threshold level. Always compile to determine logging
784 // availability.
785 //
786 extern int LOG_GET_THRESHOLD();
787 
788 //
789 // <namespace>LogSetColorEnable()
790 // Enable/disable color logging.
791 //
792 extern void LOG_SET_COLOR_ENABLE(bool_t enable);
793 
794 //
795 // <namespace>LogSetTimestampEnable()
796 // Enable/disable logging timestamps.
797 //
798 extern void LOG_SET_TIMESTAMP_ENABLE(bool_t enable);
799 
800 //
801 // <namespace>LogSetLogFile()
802 // Set logging ouput to file. Always compile for blind sets.
803 //
804 extern int LOG_SET_LOGFILE(const char *sLogFileName);
805 
806 //
807 // <namespace>LogGetLogFile()
808 // Get logging ouput to file name.
809 //
810 #ifdef LOG
811 extern const char *LOG_GET_LOGFILE();
812 #endif // LOG
813 
814 //
815 // <namespace>LogAttachLogFp()
816 // Attach file pointer as logging ouput stream.
817 //
818 #ifdef LOG
819 extern void LOG_ATTACH_LOGFP(FILE *fp, const char *sFpFileName);
820 #endif // LOG
821 
822 //
823 // <namespace>LogGetLogFp()
824 // Get current logging ouput stream file pointer.
825 //
826 #ifdef LOG
827 extern FILE *LOG_GET_LOGFP();
828 #endif // LOG
829 
830 //
831 // <namespace>LogPrintf()
832 // Print loggging diagnostics, debug, error, and system error messages to
833 // logging output stream.
834 //
835 // Arguments:
836 // sFmt - format string
837 // ... - variable format arguments
838 //
839 // Return Values:
840 // None
841 //
842 #ifdef LOG
843 extern void LOGGER(const char *sFmt, ...);
844 #endif // LOG
845 
846 //
847 // <namespace>LogCallPrintf()
848 // Print function call tracing to logging output stream.
849 //
850 // Arguments:
851 // sFmt - format string
852 // ... - format-arguments pairs
853 //
854 // Return Values:
855 // None
856 //
857 #ifdef LOG
858 extern void LOGGER_CALL(const char *sPreface, int nLevel,
859  const char *sFile, int nLine,
860  const char *sFuncName, ...);
861 #endif // LOG
862 
864 
865 
866 #endif // _RNR_LOG_H
#define LOG_SET_LOGFILE
set output log file function name
Definition: log.h:158
#define LOG_SET_THRESHOLD
set threshold function name
Definition: log.h:149
#define LOG_GET_THRESHOLD
get threshold function name
Definition: log.h:152
#define LOG_SET_TIMESTAMP_ENABLE
enable/disable logging timestamps func name
Definition: log.h:164
#define LOG_GET_LOGFP
get current logging out stream file pointer
Definition: log.h:168
#define C_DECLS_BEGIN
C declaration block begin in C.
Definition: rnrconfig.h:71
#define LOG_VAR_COLOR_EN
logging in color is [not] enabled
Definition: log.h:155
#define LOG_ATTACH_LOGFP
attach file pointer as logging out stream
Definition: log.h:166
int bool_t
"boolean" T/F
Definition: rnrconfig.h:187
RoadNarrows Robotics common configuration file.
#define LOG_VAR_THRESHOLD
current threshold variable name
Definition: log.h:146
#define C_DECLS_END
C declaration block end in C.
Definition: rnrconfig.h:72
#define LOG_GET_LOGFILE
get output log file function name
Definition: log.h:160
#define LOG_SET_COLOR_ENABLE
enable/disable logging in color func name
Definition: log.h:162
#define LOGGER
logger function name
Definition: log.h:170
#define LOGGER_CALL
logger of "function call" function name
Definition: log.h:172