MINOR: log: Extract some code to send syslog messages.
This patch extracts the code of __send_log() responsible of sending a syslog
message to a syslog destination represented as a logsrv struct to define
__do_send_log() function. __send_log() calls __do_send_log() for each syslog
destination of a proxy after having prepared some of its parameters.
diff --git a/src/log.c b/src/log.c
index 39e472b..e9d711c 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1310,13 +1310,16 @@
}
/*
- * This function sends a syslog message.
- * It doesn't care about errors nor does it report them.
+ * This function sends a syslog message to <logsrv>.
+ * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
+ * Same thing for <sd> and <sd_size> which are used for the structured-data part
+ * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
* It overrides the last byte of the message vector with an LF character.
- * The arguments <sd> and <sd_size> are used for the structured-data part
- * in RFC5424 formatted syslog messages.
+ * Does not return any error,
*/
-void __send_log(struct proxy *p, int level, char *message, size_t size, char *sd, size_t sd_size)
+static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
+ int level, char *message, size_t size, char *sd, size_t sd_size,
+ char *tag_str, size_t tag_size)
{
static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
static THREAD_LOCAL struct msghdr msghdr = {
@@ -1326,259 +1329,267 @@
static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
static THREAD_LOCAL char *dataptr = NULL;
- int fac_level;
- struct list *logsrvs = NULL;
- struct logsrv *tmp = NULL;
- int nblogger;
+ time_t time = date.tv_sec;
char *hdr, *hdr_ptr;
size_t hdr_size;
- time_t time = date.tv_sec;
struct buffer *tag = &global.log_tag;
- static THREAD_LOCAL int curr_pid;
- static THREAD_LOCAL char pidstr[100];
- static THREAD_LOCAL struct buffer pid;
+ int fac_level;
+ int *plogfd;
+ char *pid_sep1 = "", *pid_sep2 = "";
+ char logheader_short[3];
+ int sent;
+ int maxlen;
+ int hdr_max = 0;
+ int tag_max = 0;
+ int pid_sep1_max = 0;
+ int pid_sep2_max = 0;
+ int sd_max = 0;
+ int max = 0;
msghdr.msg_iov = iovec;
dataptr = message;
- if (p == NULL) {
- if (!LIST_ISEMPTY(&global.logsrvs)) {
- logsrvs = &global.logsrvs;
- }
- } else {
- if (!LIST_ISEMPTY(&p->logsrvs)) {
- logsrvs = &p->logsrvs;
- }
- if (p->log_tag.area) {
- tag = &p->log_tag;
+ if (logsrv->addr.ss_family == AF_UNSPEC) {
+ /* the socket's address is a file descriptor */
+ plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
+ if (unlikely(!((struct sockaddr_in *)&logsrv->addr)->sin_port)) {
+ /* FD not yet initialized to non-blocking mode.
+ * DON'T DO IT ON A TERMINAL!
+ */
+ if (!isatty(*plogfd))
+ fcntl(*plogfd, F_SETFL, O_NONBLOCK);
+ ((struct sockaddr_in *)&logsrv->addr)->sin_port = 1;
}
}
+ else if (logsrv->addr.ss_family == AF_UNIX)
+ plogfd = &logfdunix;
+ else
+ plogfd = &logfdinet;
- if (!logsrvs)
- return;
+ if (unlikely(*plogfd < 0)) {
+ /* socket not successfully initialized yet */
+ if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
+ (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
+ static char once;
- if (unlikely(curr_pid != getpid())) {
- curr_pid = getpid();
- ltoa_o(curr_pid, pidstr, sizeof(pidstr));
- chunk_initstr(&pid, pidstr);
+ if (!once) {
+ once = 1; /* note: no need for atomic ops here */
+ ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
+ nblogger, strerror(errno), errno);
+ }
+ return;
+ } else {
+ /* we don't want to receive anything on this socket */
+ setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
+ /* does nothing under Linux, maybe needed for others */
+ shutdown(*plogfd, SHUT_RD);
+ fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
+ }
}
- /* Send log messages to syslog server. */
- nblogger = 0;
- list_for_each_entry(tmp, logsrvs, list) {
- const struct logsrv *logsrv = tmp;
- int *plogfd;
- char *pid_sep1 = "", *pid_sep2 = "";
- char logheader_short[3];
- int sent;
- int maxlen;
- int hdr_max = 0;
- int tag_max = 0;
- int pid_sep1_max = 0;
- int pid_max = 0;
- int pid_sep2_max = 0;
- int sd_max = 0;
- int max = 0;
-
- nblogger++;
+ switch (logsrv->format) {
+ case LOG_FORMAT_RFC3164:
+ hdr = logheader;
+ hdr_ptr = update_log_hdr(time);
+ break;
- /* we can filter the level of the messages that are sent to each logger */
- if (level > logsrv->level)
- continue;
+ case LOG_FORMAT_RFC5424:
+ hdr = logheader_rfc5424;
+ hdr_ptr = update_log_hdr_rfc5424(time);
+ sd_max = sd_size; /* the SD part allowed only in RFC5424 */
+ break;
- if (logsrv->addr.ss_family == AF_UNSPEC) {
- /* the socket's address is a file descriptor */
- plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
- if (unlikely(!((struct sockaddr_in *)&logsrv->addr)->sin_port)) {
- /* FD not yet initialized to non-blocking mode.
- * DON'T DO IT ON A TERMINAL!
- */
- if (!isatty(*plogfd))
- fcntl(*plogfd, F_SETFL, O_NONBLOCK);
- ((struct sockaddr_in *)&logsrv->addr)->sin_port = 1;
- }
- }
- else if (logsrv->addr.ss_family == AF_UNIX)
- plogfd = &logfdunix;
- else
- plogfd = &logfdinet;
+ case LOG_FORMAT_SHORT:
+ /* all fields are known, skip the header generation */
+ hdr = logheader_short;
+ hdr[0] = '<';
+ hdr[1] = '0' + MAX(level, logsrv->minlvl);
+ hdr[2] = '>';
+ hdr_ptr = hdr;
+ hdr_max = 3;
+ maxlen = logsrv->maxlen - hdr_max;
+ max = MIN(size, maxlen) - 1;
+ goto send;
- if (unlikely(*plogfd < 0)) {
- /* socket not successfully initialized yet */
- if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
- (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
- static char once;
+ case LOG_FORMAT_RAW:
+ /* all fields are known, skip the header generation */
+ hdr_ptr = hdr = "";
+ hdr_max = 0;
+ maxlen = logsrv->maxlen;
+ max = MIN(size, maxlen) - 1;
+ goto send;
- if (!once) {
- once = 1; /* note: no need for atomic ops here */
- ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
- nblogger, strerror(errno), errno);
- }
- continue;
- } else {
- /* we don't want to receive anything on this socket */
- setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
- /* does nothing under Linux, maybe needed for others */
- shutdown(*plogfd, SHUT_RD);
- fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
- }
- }
+ default:
+ return; /* must never happen */
+ }
- switch (logsrv->format) {
- case LOG_FORMAT_RFC3164:
- hdr = logheader;
- hdr_ptr = update_log_hdr(time);
- break;
+ hdr_size = hdr_ptr - hdr;
- case LOG_FORMAT_RFC5424:
- hdr = logheader_rfc5424;
- hdr_ptr = update_log_hdr_rfc5424(time);
- sd_max = sd_size; /* the SD part allowed only in RFC5424 */
- break;
+ /* For each target, we may have a different facility.
+ * We can also have a different log level for each message.
+ * This induces variations in the message header length.
+ * Since we don't want to recompute it each time, nor copy it every
+ * time, we only change the facility in the pre-computed header,
+ * and we change the pointer to the header accordingly.
+ */
+ fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
+ hdr_ptr = hdr + 3; /* last digit of the log level */
+ do {
+ *hdr_ptr = '0' + fac_level % 10;
+ fac_level /= 10;
+ hdr_ptr--;
+ } while (fac_level && hdr_ptr > hdr);
+ *hdr_ptr = '<';
- case LOG_FORMAT_SHORT:
- /* all fields are known, skip the header generation */
- hdr = logheader_short;
- hdr[0] = '<';
- hdr[1] = '0' + MAX(level, logsrv->minlvl);
- hdr[2] = '>';
- hdr_ptr = hdr;
- hdr_max = 3;
- maxlen = logsrv->maxlen - hdr_max;
- max = MIN(size, maxlen) - 1;
- goto send;
+ hdr_max = hdr_size - (hdr_ptr - hdr);
- case LOG_FORMAT_RAW:
- /* all fields are known, skip the header generation */
- hdr_ptr = hdr = "";
- hdr_max = 0;
- maxlen = logsrv->maxlen;
- max = MIN(size, maxlen) - 1;
- goto send;
+ /* time-based header */
+ if (unlikely(hdr_size >= logsrv->maxlen)) {
+ hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
+ sd_max = 0;
+ goto send;
+ }
- default:
- continue; /* must never happen */
- }
+ maxlen = logsrv->maxlen - hdr_max;
- hdr_size = hdr_ptr - hdr;
+ /* tag */
+ tag_max = tag->data;
+ if (unlikely(tag_max >= maxlen)) {
+ tag_max = maxlen - 1;
+ sd_max = 0;
+ goto send;
+ }
- /* For each target, we may have a different facility.
- * We can also have a different log level for each message.
- * This induces variations in the message header length.
- * Since we don't want to recompute it each time, nor copy it every
- * time, we only change the facility in the pre-computed header,
- * and we change the pointer to the header accordingly.
- */
- fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
- hdr_ptr = hdr + 3; /* last digit of the log level */
- do {
- *hdr_ptr = '0' + fac_level % 10;
- fac_level /= 10;
- hdr_ptr--;
- } while (fac_level && hdr_ptr > hdr);
- *hdr_ptr = '<';
+ maxlen -= tag_max;
- hdr_max = hdr_size - (hdr_ptr - hdr);
+ /* first pid separator */
+ pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
+ if (unlikely(pid_sep1_max >= maxlen)) {
+ pid_sep1_max = maxlen - 1;
+ sd_max = 0;
+ goto send;
+ }
- /* time-based header */
- if (unlikely(hdr_size >= logsrv->maxlen)) {
- hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
- sd_max = 0;
- goto send;
- }
+ pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
+ maxlen -= pid_sep1_max;
- maxlen = logsrv->maxlen - hdr_max;
+ /* pid */
+ if (unlikely(pid_size >= maxlen)) {
+ pid_size = maxlen - 1;
+ sd_max = 0;
+ goto send;
+ }
- /* tag */
- tag_max = tag->data;
- if (unlikely(tag_max >= maxlen)) {
- tag_max = maxlen - 1;
- sd_max = 0;
- goto send;
- }
+ maxlen -= pid_size;
- maxlen -= tag_max;
+ /* second pid separator */
+ pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
+ if (unlikely(pid_sep2_max >= maxlen)) {
+ pid_sep2_max = maxlen - 1;
+ sd_max = 0;
+ goto send;
+ }
- /* first pid separator */
- pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
- if (unlikely(pid_sep1_max >= maxlen)) {
- pid_sep1_max = maxlen - 1;
- sd_max = 0;
- goto send;
- }
+ pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
+ maxlen -= pid_sep2_max;
- pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
- maxlen -= pid_sep1_max;
+ /* structured-data */
+ if (sd_max >= maxlen) {
+ sd_max = maxlen - 1;
+ goto send;
+ }
- /* pid */
- pid_max = pid.data;
- if (unlikely(pid_max >= maxlen)) {
- pid_max = maxlen - 1;
- sd_max = 0;
- goto send;
- }
+ max = MIN(size, maxlen - sd_max) - 1;
+send:
+ iovec[0].iov_base = hdr_ptr;
+ iovec[0].iov_len = hdr_max;
+ iovec[1].iov_base = tag_str;
+ iovec[1].iov_len = tag_size;
+ iovec[2].iov_base = pid_sep1;
+ iovec[2].iov_len = pid_sep1_max;
+ iovec[3].iov_base = pid_str;
+ iovec[3].iov_len = pid_size;
+ iovec[4].iov_base = pid_sep2;
+ iovec[4].iov_len = pid_sep2_max;
+ iovec[5].iov_base = sd;
+ iovec[5].iov_len = sd_max;
+ iovec[6].iov_base = dataptr;
+ iovec[6].iov_len = max;
+ iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
+ iovec[7].iov_len = 1;
- maxlen -= pid_max;
+ if (logsrv->addr.ss_family == AF_UNSPEC) {
+ /* the target is a direct file descriptor */
+ sent = writev(*plogfd, iovec, 8);
+ }
+ else {
+ msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
+ msghdr.msg_namelen = get_addr_len(&logsrv->addr);
- /* second pid separator */
- pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
- if (unlikely(pid_sep2_max >= maxlen)) {
- pid_sep2_max = maxlen - 1;
- sd_max = 0;
- goto send;
- }
+ sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
+ }
- pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
- maxlen -= pid_sep2_max;
+ if (sent < 0) {
+ static char once;
- /* structured-data */
- if (sd_max >= maxlen) {
- sd_max = maxlen - 1;
- goto send;
+ if (errno == EAGAIN)
+ _HA_ATOMIC_ADD(&dropped_logs, 1);
+ else if (!once) {
+ once = 1; /* note: no need for atomic ops here */
+ ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
+ nblogger, strerror(errno), errno);
}
+ }
+}
- max = MIN(size, maxlen - sd_max) - 1;
-send:
- iovec[0].iov_base = hdr_ptr;
- iovec[0].iov_len = hdr_max;
- iovec[1].iov_base = tag->area;
- iovec[1].iov_len = tag_max;
- iovec[2].iov_base = pid_sep1;
- iovec[2].iov_len = pid_sep1_max;
- iovec[3].iov_base = pid.area;
- iovec[3].iov_len = pid_max;
- iovec[4].iov_base = pid_sep2;
- iovec[4].iov_len = pid_sep2_max;
- iovec[5].iov_base = sd;
- iovec[5].iov_len = sd_max;
- iovec[6].iov_base = dataptr;
- iovec[6].iov_len = max;
- iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
- iovec[7].iov_len = 1;
+/*
+ * This function sends a syslog message.
+ * It doesn't care about errors nor does it report them.
+ * The arguments <sd> and <sd_size> are used for the structured-data part
+ * in RFC5424 formatted syslog messages.
+ */
+void __send_log(struct proxy *p, int level, char *message, size_t size, char *sd, size_t sd_size)
+{
+ struct list *logsrvs = NULL;
+ struct logsrv *logsrv;
+ int nblogger;
+ static THREAD_LOCAL int curr_pid;
+ static THREAD_LOCAL char pidstr[100];
+ static THREAD_LOCAL struct buffer pid;
+ struct buffer *tag = &global.log_tag;
- if (logsrv->addr.ss_family == AF_UNSPEC) {
- /* the target is a direct file descriptor */
- sent = writev(*plogfd, iovec, 8);
+ if (p == NULL) {
+ if (!LIST_ISEMPTY(&global.logsrvs)) {
+ logsrvs = &global.logsrvs;
}
- else {
- msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
- msghdr.msg_namelen = get_addr_len(&logsrv->addr);
-
- sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
+ } else {
+ if (!LIST_ISEMPTY(&p->logsrvs)) {
+ logsrvs = &p->logsrvs;
}
+ if (p->log_tag.area) {
+ tag = &p->log_tag;
+ }
+ }
- if (sent < 0) {
- static char once;
+ if (!logsrvs)
+ return;
- if (errno == EAGAIN)
- _HA_ATOMIC_ADD(&dropped_logs, 1);
- else if (!once) {
- once = 1; /* note: no need for atomic ops here */
- ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
- nblogger, strerror(errno), errno);
- }
- }
+ if (unlikely(curr_pid != getpid())) {
+ curr_pid = getpid();
+ ltoa_o(curr_pid, pidstr, sizeof(pidstr));
+ chunk_initstr(&pid, pidstr);
+ }
+
+ /* Send log messages to syslog server. */
+ nblogger = 0;
+ list_for_each_entry(logsrv, logsrvs, list) {
+ /* we can filter the level of the messages that are sent to each logger */
+ if (level > logsrv->level)
+ continue;
+
+ __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
+ message, size, sd, sd_size, tag->area, tag->data);
}
}