pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
output_log.c
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2020 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 Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8  */
9 #ifndef _GNU_SOURCE
10 # define _GNU_SOURCE
11 #endif
12 
13 #include <ctype.h>
14 #include <libxml/HTMLtree.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 
19 #include <crm/crm.h>
20 #include <crm/common/xml.h>
22 
23 GOptionEntry pcmk__log_output_entries[] = {
24  { NULL }
25 };
26 
27 typedef struct private_data_s {
28  /* gathered in log_begin_list */
29  GQueue/*<char*>*/ *prefixes;
31 
32 static void
33 log_subprocess_output(pcmk__output_t *out, int exit_status,
34  const char *proc_stdout, const char *proc_stderr) {
35  /* This function intentionally left blank */
36 }
37 
38 static void
39 log_free_priv(pcmk__output_t *out) {
40  private_data_t *priv = out->priv;
41 
42  if (priv == NULL) {
43  return;
44  }
45 
46  g_queue_free(priv->prefixes);
47  free(priv);
48  out->priv = NULL;
49 }
50 
51 static bool
52 log_init(pcmk__output_t *out) {
53 
54  /* If log_init was previously called on this output struct, just return. */
55  if (out->priv != NULL) {
56  return true;
57  }
58 
59  out->priv = calloc(1, sizeof(private_data_t));
60  if (out->priv == NULL) {
61  return false;
62  }
63  ((private_data_t *)out->priv)->prefixes = g_queue_new();
64  return true;
65 }
66 
67 static void
68 log_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) {
69  /* This function intentionally left blank */
70 }
71 
72 static void
73 log_reset(pcmk__output_t *out) {
74  CRM_ASSERT(out != NULL);
75 
76  out->dest = freopen(NULL, "w", out->dest);
77  CRM_ASSERT(out->dest != NULL);
78 
79  log_free_priv(out);
80  log_init(out);
81 }
82 
83 static void
84 log_version(pcmk__output_t *out, bool extended) {
85  if (extended) {
86  crm_info("Pacemaker %s (Build: %s): %s",
88  } else {
89  crm_info("Pacemaker %s", PACEMAKER_VERSION);
90  crm_info("Written by Andrew Beekhof");
91  }
92 }
93 
94 G_GNUC_PRINTF(2, 3)
95 static void
96 log_err(pcmk__output_t *out, const char *format, ...) {
97  va_list ap;
98  char* buffer = NULL;
99  int len = 0;
100 
101  va_start(ap, format);
102  /* Informational output does not get indented, to separate it from other
103  * potentially indented list output.
104  */
105  len = vasprintf(&buffer, format, ap);
106  CRM_ASSERT(len >= 0);
107  va_end(ap);
108 
109  crm_err("%s", buffer);
110 
111  free(buffer);
112 }
113 
114 static void
115 log_output_xml(pcmk__output_t *out, const char *name, const char *buf) {
116  xmlNodePtr node = NULL;
117  private_data_t *priv = out->priv;
118  CRM_ASSERT(priv != NULL);
119 
120  node = create_xml_node(NULL, name);
121  xmlNodeSetContent(node, (pcmkXmlStr) buf);
122  crm_log_xml_info(node, name);
123  free(node);
124 }
125 
126 G_GNUC_PRINTF(4, 5)
127 static void
128 log_begin_list(pcmk__output_t *out, const char *singular_noun, const char *plural_noun,
129  const char *format, ...) {
130  int len = 0;
131  va_list ap;
132  char* buffer = NULL;
133  private_data_t *priv = out->priv;
134  CRM_ASSERT(priv != NULL);
135 
136  va_start(ap, format);
137  len = vasprintf(&buffer, format, ap);
138  CRM_ASSERT(len >= 0);
139  va_end(ap);
140 
141  /* Don't skip empty prefixes,
142  * otherwise there will be mismatch
143  * in the log_end_list */
144  if(strcmp(buffer, "") == 0) {
145  /* nothing */
146  }
147 
148  g_queue_push_tail(priv->prefixes, buffer);
149 }
150 
151 G_GNUC_PRINTF(3, 4)
152 static void
153 log_list_item(pcmk__output_t *out, const char *name, const char *format, ...) {
154  int len = 0;
155  va_list ap;
156  private_data_t *priv = out->priv;
157  char prefix[LINE_MAX] = { 0 };
158  int offset = 0;
159  char* buffer = NULL;
160 
161  CRM_ASSERT(priv != NULL);
162 
163  for (GList* gIter = priv->prefixes->head; gIter; gIter = gIter->next) {
164  if (strcmp(prefix, "") != 0) {
165  offset += snprintf(prefix + offset, LINE_MAX - offset, ": %s", (char *)gIter->data);
166  } else {
167  offset = snprintf(prefix, LINE_MAX, "%s", (char *)gIter->data);
168  }
169  }
170 
171  va_start(ap, format);
172  len = vasprintf(&buffer, format, ap);
173  CRM_ASSERT(len >= 0);
174  va_end(ap);
175 
176  if (strcmp(buffer, "") != 0) { /* We don't want empty messages */
177  if ((name != NULL) && (strcmp(name, "") != 0)) {
178  if (strcmp(prefix, "") != 0) {
179  crm_info("%s: %s: %s", prefix, name, buffer);
180  } else {
181  crm_info("%s: %s", name, buffer);
182  }
183  } else {
184  if (strcmp(prefix, "") != 0) {
185  crm_info("%s: %s", prefix, buffer);
186  } else {
187  crm_info("%s", buffer);
188  }
189  }
190  }
191  free(buffer);
192 }
193 
194 static void
195 log_end_list(pcmk__output_t *out) {
196  private_data_t *priv = out->priv;
197  CRM_ASSERT(priv != NULL);
198  if (priv->prefixes == NULL) {
199  return;
200  }
201  CRM_ASSERT(priv->prefixes->tail != NULL);
202 
203  free((char *)priv->prefixes->tail->data);
204  g_queue_pop_tail(priv->prefixes);
205 }
206 
207 G_GNUC_PRINTF(2, 3)
208 static void
209 log_info(pcmk__output_t *out, const char *format, ...) {
210  int len = 0;
211  va_list ap;
212  char* buffer = NULL;
213 
214  va_start(ap, format);
215  len = vasprintf(&buffer, format, ap);
216  CRM_ASSERT(len >= 0);
217  va_end(ap);
218 
219  crm_info("%s", buffer);
220 
221  free(buffer);
222 }
223 
224 static bool
225 log_is_quiet(pcmk__output_t *out) {
226  return false;
227 }
228 
230 pcmk__mk_log_output(char **argv) {
231  pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t));
232 
233  if (retval == NULL) {
234  return NULL;
235  }
236 
237  retval->fmt_name = "log";
238  retval->request = argv == NULL ? NULL : g_strjoinv(" ", argv);
239 
240  retval->init = log_init;
241  retval->free_priv = log_free_priv;
242  retval->finish = log_finish;
243  retval->reset = log_reset;
244 
246  retval->message = pcmk__call_message;
247 
248  retval->subprocess_output = log_subprocess_output;
249  retval->version = log_version;
250  retval->info = log_info;
251  retval->err = log_err;
252  retval->output_xml = log_output_xml;
253 
254  retval->begin_list = log_begin_list;
255  retval->list_item = log_list_item;
256  retval->end_list = log_end_list;
257 
258  retval->is_quiet = log_is_quiet;
259 
260  return retval;
261 }
void(* end_list)(pcmk__output_t *out)
A dumping ground.
int(* message)(pcmk__output_t *out, const char *message_id,...)
const char * fmt_name
The name of this output formatter.
bool(* is_quiet)(pcmk__output_t *out)
void pcmk__register_message(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn)
Definition: output.c:139
enum crm_exit_e crm_exit_t
void(*) void(* err)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
#define PACEMAKER_VERSION
Definition: config.h:514
int pcmk__call_message(pcmk__output_t *out, const char *message_id,...)
Definition: output.c:121
void(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
void * priv
Implementation-specific private data.
Formatted output for pacemaker tools.
void(* register_message)(pcmk__output_t *out, const char *message_id, pcmk__message_fn_t fn)
#define BUILD_VERSION
Definition: config.h:8
struct private_data_s private_data_t
void(* free_priv)(pcmk__output_t *out)
bool(* init)(pcmk__output_t *out)
Wrappers for and extensions to libxml2.
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:663
void(*) void(*) void(* output_xml)(pcmk__output_t *out, const char *name, const char *buf)
GOptionEntry pcmk__log_output_entries[]
Definition: output_log.c:23
FILE * dest
Where output should be written.
const xmlChar * pcmkXmlStr
Definition: xml.h:51
#define crm_err(fmt, args...)
Definition: logging.h:347
#define CRM_ASSERT(expr)
Definition: results.h:42
void(*) void(* list_item)(pcmk__output_t *out, const char *name, const char *format,...) G_GNUC_PRINTF(3
struct private_data_s private_data_t
gchar * request
A copy of the request that generated this output.
This structure contains everything that makes up a single output formatter.
#define crm_log_xml_info(xml, text)
Definition: logging.h:359
void(* version)(pcmk__output_t *out, bool extended)
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
void(* reset)(pcmk__output_t *out)
char * name
Definition: pcmk_fence.c:31
#define CRM_FEATURES
Definition: config.h:35
pcmk__output_t * pcmk__mk_log_output(char **argv)
Definition: output_log.c:230
#define crm_info(fmt, args...)
Definition: logging.h:350
void(* subprocess_output)(pcmk__output_t *out, int exit_status, const char *proc_stdout, const char *proc_stderr)