]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: log: add support for logging to a ring buffer
authorWilly Tarreau <w@1wt.eu>
Fri, 30 Aug 2019 13:24:59 +0000 (15:24 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 30 Aug 2019 13:24:59 +0000 (15:24 +0200)
Now by prefixing a log server with "ring@<name>" it's possible to send
the logs to a ring buffer. One nice thing is that it allows multiple
sessions to consult the logs in real time in parallel over the CLI, and
without requiring file system access. At the moment, ring0 is created as
a default sink for tracing purposes and is available. No option is
provided to create new rings though this is trivial to add to the global
section.

doc/configuration.txt
include/types/log.h
src/log.c

index d4b7bcdef6922e70137c92fe59ad6dbd5bc9fc29..ba5a8b360f4b0a1675bd2ebff13ea5154a2fac67 100644 (file)
@@ -933,6 +933,12 @@ log <address> [len <length>] [format <format>] [sample <ranges>:<smp_size>]
         - "stdout" / "stderr", which are respectively aliases for "fd@1" and
           "fd@2", see above.
 
+        - A ring buffer in the form "ring@<name>", which will correspond to an
+          in-memory ring buffer accessible over the CLI using the "show events"
+          command, which will also list existing rings and their sizes. Such
+          buffers are lost on reload or restart but when used as a complement
+          this can help troubleshooting by having the logs instantly available.
+
         You may want to reference some environment variables in the address
         parameter, see section 2.3 about environment variables.
 
@@ -5385,6 +5391,13 @@ no log
                - "stdout" / "stderr", which are respectively aliases for "fd@1"
                  and "fd@2", see above.
 
+               - A ring buffer in the form "ring@<name>", which will correspond
+                 to an in-memory ring buffer accessible over the CLI using the
+                 "show events" command, which will also list existing rings and
+                 their sizes. Such buffers are lost on reload or restart but
+                 when used as a complement this can help troubleshooting by
+                 having the logs instantly available.
+
                You may want to reference some environment variables in the
                address parameter, see section 2.3 about environment variables.
 
index dbbd73bf70d843283a029429ffb8f4c2d8b8ee6a..a29ecf574245b0bd67007716c8d8439d871dbd18 100644 (file)
@@ -28,6 +28,7 @@
 #include <common/config.h>
 #include <common/hathreads.h>
 #include <common/mini-clist.h>
+#include <types/ring.h>
 
 #define NB_LOG_FACILITIES       24
 #define NB_LOG_LEVELS           8
@@ -51,6 +52,7 @@ enum {
 enum log_tgt {
        LOG_TARGET_DGRAM = 0, // datagram address (udp, unix socket)
        LOG_TARGET_FD,        // file descriptor
+       LOG_TARGET_BUFFER,    // ring buffer
 };
 
 /* lists of fields that can be logged */
@@ -203,6 +205,7 @@ struct logsrv {
        struct list list;
        struct sockaddr_storage addr;
        struct smp_info lb;
+       struct ring *ring;
        enum log_tgt type;
        int format;
        int facility;
index 1b34c637e23687c6920dbd183c3603f42a2886a9..b96c174bea889f2d27c43f6f69c09dc7b312029d 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -39,7 +39,9 @@
 #include <proto/fd.h>
 #include <proto/frontend.h>
 #include <proto/log.h>
+#include <proto/ring.h>
 #include <proto/sample.h>
+#include <proto/sink.h>
 #include <proto/ssl_sock.h>
 #include <proto/stream.h>
 #include <proto/stream_interface.h>
@@ -1000,6 +1002,20 @@ int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
 
        /* now, back to the address */
        logsrv->type = LOG_TARGET_DGRAM;
+       if (strncmp(args[1], "ring@", 5) == 0) {
+               struct sink *sink = sink_find(args[1] + 5);
+
+               if (!sink || sink->type != SINK_TYPE_BUFFER) {
+                       memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
+                       goto error;
+               }
+
+               logsrv->addr.ss_family = AF_UNSPEC;
+               logsrv->type = LOG_TARGET_BUFFER;
+               logsrv->ring = sink->ctx.ring;
+               goto done;
+       }
+
        if (strncmp(args[1], "fd@", 3) == 0)
                logsrv->type = LOG_TARGET_FD;
 
@@ -1017,6 +1033,7 @@ int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
                if (!port1)
                        set_host_port(&logsrv->addr, SYSLOG_PORT);
        }
+ done:
        LIST_ADDQ(logsrvs, &logsrv->list);
        return 1;
 
@@ -1510,12 +1527,15 @@ static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_
                /* the socket's address is a file descriptor */
                plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
        }
+       else if (logsrv->type == LOG_TARGET_BUFFER) {
+               plogfd = NULL;
+       }
        else if (logsrv->addr.ss_family == AF_UNIX)
                plogfd = &logfdunix;
        else
                plogfd = &logfdinet;
 
-       if (unlikely(*plogfd < 0)) {
+       if (plogfd && unlikely(*plogfd < 0)) {
                /* socket not successfully initialized yet */
                if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
                                                          (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
@@ -1652,7 +1672,7 @@ static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_
        max = MIN(size, maxlen - sd_max) - 1;
 send:
        if (logsrv->addr.ss_family == AF_UNSPEC) {
-               /* the target is a direct file descriptor */
+               /* the target is a file descriptor or a ring buffer */
                struct ist msg[7];
 
                msg[0].ptr = hdr_ptr;  msg[0].len = hdr_max;
@@ -1663,7 +1683,10 @@ send:
                msg[5].ptr = sd;       msg[5].len = sd_max;
                msg[6].ptr = dataptr;  msg[6].len = max;
 
-               sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
+               if (logsrv->type == LOG_TARGET_BUFFER)
+                       sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
+               else /* LOG_TARGET_FD */
+                       sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
        }
        else {
                iovec[0].iov_base = hdr_ptr;