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)
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
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;
* 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) {
}
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:
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];
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;
/*
* 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 = {
}
}
- 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;
*/
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;
} 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);
+ }
}
}
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;
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;
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)
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];
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);
}
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 */