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