]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: log/sink: simplify log header handling
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 24 Aug 2023 18:46:12 +0000 (20:46 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 13 Oct 2023 08:05:06 +0000 (10:05 +0200)
Introduce log_header struct to easily pass log header data between
functions and use that to simplify the logic around log header
handling.

While at it, some outdated comments were updated as well.

No change in behavior should be expected.

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

index b8a46fd951148022ba453a0e1c5e98346df5ddb0..36d9c19ec0949bceb09cb27b3d76febd65ecee88 100644 (file)
@@ -97,6 +97,20 @@ enum log_meta {
         LOG_META_FIELDS  /* must always be the last */
 };
 
+/* log header data */
+struct log_header {
+       enum log_fmt format;  /* how to format the header */
+       int level, facility;  /* used by several formats */
+       struct ist *metadata; /* optional metadata - per-format */
+};
+
+#define LOG_HEADER_NONE (struct log_header){                              \
+                                             .format = LOG_FORMAT_UNSPEC, \
+                                             .level = 0,                  \
+                                             .facility = 0,               \
+                                             .metadata = NULL             \
+                                           }
+
 /* log target types */
 enum log_tgt {
        LOG_TARGET_DGRAM = 0, // datagram address (udp, unix socket)
index d34f482b679278ee08fe0e9609d8a4cfba77e2d2..497b486eeb67c476014df3c64f6ae4bd06411e18 100644 (file)
@@ -163,7 +163,7 @@ static inline int build_logline(struct stream *s, char *dst, size_t maxsize, str
        return sess_build_logline(strm_sess(s), s, dst, maxsize, list_format);
 }
 
-struct ist *build_log_header(enum log_fmt format, int level, int facility, struct ist *metadata, size_t *nbelem);
+struct ist *build_log_header(struct log_header hdr, size_t *nbelem);
 
 /*
  * lookup log forward proxy by name
index 19f2df912d7c85da9e2d4aed4c2d4dea0e7dc9f3..bed687fe3c64876e94d27fb845ec78a8b9924ebf 100644 (file)
@@ -32,22 +32,24 @@ extern struct proxy *sink_proxies_list;
 
 struct sink *sink_find(const char *name);
 struct sink *sink_new_fd(const char *name, const char *desc, enum log_fmt, int fd);
-ssize_t __sink_write(struct sink *sink, size_t maxlen,
-                     const struct ist msg[], size_t nmsg,
-                     int level, int facility, struct ist * metadata);
-int sink_announce_dropped(struct sink *sink, int facility);
+ssize_t __sink_write(struct sink *sink, struct log_header hdr, size_t maxlen,
+                     const struct ist msg[], size_t nmsg);
+int sink_announce_dropped(struct sink *sink, struct log_header hdr);
 
 
-/* tries to send <nmsg> message parts (up to 8, ignored above) from message
- * array <msg> to sink <sink>. Formatting according to the sink's preference is
- * done here. Lost messages are accounted for in the sink's counter. If there
+/* tries to send <nmsg> message parts from message array <msg> to sink <sink>.
+ * Formatting according to the sink's preferences is done here.
+ *
+ * It will stop writing at <maxlen> instead of sink->maxlen if <maxlen> is
+ * positive and inferior to sink->maxlen.
+ *
+ * Lost messages are accounted for in the sink's counter. If there
  * were lost messages, an attempt is first made to indicate it.
  * The function returns the number of Bytes effectively sent or announced.
  * or <= 0 in other cases.
  */
-static inline ssize_t sink_write(struct sink *sink, size_t maxlen,
-                                 const struct ist msg[], size_t nmsg,
-                                 int level, int facility, struct ist *metadata)
+static inline ssize_t sink_write(struct sink *sink, struct log_header hdr,
+                                 size_t maxlen, const struct ist msg[], size_t nmsg)
 {
        ssize_t sent;
 
@@ -59,7 +61,7 @@ static inline ssize_t sink_write(struct sink *sink, size_t maxlen,
                 * position.
                 */
                HA_RWLOCK_WRLOCK(RING_LOCK, &sink->ctx.lock);
-               sent = sink_announce_dropped(sink, facility);
+               sent = sink_announce_dropped(sink, hdr);
                HA_RWLOCK_WRUNLOCK(RING_LOCK, &sink->ctx.lock);
 
                if (!sent) {
@@ -71,7 +73,7 @@ static inline ssize_t sink_write(struct sink *sink, size_t maxlen,
        }
 
        HA_RWLOCK_RDLOCK(RING_LOCK, &sink->ctx.lock);
-       sent = __sink_write(sink, maxlen, msg, nmsg, level, facility, metadata);
+       sent = __sink_write(sink, hdr, maxlen, msg, nmsg);
        HA_RWLOCK_RDUNLOCK(RING_LOCK, &sink->ctx.lock);
 
  fail:
index 3a1341020e61512f72c6b58c998c8ecb1c62a62f..efe1d5b754dea5d99cd5ce68fcbaaff84651570e 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -1435,18 +1435,18 @@ void send_log(struct proxy *p, int level, const char *format, ...)
                   logline, data_len, default_rfc5424_sd_log_format, 2);
 }
 /*
- * This function builds a log header of given format using given
- * metadata, if format is set to LOF_FORMAT_UNSPEC, it tries
- * to determine format based on given metadas. It is useful
- * for log-forwarding to be able to forward any format without
- * settings.
+ * This function builds a log header according to <hdr> settings.
+ *
+ * If hdr.format is set to LOG_FORMAT_UNSPEC, it tries to determine
+ * format based on hdr.metadata. It is useful for log-forwarding to be
+ * able to forward any format without settings.
+ *
  * This function returns a struct ist array of elements of the header
  * nbelem is set to the number of available elements.
  * This function returns currently a maximum of NB_LOG_HDR_IST_ELEMENTS
  * elements.
  */
-struct ist *build_log_header(enum log_fmt format, int level, int facility,
-                             struct ist *metadata, size_t *nbelem)
+struct ist *build_log_header(struct log_header hdr, size_t *nbelem)
 {
        static THREAD_LOCAL struct {
                struct ist ist_vector[NB_LOG_HDR_MAX_ELEMENTS];
@@ -1459,6 +1459,10 @@ struct ist *build_log_header(enum log_fmt format, int level, int facility,
        int len;
        int fac_level = 0;
        time_t time = date.tv_sec;
+       struct ist *metadata = hdr.metadata;
+       enum log_fmt format = hdr.format;
+       int facility = hdr.facility;
+       int level = hdr.level;
 
        *nbelem = 0;
 
@@ -1740,18 +1744,16 @@ struct ist *build_log_header(enum log_fmt format, int level, int facility,
 /*
  * This function sends a syslog message.
  * <target> is the actual log target where log will be sent,
- * The argument <metadata> MUST be an array of size
- * LOG_META_FIELDS*sizeof(struct ist) containing data to build the header.
- * It overrides the last byte of the message vector with an LF character.
  *
+ * Message will be prefixed by header according to <hdr> setting.
  * Final message will be truncated <maxlen> parameter and will be
  * terminated with an LF character.
  *
  * Does not return any error
  */
-static inline void __do_send_log(struct log_target *target, enum log_fmt format,
+static inline void __do_send_log(struct log_target *target, struct log_header hdr,
                                  int nblogger, size_t maxlen,
-                                 int level, int facility, struct ist *metadata, char *message, size_t size)
+                                 char *message, size_t size)
 {
        static THREAD_LOCAL struct iovec iovec[NB_LOG_HDR_MAX_ELEMENTS+1+1] = { }; /* header elements + message + LF */
        static THREAD_LOCAL struct msghdr msghdr = {
@@ -1807,7 +1809,7 @@ static inline void __do_send_log(struct log_target *target, enum log_fmt format,
                }
        }
 
-       msg_header = build_log_header(format, level, facility, metadata, &nbelem);
+       msg_header = build_log_header(hdr, &nbelem);
  send:
        if (target->type == LOG_TARGET_BUFFER) {
                struct ist msg;
@@ -1820,7 +1822,7 @@ static inline void __do_send_log(struct log_target *target, enum log_fmt format,
                 */
                e_maxlen -= 1;
 
-               sent = sink_write(target->sink, e_maxlen, &msg, 1, level, facility, metadata);
+               sent = sink_write(target->sink, hdr, e_maxlen, &msg, 1);
        }
        else if (target->addr->ss_family == AF_CUST_EXISTING_FD) {
                struct ist msg;
@@ -1922,11 +1924,15 @@ void process_send_log(struct list *loggers, int level, int facility,
                        } while (!_HA_ATOMIC_CAS(&logger->lb.curr_rg_idx, &curr_rg_idx, next_rg_idx) &&
                                 __ha_cpu_relax());
                }
-               if (in_range)
-                       __do_send_log(&logger->target, logger->format, ++nblogger, logger->maxlen,
-                                     MAX(level, logger->minlvl),
-                                     (facility == -1) ? logger->facility : facility,
-                                     metadata, message, size);
+               if (in_range) {
+                       struct log_header hdr;
+
+                       hdr.level = MAX(level, logger->minlvl);
+                       hdr.facility = (facility == -1) ? logger->facility : facility;
+                       hdr.format = logger->format;
+                       hdr.metadata = metadata;
+                       __do_send_log(&logger->target, hdr, ++nblogger, logger->maxlen, message, size);
+               }
        }
 }
 
index 57cb7c6f826652c32b7cb5da8b9c65b1e45f4cc9..65985e32b86411937659fb69b8a52c887f8fd9a6 100644 (file)
@@ -1761,7 +1761,7 @@ static int sample_conv_debug(const struct arg *arg_p, struct sample *smp, void *
 
  done:
        line = ist2(buf->area, buf->data);
-       sink_write(sink, 0, &line, 1, 0, 0, NULL);
+       sink_write(sink, LOG_HEADER_NONE, 0, &line, 1);
  end:
        free_trash_chunk(buf);
        return 1;
index 177505a6fb686cffe84e95064667530b5f5aaa05..569b4c8d275203a6b4f068aa43697e0acc3d4674 100644 (file)
@@ -164,18 +164,18 @@ struct sink *sink_new_buf(const char *name, const char *desc, enum log_fmt fmt,
        return NULL;
 }
 
-/* tries to send <nmsg> message parts (up to 8, ignored above) from message
- * array <msg> to sink <sink>. Formatting according to the sink's preference is
- * done here. Lost messages are NOT accounted for. It is preferable to call
- * sink_write() instead which will also try to emit the number of dropped
- * messages when there are any. It will stop writing at <maxlen> instead of
- * sink->maxlen if <maxlen> is positive and inferior to sink->maxlen.
+/* tries to send <nmsg> message parts from message array <msg> to sink <sink>.
+ * Formatting according to the sink's preference is done here. Lost messages
+ * are NOT accounted for. It is preferable to call sink_write() instead which
+ * will also try to emit the number of dropped messages when there are any.
+ *
+ * It will stop writing at <maxlen> instead of sink->maxlen if <maxlen> is
+ * positive and inferior to sink->maxlen.
  *
  * It returns >0 if it could write anything, <=0 otherwise.
  */
- ssize_t __sink_write(struct sink *sink, size_t maxlen,
-                    const struct ist msg[], size_t nmsg,
-                    int level, int facility, struct ist *metadata)
+ ssize_t __sink_write(struct sink *sink, struct log_header hdr,
+                      size_t maxlen, const struct ist msg[], size_t nmsg)
  {
        struct ist *pfx = NULL;
        size_t npfx = 0;
@@ -183,7 +183,8 @@ struct sink *sink_new_buf(const char *name, const char *desc, enum log_fmt fmt,
        if (sink->fmt == LOG_FORMAT_RAW)
                goto send;
 
-       pfx = build_log_header(sink->fmt, level, facility, metadata, &npfx);
+       hdr.format = sink->fmt; /* sink format prevails over log one */
+       pfx = build_log_header(hdr, &npfx);
 
 send:
        if (!maxlen)
@@ -197,16 +198,17 @@ send:
        return 0;
 }
 
-/* Tries to emit a message indicating the number of dropped events. In case of
- * success, the amount of drops is reduced by as much. It's supposed to be
- * called under an exclusive lock on the sink to avoid multiple produces doing
- * the same. On success, >0 is returned, otherwise <=0 on failure.
+/* Tries to emit a message indicating the number of dropped events.
+ * The log header of the original message that we tried to emit is reused
+ * here with the only difference that we override the log level. This is
+ * possible since the announce message will be sent from the same context.
+ *
+ * In case of success, the amount of drops is reduced by as much. It's supposed
+ * to be called under an exclusive lock on the sink to avoid multiple producers
+ * doing the same. On success, >0 is returned, otherwise <=0 on failure.
  */
-int sink_announce_dropped(struct sink *sink, int facility)
+int sink_announce_dropped(struct sink *sink, struct log_header hdr)
 {
-       static THREAD_LOCAL struct ist metadata[LOG_META_FIELDS];
-       static THREAD_LOCAL pid_t curr_pid;
-       static THREAD_LOCAL char pidstr[16];
        unsigned int dropped;
        struct buffer msg;
        struct ist msgvec[1];
@@ -217,24 +219,9 @@ int sink_announce_dropped(struct sink *sink, int facility)
                chunk_printf(&msg, "%u event%s dropped", dropped, dropped > 1 ? "s" : "");
                msgvec[0] = ist2(msg.area, msg.data);
 
-               if (!metadata[LOG_META_HOST].len) {
-                       if (global.log_send_hostname)
-                               metadata[LOG_META_HOST] = ist(global.log_send_hostname);
-               }
-
-               if (!metadata[LOG_META_TAG].len)
-                       metadata[LOG_META_TAG] = ist2(global.log_tag.area, global.log_tag.data);
-
-               if (unlikely(curr_pid != getpid()))
-                        metadata[LOG_META_PID].len = 0;
-
-               if (!metadata[LOG_META_PID].len) {
-                       curr_pid = getpid();
-                       ltoa_o(curr_pid, pidstr, sizeof(pidstr));
-                       metadata[LOG_META_PID] = ist2(pidstr, strlen(pidstr));
-               }
+               hdr.level = LOG_NOTICE; /* override level but keep original log header data */
 
-               if (__sink_write(sink, 0, msgvec, 1, LOG_NOTICE, facility, metadata) <= 0)
+               if (__sink_write(sink, hdr, 0, msgvec, 1) <= 0)
                        return 0;
                /* success! */
                HA_ATOMIC_SUB(&sink->ctx.dropped, dropped);
index 30fca7ae130179113959ae36b317c225da7ac84e..7cbbd132b99a07b5d2f3d175093a3ea3e89e1675 100644 (file)
@@ -291,7 +291,7 @@ void __trace(enum trace_level level, uint64_t mask, struct trace_source *src,
        }
 
        if (src->sink)
-               sink_write(src->sink, 0, line, words, 0, 0, NULL);
+               sink_write(src->sink, LOG_HEADER_NONE, 0, line, words);
 
  end:
        /* check if we need to stop the trace now */