From c7c7be21bf6c7e9afd897d4bf451dc450187a77e Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 23 Jun 2014 18:07:15 +0200 Subject: [PATCH] BUG/MINOR: logs: properly initialize and count log sockets Commit 81ae195 ("[MEDIUM] add support for logging via a UNIX socket") merged in 1.3.14 introduced a few minor issues with log sockets. All of them happen only when a failure is encountered when trying to set up the logging socket (eg: socket family is not available or is temporarily short in resources). The first socket which experiences an error causes the socket setup loop to abort, possibly preventing any log from being sent if it was the first logger. The second issue is that if this socket finally succeeds after a second attempt, errors are reported for the wrong logger (eg: logger #1 failed instead of #2). The last point is that we now have multiple loggers, and it's a waste of time to walk over their list for every log while they're almost always properly set up. So in order to fix all this, let's merge the two lists. If a logger experiences an error, it simply sends an alert and skips to the next one. That way they don't prevent messages from being sent and are all properly accounted for. --- src/log.c | 49 +++++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/src/log.c b/src/log.c index eb7ccb1778..114ab7b610 100644 --- a/src/log.c +++ b/src/log.c @@ -813,37 +813,6 @@ void __send_log(struct proxy *p, int level, char *message, size_t size) message[size - 1] = '\n'; - /* Lazily set up syslog sockets for protocol families of configured - * syslog servers. */ - nblogger = 0; - list_for_each_entry(tmp, logsrvs, list) { - const struct logsrv *logsrv = tmp; - int proto, *plogfd; - - if (logsrv->addr.ss_family == AF_UNIX) { - proto = 0; - plogfd = &logfdunix; - } else { - proto = IPPROTO_UDP; - plogfd = &logfdinet; - } - if (*plogfd >= 0) { - /* socket already created. */ - continue; - } - if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM, - proto)) < 0) { - Alert("socket for logger #%d failed: %s (errno=%d)\n", - nblogger + 1, strerror(errno), errno); - return; - } - /* 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); - nblogger++; - } - /* Send log messages to syslog server. */ nblogger = 0; list_for_each_entry(tmp, logsrvs, list) { @@ -852,10 +821,27 @@ void __send_log(struct proxy *p, int level, char *message, size_t size) &logfdunix : &logfdinet; int sent; + nblogger++; + /* we can filter the level of the messages that are sent to each logger */ if (level > logsrv->level) continue; + if (unlikely(*plogfd < 0)) { + /* socket not successfully initialized yet */ + int proto = logsrv->addr.ss_family == AF_UNIX ? 0 : IPPROTO_UDP; + + if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM, proto)) < 0) { + Alert("socket for logger #%d failed: %s (errno=%d)\n", + nblogger, strerror(errno), errno); + continue; + } + /* 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); + } + /* 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. @@ -879,7 +865,6 @@ void __send_log(struct proxy *p, int level, char *message, size_t size) Alert("sendto logger #%d failed: %s (errno=%d)\n", nblogger, strerror(errno), errno); } - nblogger++; } }