]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: log: Extract some code to send syslog messages.
authorFrédéric Lécaille <flecaille@haproxy.com>
Wed, 10 Apr 2019 06:22:17 +0000 (08:22 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 23 Apr 2019 12:16:51 +0000 (14:16 +0200)
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.

src/log.c

index 39e472b3309f23f2cdbd12417b1b9bbd9b1ba4bd..e9d711c72b2026d0b5efe36abbc8e4fa2839b1f1 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -1310,13 +1310,16 @@ void send_log(struct proxy *p, int level, const char *format, ...)
 }
 
 /*
- * 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 @@ void __send_log(struct proxy *p, int level, char *message, size_t size, char *sd
        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 (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;
                }
-               if (p->log_tag.area) {
-                       tag = &p->log_tag;
+       }
+       else if (logsrv->addr.ss_family == AF_UNIX)
+               plogfd = &logfdunix;
+       else
+               plogfd = &logfdinet;
+
+       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 (!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);
                }
        }
 
-       if (!logsrvs)
-               return;
+       switch (logsrv->format) {
+       case LOG_FORMAT_RFC3164:
+               hdr = logheader;
+               hdr_ptr = update_log_hdr(time);
+               break;
+
+       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;
+
+       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(curr_pid != getpid())) {
-               curr_pid = getpid();
-               ltoa_o(curr_pid, pidstr, sizeof(pidstr));
-               chunk_initstr(&pid, pidstr);
-       }
+       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;
 
-       /* 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++;
+       default:
+               return; /* must never happen */
+       }
 
-               /* we can filter the level of the messages that are sent to each logger */
-               if (level > logsrv->level)
-                       continue;
+       hdr_size = hdr_ptr - hdr;
 
-               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 (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 (!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);
-                       }
-               }
+       /* 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 = '<';
+
+       hdr_max = hdr_size - (hdr_ptr - hdr);
+
+       /* time-based header */
+       if (unlikely(hdr_size >= logsrv->maxlen)) {
+               hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
+               sd_max = 0;
+               goto send;
+       }
 
-               switch (logsrv->format) {
-               case LOG_FORMAT_RFC3164:
-                       hdr = logheader;
-                       hdr_ptr = update_log_hdr(time);
-                       break;
+       maxlen = logsrv->maxlen - hdr_max;
 
-               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;
+       /* tag */
+       tag_max = tag->data;
+       if (unlikely(tag_max >= maxlen)) {
+               tag_max = maxlen - 1;
+               sd_max = 0;
+               goto send;
+       }
 
-               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;
-
-               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;
+       maxlen -= tag_max;
 
-               default:
-                       continue; /* must never happen */
-               }
+       /* 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;
+       }
 
-               hdr_size = hdr_ptr - hdr;
+       pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
+       maxlen -= pid_sep1_max;
 
-               /* 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 = '<';
-
-               hdr_max = hdr_size - (hdr_ptr - hdr);
-
-               /* time-based header */
-               if (unlikely(hdr_size >= logsrv->maxlen)) {
-                       hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
-                       sd_max = 0;
-                       goto send;
-               }
+       /* pid */
+       if (unlikely(pid_size >= maxlen)) {
+               pid_size = maxlen - 1;
+               sd_max = 0;
+               goto send;
+       }
 
-               maxlen = logsrv->maxlen - hdr_max;
+       maxlen -= pid_size;
 
-               /* tag */
-               tag_max = tag->data;
-               if (unlikely(tag_max >= maxlen)) {
-                       tag_max = maxlen - 1;
-                       sd_max = 0;
-                       goto send;
-               }
+       /* 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;
+       }
 
-               maxlen -= tag_max;
+       pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
+       maxlen -= pid_sep2_max;
 
-               /* 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;
-               }
+       /* structured-data */
+       if (sd_max >= maxlen) {
+               sd_max = maxlen - 1;
+               goto send;
+       }
 
-               pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
-               maxlen -= pid_sep1_max;
+       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;
+
+       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);
 
-               /* pid */
-               pid_max = pid.data;
-               if (unlikely(pid_max >= maxlen)) {
-                       pid_max = maxlen - 1;
-                       sd_max = 0;
-                       goto send;
-               }
+               sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
+       }
 
-               maxlen -= pid_max;
+       if (sent < 0) {
+               static char once;
 
-               /* 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;
+               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);
                }
+       }
+}
 
-               pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
-               maxlen -= pid_sep2_max;
+/*
+ * 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;
 
-               /* structured-data */
-               if (sd_max >= maxlen) {
-                       sd_max = maxlen - 1;
-                       goto send;
+       if (p == NULL) {
+               if (!LIST_ISEMPTY(&global.logsrvs)) {
+                       logsrvs = &global.logsrvs;
                }
-
-               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;
-
-               if (logsrv->addr.ss_family == AF_UNSPEC) {
-                       /* the target is a direct file descriptor */
-                       sent = writev(*plogfd, iovec, 8);
+       } else {
+               if (!LIST_ISEMPTY(&p->logsrvs)) {
+                       logsrvs = &p->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);
+               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);
        }
 }