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. G_GNUC_PRINTF
  14. log_is_quiet
  15. log_spacer
  16. log_progress
  17. log_prompt
  18. pcmk__mk_log_output
  19. pcmk__output_get_log_level
  20. pcmk__output_set_log_level

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

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