]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: log: split of log_format generation
authorWilliam Lallemand <wlallemand@exceliance.fr>
Mon, 12 Mar 2012 11:46:41 +0000 (12:46 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 7 Apr 2012 14:05:02 +0000 (16:05 +0200)
* logformat functions now take a format linked list as argument
* build_logline() build a logline using a format linked list
* rename LOG_* by LOG_FMT_* in enum
* improve error management in build_logline()

include/proto/log.h
include/types/log.h
src/cfgparse.c
src/log.c

index 0ee60a00dd52697b4adeb09875959f125e1a0585..2efb53940580996b2c529698da17946130183344 100644 (file)
@@ -40,6 +40,8 @@ extern char default_http_log_format[];
 extern char clf_http_log_format[];
 
 
+int build_logline(struct session *s, char *dst, size_t maxsize, struct list *list_format);
+
 /*
  * send a log for the session when we have enough info about it.
  * Will not log if the frontend has no log defined.
@@ -55,20 +57,19 @@ int parse_logformat_var_args(char *args, struct logformat_node *node);
  * Parse a variable '%varname' or '%{args}varname' in logformat
  *
  */
-int parse_logformat_var(char *str, size_t len, struct proxy *curproxy, int *options);
+int parse_logformat_var(char *str, size_t len, struct proxy *curproxy, struct list *list_format, int *defoptions);
 
 /*
  * add to the logformat linked list
  */
-void add_to_logformat_list(char *start, char *end, int type, struct proxy *curproxy);
+void add_to_logformat_list(char *start, char *end, int type, struct list *list_format);
 
 /*
  * Parse the log_format string and fill a linked list.
  * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
  * You can set arguments using { } : %{many arguments}varname
  */
-void parse_logformat_string(char *str, struct proxy *curproxy);
-
+void parse_logformat_string(char *str, struct proxy *curproxy, struct list *list_format, int capabilities);
 /*
  * Displays the message on stderr with the date and pid. Overrides the quiet
  * mode during startup.
index 741fba935ddce1f4c804fe5862d869460b1c0e34..efb1d91f5f1919c1d5029557f6f31ec2b646da40 100644 (file)
 /* lists of fields that can be logged */
 enum {
 
-       LOG_TEXT = 0, /* raw text */
+       LOG_FMT_TEXT = 0, /* raw text */
 
-       LOG_SEPARATOR, /* separator replaced by one space */
-       LOG_VARIABLE,
+       LOG_FMT_SEPARATOR, /* separator replaced by one space */
+       LOG_FMT_VARIABLE,
 
        /* information fields */
-       LOG_GLOBAL,
-       LOG_CLIENTIP,
-       LOG_CLIENTPORT,
-       LOG_SOURCEPORT,
-       LOG_SOURCEIP,
-       LOG_DATE,
-       LOG_DATEGMT,
-       LOG_MS,
-       LOG_FRONTEND,
-       LOG_BACKEND,
-       LOG_SERVER,
-       LOG_BYTES,
-       LOG_T,
-       LOG_TQ,
-       LOG_TW,
-       LOG_TC,
-       LOG_TR,
-       LOG_TT,
-       LOG_STATUS,
-       LOG_CCLIENT,
-       LOG_CSERVER,
-       LOG_TERMSTATE,
-       LOG_TERMSTATE_CK,
-       LOG_CONN,
-       LOG_ACTCONN,
-       LOG_FECONN,
-       LOG_BECONN,
-       LOG_SRVCONN,
-       LOG_RETRIES,
-       LOG_QUEUES,
-       LOG_SRVQUEUE,
-       LOG_BCKQUEUE,
-       LOG_HDRREQUEST,
-       LOG_HDRRESPONS,
-       LOG_HDRREQUESTLIST,
-       LOG_HDRRESPONSLIST,
-       LOG_REQ,
+       LOG_FMT_GLOBAL,
+       LOG_FMT_CLIENTIP,
+       LOG_FMT_CLIENTPORT,
+       LOG_FMT_BACKENDIP,
+       LOG_FMT_BACKENDPORT,
+       LOG_FMT_DATE,
+       LOG_FMT_DATEGMT,
+       LOG_FMT_MS,
+       LOG_FMT_FRONTEND,
+       LOG_FMT_BACKEND,
+       LOG_FMT_SERVER,
+       LOG_FMT_BYTES,
+       LOG_FMT_T,
+       LOG_FMT_TQ,
+       LOG_FMT_TW,
+       LOG_FMT_TC,
+       LOG_FMT_TR,
+       LOG_FMT_TT,
+       LOG_FMT_STATUS,
+       LOG_FMT_CCLIENT,
+       LOG_FMT_CSERVER,
+       LOG_FMT_TERMSTATE,
+       LOG_FMT_TERMSTATE_CK,
+       LOG_FMT_CONN,
+       LOG_FMT_ACTCONN,
+       LOG_FMT_FECONN,
+       LOG_FMT_BECONN,
+       LOG_FMT_SRVCONN,
+       LOG_FMT_RETRIES,
+       LOG_FMT_QUEUES,
+       LOG_FMT_SRVQUEUE,
+       LOG_FMT_BCKQUEUE,
+       LOG_FMT_HDRREQUEST,
+       LOG_FMT_HDRRESPONS,
+       LOG_FMT_HDRREQUESTLIST,
+       LOG_FMT_HDRRESPONSLIST,
+       LOG_FMT_REQ,
 };
 
 /* enum for parse_logformat */
index d827d4c0fbb7a4168ea6feaf72c084cf3c1e8e36..aa57b9b55a55a85b4f66d3473bc94255160ed50b 100644 (file)
@@ -3352,14 +3352,14 @@ stats_error_parsing:
                                        goto out;
                                }
                        }
