root/include/crm/common/logging.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. pcmk__clip_log_level

   1 /*
   2  * Copyright 2004-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #ifndef PCMK__CRM_COMMON_LOGGING__H
  11 #define PCMK__CRM_COMMON_LOGGING__H
  12 
  13 #include <stdio.h>
  14 #include <stdint.h>             // uint8_t, uint32_t
  15 #include <glib.h>
  16 #include <qb/qblog.h>
  17 #include <libxml/tree.h>
  18 
  19 #ifdef __cplusplus
  20 extern "C" {
  21 #endif
  22 
  23 /**
  24  * \file
  25  * \brief Wrappers for and extensions to libqb logging
  26  * \ingroup core
  27  */
  28 
  29 
  30 /* Define custom log priorities.
  31  *
  32  * syslog(3) uses int for priorities, but libqb's struct qb_log_callsite uses
  33  * uint8_t, so make sure they fit in the latter.
  34  */
  35 
  36 // Define something even less desired than debug
  37 #ifndef LOG_TRACE
  38 #define LOG_TRACE   (LOG_DEBUG+1)
  39 #endif
  40 
  41 // Print message to stdout instead of logging it
  42 #ifndef LOG_STDOUT
  43 #define LOG_STDOUT  254
  44 #endif
  45 
  46 // Don't send message anywhere
  47 #ifndef LOG_NEVER
  48 #define LOG_NEVER   255
  49 #endif
  50 
  51 // @COMPAT Make internal when we can break API backward compatibility
  52 //! \deprecated Do not use
  53 extern unsigned int crm_log_level;
  54 
  55 // @COMPAT Make internal when we can break API backward compatibility
  56 //! \deprecated Do not use
  57 extern unsigned int crm_trace_nonlog;
  58 
  59 void crm_enable_blackbox(int nsig);
  60 void crm_disable_blackbox(int nsig);
  61 void crm_write_blackbox(int nsig, const struct qb_log_callsite *callsite);
  62 
  63 void crm_update_callsites(void);
  64 
  65 void crm_log_deinit(void);
  66 
  67 /*!
  68  * \brief Initializes the logging system and defaults to the least verbose output level
  69  *
  70  * \param[in] entity  If not NULL, will be used as the identity for logging purposes
  71  * \param[in] argc    The number of command line parameters
  72  * \param[in] argv    The command line parameter values
  73  */
  74 void crm_log_preinit(const char *entity, int argc, char *const *argv);
  75 gboolean crm_log_init(const char *entity, uint8_t level, gboolean daemon,
  76                       gboolean to_stderr, int argc, char **argv, gboolean quiet);
  77 
  78 void crm_log_args(int argc, char **argv);
  79 void crm_log_output_fn(const char *file, const char *function, int line, int level,
  80                        const char *prefix, const char *output);
  81 
  82 // Log a block of text line by line
  83 #define crm_log_output(level, prefix, output)   \
  84     crm_log_output_fn(__FILE__, __func__, __LINE__, level, prefix, output)
  85 
  86 void crm_bump_log_level(int argc, char **argv);
  87 
  88 void crm_enable_stderr(int enable);
  89 
  90 gboolean crm_is_callsite_active(struct qb_log_callsite *cs, uint8_t level, uint32_t tags);
  91 
  92 // NOTE: sbd (as of at least 1.5.2) uses this
  93 /* returns the old value */
  94 unsigned int set_crm_log_level(unsigned int level);
  95 
  96 unsigned int get_crm_log_level(void);
  97 
  98 void pcmk_log_xml_as(const char *file, const char *function, uint32_t line,
  99                      uint32_t tags, uint8_t level, const char *text,
 100                      const xmlNode *xml);
 101 
 102 /*
 103  * Throughout the macros below, note the leading, pre-comma, space in the
 104  * various ' , ##args' occurrences to aid portability across versions of 'gcc'.
 105  * https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros
 106  */
 107 #if defined(__clang__)
 108 #define CRM_TRACE_INIT_DATA(name)
 109 #else
 110 #include <assert.h> // required by QB_LOG_INIT_DATA() macro
 111 #define CRM_TRACE_INIT_DATA(name) QB_LOG_INIT_DATA(name)
 112 #endif
 113 
 114 /*!
 115  * \internal
 116  * \brief Clip log_level to \p uint8_t range
 117  *
 118  * \param[in] level  Log level to clip
 119  *
 120  * \return 0 if \p level is less than 0, \p UINT8_MAX if \p level is greater
 121  *         than \p UINT8_MAX, or \p level otherwise
 122  */
 123 /* @COMPAT: Make this function internal at a compatibility break. It's used in
 124  * public macros for now.
 125  */
 126 static inline uint8_t
 127 pcmk__clip_log_level(int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129     if (level <= 0) {
 130         return 0;
 131     }
 132     if (level >= UINT8_MAX) {
 133         return UINT8_MAX;
 134     }
 135     return level;
 136 }
 137 
 138 /* Using "switch" instead of "if" in these macro definitions keeps
 139  * static analysis from complaining about constant evaluations
 140  */
 141 
 142 /*!
 143  * \brief Log a message
 144  *
 145  * \param[in] level  Priority at which to log the message
 146  * \param[in] fmt    printf-style format string literal for message
 147  * \param[in] args   Any arguments needed by format string
 148  */
 149 #define do_crm_log(level, fmt, args...) do {                                \
 150         uint8_t _level = pcmk__clip_log_level(level);                       \
 151                                                                             \
 152         switch (_level) {                                                   \
 153             case LOG_STDOUT:                                                \
 154                 printf(fmt "\n" , ##args);                                  \
 155                 break;                                                      \
 156             case LOG_NEVER:                                                 \
 157                 break;                                                      \
 158             default:                                                        \
 159                 qb_log_from_external_source(__func__, __FILE__, fmt,        \
 160                                             _level, __LINE__, 0 , ##args);  \
 161                 break;                                                      \
 162         }                                                                   \
 163     } while (0)
 164 
 165 /*!
 166  * \brief Log a message that is likely to be filtered out
 167  *
 168  * \param[in] level  Priority at which to log the message
 169  * \param[in] fmt    printf-style format string for message
 170  * \param[in] args   Any arguments needed by format string
 171  *
 172  * \note This does nothing when level is \p LOG_STDOUT.
 173  */
 174 #define do_crm_log_unlikely(level, fmt, args...) do {                       \
 175         uint8_t _level = pcmk__clip_log_level(level);                       \
 176                                                                             \
 177         switch (_level) {                                                   \
 178             case LOG_STDOUT: case LOG_NEVER:                                \
 179                 break;                                                      \
 180             default: {                                                      \
 181                 static struct qb_log_callsite *trace_cs = NULL;             \
 182                 if (trace_cs == NULL) {                                     \
 183                     trace_cs = qb_log_callsite_get(__func__, __FILE__, fmt, \
 184                                                    _level, __LINE__, 0);    \
 185                 }                                                           \
 186                 if (crm_is_callsite_active(trace_cs, _level, 0)) {          \
 187                     qb_log_from_external_source(__func__, __FILE__, fmt,    \
 188                                                 _level, __LINE__, 0 ,       \
 189                                                 ##args);                    \
 190                 }                                                           \
 191             }                                                               \
 192             break;                                                          \
 193         }                                                                   \
 194     } while (0)
 195 
 196 #define CRM_LOG_ASSERT(expr) do {                                       \
 197         if (!(expr)) {                                                  \
 198             static struct qb_log_callsite *core_cs = NULL;              \
 199             if(core_cs == NULL) {                                       \
 200                 core_cs = qb_log_callsite_get(__func__, __FILE__,       \
 201                                               "log-assert", LOG_TRACE,  \
 202                                               __LINE__, 0);             \
 203             }                                                           \
 204             crm_abort(__FILE__, __func__, __LINE__, #expr,              \
 205                       core_cs?core_cs->targets:FALSE, TRUE);            \
 206         }                                                               \
 207     } while(0)
 208 
 209 // NOTE: sbd (as of at least 1.5.2) uses this
 210 /* 'failure_action' MUST NOT be 'continue' as it will apply to the
 211  * macro's do-while loop
 212  */
 213 #define CRM_CHECK(expr, failure_action) do {                            \
 214         if (!(expr)) {                                                  \
 215             static struct qb_log_callsite *core_cs = NULL;              \
 216             if (core_cs == NULL) {                                      \
 217                 core_cs = qb_log_callsite_get(__func__, __FILE__,       \
 218                                               "check-assert",           \
 219                                               LOG_TRACE, __LINE__, 0);  \
 220             }                                                           \
 221             crm_abort(__FILE__, __func__, __LINE__, #expr,              \
 222                 (core_cs? core_cs->targets: FALSE), TRUE);              \
 223             failure_action;                                             \
 224         }                                                               \
 225     } while(0)
 226 
 227 /*!
 228  * \brief Log XML line-by-line in a formatted fashion
 229  *
 230  * \param[in] level  Priority at which to log the messages
 231  * \param[in] text   Prefix for each line
 232  * \param[in] xml    XML to log
 233  *
 234  * \note This does nothing when \p level is \p LOG_STDOUT.
 235  */
 236 #define do_crm_log_xml(level, text, xml) do {                           \
 237         uint8_t _level = pcmk__clip_log_level(level);                   \
 238         static struct qb_log_callsite *xml_cs = NULL;                   \
 239                                                                         \
 240         switch (_level) {                                               \
 241             case LOG_STDOUT:                                            \
 242             case LOG_NEVER:                                             \
 243                 break;                                                  \
 244             default:                                                    \
 245                 if (xml_cs == NULL) {                                   \
 246                     xml_cs = qb_log_callsite_get(__func__, __FILE__,    \
 247                                                  "xml-blob", _level,    \
 248                                                  __LINE__, 0);          \
 249                 }                                                       \
 250                 if (crm_is_callsite_active(xml_cs, _level, 0)) {        \
 251                     pcmk_log_xml_as(__FILE__, __func__, __LINE__, 0,    \
 252                                     _level, text, (xml));               \
 253                 }                                                       \
 254                 break;                                                  \
 255         }                                                               \
 256     } while(0)
 257 
 258 /*!
 259  * \brief Log a message as if it came from a different code location
 260  *
 261  * \param[in] level     Priority at which to log the message
 262  * \param[in] file      Source file name to use instead of __FILE__
 263  * \param[in] function  Source function name to use instead of __func__
 264  * \param[in] line      Source line number to use instead of __line__
 265  * \param[in] fmt       printf-style format string literal for message
 266  * \param[in] args      Any arguments needed by format string
 267  */
 268 #define do_crm_log_alias(level, file, function, line, fmt, args...) do {    \
 269         uint8_t _level = pcmk__clip_log_level(level);                       \
 270                                                                             \
 271         switch (_level) {                                                   \
 272             case LOG_STDOUT:                                                \
 273                 printf(fmt "\n" , ##args);                                  \
 274                 break;                                                      \
 275             case LOG_NEVER:                                                 \
 276                 break;                                                      \
 277             default:                                                        \
 278                 qb_log_from_external_source(function, file, fmt, _level,    \
 279                                             line, 0 , ##args);              \
 280                 break;                                                      \
 281         }                                                                   \
 282     } while (0)
 283 
 284 // NOTE: sbd (as of at least 1.5.2) uses this
 285 /*!
 286  * \brief Send a system error message to both the log and stderr
 287  *
 288  * \param[in] level  Priority at which to log the message
 289  * \param[in] fmt    printf-style format string for message
 290  * \param[in] args   Any arguments needed by format string
 291  *
 292  * \deprecated One of the other logging functions should be used with
 293  *             pcmk_strerror() instead.
 294  * \note This is a macro, and \p level may be evaluated more than once.
 295  * \note Because crm_perror() adds the system error message and error number
 296  *       onto the end of fmt, that information will become extended information
 297  *       if QB_XS is used inside fmt and will not show up in syslog.
 298  */
 299 #define crm_perror(level, fmt, args...) do {                                \
 300         uint8_t _level = pcmk__clip_log_level(level);                       \
 301                                                                             \
 302         switch (_level) {                                                   \
 303             case LOG_NEVER:                                                 \
 304                 break;                                                      \
 305             default: {                                                      \
 306                 const char *err = strerror(errno);                          \
 307                 if (_level <= crm_log_level) {                              \
 308                     fprintf(stderr, fmt ": %s (%d)\n" , ##args, err,        \
 309                             errno);                                         \
 310                 }                                                           \
 311                 /* Pass original level arg since do_crm_log() also declares \
 312                  * _level                                                   \
 313                  */                                                         \
 314                 do_crm_log((level), fmt ": %s (%d)" , ##args, err, errno);  \
 315             }                                                               \
 316             break;                                                          \
 317         }                                                                   \
 318     } while (0)
 319 
 320 /*!
 321  * \brief Log a message with a tag (for use with PCMK_trace_tags)
 322  *
 323  * \param[in] level  Priority at which to log the message
 324  * \param[in] tag    String to tag message with
 325  * \param[in] fmt    printf-style format string for message
 326  * \param[in] args   Any arguments needed by format string
 327  *
 328  * \note This does nothing when level is LOG_STDOUT.
 329  */
 330 #define crm_log_tag(level, tag, fmt, args...) do {                          \
 331         uint8_t _level = pcmk__clip_log_level(level);                       \
 332                                                                             \
 333         switch (_level) {                                                   \
 334             case LOG_STDOUT: case LOG_NEVER:                                \
 335                 break;                                                      \
 336             default: {                                                      \
 337                 static struct qb_log_callsite *trace_tag_cs = NULL;         \
 338                 int converted_tag = g_quark_try_string(tag);                \
 339                 if (trace_tag_cs == NULL) {                                 \
 340                     trace_tag_cs = qb_log_callsite_get(__func__, __FILE__,  \
 341                                                        fmt, _level,         \
 342                                                        __LINE__,            \
 343                                                        converted_tag);      \
 344                 }                                                           \
 345                 if (crm_is_callsite_active(trace_tag_cs, _level,            \
 346                                            converted_tag)) {                \
 347                     qb_log_from_external_source(__func__, __FILE__, fmt,    \
 348                                                 _level, __LINE__,           \
 349                                                 converted_tag , ##args);    \
 350                 }                                                           \
 351             }                                                               \
 352         }                                                                   \
 353     } while (0)
 354 
 355 #define crm_emerg(fmt, args...)   qb_log(LOG_EMERG,       fmt , ##args)
 356 #define crm_crit(fmt, args...)    qb_logt(LOG_CRIT,    0, fmt , ##args)
 357 
 358 // NOTE: sbd (as of at least 1.5.2) uses this
 359 #define crm_err(fmt, args...)     qb_logt(LOG_ERR,     0, fmt , ##args)
 360 
 361 // NOTE: sbd (as of at least 1.5.2) uses this
 362 #define crm_warn(fmt, args...)    qb_logt(LOG_WARNING, 0, fmt , ##args)
 363 
 364 // NOTE: sbd (as of at least 1.5.2) uses this
 365 #define crm_notice(fmt, args...)  qb_logt(LOG_NOTICE,  0, fmt , ##args)
 366 
 367 #define crm_info(fmt, args...)    qb_logt(LOG_INFO,    0, fmt , ##args)
 368                                                 //
 369 // NOTE: sbd (as of at least 1.5.2) uses this
 370 #define crm_debug(fmt, args...)   do_crm_log_unlikely(LOG_DEBUG, fmt , ##args)
 371 
 372 #define crm_trace(fmt, args...)   do_crm_log_unlikely(LOG_TRACE, fmt , ##args)
 373 
 374 #define crm_log_xml_crit(xml, text)    do_crm_log_xml(LOG_CRIT,    text, xml)
 375 #define crm_log_xml_err(xml, text)     do_crm_log_xml(LOG_ERR,     text, xml)
 376 #define crm_log_xml_warn(xml, text)    do_crm_log_xml(LOG_WARNING, text, xml)
 377 #define crm_log_xml_notice(xml, text)  do_crm_log_xml(LOG_NOTICE,  text, xml)
 378 #define crm_log_xml_info(xml, text)    do_crm_log_xml(LOG_INFO,    text, xml)
 379 #define crm_log_xml_debug(xml, text)   do_crm_log_xml(LOG_DEBUG,   text, xml)
 380 #define crm_log_xml_trace(xml, text)   do_crm_log_xml(LOG_TRACE,   text, xml)
 381 
 382 #define crm_log_xml_explicit(xml, text)  do {                   \
 383         static struct qb_log_callsite *digest_cs = NULL;        \
 384         digest_cs = qb_log_callsite_get(                        \
 385             __func__, __FILE__, text, LOG_TRACE, __LINE__,      \
 386             crm_trace_nonlog);                                  \
 387         if (digest_cs && digest_cs->targets) {                  \
 388             do_crm_log_xml(LOG_TRACE,   text, xml);             \
 389         }                                                       \
 390     } while(0)
 391 
 392 #ifdef __cplusplus
 393 }
 394 #endif
 395 
 396 #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
 397 #include <crm/common/logging_compat.h>
 398 #endif
 399 
 400 #endif

/* [previous][next][first][last][top][bottom][index][help] */