diff --git a/include/proto/log.h b/include/proto/log.h index 0967ae8bf..14dfc5bcd 100644 --- a/include/proto/log.h +++ b/include/proto/log.h @@ -39,6 +39,7 @@ extern char *log_format; extern char default_tcp_log_format[]; extern char default_http_log_format[]; extern char clf_http_log_format[]; +extern char *logheader; extern char *logline; diff --git a/include/types/log.h b/include/types/log.h index f6f6e99a6..6707aa6b5 100644 --- a/include/types/log.h +++ b/include/types/log.h @@ -30,7 +30,7 @@ #define NB_LOG_FACILITIES 24 #define NB_LOG_LEVELS 8 -#define NB_MSG_IOVEC_ELEMENTS 1 +#define NB_MSG_IOVEC_ELEMENTS 2 #define SYSLOG_PORT 514 #define UNIQUEID_LEN 128 diff --git a/src/cfgparse.c b/src/cfgparse.c index b40588fb6..39ee35988 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1571,6 +1571,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) if (logsrv->maxlen > global.max_syslog_len) { global.max_syslog_len = logsrv->maxlen; + logheader = realloc(logheader, global.max_syslog_len + 1); logline = realloc(logline, global.max_syslog_len + 1); } @@ -5853,6 +5854,7 @@ stats_error_parsing: if (logsrv->maxlen > global.max_syslog_len) { global.max_syslog_len = logsrv->maxlen; + logheader = realloc(logheader, global.max_syslog_len + 1); logline = realloc(logline, global.max_syslog_len + 1); } diff --git a/src/log.c b/src/log.c index 8a7e5f482..3724dd47e 100644 --- a/src/log.c +++ b/src/log.c @@ -151,8 +151,14 @@ char clf_http_log_format[] = "%{+Q}o %{-Q}ci - - [%T] %r %ST %B \"\" \"\" %cp %m char default_tcp_log_format[] = "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"; char *log_format = NULL; -/* This is a global syslog line, common to all outgoing messages. It begins - * with the syslog tag and the date that are updated by update_log_hdr(). +/* This is a global syslog header, common to all outgoing messages. It + * begins with the syslog tag and the date that are updated by + * update_log_hdr(). + */ +char *logheader = NULL; + +/* This is a global syslog message buffer, common to all outgoing + * messages. It contains only the data part. */ char *logline = NULL; @@ -734,7 +740,7 @@ char *lf_port(char *dst, struct sockaddr *sockaddr, size_t size, struct logforma return ret; } -/* Re-generate the syslog header at the beginning of logline once a second and +/* Re-generate the syslog header at the beginning of logheader once a second and * return the pointer to the first character after the header. */ static char *update_log_hdr(const char *log_tag) @@ -751,7 +757,7 @@ static char *update_log_hdr(const char *log_tag) tvsec = date.tv_sec; get_localtime(tvsec, &tm); - hdr_len = snprintf(logline, global.max_syslog_len, + hdr_len = snprintf(logheader, global.max_syslog_len, "<<<<>%s %2d %02d:%02d:%02d %s", monthname[tm.tm_mon], tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, @@ -763,36 +769,32 @@ static char *update_log_hdr(const char *log_tag) if (hdr_len < 0 || hdr_len > global.max_syslog_len) hdr_len = global.max_syslog_len; - dataptr = logline + hdr_len; + dataptr = logheader + hdr_len; } dataptr[0] = 0; // ensure we get rid of any previous attempt - tag_len = snprintf(dataptr, logline + global.max_syslog_len - dataptr, "%s[%d]: ", log_tag, pid); - if (tag_len < 0 || tag_len > logline + global.max_syslog_len - dataptr) - tag_len = logline + global.max_syslog_len - dataptr; + tag_len = snprintf(dataptr, logheader + global.max_syslog_len - dataptr, "%s[%d]: ", log_tag, pid); + if (tag_len < 0 || tag_len > logheader + global.max_syslog_len - dataptr) + tag_len = logheader + global.max_syslog_len - dataptr; return dataptr + tag_len; } /* - * This function adds a header to the message and sends the syslog message - * using a printf format string. It expects an LF-terminated message. + * This function sends the syslog message using a printf format string. It + * expects an LF-terminated message. */ void send_log(struct proxy *p, int level, const char *format, ...) { va_list argp; - char *dataptr; int data_len; if (level < 0 || format == NULL || logline == NULL) return; - dataptr = update_log_hdr(p && p->log_tag ? p->log_tag : global.log_tag); /* update log header and skip it */ - data_len = dataptr - logline; - va_start(argp, format); - data_len += vsnprintf(dataptr, logline + global.max_syslog_len - dataptr, format, argp); + data_len = vsnprintf(logline, global.max_syslog_len, format, argp); if (data_len < 0 || data_len > global.max_syslog_len) data_len = global.max_syslog_len; va_end(argp); @@ -803,7 +805,7 @@ 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. - * It overrides the last byte (message[size-1]) with an LF character. + * It overrides the last byte of the vector with an LF character. */ void __send_log(struct proxy *p, int level, char *message, size_t size) { @@ -819,7 +821,10 @@ void __send_log(struct proxy *p, int level, char *message, size_t size) struct list *logsrvs = NULL; struct logsrv *tmp = NULL; int nblogger; + char *log_tag = global.log_tag; char *log_ptr; + char *hdr_ptr; + size_t hdr_size; dataptr = message; @@ -831,11 +836,17 @@ void __send_log(struct proxy *p, int level, char *message, size_t size) if (!LIST_ISEMPTY(&p->logsrvs)) { logsrvs = &p->logsrvs; } + if (p->log_tag) { + log_tag = p->log_tag; + } } if (!logsrvs) return; + hdr_ptr = update_log_hdr(log_tag); + hdr_size = hdr_ptr - logheader; + /* Send log messages to syslog server. */ nblogger = 0; list_for_each_entry(tmp, logsrvs, list) { @@ -843,7 +854,8 @@ void __send_log(struct proxy *p, int level, char *message, size_t size) int *plogfd = logsrv->addr.ss_family == AF_UNIX ? &logfdunix : &logfdinet; int sent; - int max; + int hdr_max = 0; + int max = 1; char backup; nblogger++; @@ -875,34 +887,46 @@ void __send_log(struct proxy *p, int level, char *message, size_t size) * and we change the pointer to the header accordingly. */ fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl); - log_ptr = dataptr + 3; /* last digit of the log level */ + hdr_ptr = logheader + 3; /* last digit of the log level */ do { - *log_ptr = '0' + fac_level % 10; + *hdr_ptr = '0' + fac_level % 10; fac_level /= 10; - log_ptr--; - } while (fac_level && log_ptr > dataptr); - *log_ptr = '<'; + hdr_ptr--; + } while (fac_level && hdr_ptr > logheader); + *hdr_ptr = '<'; - max = size - (log_ptr - dataptr); - if (max > logsrv->maxlen) - max = logsrv->maxlen; + log_ptr = dataptr; + hdr_max = hdr_size - (hdr_ptr - logheader); + + if (unlikely(hdr_size >= logsrv->maxlen)) { + hdr_max = MIN(hdr_max, logsrv->maxlen) - 1; + goto send; + } + + max = MIN(size, logsrv->maxlen - hdr_max); + + log_ptr += max - 1; + +send: /* insert a \n at the end of the message, but save what was * there first because we could have different max lengths * for different log targets. */ - backup = log_ptr[max - 1]; - log_ptr[max - 1] = '\n'; + backup = *log_ptr; + *log_ptr = '\n'; - iovec[0].iov_base = log_ptr; - iovec[0].iov_len = max; + iovec[0].iov_base = hdr_ptr; + iovec[0].iov_len = hdr_max; + iovec[1].iov_base = dataptr; + iovec[1].iov_len = max; msghdr.msg_name = (struct sockaddr *)&logsrv->addr; msghdr.msg_namelen = get_addr_len(&logsrv->addr); sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL); - log_ptr[max - 1] = backup; + *log_ptr = backup; if (sent < 0) { Alert("sendmsg logger #%d failed: %s (errno=%d)\n", @@ -1822,7 +1846,6 @@ out: void strm_log(struct stream *s) { struct session *sess = s->sess; - char *tmplog; int size, err, level; /* if we don't want to log normal traffic, return now */ @@ -1857,9 +1880,7 @@ void strm_log(struct stream *s) build_logline(s, s->unique_id, UNIQUEID_LEN, &sess->fe->format_unique_id); } - tmplog = update_log_hdr(sess->fe->log_tag ? sess->fe->log_tag : global.log_tag); - size = tmplog - logline; - size += build_logline(s, tmplog, global.max_syslog_len - size, &sess->fe->logformat); + size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat); if (size > 0) { sess->fe->log_count++; __send_log(sess->fe, level, logline, size + 1);