MEDIUM: logs: remove the hostname, tag and pid part from the logheader
At the moment we have to call snprintf() for every log line just to
rebuild a constant. Thanks to sendmsg(), we send the message in 3 parts:
time-based header, proxy-specific hostname+log-tag+pid, session-specific
message.
diff --git a/include/proto/log.h b/include/proto/log.h
index 14dfc5b..e8b57d8 100644
--- a/include/proto/log.h
+++ b/include/proto/log.h
@@ -138,6 +138,11 @@
*/
char *lf_port(char *dst, struct sockaddr *sockaddr, size_t size, struct logformat_node *node);
+/*
+ * Write hostname, log_tag and pid to the log string
+ */
+char *lf_host_tag_pid(char *dst, const char *hostname, const char *log_tag, int pid, size_t size);
+
#endif /* _PROTO_LOG_H */
diff --git a/include/types/log.h b/include/types/log.h
index 6707aa6..0214ae6 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 2
+#define NB_MSG_IOVEC_ELEMENTS 3
#define SYSLOG_PORT 514
#define UNIQUEID_LEN 128
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 170e6f7..1400126 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -346,6 +346,7 @@
struct list logsrvs;
struct list logformat; /* log_format linked list */
char *log_tag; /* override default syslog tag */
+ struct chunk log_htp; /* a syslog header part that contains hostname, log_tag and pid */
char *header_unique_id; /* unique-id header */
struct list format_unique_id; /* unique-id format */
int to_log; /* things to be logged (LW_*) */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 39ee359..fdbb462 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -7818,6 +7818,27 @@
}
out_uri_auth_compat:
+ /* write a syslog header string that contains hostname, log_tag and pid */
+ curproxy->log_htp.str = lf_host_tag_pid(logheader,
+ global.log_send_hostname ? global.log_send_hostname : "",
+ curproxy->log_tag ? curproxy->log_tag : global.log_tag, pid,
+ global.max_syslog_len);
+
+ if ((curproxy->log_htp.str == NULL) ||
+ (curproxy->log_htp.len = curproxy->log_htp.str - logheader) >= global.max_syslog_len) {
+ Alert("Proxy '%s': cannot write a syslog header string that contains "
+ "hostname, log_tag and pid.\n",
+ curproxy->id);
+ cfgerr++;
+ }
+ else {
+ curproxy->log_htp.str = (char *)malloc(curproxy->log_htp.len);
+ memcpy(curproxy->log_htp.str, logheader, curproxy->log_htp.len);
+ curproxy->log_htp.size = 0;
+ }
+
+ logheader[0] = 0;
+
/* compile the log format */
if (!(curproxy->cap & PR_CAP_FE)) {
if (curproxy->conf.logformat_string != default_http_log_format &&
diff --git a/src/haproxy.c b/src/haproxy.c
index f6ba96b..1edb823 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1328,6 +1328,7 @@
LIST_DEL(&log->list);
free(log);
}
+ chunk_destroy(&p->log_htp);
list_for_each_entry_safe(lf, lfb, &p->logformat, list) {
LIST_DEL(&lf->list);
diff --git a/src/log.c b/src/log.c
index 3724dd4..ad25174 100644
--- a/src/log.c
+++ b/src/log.c
@@ -152,8 +152,7 @@
char *log_format = NULL;
/* 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().
+ * begins with time-based part and is updated by update_log_hdr().
*/
char *logheader = NULL;
@@ -740,14 +739,26 @@
return ret;
}
+char *lf_host_tag_pid(char *dst, const char *hostname, const char *log_tag, int pid, size_t size)
+{
+ char *ret = dst;
+ int iret;
+
+ iret = snprintf(dst, size, "%s%s[%d]: ", hostname, log_tag, pid);
+ if (iret < 0 || iret > size)
+ return NULL;
+ ret += iret;
+
+ return ret;
+}
+
/* 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)
+char *update_log_hdr()
{
static long tvsec;
static char *dataptr = NULL; /* backup of last end of header, NULL first time */
- int tag_len;
if (unlikely(date.tv_sec != tvsec || dataptr == NULL)) {
/* this string is rebuild only once a second */
@@ -758,10 +769,9 @@
get_localtime(tvsec, &tm);
hdr_len = snprintf(logheader, global.max_syslog_len,
- "<<<<>%s %2d %02d:%02d:%02d %s",
+ "<<<<>%s %2d %02d:%02d:%02d ",
monthname[tm.tm_mon],
- tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
- global.log_send_hostname ? global.log_send_hostname : "");
+ tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
/* WARNING: depending upon implementations, snprintf may return
* either -1 or the number of bytes that would be needed to store
* the total message. In both cases, we must adjust it.
@@ -774,11 +784,7 @@
dataptr[0] = 0; // ensure we get rid of any previous attempt
- 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;
+ return dataptr;
}
/*
@@ -821,7 +827,6 @@
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;
@@ -836,15 +841,12 @@
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_ptr = update_log_hdr();
hdr_size = hdr_ptr - logheader;
/* Send log messages to syslog server. */
@@ -854,7 +856,9 @@
int *plogfd = logsrv->addr.ss_family == AF_UNIX ?
&logfdunix : &logfdinet;
int sent;
+ int maxlen;
int hdr_max = 0;
+ int htp_max = 0;
int max = 1;
char backup;
@@ -904,7 +908,15 @@
goto send;
}
+ maxlen = logsrv->maxlen - hdr_max;
+ htp_max = p->log_htp.len;
+
+ if (unlikely(htp_max >= maxlen)) {
+ htp_max = maxlen - 1;
+ goto send;
+ }
+
- max = MIN(size, logsrv->maxlen - hdr_max);
+ max = MIN(size, maxlen - htp_max);
log_ptr += max - 1;
@@ -918,8 +930,10 @@
iovec[0].iov_base = hdr_ptr;
iovec[0].iov_len = hdr_max;
- iovec[1].iov_base = dataptr;
- iovec[1].iov_len = max;
+ iovec[1].iov_base = p->log_htp.str;
+ iovec[1].iov_len = htp_max;
+ iovec[2].iov_base = dataptr;
+ iovec[2].iov_len = max;
msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
msghdr.msg_namelen = get_addr_len(&logsrv->addr);