1 /*
2 * Copyright 2015-2023 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 #ifdef __cplusplus
11 extern "C" {
12 #endif
13
14 #ifndef PCMK__LOGGING_INTERNAL_H
15 # define PCMK__LOGGING_INTERNAL_H
16
17 # include <glib.h>
18
19 # include <crm/common/logging.h>
20 # include <crm/common/output_internal.h>
21
22 typedef void (*pcmk__config_error_func) (void *ctx, const char *msg, ...);
23 typedef void (*pcmk__config_warning_func) (void *ctx, const char *msg, ...);
24
25 extern pcmk__config_error_func pcmk__config_error_handler;
26 extern pcmk__config_warning_func pcmk__config_warning_handler;
27
28 extern void *pcmk__config_error_context;
29 extern void *pcmk__config_warning_context;
30
31 void pcmk__set_config_error_handler(pcmk__config_error_func error_handler, void *error_context);
32 void pcmk__set_config_warning_handler(pcmk__config_warning_func warning_handler, void *warning_context);
33
34 /*!
35 * \internal
36 * \brief Log a configuration error
37 *
38 * \param[in] fmt printf(3)-style format string
39 * \param[in] ... Arguments for format string
40 */
41 # define pcmk__config_err(fmt...) do { \
42 crm_config_error = TRUE; \
43 if (pcmk__config_error_handler == NULL) { \
44 crm_err(fmt); \
45 } else { \
46 pcmk__config_error_handler(pcmk__config_error_context, fmt); \
47 } \
48 } while (0)
49
50 /*!
51 * \internal
52 * \brief Log a configuration warning
53 *
54 * \param[in] fmt printf(3)-style format string
55 * \param[in] ... Arguments for format string
56 */
57 # define pcmk__config_warn(fmt...) do { \
58 crm_config_warning = TRUE; \
59 if (pcmk__config_warning_handler == NULL) { \
60 crm_warn(fmt); \
61 } else { \
62 pcmk__config_warning_handler(pcmk__config_warning_context, fmt); \
63 } \
64 } while (0)
65
66 /*!
67 * \internal
68 * \brief Execute code depending on whether trace logging is enabled
69 *
70 * This is similar to \p do_crm_log_unlikely() except instead of logging, it
71 * selects one of two code blocks to execute.
72 *
73 * \param[in] if_action Code block to execute if trace logging is enabled
74 * \param[in] else_action Code block to execute if trace logging is not enabled
75 *
76 * \note Neither \p if_action nor \p else_action can contain a \p break or
77 * \p continue statement.
78 */
79 # define pcmk__if_tracing(if_action, else_action) do { \
80 static struct qb_log_callsite *trace_cs = NULL; \
81 \
82 if (trace_cs == NULL) { \
83 trace_cs = qb_log_callsite_get(__func__, __FILE__, \
84 "if_tracing", LOG_TRACE, \
85 __LINE__, crm_trace_nonlog); \
86 } \
87 if (crm_is_callsite_active(trace_cs, LOG_TRACE, \
88 crm_trace_nonlog)) { \
89 if_action; \
90 } else { \
91 else_action; \
92 } \
93 } while (0)
94
95 /*!
96 * \internal
97 * \brief Log XML changes line-by-line in a formatted fashion
98 *
99 * \param[in] level Priority at which to log the messages
100 * \param[in] xml XML to log
101 *
102 * \note This does nothing when \p level is \c LOG_STDOUT.
103 */
104 #define pcmk__log_xml_changes(level, xml) do { \
105 uint8_t _level = pcmk__clip_log_level(level); \
106 static struct qb_log_callsite *xml_cs = NULL; \
107 \
108 switch (_level) { \
109 case LOG_STDOUT: \
110 case LOG_NEVER: \
111 break; \
112 default: \
113 if (xml_cs == NULL) { \
114 xml_cs = qb_log_callsite_get(__func__, __FILE__, \
115 "xml-changes", _level, \
116 __LINE__, 0); \
117 } \
118 if (crm_is_callsite_active(xml_cs, _level, 0)) { \
119 pcmk__log_xml_changes_as(__FILE__, __func__, __LINE__, \
120 0, _level, xml); \
121 } \
122 break; \
123 } \
124 } while(0)
125
126 /*!
127 * \internal
128 * \brief Log an XML patchset line-by-line in a formatted fashion
129 *
130 * \param[in] level Priority at which to log the messages
131 * \param[in] patchset XML patchset to log
132 *
133 * \note This does nothing when \p level is \c LOG_STDOUT.
134 */
135 #define pcmk__log_xml_patchset(level, patchset) do { \
136 uint8_t _level = pcmk__clip_log_level(level); \
137 static struct qb_log_callsite *xml_cs = NULL; \
138 \
139 switch (_level) { \
140 case LOG_STDOUT: \
141 case LOG_NEVER: \
142 break; \
143 default: \
144 if (xml_cs == NULL) { \
145 xml_cs = qb_log_callsite_get(__func__, __FILE__, \
146 "xml-patchset", _level, \
147 __LINE__, 0); \
148 } \
149 if (crm_is_callsite_active(xml_cs, _level, 0)) { \
150 pcmk__log_xml_patchset_as(__FILE__, __func__, __LINE__, \
151 0, _level, patchset); \
152 } \
153 break; \
154 } \
155 } while(0)
156
157 void pcmk__log_xml_changes_as(const char *file, const char *function,
158 uint32_t line, uint32_t tags, uint8_t level,
159 const xmlNode *xml);
160
161 void pcmk__log_xml_patchset_as(const char *file, const char *function,
162 uint32_t line, uint32_t tags, uint8_t level,
163 const xmlNode *patchset);
164
165 /*!
166 * \internal
167 * \brief Initialize logging for command line tools
168 *
169 * \param[in] name The name of the program
170 * \param[in] verbosity How verbose to be in logging
171 *
172 * \note \p verbosity is not the same as the logging level (LOG_ERR, etc.).
173 */
174 void pcmk__cli_init_logging(const char *name, unsigned int verbosity);
175
176 int pcmk__add_logfile(const char *filename);
177 void pcmk__add_logfiles(gchar **log_files, pcmk__output_t *out);
178
179 void pcmk__free_common_logger(void);
180
181 #ifdef __cplusplus
182 }
183 #endif
184
185 #endif