1 /*
2 * Copyright 2015-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 #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 /* Some warnings are too noisy when logged every time a given function is called
23 * (for example, using a deprecated feature). As an alternative, we allow
24 * warnings to be logged once per invocation of the calling program. Each of
25 * those warnings needs a flag defined here.
26 */
27 enum pcmk__warnings {
28 pcmk__wo_blind = (1 << 0),
29 pcmk__wo_restart_type = (1 << 1),
30 pcmk__wo_role_after = (1 << 2),
31 pcmk__wo_poweroff = (1 << 3),
32 pcmk__wo_require_all = (1 << 4),
33 pcmk__wo_order_score = (1 << 5),
34 pcmk__wo_neg_threshold = (1 << 6),
35 pcmk__wo_remove_after = (1 << 7),
36 pcmk__wo_ping_node = (1 << 8),
37 pcmk__wo_order_inst = (1 << 9),
38 pcmk__wo_coloc_inst = (1 << 10),
39 pcmk__wo_group_order = (1 << 11),
40 pcmk__wo_group_coloc = (1 << 12),
41 pcmk__wo_upstart = (1 << 13),
42 pcmk__wo_nagios = (1 << 14),
43 pcmk__wo_set_ordering = (1 << 15),
44 pcmk__wo_rdisc_enabled = (1 << 16),
45 pcmk__wo_rkt = (1 << 17),
46 pcmk__wo_location_rules = (1 << 18),
47 pcmk__wo_op_attr_expr = (1 << 19),
48 pcmk__wo_instance_defaults = (1 << 20),
49 pcmk__wo_multiple_rules = (1 << 21),
50 pcmk__wo_master_element = (1 << 22),
51 pcmk__wo_clone_master_max = (1 << 23),
52 pcmk__wo_clone_master_node_max = (1 << 24),
53 pcmk__wo_bundle_master = (1 << 25),
54 pcmk__wo_master_role = (1 << 26),
55 pcmk__wo_slave_role = (1 << 27),
56 };
57
58 /*!
59 * \internal
60 * \brief Log a warning once per invocation of calling program
61 *
62 * \param[in] wo_flag enum pcmk__warnings value for this warning
63 * \param[in] fmt... printf(3)-style format and arguments
64 */
65 #define pcmk__warn_once(wo_flag, fmt...) do { \
66 if (!pcmk_is_set(pcmk__warnings, wo_flag)) { \
67 if (wo_flag == pcmk__wo_blind) { \
68 crm_warn(fmt); \
69 } else { \
70 pcmk__config_warn(fmt); \
71 } \
72 pcmk__warnings = pcmk__set_flags_as(__func__, __LINE__, \
73 LOG_TRACE, \
74 "Warn-once", "logging", \
75 pcmk__warnings, \
76 (wo_flag), #wo_flag); \
77 } \
78 } while (0)
79
80 typedef void (*pcmk__config_error_func) (void *ctx, const char *msg, ...)
81 G_GNUC_PRINTF(2, 3);
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
82 typedef void (*pcmk__config_warning_func) (void *ctx, const char *msg, ...)
83 G_GNUC_PRINTF(2, 3);
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
84
85 extern pcmk__config_error_func pcmk__config_error_handler;
86 extern pcmk__config_warning_func pcmk__config_warning_handler;
87
88 extern void *pcmk__config_error_context;
89 extern void *pcmk__config_warning_context;
90
91 void pcmk__set_config_error_handler(pcmk__config_error_func error_handler, void *error_context);
92 void pcmk__set_config_warning_handler(pcmk__config_warning_func warning_handler, void *warning_context);
93
94 /*!
95 * \internal
96 * \brief Log an error and make crm_verify return failure status
97 *
98 * \param[in] fmt... printf(3)-style format string and arguments
99 */
100 #define pcmk__config_err(fmt...) do { \
101 crm_config_error = TRUE; \
102 if (pcmk__config_error_handler == NULL) { \
103 crm_err(fmt); \
104 } else { \
105 pcmk__config_error_handler(pcmk__config_error_context, fmt); \
106 } \
107 } while (0)
108
109 /*!
110 * \internal
111 * \brief Log a warning and make crm_verify return failure status
112 *
113 * \param[in] fmt... printf(3)-style format string and arguments
114 */
115 #define pcmk__config_warn(fmt...) do { \
116 crm_config_warning = TRUE; \
117 if (pcmk__config_warning_handler == NULL) { \
118 crm_warn(fmt); \
119 } else { \
120 pcmk__config_warning_handler(pcmk__config_warning_context, fmt);\
121 } \
122 } while (0)
123
124 /*!
125 * \internal
126 * \brief Execute code depending on whether trace logging is enabled
127 *
128 * This is similar to \p do_crm_log_unlikely() except instead of logging, it
129 * selects one of two code blocks to execute.
130 *
131 * \param[in] if_action Code block to execute if trace logging is enabled
132 * \param[in] else_action Code block to execute if trace logging is not enabled
133 *
134 * \note Neither \p if_action nor \p else_action can contain a \p break or
135 * \p continue statement.
136 */
137 #define pcmk__if_tracing(if_action, else_action) do { \
138 static struct qb_log_callsite *trace_cs = NULL; \
139 \
140 if (trace_cs == NULL) { \
141 trace_cs = qb_log_callsite_get(__func__, __FILE__, \
142 "if_tracing", LOG_TRACE, \
143 __LINE__, crm_trace_nonlog); \
144 } \
145 if (crm_is_callsite_active(trace_cs, LOG_TRACE, \
146 crm_trace_nonlog)) { \
147 if_action; \
148 } else { \
149 else_action; \
150 } \
151 } while (0)
152
153 /*!
154 * \internal
155 * \brief Log XML changes line-by-line in a formatted fashion
156 *
157 * \param[in] level Priority at which to log the messages
158 * \param[in] xml XML to log
159 *
160 * \note This does nothing when \p level is \c LOG_STDOUT.
161 */
162 #define pcmk__log_xml_changes(level, xml) do { \
163 uint8_t _level = pcmk__clip_log_level(level); \
164 static struct qb_log_callsite *xml_cs = NULL; \
165 \
166 switch (_level) { \
167 case LOG_STDOUT: \
168 case LOG_NEVER: \
169 break; \
170 default: \
171 if (xml_cs == NULL) { \
172 xml_cs = qb_log_callsite_get(__func__, __FILE__, \
173 "xml-changes", _level, \
174 __LINE__, 0); \
175 } \
176 if (crm_is_callsite_active(xml_cs, _level, 0)) { \
177 pcmk__log_xml_changes_as(__FILE__, __func__, __LINE__, \
178 0, _level, xml); \
179 } \
180 break; \
181 } \
182 } while(0)
183
184 /*!
185 * \internal
186 * \brief Log an XML patchset line-by-line in a formatted fashion
187 *
188 * \param[in] level Priority at which to log the messages
189 * \param[in] patchset XML patchset to log
190 *
191 * \note This does nothing when \p level is \c LOG_STDOUT.
192 */
193 #define pcmk__log_xml_patchset(level, patchset) do { \
194 uint8_t _level = pcmk__clip_log_level(level); \
195 static struct qb_log_callsite *xml_cs = NULL; \
196 \
197 switch (_level) { \
198 case LOG_STDOUT: \
199 case LOG_NEVER: \
200 break; \
201 default: \
202 if (xml_cs == NULL) { \
203 xml_cs = qb_log_callsite_get(__func__, __FILE__, \
204 "xml-patchset", _level, \
205 __LINE__, 0); \
206 } \
207 if (crm_is_callsite_active(xml_cs, _level, 0)) { \
208 pcmk__log_xml_patchset_as(__FILE__, __func__, __LINE__, \
209 0, _level, patchset); \
210 } \
211 break; \
212 } \
213 } while(0)
214
215 void pcmk__log_xml_changes_as(const char *file, const char *function,
216 uint32_t line, uint32_t tags, uint8_t level,
217 const xmlNode *xml);
218
219 void pcmk__log_xml_patchset_as(const char *file, const char *function,
220 uint32_t line, uint32_t tags, uint8_t level,
221 const xmlNode *patchset);
222
223 /*!
224 * \internal
225 * \brief Initialize logging for command line tools
226 *
227 * \param[in] name The name of the program
228 * \param[in] verbosity How verbose to be in logging
229 *
230 * \note \p verbosity is not the same as the logging level (LOG_ERR, etc.).
231 */
232 void pcmk__cli_init_logging(const char *name, unsigned int verbosity);
233
234 int pcmk__add_logfile(const char *filename);
235 void pcmk__add_logfiles(gchar **log_files, pcmk__output_t *out);
236
237 void pcmk__free_common_logger(void);
238
239 #ifdef __cplusplus
240 }
241 #endif
242
243 #endif