]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: log: introduce log target
authorAurelien DARRAGON <adarragon@haproxy.com>
Mon, 11 Sep 2023 14:10:37 +0000 (16:10 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 13 Oct 2023 08:05:06 +0000 (10:05 +0200)
log targets were immediately embedded in logger struct (previously
named logsrv) and could not be used outside of this context.

In this patch, we're introducing log_target type with the associated
helper functions so that it becomes possible to declare and use log
targets outside of loggers scope.

include/haproxy/log-t.h
src/log.c
src/sink.c

index 80b6f7dc788582470302a921695778af56ff4a1c..b8a46fd951148022ba453a0e1c5e98346df5ddb0 100644 (file)
@@ -218,13 +218,25 @@ struct smp_info {
        ullong curr_rg_idx;        /* 63:32 = current range; 31:0 = current index */
 };
 
+enum log_target_flags {
+       LOG_TARGET_FL_NONE     = 0x00,
+       LOG_TARGET_FL_RESOLVED = 0x01
+};
+
+struct log_target {
+       struct sockaddr_storage *addr;
+       union {
+               char *ring_name;   /* type = BUFFER - preparsing */
+               struct sink *sink; /* type = BUFFER - postparsing */
+       };
+       enum log_tgt type;
+       uint16_t flags;
+};
+
 struct logger {
        struct list list;
-       struct sockaddr_storage addr;
+       struct log_target target;
        struct smp_info lb;
-       struct sink *sink;
-       char *ring_name;
-       enum log_tgt type;
        enum log_fmt format;
        int facility;
        int level;
index 1af0e646436a4839ae579310328adb1c19d054b5..4491bde9f4702373128d40ca2fcb9d296056d34c 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -734,6 +734,43 @@ int smp_log_range_cmp(const void *a, const void *b)
        return 0;
 }
 
+/* helper func */
+static inline void init_log_target(struct log_target *target)
+{
+       target->type = 0;
+       target->flags = LOG_TARGET_FL_NONE;
+       target->addr = NULL;
+       target->ring_name = NULL;
+}
+
+static void deinit_log_target(struct log_target *target)
+{
+       ha_free(&target->addr);
+       if (!(target->flags & LOG_TARGET_FL_RESOLVED))
+               ha_free(&target->ring_name);
+}
+
+/* returns 0 on failure and positive value on success */
+static int dup_log_target(struct log_target *def, struct log_target *cpy)
+{
+       BUG_ON((def->flags & LOG_TARGET_FL_RESOLVED)); /* postparsing already done, invalid use */
+       init_log_target(cpy);
+       cpy->addr = malloc(sizeof(*cpy->addr));
+       if (!cpy->addr)
+               goto error;
+       *cpy->addr = *def->addr;
+       if (def->ring_name) {
+               cpy->ring_name = strdup(def->ring_name);
+               if (!cpy->ring_name)
+                       goto error;
+       }
+       cpy->type = def->type;
+       return 1;
+ error:
+       deinit_log_target(cpy);
+       return 0;
+}
+
 /* resolves a single logger entry (it is expected to be called
  * at postparsing stage)
  *
@@ -747,10 +784,14 @@ int smp_log_range_cmp(const void *a, const void *b)
  */
 int resolve_logger(struct logger *logger, char **msg)
 {
+       struct log_target *target = &logger->target;
        int err_code = ERR_NONE;
 
-       if (logger->type == LOG_TARGET_BUFFER)
+       if (target->type == LOG_TARGET_BUFFER)
                err_code = sink_resolve_logger_buffer(logger, msg);
+
+       target->flags |= LOG_TARGET_FL_RESOLVED;
+
        return err_code;
 }
 
@@ -767,16 +808,12 @@ struct logger *dup_logger(struct logger *def)
        memcpy(cpy, def, sizeof(*cpy));
 
        /* default values */
-       cpy->ring_name = NULL;
        cpy->conf.file = NULL;
        LIST_INIT(&cpy->list);
 
        /* special members */
-       if (def->ring_name) {
-               cpy->ring_name = strdup(def->ring_name);
-               if (!cpy->ring_name)
-                       goto error;
-       }
+       if (dup_log_target(&def->target, &cpy->target) == 0)
+               goto error;
        if (def->conf.file) {
                cpy->conf.file = strdup(def->conf.file);
                if (!cpy->conf.file)
@@ -801,10 +838,69 @@ void free_logger(struct logger *logger)
 
        BUG_ON(LIST_INLIST(&logger->list));
        ha_free(&logger->conf.file);
-       ha_free(&logger->ring_name);
+       deinit_log_target(&logger->target);
        free(logger);
 }
 
+/* Parse single log target
+ * Returns 0 on failure and positive value on success
+ */
+static int parse_log_target(char *raw, struct log_target *target, char **err)
+{
+       int port1, port2, fd;
+       struct protocol *proto;
+       struct sockaddr_storage *sk;
+
+       init_log_target(target);
+
+       /* first, try to allocate log target addr */
+       target->addr = malloc(sizeof(*target->addr));
+       if (!target->addr) {
+               memprintf(err, "memory error");
+               goto error;
+       }
+
+       target->type = LOG_TARGET_DGRAM;
+       if (strncmp(raw, "ring@", 5) == 0) {
+               target->addr->ss_family = AF_UNSPEC;
+               target->type = LOG_TARGET_BUFFER;
+               target->ring_name = strdup(raw + 5);
+               goto done;
+       }
+
+       /* parse the target address */
+       sk = str2sa_range(raw, NULL, &port1, &port2, &fd, &proto,
+                         err, NULL, NULL,
+                         PA_O_RESOLVE | PA_O_PORT_OK | PA_O_RAW_FD | PA_O_DGRAM | PA_O_STREAM | PA_O_DEFAULT_DGRAM);
+       if (!sk)
+               goto error;
+       if (fd != -1)
+               target->type = LOG_TARGET_FD;
+       *target->addr = *sk;
+
+       if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
+               if (!port1)
+                       set_host_port(target->addr, SYSLOG_PORT);
+       }
+
+       if (proto && proto->xprt_type == PROTO_TYPE_STREAM) {
+               static unsigned long ring_ids;
+
+               /* Implicit sink buffer will be
+                * initialized in post_check
+                */
+               target->type = LOG_TARGET_BUFFER;
+               /* compute unique name for the ring */
+               memprintf(&target->ring_name, "ring#%lu", ++ring_ids);
+       }
+
+ done:
+       return 1;
+ error:
+       deinit_log_target(target);
+       return 0;
+}
+
 /*
  * Parse "log" keyword and update <loggers> list accordingly.
  *
@@ -821,12 +917,8 @@ void free_logger(struct logger *logger)
 int parse_logger(char **args, struct list *loggers, int do_del, const char *file, int linenum, char **err)
 {
        struct smp_log_range *smp_rgs = NULL;
-       struct sockaddr_storage *sk;
-       struct protocol *proto;
        struct logger *logger = NULL;
-       int port1, port2;
        int cur_arg;
-       int fd;
 
        /*
         * "no log": delete previous herited or defined syslog
@@ -1042,43 +1134,10 @@ int parse_logger(char **args, struct list *loggers, int do_del, const char *file
                goto error;
        }
 
-       /* now, back to the address */
-       logger->type = LOG_TARGET_DGRAM;
-       if (strncmp(args[1], "ring@", 5) == 0) {
-               logger->addr.ss_family = AF_UNSPEC;
-               logger->type = LOG_TARGET_BUFFER;
-               logger->sink = NULL;
-               logger->ring_name = strdup(args[1] + 5);
-               goto done;
-       }
-
-       sk = str2sa_range(args[1], NULL, &port1, &port2, &fd, &proto,
-                         err, NULL, NULL,
-                         PA_O_RESOLVE | PA_O_PORT_OK | PA_O_RAW_FD | PA_O_DGRAM | PA_O_STREAM | PA_O_DEFAULT_DGRAM);
-       if (!sk)
+       /* now, back to the log target */
+       if (!parse_log_target(args[1], &logger->target, err))
                goto error;
 
