diff --git a/include/haproxy/log-t.h b/include/haproxy/log-t.h index b8a46fd95..36d9c19ec 100644 --- a/include/haproxy/log-t.h +++ b/include/haproxy/log-t.h @@ -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) diff --git a/include/haproxy/log.h b/include/haproxy/log.h index d34f482b6..497b486ee 100644 --- a/include/haproxy/log.h +++ b/include/haproxy/log.h @@ -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 diff --git a/include/haproxy/sink.h b/include/haproxy/sink.h index 19f2df912..bed687fe3 100644 --- a/include/haproxy/sink.h +++ b/include/haproxy/sink.h @@ -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 message parts (up to 8, ignored above) from message - * array to 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 message parts from message array to sink . + * Formatting according to the sink's preferences is done here. + * + * It will stop writing at instead of sink->maxlen if 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: diff --git a/src/log.c b/src/log.c index 3a1341020..efe1d5b75 100644 --- 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 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. * is the actual log target where log will be sent, - * The argument 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 setting. * Final message will be truncated 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); + } } } diff --git a/src/sample.c b/src/sample.c index 57cb7c6f8..65985e32b 100644 --- a/src/sample.c +++ b/src/sample.c @@ -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; diff --git a/src/sink.c b/src/sink.c index 177505a6f..569b4c8d2 100644 --- a/src/sink.c +++ b/src/sink.c @@ -164,18 +164,18 @@ struct sink *sink_new_buf(const char *name, const char *desc, enum log_fmt fmt, return NULL; } -/* tries to send message parts (up to 8, ignored above) from message - * array to 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 instead of - * sink->maxlen if is positive and inferior to sink->maxlen. +/* tries to send message parts from message array to 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 instead of sink->maxlen if 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); - } + hdr.level = LOG_NOTICE; /* override level but keep original log header data */ - 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)); - } - - 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); diff --git a/src/trace.c b/src/trace.c index 30fca7ae1..7cbbd132b 100644 --- a/src/trace.c +++ b/src/trace.c @@ -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 */