root/lib/common/output_log.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. log_subprocess_output
  2. log_free_priv
  3. log_init
  4. log_finish
  5. log_reset
  6. log_version
  7. G_GNUC_PRINTF
  8. log_output_xml
  9. G_GNUC_PRINTF
  10. G_GNUC_PRINTF
  11. log_end_list
  12. G_GNUC_PRINTF
  13. log_is_quiet
  14. log_spacer
  15. log_progress
  16. log_prompt
  17. pcmk__mk_log_output
  18. pcmk__output_set_log_level

   1 /*
   2  * Copyright 2019-2021 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 
  10 #include <crm_internal.h>
  11 
  12 #include <ctype.h>
  13 #include <stdarg.h>
  14 #include <stdlib.h>
  15 #include <stdio.h>
  16 
  17 GOptionEntry pcmk__log_output_entries[] = {
  18     { NULL }
  19 };
  20 
  21 typedef struct private_data_s {
  22     /* gathered in log_begin_list */
  23     GQueue/*<char*>*/ *prefixes;
  24     int log_level;
  25 } private_data_t;
  26 
  27 static void
  28 log_subprocess_output(pcmk__output_t *out, int exit_status,
     /* [previous][next][first][last][top][bottom][index][help] */
  29                       const char *proc_stdout, const char *proc_stderr) {
  30     /* This function intentionally left blank */
  31 }
  32 
  33 static void
  34 log_free_priv(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
  35     private_data_t *priv = out->priv;
  36 
  37     if (priv == NULL) {
  38         return;
  39     }
  40 
  41     g_queue_free(priv->prefixes);
  42     free(priv);
  43     out->priv = NULL;
  44 }
  45 
  46 static bool
  47 log_init(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
  48     private_data_t *priv = NULL;
  49 
  50     /* If log_init was previously called on this output struct, just return. */
  51     if (out->priv != NULL) {
  52         return true;
  53     }
  54 
  55     out->priv = calloc(1, sizeof(private_data_t));
  56     if (out->priv == NULL) {
  57          return false;
  58     }
  59 
  60     priv = out->priv;
  61 
  62     priv->prefixes = g_queue_new();
  63     priv->log_level = LOG_INFO;
  64 
  65     return true;
  66 }
  67 
  68 static void
  69 log_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) {
     /* [previous][next][first][last][top][bottom][index][help] */
  70     /* This function intentionally left blank */
  71 }
  72 
  73 static void
  74 log_reset(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
  75     CRM_ASSERT(out != NULL);
  76 
  77     out->dest = freopen(NULL, "w", out->dest);
  78     CRM_ASSERT(out->dest != NULL);
  79 
  80     log_free_priv(out);
  81     log_init(out);
  82 }
  83 
  84 static void
  85 log_version(pcmk__output_t *out, bool extended) {
     /* [previous][next][first][last][top][bottom][index][help] */
  86     private_data_t *priv = NULL;
  87 
  88     CRM_ASSERT(out != NULL && out->priv != NULL);
  89     priv = out->priv;
  90 
  91     if (extended) {
  92         do_crm_log(priv->log_level, "Pacemaker %s (Build: %s): %s",
  93                    PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
  94     } else {
  95         do_crm_log(priv->log_level, "Pacemaker %s", PACEMAKER_VERSION);
  96         do_crm_log(priv->log_level, "Written by Andrew Beekhof");
  97     }
  98 }
  99 
 100 G_GNUC_PRINTF(2, 3)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 static void
 102 log_err(pcmk__output_t *out, const char *format, ...) {
 103     va_list ap;
 104     char* buffer = NULL;
 105     int len = 0;
 106 
 107     CRM_ASSERT(out != NULL);
 108 
 109     va_start(ap, format);
 110     /* Informational output does not get indented, to separate it from other
 111      * potentially indented list output.
 112      */
 113     len = vasprintf(&buffer, format, ap);
 114     CRM_ASSERT(len >= 0);
 115     va_end(ap);
 116 
 117     crm_err("%s", buffer);
 118 
 119     free(buffer);
 120 }
 121 
 122 static void
 123 log_output_xml(pcmk__output_t *out, const char *name, const char *buf) {
     /* [previous][next][first][last][top][bottom][index][help] */
 124     xmlNodePtr node = NULL;
 125     private_data_t *priv = NULL;
 126 
 127     CRM_ASSERT(out != NULL && out->priv != NULL);
 128     priv = out->priv;
 129 
 130     node = create_xml_node(NULL, name);
 131     xmlNodeSetContent(node, (pcmkXmlStr) buf);
 132     do_crm_log_xml(priv->log_level, name, node);
 133     free(node);
 134 }
 135 
 136 G_GNUC_PRINTF(4, 5)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 static void
 138 log_begin_list(pcmk__output_t *out, const char *singular_noun, const char *plural_noun,
 139                const char *format, ...) {
 140     int len = 0;
 141     va_list ap;
 142     char* buffer = NULL;
 143     private_data_t *priv = NULL;
 144 
 145     CRM_ASSERT(out != NULL && out->priv != NULL);
 146     priv = out->priv;
 147 
 148     va_start(ap, format);
 149     len = vasprintf(&buffer, format, ap);
 150     CRM_ASSERT(len >= 0);
 151     va_end(ap);
 152 
 153     /* Don't skip empty prefixes,
 154      * otherwise there will be mismatch
 155      * in the log_end_list */
 156     if(strcmp(buffer, "") == 0) {
 157         /* nothing */
 158     }
 159 
 160     g_queue_push_tail(priv->prefixes, buffer);
 161 }
 162 
 163 G_GNUC_PRINTF(3, 4)
     /* [previous][next][first][last][top][bottom][index][help] */
 164 static void
 165 log_list_item(pcmk__output_t *out, const char *name, const char *format, ...) {
 166     int len = 0;
 167     va_list ap;
 168     private_data_t *priv = NULL;
 169     char prefix[LINE_MAX] = { 0 };
 170     int offset = 0;
 171     char* buffer = NULL;
 172 
 173     CRM_ASSERT(out != NULL && out->priv != NULL);
 174     priv = out->priv;
 175 
 176     for (GList* gIter = priv->prefixes->head; gIter; gIter = gIter->next) {
 177         if (strcmp(prefix, "") != 0) {
 178             offset += snprintf(prefix + offset, LINE_MAX - offset, ": %s", (char *)gIter->data);
 179         } else {
 180             offset = snprintf(prefix, LINE_MAX, "%s", (char *)gIter->data);
 181         }
 182     }
 183 
 184     va_start(ap, format);
 185     len = vasprintf(&buffer, format, ap);
 186     CRM_ASSERT(len >= 0);
 187     va_end(ap);
 188 
 189     if (strcmp(buffer, "") != 0) { /* We don't want empty messages */
 190         if ((name != NULL) && (strcmp(name, "") != 0)) {
 191             if (strcmp(prefix, "") != 0) {
 192                 do_crm_log(priv->log_level, "%s: %s: %s", prefix, name, buffer);
 193             } else {
 194                 do_crm_log(priv->log_level, "%s: %s", name, buffer);
 195             }
 196         } else {
 197             if (strcmp(prefix, "") != 0) {
 198                 do_crm_log(priv->log_level, "%s: %s", prefix, buffer);
 199             } else {
 200                 do_crm_log(priv->log_level, "%s", buffer);
 201             }
 202         }
 203     }
 204     free(buffer);
 205 }
 206 
 207 static void
 208 log_end_list(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 209     private_data_t *priv = NULL;
 210 
 211     CRM_ASSERT(out != NULL && out->priv != NULL);
 212     priv = out->priv;
 213 
 214     if (priv->prefixes == NULL) {
 215       return;
 216     }
 217     CRM_ASSERT(priv->prefixes->tail != NULL);
 218 
 219     free((char *)priv->prefixes->tail->data);
 220     g_queue_pop_tail(priv->prefixes);
 221 }
 222 
 223 G_GNUC_PRINTF(2, 3)
     /* [previous][next][first][last][top][bottom][index][help] */
 224 static int
 225 log_info(pcmk__output_t *out, const char *format, ...) {
 226     private_data_t *priv = NULL;
 227     int len = 0;
 228     va_list ap;
 229     char* buffer = NULL;
 230 
 231     CRM_ASSERT(out != NULL && out->priv != NULL);
 232     priv = out->priv;
 233 
 234     va_start(ap, format);
 235     len = vasprintf(&buffer, format, ap);
 236     CRM_ASSERT(len >= 0);
 237     va_end(ap);
 238 
 239     do_crm_log(priv->log_level, "%s", buffer);
 240 
 241     free(buffer);
 242     return pcmk_rc_ok;
 243 }
 244 
 245 static bool
 246 log_is_quiet(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 247     return false;
 248 }
 249 
 250 static void
 251 log_spacer(pcmk__output_t *out) {
     /* [previous][next][first][last][top][bottom][index][help] */
 252     /* This function intentionally left blank */
 253 }
 254 
 255 static void
 256 log_progress(pcmk__output_t *out, bool end) {
     /* [previous][next][first][last][top][bottom][index][help] */
 257     /* This function intentionally left blank */
 258 }
 259 
 260 static void
 261 log_prompt(const char *prompt, bool echo, char **dest) {
     /* [previous][next][first][last][top][bottom][index][help] */
 262     /* This function intentionally left blank */
 263 }
 264 
 265 pcmk__output_t *
 266 pcmk__mk_log_output(char **argv) {
     /* [previous][next][first][last][top][bottom][index][help] */
 267     pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t));
 268 
 269     if (retval == NULL) {
 270         return NULL;
 271     }
 272 
 273     retval->fmt_name = "log";
 274     retval->request = argv == NULL ? NULL : g_strjoinv(" ", argv);
 275 
 276     retval->init = log_init;
 277     retval->free_priv = log_free_priv;
 278     retval->finish = log_finish;
 279     retval->reset = log_reset;
 280 
 281     retval->register_message = pcmk__register_message;
 282     retval->message = pcmk__call_message;
 283 
 284     retval->subprocess_output = log_subprocess_output;
 285     retval->version = log_version;
 286     retval->info = log_info;
 287     retval->err = log_err;
 288     retval->output_xml = log_output_xml;
 289 
 290     retval->begin_list = log_begin_list;
 291     retval->list_item = log_list_item;
 292     retval->end_list = log_end_list;
 293 
 294     retval->is_quiet = log_is_quiet;
 295     retval->spacer = log_spacer;
 296     retval->progress = log_progress;
 297     retval->prompt = log_prompt;
 298 
 299     return retval;
 300 }
 301 
 302 void
 303 pcmk__output_set_log_level(pcmk__output_t *out, int log_level) {
     /* [previous][next][first][last][top][bottom][index][help] */
 304     private_data_t *priv = NULL;
 305 
 306     CRM_ASSERT(out != NULL && out->priv != NULL);
 307 
 308     if (!pcmk__str_eq(out->fmt_name, "log", pcmk__str_none)) {
 309         return;
 310     }
 311 
 312     priv = out->priv;
 313     priv->log_level = log_level;
 314 }

/* [previous][next][first][last][top][bottom][index][help] */