]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: errors: implement user messages buffer
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 26 May 2021 09:05:22 +0000 (11:05 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 7 Jun 2021 14:58:16 +0000 (16:58 +0200)
The user messages buffer is used to store the stderr output after the
starting is over. Each thread has it own user messages buffer. Add some
functions to add a new message, retrieve and clear the content.

The user messages buffer primary goal is to be consulted by CLI
handlers. Each handlers using it must clear the buffer before starting
its operation.

include/haproxy/errors.h
src/errors.c

index 629b7209a9eabaa811d018ac360221b091e1322e..aaf5cd86630184f4e0c26960760653e769ffe88b 100644 (file)
@@ -60,6 +60,10 @@ enum {
 };
 
 
+void usermsgs_clr(void);
+int usermsgs_empty(void);
+const char *usermsgs_str(void);
+
 /************ Error reporting functions ***********/
 
 /*
index d3ca6f1c307a4de616102c5aef1871d096c0601a..b2ff42970717a224ed51708810f2b62c954687ca 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <haproxy/api.h>
 #include <haproxy/applet-t.h>
+#include <haproxy/buf.h>
 #include <haproxy/cli.h>
 #include <haproxy/errors.h>
 #include <haproxy/global.h>
  * retrieve on the CLI. */
 static struct ring *startup_logs = NULL;
 
+/* A thread local buffer used to store all alerts/warnings. It can be used to
+ * retrieve them for CLI commands after startup.
+ */
+#define USER_MESSAGES_BUFSIZE 1024
+static THREAD_LOCAL struct buffer usermsgs_buf = BUF_NULL;
+
+/* Put msg in usermsgs_buf.
+ *
+ * The message should not be terminated by a newline because this function
+ * manually insert it.
+ *
+ * If there is not enough room in the buffer, the message is silently discarded.
+ * Do not forget to frequently clear the buffer.
+ */
+static void usermsgs_put(const struct ist *msg)
+{
+       /* Allocate the buffer if not already done. */
+       if (unlikely(b_is_null(&usermsgs_buf))) {
+               usermsgs_buf.area = malloc(USER_MESSAGES_BUFSIZE * sizeof(char));
+               usermsgs_buf.size = USER_MESSAGES_BUFSIZE;
+       }
+
+       if (likely(!b_is_null(&usermsgs_buf))) {
+               if (b_room(&usermsgs_buf) >= msg->len + 2) {
+                       /* Insert the message + newline. */
+                       b_putblk(&usermsgs_buf, msg->ptr, msg->len);
+                       b_putchr(&usermsgs_buf, '\n');
+                       /* Insert NUL outside of the buffer. */
+                       *b_tail(&usermsgs_buf) = '\0';
+               }
+       }
+}
+
+/* Clear the messages log buffer. */
+void usermsgs_clr(void)
+{
+       if (likely(!b_is_null(&usermsgs_buf))) {
+               b_reset(&usermsgs_buf);
+               usermsgs_buf.area[0] = '\0';
+       }
+}
+
+/* Check if the user messages buffer is empty. */
+int usermsgs_empty(void)
+{
+       return !!(b_is_null(&usermsgs_buf) || !b_data(&usermsgs_buf));
+}
+
+/* Return the messages log buffer content. */
+const char *usermsgs_str(void)
+{
+       if (unlikely(b_is_null(&usermsgs_buf)))
+               return "";
+
+       return b_head(&usermsgs_buf);
+}
+
 /* Generic function to display messages prefixed by a label */
 static void print_message(const char *label, const char *fmt, va_list argp)
 {
+       struct ist msg_ist = IST_NULL;
        char *head, *msg;
        char prefix[11]; // '[' + 8 chars + ']' + 0.
 
@@ -33,6 +92,11 @@ static void print_message(const char *label, const char *fmt, va_list argp)
        memprintf(&head, "%s (%u) : ", prefix, (uint)getpid());
        memvprintf(&msg, fmt, argp);
 
+       /* trim the trailing '\n' */
+       msg_ist = ist(msg);
+       if (msg_ist.len > 0 && msg_ist.ptr[msg_ist.len - 1] == '\n')
+               msg_ist.len--;
+
        if (global.mode & MODE_STARTING) {
                if (unlikely(!startup_logs))
                        startup_logs = ring_new(STARTUP_LOG_SIZE);
@@ -41,13 +105,14 @@ static void print_message(const char *label, const char *fmt, va_list argp)
                        struct ist m[2];
 
                        m[0] = ist(head);
-                       m[1] = ist(msg);
-                       /* trim the trailing '\n' */
-                       if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
-                               m[1].len--;
+                       m[1] = msg_ist;
+
                        ring_write(startup_logs, ~0, 0, 0, m, 2);
                }
        }
+       else {
+               usermsgs_put(&msg_ist);
+       }
 
        fprintf(stderr, "%s%s", head, msg);
        fflush(stderr);
@@ -185,6 +250,7 @@ INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
 static void deinit_errors_buffers()
 {
        ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
+       ha_free(&usermsgs_buf.area);
 }
 
 REGISTER_PER_THREAD_FREE(deinit_errors_buffers);