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