-                       parse_logformat_string(logformat, curproxy);
+                       parse_logformat_string(logformat, curproxy, &curproxy->logformat, curproxy->mode);
                }
                else if (!strcmp(args[1], "tcplog")) {
                        char *logformat;
                        /* generate a detailed TCP log */
                        curproxy->to_log |= LW_DATE | LW_CLIP | LW_SVID | LW_PXID | LW_BYTES;
                        logformat = default_tcp_log_format;
-                       parse_logformat_string(logformat, curproxy);
+                       parse_logformat_string(logformat, curproxy, &curproxy->logformat, curproxy->mode);
                }
                else if (!strcmp(args[1], "tcpka")) {
                        /* enable TCP keep-alives on client and server sessions */
@@ -4598,7 +4598,7 @@ stats_error_parsing:
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
-               parse_logformat_string(args[1], curproxy);
+               parse_logformat_string(args[1], curproxy, &curproxy->logformat, curproxy->mode);
        }
 
        else if (!strcmp(args[0], "log") && kwm == KWM_NO) {
index 9065a5b38c3fa4c92ccf534e731903f8921dc89a..8a0912137fb1b1f6770ccae78f45046fd47d0f2e 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -64,40 +64,40 @@ int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
 
 /* log_format variable names */
 static const struct logformat_type logformat_keywords[] = {
-       { "o", LOG_GLOBAL, PR_MODE_TCP, NULL },  /* global option */
-       { "Ci", LOG_CLIENTIP, PR_MODE_TCP, NULL },  /* client ip */
-       { "Cp", LOG_CLIENTPORT, PR_MODE_TCP, NULL }, /* client port */
-       { "Bp", LOG_SOURCEPORT, PR_MODE_TCP, prepare_addrsource }, /* backend source port */
-       { "Bi", LOG_SOURCEIP, PR_MODE_TCP, prepare_addrsource }, /* backend source ip */
-       { "t", LOG_DATE, PR_MODE_TCP, NULL },      /* date */
-       { "T", LOG_DATEGMT, PR_MODE_TCP, NULL },   /* date GMT */
-       { "ms", LOG_MS, PR_MODE_TCP, NULL },       /* accept date millisecond */
-       { "f", LOG_FRONTEND, PR_MODE_TCP, NULL },  /* frontend */
-       { "b", LOG_BACKEND, PR_MODE_TCP, NULL },   /* backend */
-       { "s", LOG_SERVER, PR_MODE_TCP, NULL },    /* server */
-       { "B", LOG_BYTES, PR_MODE_TCP, NULL },     /* bytes read */
-       { "Tq", LOG_TQ, PR_MODE_HTTP, NULL },       /* Tq */
-       { "Tw", LOG_TW, PR_MODE_TCP, NULL },       /* Tw */
-       { "Tc", LOG_TC, PR_MODE_TCP, NULL },       /* Tc */
-       { "Tr", LOG_TR, PR_MODE_HTTP, NULL },       /* Tr */
-       { "Tt", LOG_TT, PR_MODE_TCP, NULL },       /* Tt */
-       { "st", LOG_STATUS, PR_MODE_HTTP, NULL },   /* status code */
-       { "cc", LOG_CCLIENT, PR_MODE_HTTP, NULL },  /* client cookie */
-       { "cs", LOG_CSERVER, PR_MODE_HTTP, NULL },  /* server cookie */
-       { "ts", LOG_TERMSTATE, PR_MODE_TCP, NULL },/* terminaison state */
-       { "tsc", LOG_TERMSTATE_CK, PR_MODE_HTTP, NULL },/* terminaison state with cookie status */
-       { "ac", LOG_ACTCONN, PR_MODE_TCP, NULL },  /* actconn */
-       { "fc", LOG_FECONN, PR_MODE_TCP, NULL },   /* feconn */
-       { "bc", LOG_BECONN, PR_MODE_TCP, NULL },   /* beconn */
-       { "sc", LOG_SRVCONN, PR_MODE_TCP, NULL },  /* srv_conn */
-       { "rc", LOG_RETRIES, PR_MODE_TCP, NULL },  /* retries */
-       { "sq", LOG_SRVQUEUE, PR_MODE_TCP, NULL  }, /* srv_queue */
-       { "bq", LOG_BCKQUEUE, PR_MODE_TCP, NULL }, /* backend_queue */
-       { "hr", LOG_HDRREQUEST, PR_MODE_HTTP, NULL }, /* header request */
-       { "hs", LOG_HDRRESPONS, PR_MODE_HTTP, NULL },  /* header response */
-       { "hrl", LOG_HDRREQUESTLIST, PR_MODE_HTTP, NULL }, /* header request list */
-       { "hsl", LOG_HDRRESPONSLIST, PR_MODE_HTTP, NULL },  /* header response list */
-       { "r", LOG_REQ, PR_MODE_HTTP, NULL },  /* request */
+       { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, NULL },  /* global option */
+       { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, NULL },  /* client ip */
+       { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, NULL }, /* client port */
+       { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, prepare_addrsource }, /* backend source port */
+       { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, prepare_addrsource }, /* backend source ip */
+       { "t", LOG_FMT_DATE, PR_MODE_TCP, NULL },      /* date */
+       { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, NULL },   /* date GMT */
+       { "ms", LOG_FMT_MS, PR_MODE_TCP, NULL },       /* accept date millisecond */
+       { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, NULL },  /* frontend */
+       { "b", LOG_FMT_BACKEND, PR_MODE_TCP, NULL },   /* backend */
+       { "s", LOG_FMT_SERVER, PR_MODE_TCP, NULL },    /* server */
+       { "B", LOG_FMT_BYTES, PR_MODE_TCP, NULL },     /* bytes read */
+       { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, NULL },       /* Tq */
+       { "Tw", LOG_FMT_TW, PR_MODE_TCP, NULL },       /* Tw */
+       { "Tc", LOG_FMT_TC, PR_MODE_TCP, NULL },       /* Tc */
+       { "Tr", LOG_FMT_TR, PR_MODE_HTTP, NULL },       /* Tr */
+       { "Tt", LOG_FMT_TT, PR_MODE_TCP, NULL },       /* Tt */
+       { "st", LOG_FMT_STATUS, PR_MODE_HTTP, NULL },   /* status code */
+       { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, NULL },  /* client cookie */
+       { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, NULL },  /* server cookie */
+       { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, NULL },/* terminaison state */
+       { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, NULL },/* terminaison state */
+       { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, NULL },  /* actconn */
+       { "fc", LOG_FMT_FECONN, PR_MODE_TCP, NULL },   /* feconn */
+       { "bc", LOG_FMT_BECONN, PR_MODE_TCP, NULL },   /* beconn */
+       { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, NULL },  /* srv_conn */
+       { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, NULL },  /* retries */
+       { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, NULL  }, /* srv_queue */
+       { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, NULL }, /* backend_queue */
+       { "hr", LOG_FMT_HDRREQUEST, PR_MODE_HTTP, NULL }, /* header request */
+       { "hs", LOG_FMT_HDRRESPONS, PR_MODE_HTTP, NULL },  /* header response */
+       { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_HTTP, NULL }, /* header request list */
+       { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_HTTP, NULL },  /* header response list */
+       { "r", LOG_FMT_REQ, PR_MODE_HTTP, NULL },  /* request */
        { 0, 0, 0, NULL }
 };
 
@@ -188,7 +188,7 @@ int parse_logformat_var_args(char *args, struct logformat_node *node)
  * Parse a variable '%varname' or '%{args}varname' in logformat
  *
  */
-int parse_logformat_var(char *str, size_t len, struct proxy *curproxy, int *defoptions)
+int parse_logformat_var(char *str, size_t len, struct proxy *curproxy, struct list *list_format, int *defoptions)
 {
        int i, j;
        char *arg = NULL; // arguments
@@ -218,7 +218,7 @@ int parse_logformat_var(char *str, size_t len, struct proxy *curproxy, int *defo
                                                node->options = *defoptions;
                                                node->arg = arg;
                                                parse_logformat_var_args(node->arg, node);
-                                               if (node->type == LOG_GLOBAL) {
+                                               if (node->type == LOG_FMT_GLOBAL) {
                                                        *defoptions = node->options;
                                                        free(node);
                                                } else {
@@ -227,7 +227,7 @@ int parse_logformat_var(char *str, size_t len, struct proxy *curproxy, int *defo
                                                                        return -1;
                                                                 }
                                                        }
-                                                       LIST_ADDQ(&curproxy->logformat, &node->list);
+                                                       LIST_ADDQ(list_format, &node->list);
                                                }
                                                return 0;
                                        } else {
@@ -253,28 +253,27 @@ int parse_logformat_var(char *str, size_t len, struct proxy *curproxy, int *defo
  *  start: start pointer
  *  end: end text pointer
  *  type: string type
+ *  list_format: destination list
  *
  *  LOG_TEXT: copy chars from start to end excluding end.
  *
 */
-void add_to_logformat_list(char *start, char *end, int type, struct proxy *curproxy)
+void add_to_logformat_list(char *start, char *end, int type, struct list *list_format)
 {
        char *str;
 
-       if (type == LOG_TEXT) { /* type text */
+       if (type == LOG_FMT_TEXT) { /* type text */
                struct logformat_node *node = calloc(1, sizeof(struct logformat_node));
-
                str = calloc(end - start + 1, 1);
                strncpy(str, start, end - start);
-
                str[end - start] = '\0';
                node->arg = str;
-               node->type = LOG_TEXT; // type string
-               LIST_ADDQ(&curproxy->logformat, &node->list);
-       } else if (type == LOG_SEPARATOR) {
+               node->type = LOG_FMT_TEXT; // type string
+               LIST_ADDQ(list_format, &node->list);
+       } else if (type == LOG_FMT_SEPARATOR) {
                struct logformat_node *node = calloc(1, sizeof(struct logformat_node));
-               node->type = LOG_SEPARATOR;
-               LIST_ADDQ(&curproxy->logformat, &node->list);
+               node->type = LOG_FMT_SEPARATOR;
+               LIST_ADDQ(list_format, &node->list);
        }
 }
 
@@ -282,8 +281,13 @@ void add_to_logformat_list(char *start, char *end, int type, struct proxy *curpr
  * Parse the log_format string and fill a linked list.
  * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
  * You can set arguments using { } : %{many arguments}varname
+ *
+ *  str: the string to parse
+ *  curproxy: the proxy affected
+ *  list_format: the destination list
+ *  capabilities: PR_MODE_TCP_ | PR_MODE_HTTP
  */
-void parse_logformat_string(char *str, struct proxy *curproxy)
+void parse_logformat_string(char *str, struct proxy *curproxy, struct list *list_format, int capabilities)
 {
        char *sp = str; /* start pointer */
        int cformat = -1; /* current token format : LOG_TEXT, LOG_SEPARATOR, LOG_VARIABLE */
@@ -292,7 +296,7 @@ void parse_logformat_string(char *str, struct proxy *curproxy)
        int options = 0;
 
        /* flush the list first. */
-       list_for_each_entry_safe(tmplf, back, &curproxy->logformat, list) {
+       list_for_each_entry_safe(tmplf, back, list_format, list) {
                LIST_DEL(&tmplf->list);
                free(tmplf);
        }
@@ -308,9 +312,9 @@ void parse_logformat_string(char *str, struct proxy *curproxy)
                                if (pformat > LF_VAR) // unfinished string
                                        pformat = LF_TEXT;
                                if (pformat == LF_VAR)
-                                       parse_logformat_var(sp, str - sp, curproxy, &options);
+                                       parse_logformat_var(sp, str - sp, curproxy, list_format, &options);
                                else
-                                       add_to_logformat_list(sp, str, pformat, curproxy);
+                                       add_to_logformat_list(sp, str, pformat, list_format);
                                sp = str;
                                if (*str == '\0')
                                        break;
@@ -482,7 +486,6 @@ char *logformat_write_string(char *dst, char *src, size_t size, struct logformat
                                *(dst++) = '"';
                                *(dst++) = '"';
                                *dst = '\0';
-                               node->options |= LOG_OPT_WRITTEN;
                        } else {
                                dst = NULL;
                                return dst;
@@ -491,7 +494,6 @@ char *logformat_write_string(char *dst, char *src, size_t size, struct logformat
                        if (size > 1) {
                                *(dst++) = '-';
                                *dst = '\0';
-                               node->options |= LOG_OPT_WRITTEN;
                        } else { // error no space available
                                dst = NULL;
                                return dst;
@@ -693,27 +695,26 @@ const char sess_set_cookie[8] = "NPDIRU67";       /* No set-cookie, Set-cookie found a
                                                   Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
                                                   Set-cookie Updated, unknown, unknown */
 
+/*
+ * try to write a character if there is enough space, or goto out
+ */
 #define LOGCHAR(x) do { \
-                       if (tmplog < logline + MAX_SYSLOG_LEN - 1) { \
+                       if (tmplog < dst + maxsize - 1) { \
                                *(tmplog++) = (x);                     \
                        } else {                                       \
                                goto out;                              \
                        }                                              \
                } while(0)
 
-/*
- * send a log for the session when we have enough info about it.
- * Will not log if the frontend has no log defined.
- */
-void sess_log(struct session *s)
+
+
+int build_logline(struct session *s, char *dst, size_t maxsize, struct list *list_format)
 {
        char pn[INET6_ADDRSTRLEN];
-       char sn[INET6_ADDRSTRLEN];
        struct proxy *fe = s->fe;
        struct proxy *be = s->be;
-       struct proxy *prx_log;
        struct http_txn *txn = &s->txn;
-       int tolog, level, err;
+       int tolog;
        char *uri;
        const char *svid;
        struct tm tm;
@@ -721,27 +722,10 @@ void sess_log(struct session *s)
        int hdr;
        int last_isspace = 1;
        char *tmplog;
+       char *ret;
+       int iret;
        struct logformat_node *tmp;
 
-       /* if we don't want to log normal traffic, return now */
-       err = (s->flags & (SN_ERR_MASK | SN_REDISP)) ||
-               (s->req->cons->conn_retries != be->conn_retries) ||
-               ((s->fe->mode == PR_MODE_HTTP) && txn->status >= 500);
-       if (!err && (fe->options2 & PR_O2_NOLOGNORM))
-               return;
-
-       if (LIST_ISEMPTY(&fe->logsrvs))
-               return;
-       prx_log = fe;
-
-       if (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn)) == AF_UNIX)
-               snprintf(pn, sizeof(pn), "unix:%d", s->listener->luid);
-
-       if (be->options2 & PR_O2_SRC_ADDR) {
-             if (addr_to_str(&s->req->cons->addr.from, sn, sizeof(sn)) == AF_UNIX)
-               snprintf(sn, sizeof(sn), "unix:%d", s->listener->luid);
-       }
-
        /* FIXME: let's limit ourselves to frontend logging for now. */
        tolog = fe->to_log;
 
@@ -763,85 +747,94 @@ void sess_log(struct session *s)
        if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
                t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
 
-       level = LOG_INFO;
-       if (err && (fe->options2 & PR_O2_LOGERRORS))
-               level = LOG_ERR;
+       tmplog = dst;
 
        /* fill logbuffer */
+       if (LIST_ISEMPTY(list_format))
+               return 0;
 
-       tmplog = update_log_hdr(); /* update log header and skip it */
-
-       list_for_each_entry(tmp, &fe->logformat, list) {
+       list_for_each_entry(tmp, list_format, list) {
                char *src = NULL;
                switch (tmp->type) {
 
-                       case LOG_SEPARATOR:
+                       case LOG_FMT_SEPARATOR:
                                if (!last_isspace) {
                                        LOGCHAR(' ');
                                        last_isspace = 1;
-                                       *tmplog = '\0';
                                }
                                break;
 
-                       case LOG_TEXT: // text
+                       case LOG_FMT_TEXT: // text
                                src = tmp->arg;
-                               tmplog += strlcpy2(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (tmplog > logline + MAX_SYSLOG_LEN - 2)
+                               iret = strlcpy2(tmplog, src, maxsize - (tmplog - dst));
+                               if (iret == 0)
                                        goto out;
+                               tmplog += iret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_CLIENTIP:  // %Ci
+                       case LOG_FMT_CLIENTIP:  // %Ci
+                               /* client addr */
+                               if (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn)) == AF_UNIX)
+                                       snprintf(pn, sizeof(pn), "unix:%d", s->listener->luid);
                                src = (s->req->prod->addr.from.ss_family == AF_UNIX) ? "unix" : pn;
-                               tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
-                               if (!tmplog)
+                               ret = logformat_write_string(tmplog, src, maxsize - (tmplog - dst), tmp);
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_CLIENTPORT:  // %Cp
-                               tmplog = ltoa_o((s->req->prod->addr.from.ss_family == AF_UNIX) ? s->listener->luid : get_host_port(&s->req->prod->addr.from),
-                                               tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_CLIENTPORT:  // %Cp
+                               ret = ltoa_o((s->req->prod->addr.from.ss_family == AF_UNIX) ?
+                                            s->listener->luid : get_host_port(&s->req->prod->addr.from),
+                                            tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_SOURCEIP:  // Bi
-                               src = (s->req->cons->addr.from.ss_family == AF_UNIX) ? "unix" : sn;
-                               tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
-                               if (!tmplog)
+                       case LOG_FMT_BACKENDIP:  // %Bi
+                               /* backend addr  */
+                               if (be->options2 & PR_O2_SRC_ADDR)
+                                       addr_to_str(&s->req->cons->addr.from, pn, sizeof(pn));
+                               ret = logformat_write_string(tmplog, pn, maxsize - (tmplog - dst), tmp);
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_SOURCEPORT:  // %Bp
-                               tmplog = ltoa_o((s->req->cons->addr.from.ss_family == AF_UNIX) ? s->listener->luid : get_host_port(&s->req->cons->addr.from),
-                                               tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_BACKENDPORT:  // %Bp
+                               ret = ltoa_o(get_host_port(&s->req->cons->addr.from),
+                                            tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_DATE: // %t
+                       case LOG_FMT_DATE: // %t
                                get_localtime(s->logs.accept_date.tv_sec, &tm);
-                               tmplog = date2str_log(tmplog, &tm, &(s->logs.accept_date), MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                               ret = date2str_log(tmplog, &tm, &(s->logs.accept_date), maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_DATEGMT: // %T
+                       case LOG_FMT_DATEGMT: // %T
                                get_gmtime(s->logs.accept_date.tv_sec, &tm);
-                               tmplog = gmt2str_log(tmplog, &tm, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                               ret = gmt2str_log(tmplog, &tm, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_MS: // %ms
-                               if ((MAX_SYSLOG_LEN - (tmplog - logline)) < 4) {
-                                       tmplog = NULL;
+                       case LOG_FMT_MS: // %ms
+                               if ((maxsize - (tmplog - dst)) < 4) {
                                        goto out;
                                }
                                tmplog = utoa_pad((unsigned int)s->logs.accept_date.tv_usec/1000,
@@ -851,167 +844,192 @@ void sess_log(struct session *s)
                                last_isspace = 0;
                                break;
 
-                       case LOG_FRONTEND: // %f
+                       case LOG_FMT_FRONTEND: // %f
                                src = fe->id;
-                               tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
-                               if (!tmplog)
+                               ret = logformat_write_string(tmplog, src, maxsize - (tmplog - dst), tmp);
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_BACKEND: // %b
+                       case LOG_FMT_BACKEND: // %b
                                src = be->id;
-                               tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
-                               if (!tmplog)
+                               ret = logformat_write_string(tmplog, src, maxsize - (tmplog - dst), tmp);
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_SERVER: // %s
+                       case LOG_FMT_SERVER: // %s
                                src = (char *)svid;
-                               tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
-                               if (!tmplog)
+                               ret = logformat_write_string(tmplog, src, maxsize - (tmplog - dst), tmp);
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_TQ: // %Tq
-                               tmplog = ltoa_o(t_request, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_TQ: // %Tq
+                               ret = ltoa_o(t_request, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_TW: // %Tw
-                               tmplog = ltoa_o((s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_TW: // %Tw
+                               ret = ltoa_o((s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
+                                               tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_TC: // %Tc
-                               tmplog = ltoa_o((s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_TC: // %Tc
+                               ret = ltoa_o((s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
+                                               tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_TR: // %Tr
-                               tmplog = ltoa_o((s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_TR: // %Tr
+                               ret = ltoa_o((s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
+                                               tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_TT:  // %Tt
+                       case LOG_FMT_TT:  // %Tt
                                if (!(tolog & LW_BYTES))
-                                       *(tmplog++) = '+';
-                               tmplog = ltoa_o(s->logs.t_close, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                                       LOGCHAR('+');
+                               ret = ltoa_o(s->logs.t_close, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_STATUS: // %st
-                               tmplog = ltoa_o(txn->status, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_STATUS: // %st
+                               ret = ltoa_o(txn->status, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_BYTES: // %B
+                       case LOG_FMT_BYTES: // %B
                                if (!(tolog & LW_BYTES))
-                                       *(tmplog++) = '+';
-                               tmplog = lltoa(s->logs.bytes_out, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                                       LOGCHAR('+');
+                               ret = lltoa(s->logs.bytes_out, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_CCLIENT: // %cc
+                       case LOG_FMT_CCLIENT: // %cc
                                src = txn->cli_cookie;
-                               tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
-                               if (!tmplog)
+                               ret = logformat_write_string(tmplog, src, maxsize - (tmplog - dst), tmp);
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_CSERVER: // %cs
+                       case LOG_FMT_CSERVER: // %cs
                                src = txn->srv_cookie;
-                               tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
-                               if (!tmplog)
+                               ret = logformat_write_string(tmplog, src, maxsize - (tmplog - dst), tmp);
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_TERMSTATE: // %ts
+                       case LOG_FMT_TERMSTATE: // %ts
                                LOGCHAR(sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT]);
                                LOGCHAR(sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
                                *tmplog = '\0';
                                last_isspace = 0;
                                break;
 
-                       case LOG_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
+                       case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
                                LOGCHAR(sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT]);
                                LOGCHAR(sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
                                LOGCHAR((be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
                                LOGCHAR((be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-');
-                               *tmplog = '\0';
                                last_isspace = 0;
                                break;
 
-                       case LOG_ACTCONN: // %ac
-                               tmplog = ltoa_o(actconn, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_ACTCONN: // %ac
+                               ret = ltoa_o(actconn, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_FECONN:  // %fc
-                               tmplog = ltoa_o(fe->feconn, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_FECONN:  // %fc
+                               ret = ltoa_o(fe->feconn, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_BECONN:  // %bc
-                               tmplog = ltoa_o(be->beconn, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_BECONN:  // %bc
+                               ret = ltoa_o(be->beconn, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_SRVCONN:  // %sc
-                               tmplog = ultoa_o(target_srv(&s->target) ? target_srv(&s->target)->cur_sess : 0, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_SRVCONN:  // %sc
+                               ret = ultoa_o(target_srv(&s->target) ?
+                                                target_srv(&s->target)->cur_sess :
+                                                0, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_RETRIES:  // %rq
+                       case LOG_FMT_RETRIES:  // %rq
                                if (s->flags & SN_REDISP)
-                                       *(tmplog++) = '+';
-                               tmplog = ltoa_o((s->req->cons->conn_retries>0)?(be->conn_retries - s->req->cons->conn_retries):be->conn_retries, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                                       LOGCHAR('+');
+                               ret = ltoa_o((s->req->cons->conn_retries>0) ?
+                                               (be->conn_retries - s->req->cons->conn_retries) :
+                                               be->conn_retries, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_SRVQUEUE: // %sq
-                               tmplog = ltoa_o(s->logs.srv_queue_size, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_SRVQUEUE: // %sq
+                               ret = ltoa_o(s->logs.srv_queue_size, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_BCKQUEUE:  // %bq
-                               tmplog = ltoa_o(s->logs.prx_queue_size, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
-                               if (!tmplog)
+                       case LOG_FMT_BCKQUEUE:  // %bq
+                               ret = ltoa_o(s->logs.prx_queue_size, tmplog, maxsize - (tmplog - dst));
+                               if (ret == NULL)
                                        goto out;
+                               tmplog = ret;
                                last_isspace = 0;
                                break;
 
-                       case LOG_HDRREQUEST: // %hr
+                       case LOG_FMT_HDRREQUEST: // %hr
                                /* request header */
                                if (fe->to_log & LW_REQHDR && txn->req.cap) {
                                        if (tmp->options & LOG_OPT_QUOTE)
@@ -1021,21 +1039,23 @@ void sess_log(struct session *s)
                                                if (hdr)
                                                        LOGCHAR('|');
                                                if (txn->req.cap[hdr] != NULL) {
-                                                       tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
+                                                       ret = encode_string(tmplog, dst + maxsize,
                                                                               '#', hdr_encode_map, txn->req.cap[hdr]);
-                                                       if (*tmplog != '\0')
+                                                       if (ret == NULL || *ret != '\0')
                                                                goto out;
+                                                       tmplog = ret;
                                                }
                                        }
                                        LOGCHAR('}');
                                        if (tmp->options & LOG_OPT_QUOTE)
                                                LOGCHAR('"');
                                        last_isspace = 0;
+                                       if (tmp->options & LOG_OPT_QUOTE)
+                                               LOGCHAR('"');
                                }
-                               *tmplog = '\0';
                                break;
 
-                       case LOG_HDRREQUESTLIST: // %hrl
+                       case LOG_FMT_HDRREQUESTLIST: // %hrl
                                /* request header list */
                                if (fe->to_log & LW_REQHDR && txn->req.cap) {
                                        for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
@@ -1044,22 +1064,22 @@ void sess_log(struct session *s)
                                                if (tmp->options & LOG_OPT_QUOTE)
                                                        LOGCHAR('"');
                                                if (txn->req.cap[hdr] != NULL) {
-                                                       tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
+                                                       ret = encode_string(tmplog, dst + maxsize,
                                                                               '#', hdr_encode_map, txn->req.cap[hdr]);
-                                                       if (*tmplog != '\0')
+                                                       if (ret == NULL || *ret != '\0')
                                                                goto out;
-
+                                                       tmplog = ret;
                                                } else if (!(tmp->options & LOG_OPT_QUOTE))
                                                        LOGCHAR('-');
                                                if (tmp->options & LOG_OPT_QUOTE)
                                                        LOGCHAR('"');
-                                               *tmplog = '\0';
                                                last_isspace = 0;
                                        }
                                }
                                break;
 
-                       case LOG_HDRRESPONS: // %hs
+
+                       case LOG_FMT_HDRRESPONS: // %hs
                                /* response header */
                                if (fe->to_log & LW_RSPHDR &&
                                    txn->rsp.cap) {
@@ -1070,10 +1090,11 @@ void sess_log(struct session *s)
                                                if (hdr)
                                                        LOGCHAR('|');
                                                if (txn->rsp.cap[hdr] != NULL) {
-                                                       tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
-                                                                              '#', hdr_encode_map, txn->rsp.cap[hdr]);
-                                                       if (*tmplog != '\0')
+                                                       ret = encode_string(tmplog, dst + maxsize,
+                                                                           '#', hdr_encode_map, txn->rsp.cap[hdr]);
+                                                       if (ret == NULL || *ret != '\0')
                                                                goto out;
+                                                       tmplog = ret;
                                                }
                                        }
                                        LOGCHAR('}');
@@ -1081,10 +1102,9 @@ void sess_log(struct session *s)
                                        if (tmp->options & LOG_OPT_QUOTE)
                                                LOGCHAR('"');
                                }
-                               *tmplog = '\0';
                                break;
 
-                       case LOG_HDRRESPONSLIST: // %hsl
+                       case LOG_FMT_HDRRESPONSLIST: // %hsl
                                /* response header list */
                                if (fe->to_log & LW_RSPHDR && txn->rsp.cap) {
                                        for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
@@ -1093,50 +1113,77 @@ void sess_log(struct session *s)
                                                if (tmp->options & LOG_OPT_QUOTE)
                                                        LOGCHAR('"');
                                                if (txn->rsp.cap[hdr] != NULL) {
-                                                       tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
-                                                                              '#', hdr_encode_map, txn->rsp.cap[hdr]);
-                                                       if (*tmplog != '\0')
+                                                       ret = encode_string(tmplog, dst + maxsize,
+                                                                           '#', hdr_encode_map, txn->rsp.cap[hdr]);
+                                                       if (ret == NULL || *ret != '\0')
                                                                goto out;
+                                                       tmplog = ret;
                                                } else if (!(tmp->options & LOG_OPT_QUOTE))
                                                        LOGCHAR('-');
                                                if (tmp->options & LOG_OPT_QUOTE)
                                                        LOGCHAR('"');
-                                               *tmplog = '\0';
                                                last_isspace = 0;
                                        }
                                }
                                break;
 
-                       case LOG_REQ: // %r
+                       case LOG_FMT_REQ: // %r
                                /* Request */
                                if (tmp->options & LOG_OPT_QUOTE)
                                        LOGCHAR('"');
                                uri = txn->uri ? txn->uri : "<BADREQ>";
-                               tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
+                               ret = encode_string(tmplog, dst + maxsize,
                                                       '#', url_encode_map, uri);
-                               if (*tmplog != '\0')
+                               if (ret == NULL || *ret != '\0')
                                        goto out;
+                               tmplog = ret;
                                if (tmp->options & LOG_OPT_QUOTE)
                                        LOGCHAR('"');
-                               *tmplog = '\0';
                                last_isspace = 0;
                                break;
                }
        }
 
 out:
+       /* *tmplog is a unused character */
+       *tmplog = '\0';
 
-       if (tmplog == NULL) // if previous error
-               tmplog = logline + MAX_SYSLOG_LEN - 1;
-
-       __send_log(prx_log, level, logline, tmplog - logline + 1);
-       s->logs.logwait = 0;
+       return tmplog - dst + 1;
 
 }
 
+/*
+ * send a log for the session when we have enough info about it.
+ * Will not log if the frontend has no log defined.
+ */
+void sess_log(struct session *s)
+{
+       char *tmplog;
+       int size, err, level;
+
+       /* if we don't want to log normal traffic, return now */
+       err = (s->flags & (SN_ERR_MASK | SN_REDISP)) ||
+               (s->req->cons->conn_retries != s->be->conn_retries) ||
+                       ((s->fe->mode == PR_MODE_HTTP) && s->txn.status >= 500);
 
+       if (!err && (s->fe->options2 & PR_O2_NOLOGNORM))
+               return;
 
+       if (LIST_ISEMPTY(&s->fe->logsrvs))
+               return;
 
+       level = LOG_INFO;
+       if (err && (s->fe->options2 & PR_O2_LOGERRORS))
+               level = LOG_ERR;
+
+       tmplog = update_log_hdr();
+       size = tmplog - logline;
+       size += build_logline(s, tmplog, sizeof(logline) - size, &s->fe->logformat);
+       if (size > 0) {
+               __send_log(s->fe, level, logline, size);
+               s->logs.logwait = 0;
+       }
+}
 
 /*
  * Local variables: