]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: sink: add global statement to create a new ring (sink buffer)
authorEmeric Brun <ebrun@haproxy.com>
Mon, 11 May 2020 12:41:31 +0000 (14:41 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 19 May 2020 09:04:11 +0000 (11:04 +0200)
This patch adds the new global statement:
ring <name> [desc <desc>] [format <format>] [size <size>] [maxlen <length>]
  Creates a named ring buffer which could be used on log line for instance.

  <desc> is an optionnal description string of the ring. It will appear on
         CLI. By default, <name> is reused to fill this field.

  <format> is the log format used when generating syslog messages. It may be
           one of the following :

    iso       A message containing only the ISO date, followed by the text.
              The PID, process name and system name are omitted. This is
              designed to be used with a local log server.

    raw       A message containing only the text. The level, PID, date, time,
              process name and system name are omitted. This is designed to be
              used in containers or during development, where the severity only
              depends on the file descriptor used (stdout/stderr). This is
              the default.

    rfc3164   The RFC3164 syslog message format. This is the default.
              (https://tools.ietf.org/html/rfc3164)

    rfc5424   The RFC5424 syslog message format.
              (https://tools.ietf.org/html/rfc5424)

    short     A message containing only a level between angle brackets such as
              '<3>', followed by the text. The PID, date, time, process name
              and system name are omitted. This is designed to be used with a
              local log server. This format is compatible with what the systemd
              logger consumes.

    timed     A message containing only a level between angle brackets such as
              '<3>', followed by ISO date and by the text. The PID, process
              name and system name are omitted. This is designed to be
              used with a local log server.

  <length> is the maximum length of event message stored into the ring,
           including formatted header. If the event message is longer
           than <length>, it would be truncated to this length.

  <name> is the ring identifier, which follows the same naming convention as
         proxies and servers.

  <size> is the optionnal size in bytes. Default value is set to BUFSIZE.

Note: Historically sink's name and desc were refs on const strings. But with new
configurable rings a dynamic allocation is needed.

doc/configuration.txt
include/common/cfgparse.h
include/proto/sink.h
include/types/sink.h
src/cfgparse-global.c
src/sink.c

index e434a4750d5eb1c99358cbc44b1e7cb3d1943c6a..6e86a0a794a867c967afb6cc3606f5e008928e9d 100644 (file)
@@ -614,6 +614,7 @@ The following keywords are supported in the "global" section :
    - pidfile
    - presetenv
    - resetenv
+   - ring
    - uid
    - ulimit-n
    - user
@@ -1193,6 +1194,51 @@ resetenv [<name> ...]
   next line in the configuration file sees the new environment. See also
   "setenv", "presetenv", and "unsetenv".
 
+ring <name> [desc <desc>] [format <format>] [size <size>] [maxlen <length>]
+  Creates a named ring buffer which could be used on log line for instance.
+
+  <desc> is an optionnal description string of the ring. It will appear on
+         CLI. By default, <name> is reused to fill this field.
+
+  <format> is the log format used when generating syslog messages. It may be
+           one of the following :
+
+    iso       A message containing only the ISO date, followed by the text.
+              The PID, process name and system name are omitted. This is
+              designed to be used with a local log server.
+
+    raw       A message containing only the text. The level, PID, date, time,
+              process name and system name are omitted. This is designed to be
+              used in containers or during development, where the severity only
+              depends on the file descriptor used (stdout/stderr). This is
+              the default.
+
+    rfc3164   The RFC3164 syslog message format. This is the default.
+              (https://tools.ietf.org/html/rfc3164)
+
+    rfc5424   The RFC5424 syslog message format.
+              (https://tools.ietf.org/html/rfc5424)
+
+    short     A message containing only a level between angle brackets such as
+              '<3>', followed by the text. The PID, date, time, process name
+              and system name are omitted. This is designed to be used with a
+              local log server. This format is compatible with what the systemd
+              logger consumes.
+
+    timed     A message containing only a level between angle brackets such as
+              '<3>', followed by ISO date and by the text. The PID, process
+              name and system name are omitted. This is designed to be
+              used with a local log server.
+
+  <length> is the maximum length of an event message stored into the ring,
+           including formatted header. If an event message is longer than
+           <length>, it will be truncated to this length.
+
+  <name> is the ring identifier, which follows the same naming convention as
+         proxies and servers.
+
+  <size> is the optionnal size in bytes. Default value is set to BUFSIZE.
+
 stats bind-process [ all | odd | even | <process_num>[-[process_num>]] ] ...
   Limits the stats socket to a certain set of processes numbers. By default the
   stats socket is bound to all processes, causing a warning to be emitted when
index 1a288166aa2525975aef292b2aa4770f4d5c6a6b..286099b37723d9b67c89d06716e13d8e61a7af8d 100644 (file)
@@ -28,6 +28,7 @@
 #include <common/mini-clist.h>
 
 #include <proto/log.h>
+#include <proto/sink.h>
 #include <proto/proxy.h>
 
 /* configuration sections */
index d30f30a742791ed8aca034ac69e0542282bf5f51..c3121855ee0c06d300fd0ceeca5aa8797e3b0cc1 100644 (file)
@@ -78,6 +78,9 @@ static inline ssize_t sink_write(struct sink *sink, const struct ist msg[], size
        return sent;
 }
 
+
+int parse_sinkbuf(char **args, char **err);
+
 #endif /* _PROTO_SINK_H */
 
 /*
index 28b037920873f1496b374c03c53e67c950049b89..ef11096793ce759f340f4e6ba6a5acc8279be5b2 100644 (file)
@@ -52,8 +52,8 @@ enum sink_fmt {
 /* describes the configuration and current state of an event sink */
 struct sink {
        struct list sink_list;     // position in the sink list
-       const char *name;          // sink name
-       const char *desc;          // sink description
+       char *name;                // sink name
+       char *desc;                // sink description
        enum sink_fmt fmt;         // format expected by the sink
        enum sink_type type;       // type of storage
        uint32_t maxlen;           // max message length (truncated above)
index 2b3249758e8ddcc7a1a30fab0b8eaaab8b8fcb07..d971c11ab5056536c9b722e222dfa9a5d83c8a2d 100644 (file)
@@ -905,6 +905,13 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                free(global.log_send_hostname);
                global.log_send_hostname = strdup(name);
        }
+       else if (!strcmp(args[0], "ring")) {
+               if (!parse_sinkbuf(args, &errmsg)) {
+                       ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+       }
        else if (!strcmp(args[0], "server-state-base")) { /* path base where HAProxy can find server state files */
                if (global.server_state_base != NULL) {
                        ha_alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
index 15595cd271a07af81eb894cd79a96228c82222f4..34bc97cddab5969d828133601423a683cd8021e1 100644 (file)
@@ -58,8 +58,8 @@ static struct sink *__sink_new(const char *name, const char *desc, enum sink_fmt
        if (!sink)
                goto end;
 
-       sink->name = name;
-       sink->desc = desc;
+       sink->name = strdup(name);
+       sink->desc = strdup(desc);
        sink->fmt  = fmt;
        sink->type = SINK_TYPE_NEW;
        sink->maxlen = BUFSIZE;
@@ -123,6 +123,8 @@ struct sink *sink_new_buf(const char *name, const char *desc, enum sink_fmt fmt,
        sink->ctx.ring = ring_new(size);
        if (!sink->ctx.ring) {
                LIST_DEL(&sink->sink_list);
+               free(sink->name);
+               free(sink->desc);
                free(sink);
                goto fail;
        }
@@ -326,10 +328,130 @@ static void sink_deinit()
                if (sink->type == SINK_TYPE_BUFFER)
                        ring_free(sink->ctx.ring);
                LIST_DEL(&sink->sink_list);
+               free(sink->name);
+               free(sink->desc);
                free(sink);
        }
 }
 
+/*
+ * Parse "ring" keyword and create corresponding sink buffer.
+ *
+ * The function returns 1 in success case, otherwise, it returns 0 and err is
+ * filled.
+ */
+
+int parse_sinkbuf(char **args, char **err)
+{
+       int myidx = 2;
+       size_t size = BUFSIZE;
+       size_t maxlen = size;
+       int format = SINK_FMT_RAW;
+       struct sink *sink = NULL;
+       char *desc, *name = args[1];
+       const char *inv;
+
+       if (!*name) {
+               memprintf(err, "missing sink name");
+               goto error;
+       }
+
+       inv = invalid_char(name);
+       if (inv) {
+               memprintf(err, "invalid sink name '%s' (character '%c' is not permitted)", name, *inv);
+               goto error;
+       }
+
+       desc = name;
+
+       while (*args[myidx]) {
+               if (!strcmp(args[myidx], "size")) {
+                       myidx++;
+                       size = atol(args[myidx]);
+                       if (!size) {
+                               memprintf(err, "invalid size '%s' for new sink buffer for ring '%s'", args[myidx], name);
+                               goto error;
+                       }
+               }
+               else if (!strcmp(args[myidx], "maxlen")) {
+                       myidx++;
+                       maxlen = atol(args[myidx]);
+                       if (!maxlen) {
+                               memprintf(err, "invalid size '%s' for new sink buffer for ring '%s'", args[myidx], name);
+                               goto error;
+                       }
+               }
+               else if (!strcmp(args[myidx], "maxlen")) {
+                       myidx++;
+                       maxlen = atol(args[myidx]);
+                       if (!maxlen) {
+                               memprintf(err, "invalid size '%s' for new sink buffer for ring '%s'", args[myidx], name);
+                               goto error;
+                       }
+               }
+               else if (!strcmp(args[myidx], "desc")) {
+                       myidx++;
+                       desc = args[myidx];
+               }
+               else if (!strcmp(args[myidx],"format")) {
+                       myidx++;
+                       if (!strcmp(args[myidx], "raw")) {
+                               format = SINK_FMT_RAW;
+                       }
+                       else if (!strcmp(args[myidx], "short")) {
+                               format = SINK_FMT_SHORT;
+                       }
+                       else if (!strcmp(args[myidx], "iso")) {
+                               format = SINK_FMT_ISO;
+                       }
+                       else if (!strcmp(args[myidx], "timed")) {
+                               format = SINK_FMT_TIMED;
+                       }
+                       else if (!strcmp(args[myidx], "rfc3164")) {
+                               format = SINK_FMT_RFC3164;
+                       }
+                       else if (!strcmp(args[myidx], "rfc5424")) {
+                               format = SINK_FMT_RFC5424;
+                       }
+                       else {
+                               memprintf(err, "unknown format '%s' for new sink buffer for ring '%s'", args[myidx], name);
+                               goto error;
+                       }
+               }
+               else {
+                       memprintf(err, "unknown parameter '%s' for new sink buffer for ring '%s'", args[myidx], name);
+                       goto error;
+               }
+               myidx++;
+       }
+
+       if (maxlen > size) {
+               memprintf(err, "maxlen '%lu' exceeds size of the new sink buffer for ring '%s'", maxlen, name);
+               goto error;
+       }
+
+       sink = sink_new_buf(name, desc, format, size);
+       if (!sink || sink->type != SINK_TYPE_BUFFER) {
+               memprintf(err, "failed to create a new sink buffer for ring '%s'", name);
+               goto error;
+       }
+
+       sink->maxlen = maxlen;
+
+       return 1;
+error:
+       if (sink) {
+               if (sink->type == SINK_TYPE_BUFFER)
+                       ring_free(sink->ctx.ring);
+               LIST_DEL(&sink->sink_list);
+               free(sink->name);
+               free(sink->desc);
+               free(sink);
+       }
+       return 0;
+
+}
+
 INITCALL0(STG_REGISTER, sink_init);
 REGISTER_POST_DEINIT(sink_deinit);