-       if (fd != -1)
-               logger->type = LOG_TARGET_FD;
-       logger->addr = *sk;
-
-       if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
-               if (!port1)
-                       set_host_port(&logger->addr, SYSLOG_PORT);
-       }
-
-       if (proto && proto->xprt_type == PROTO_TYPE_STREAM) {
-               static unsigned long ring_ids;
-
-               /* Implicit sink buffer will be
-                * initialized in post_check
-                */
-               logger->type = LOG_TARGET_BUFFER;
-               logger->sink = NULL;
-               /* compute uniq name for the ring */
-               memprintf(&logger->ring_name, "ring#%lu", ++ring_ids);
-       }
-
  done:
        LIST_APPEND(loggers, &logger->list);
        return 1;
@@ -1704,23 +1763,23 @@ static inline void __do_send_log(struct logger *logger, int nblogger, int level,
        while (size && (message[size-1] == '\n' || (message[size-1] == 0)))
                size--;
 
-       if (logger->type == LOG_TARGET_BUFFER) {
+       if (logger->target.type == LOG_TARGET_BUFFER) {
                plogfd = NULL;
                goto send;
        }
-       else if (logger->addr.ss_family == AF_CUST_EXISTING_FD) {
+       else if (logger->target.addr->ss_family == AF_CUST_EXISTING_FD) {
                /* the socket's address is a file descriptor */
-               plogfd = (int *)&((struct sockaddr_in *)&logger->addr)->sin_addr.s_addr;
+               plogfd = (int *)&((struct sockaddr_in *)logger->target.addr)->sin_addr.s_addr;
        }
-       else if (logger->addr.ss_family == AF_UNIX)
+       else if (logger->target.addr->ss_family == AF_UNIX)
                plogfd = &logfdunix;
        else
                plogfd = &logfdinet;
 
        if (plogfd && unlikely(*plogfd < 0)) {
                /* socket not successfully initialized yet */
-               if ((*plogfd = socket(logger->addr.ss_family, SOCK_DGRAM,
-                                                         (logger->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
+               if ((*plogfd = socket(logger->target.addr->ss_family, SOCK_DGRAM,
+                                     (logger->target.addr->ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
                        static char once;
 
                        if (!once) {
@@ -1740,7 +1799,7 @@ static inline void __do_send_log(struct logger *logger, int nblogger, int level,
 
        msg_header = build_log_header(logger->format, level, facility, metadata, &nbelem);
  send:
-       if (logger->type == LOG_TARGET_BUFFER) {
+       if (logger->target.type == LOG_TARGET_BUFFER) {
                struct ist msg;
                size_t maxlen = logger->maxlen;
 
@@ -1751,9 +1810,9 @@ static inline void __do_send_log(struct logger *logger, int nblogger, int level,
                 */
                maxlen -= 1;
 
-               sent = sink_write(logger->sink, maxlen, &msg, 1, level, facility, metadata);
+               sent = sink_write(logger->target.sink, maxlen, &msg, 1, level, facility, metadata);
        }
-       else if (logger->addr.ss_family == AF_CUST_EXISTING_FD) {
+       else if (logger->target.addr->ss_family == AF_CUST_EXISTING_FD) {
                struct ist msg;
 
                msg = ist2(message, size);
@@ -1786,8 +1845,8 @@ static inline void __do_send_log(struct logger *logger, int nblogger, int level,
                i++;
 
                msghdr.msg_iovlen = i;
-               msghdr.msg_name = (struct sockaddr *)&logger->addr;
-               msghdr.msg_namelen = get_addr_len(&logger->addr);
+               msghdr.msg_name = (struct sockaddr *)logger->target.addr;
+               msghdr.msg_namelen = get_addr_len(logger->target.addr);
 
                sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
        }
index c9c83a7db7f895c6a78994ee9cece25b7245e7f4..ae82394653c84037932c7a64e44dd170ca087354 100644 (file)
@@ -1184,7 +1184,7 @@ err:
  * it returns NULL.
  *
  * Note: the sink is created using the name
- *       specified into logger->ring_name
+ *       specified into logger->target.ring_name
  */
 struct sink *sink_new_from_logger(struct logger *logger)
 {
@@ -1197,7 +1197,7 @@ struct sink *sink_new_from_logger(struct logger *logger)
        chunk_printf(&trash, "created from log directive declared into '%s' at line %d", logger->conf.file, logger->conf.line);
 
        /* allocate a new sink buffer */
-       sink = sink_new_ringbuf(logger->ring_name, trash.area, logger->conf.file, logger->conf.line, &err_msg);
+       sink = sink_new_ringbuf(logger->target.ring_name, trash.area, logger->conf.file, logger->conf.line, &err_msg);
        if (!sink) {
                ha_alert("%s.\n", err_msg);
                ha_free(&err_msg);
@@ -1222,11 +1222,11 @@ struct sink *sink_new_from_logger(struct logger *logger)
                goto error;
 
        /* init server */
-       srv->id = strdup(logger->ring_name);
+       srv->id = strdup(logger->target.ring_name);
        srv->conf.file = strdup(logger->conf.file);
        srv->conf.line = logger->conf.line;
-       srv->addr = logger->addr;
-        srv->svc_port = get_host_port(&logger->addr);
+       srv->addr = *logger->target.addr;
+        srv->svc_port = get_host_port(logger->target.addr);
        HA_SPIN_INIT(&srv->lock);
 
        /* process per thread init */
@@ -1242,8 +1242,8 @@ struct sink *sink_new_from_logger(struct logger *logger)
        if (sink_finalize(sink) & ERR_CODE)
                goto error_final;
 
-       /* reset familyt of logger to consider the ring buffer target */
-       logger->addr.ss_family = AF_UNSPEC;
+       /* reset family of logger to consider the ring buffer target */
+       logger->target.addr->ss_family = AF_UNSPEC;
 
        return sink;
  error:
@@ -1279,20 +1279,21 @@ int cfg_post_parse_ring()
  * could also be set when no error occured to report a diag warning), thus is
  * up to the caller to check it and to free it.
  */
-int sink_resolve_logger_buffer(struct logger *target, char **msg)
+int sink_resolve_logger_buffer(struct logger *logger, char **msg)
 {
+       struct log_target *target = &logger->target;
        int err_code = ERR_NONE;
        struct sink *sink;
 
-       BUG_ON(target->type != LOG_TARGET_BUFFER);
+       BUG_ON(target->type != LOG_TARGET_BUFFER || (target->flags & LOG_TARGET_FL_RESOLVED));
        sink = sink_find(target->ring_name);
        if (!sink) {
                /* LOG_TARGET_BUFFER but !AF_UNSPEC
                 * means we must allocate a sink
                 * buffer to send messages to this logger
                 */
-               if (target->addr.ss_family != AF_UNSPEC) {
-                       sink = sink_new_from_logger(target);
+               if (target->addr->ss_family != AF_UNSPEC) {
+                       sink = sink_new_from_logger(logger);
                        if (!sink) {
                                memprintf(msg, "cannot be initialized (failed to create implicit ring)");
                                err_code |= ERR_ALERT | ERR_FATAL;
@@ -1310,16 +1311,18 @@ int sink_resolve_logger_buffer(struct logger *target, char **msg)
                err_code |= ERR_ALERT | ERR_FATAL;
                goto end;
        }
-       if (sink && target->maxlen > ring_max_payload(sink->ctx.ring)) {
+       if (sink && logger->maxlen > ring_max_payload(sink->ctx.ring)) {
                memprintf(msg, "uses a max length which exceeds ring capacity ('%s' supports %lu bytes at most)",
                          target->ring_name, (unsigned long)ring_max_payload(sink->ctx.ring));
        }
-       else if (sink && target->maxlen > sink->maxlen) {
+       else if (sink && logger->maxlen > sink->maxlen) {
                memprintf(msg, "uses a ring with a smaller maxlen than the one specified on the log directive ('%s' has maxlen = %d), logs will be truncated according to the lowest maxlen between the two",
                          target->ring_name, sink->maxlen);
        }
  end:
+       ha_free(&target->ring_name); /* sink is resolved and will replace ring_name hint */
        target->sink = sink;
+       ha_free(&target->addr); /* we no longer need this */
        return err_code;
 }