]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: log: Unique ID
authorWilliam Lallemand <wlallemand@exceliance.fr>
Mon, 12 Mar 2012 11:48:57 +0000 (12:48 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 7 Apr 2012 14:25:26 +0000 (16:25 +0200)
The Unique ID, is an ID generated with several informations. You can use
a log-format string to customize it, with the "unique-id-format" keyword,
and insert it in the request header, with the "unique-id-header" keyword.

doc/configuration.txt
include/proto/log.h
include/types/log.h
include/types/proxy.h
include/types/session.h
src/cfgparse.c
src/log.c
src/proto_http.c
src/proxy.c

index 66b61ff25a9921782c493a6b6d7d7e5ee4eadd12..8f502132beb02d0fd7da9327bf3ce5a98c27aa6b 100644 (file)
@@ -1117,6 +1117,8 @@ timeout server                            X          -         X         X
 timeout srvtimeout          (deprecated)  X          -         X         X
 timeout tarpit                            X          X         X         X
 transparent                 (deprecated)  X          -         X         X
+unique-id-format                          X          X         X         -
+unique-id-header                          X          X         X         -
 use_backend                               -          X         X         -
 use-server                                -          -         X         X
 ------------------------------------+----------+----------+---------+---------
@@ -6564,6 +6566,60 @@ transparent (deprecated)
 
   See also: "option transparent"
 
+unique-id-format <string>
+  Generate a unique ID for each request.
+  May be used in sections :   defaults | frontend | listen | backend
+                                  yes  |    yes   |   yes  |   no
+  Arguments :
+    <string>   is a log-format string.
+
+    This keyword creates a ID for each request using the custom log format. A
+    unique ID is useful to trace a request passing through many components of
+    a complex infrastructure. The newly created ID may also be logged using the
+    %ID tag the log-format string.
+
+    The format should be composed from elements that are guaranteed to be
+    unique when combined together. For instance, if multiple haproxy instances
+    are involved, it might be important to include the node name. It is often
+    needed to log the incoming connection's source and destination addresses
+    and ports. Note that since multiple requests may be performed over the same
+    connection, including a request counter may help differentiate them.
+    Similarly, a timestamp may protect against a rollover of the counter.
+    Logging the process ID will avoid collisions after a service restart.
+
+    It is recommended to use hexadecimal notation for many fields since it
+    makes them more compact and saves space in logs.
+
+    Example:
+
+        unique-id-format %{+X}o\ %Ci:%Cp_%Fi:%Fp_%Ts_%rt:%pid
+
+        will generate:
+
+               7F000001:8296_7F00001E:1F90_4F7B0A69_0003:790A
+
+  See also: "unique-id-header"
+
+unique-id-header <name>
+  Add a unique ID header in the HTTP request.
+  May be used in sections :   defaults | frontend | listen | backend
+                                  yes  |    yes   |   yes  |   no
+  Arguments :
+    <name>   is the name of the header.
+
+    Add a unique-id header in the HTTP request sent to the server, using the
+    unique-id-format. It can't work if the unique-id-format doesn't exist.
+
+    Example:
+
+        unique-id-format %{+X}o\ %Ci:%Cp_%Fi:%Fp_%Ts_%rt:%pid
+        unique-id-header X-Unique-ID
+
+        will generate:
+
+           X-Unique-ID: 7F000001:8296_7F00001E:1F90_4F7B0A69_0003:790A
+
+    See also: "unique-id-format"
 
 use_backend <backend> if <condition>
 use_backend <backend> unless <condition>
@@ -8919,6 +8975,7 @@ Please refer to the table below for currently defined variables :
   |   | %Fi  | frontend_ip                                   | IP          |
   |   | %Fp  | frontend_port                                 | numeric     |
   |   | %H   | hostname                                      | string      |
+  |   | %ID  | unique-id                                     | string      |
   |   | %Si  | server_IP                                     | IP          |
   |   | %Sp  | server_port                                   | numeric     |
   |   | %T   | gmt_date_time                                 | date        |
index 0e41ecab9e4e072f91f6a6b1e68e92c9782edb73..5adf6740e7b76b830bf503b37a7e9e21ba92b8bc 100644 (file)
@@ -33,6 +33,7 @@
 #include <types/session.h>
 
 extern struct pool_head *pool2_requri;
+extern struct pool_head *pool2_uniqueid;
 
 extern char *log_format;
 extern char default_tcp_log_format[];
index ad96e9a1a39cf696fe088be45f3e888f13784976..269fb46326e6f33d1bfe545ea89d492a9d2a551a 100644 (file)
@@ -31,6 +31,8 @@
 #define NB_LOG_FACILITIES       24
 #define NB_LOG_LEVELS           8
 #define SYSLOG_PORT             514
+#define UNIQUEID_LEN            128
+
 
 /* lists of fields that can be logged */
 enum {
@@ -86,6 +88,7 @@ enum {
        LOG_FMT_HDRRESPONSLIST,
        LOG_FMT_REQ,
        LOG_FMT_HOSTNAME,
+       LOG_FMT_UNIQUEID,
 };
 
 /* enum for parse_logformat */
index d69a91416c6c19d512d6d43e7b43b77e1a7575a4..aa6cec82c6bd47e38cad454088fe6b41a881b593 100644 (file)
@@ -290,6 +290,8 @@ struct proxy {
        struct proxy *next;
        struct list logsrvs;
        struct list logformat;                  /* log_format linked list */
+       char *header_unique_id;                 /* unique-id header */
+       struct list format_unique_id;           /* unique-id format */
        int to_log;                             /* things to be logged (LW_*) */
        int stop_time;                          /* date to stop listening, when stopping != 0 (int ticks) */
        struct hdr_exp *req_exp;                /* regular expressions for request headers */
index 5678e5c069a1df42f154bb825deb3c71d5ecc713..7539c0cd83825a892d91762d307522afe25c0889 100644 (file)
@@ -207,6 +207,7 @@ struct session {
        void (*srv_error)(struct session *s,    /* the function to call upon unrecoverable server errors (or NULL) */
                          struct stream_interface *si);
        unsigned int uniq_id;                   /* unique ID used for the traces */
+       char *unique_id;                        /* custom unique ID */
 };
 
 /* parameters to configure tracked counters */
index aa57b9b55a55a85b4f66d3473bc94255160ed50b..1267cd7eeb03636ca10e6145e887ad5cc6bd4074 100644 (file)
@@ -1550,6 +1550,18 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                        LIST_ADDQ(&curproxy->logformat, &node->list);
                }
 
+               /* copy default unique_id to curproxy */
+               list_for_each_entry(tmplf, &defproxy.format_unique_id, list) {
+                       struct logformat_node *node = malloc(sizeof(struct logformat_node));
+                       memcpy(node, tmplf, sizeof(struct logformat_node));
+                       LIST_INIT(&node->list);
+                       LIST_ADDQ(&curproxy->format_unique_id, &node->list);
+               }
+
+               /* copy default header unique id */
+               if (defproxy.header_unique_id)
+                       curproxy->header_unique_id = strdup(defproxy.header_unique_id);
+
                curproxy->grace  = defproxy.grace;
                curproxy->conf.used_listener_id = EB_ROOT;
                curproxy->conf.used_server_id = EB_ROOT;
@@ -4592,6 +4604,26 @@ stats_error_parsing:
                        newsrv->prev_state = newsrv->state;
                }
        }
+
+       else if (strcmp(args[0], "unique-id-format") == 0) {
+               if (!*(args[1])) {
+                       Alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               parse_logformat_string(args[1], curproxy, &curproxy->format_unique_id, PR_MODE_HTTP);
+       }
+
+       else if (strcmp(args[0], "unique-id-header") == 0) {
+               if (!*(args[1])) {
+                       Alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               free(curproxy->header_unique_id);
+               curproxy->header_unique_id = strdup(args[1]);
+       }
+
        else if (strcmp(args[0], "log-format") == 0) {
                if (!*(args[1])) {
                        Alert("parsing [%s:%d] : %s expects an argument.\n", file, linenum, args[0]);
index af2aee97b1cedf128325e71a7c570b9b14f6c1aa..130d627ba438d6129dc610f06b94ae2e4516ab90 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -107,6 +107,7 @@ static const struct logformat_type logformat_keywords[] = {
        { "pid", LOG_FMT_PID, PR_MODE_TCP, NULL }, /* log pid */
        { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, NULL }, /* log counter */
        { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, NULL }, /* Hostname */
+       { "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, NULL }, /* Unique ID */
        { 0, 0, 0, NULL }
 };
 
@@ -1305,6 +1306,16 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis
                                        last_isspace = 0;
                                }
                                break;
+
+                       case LOG_FMT_UNIQUEID: // %ID
+                               src = s->unique_id;
+                               ret = lf_text(tmplog, src, maxsize - (tmplog - dst), tmp);
+                               if (ret == NULL)
+                                       goto out;
+                               tmplog = ret;
+                               last_isspace = 0;
+                               break;
+
                }
        }
 
index 2f9d3e8eecff3ee7c06dbb60433cb2bbe853c224..dd2f0d07d8b7f08007b2c3f747e3e1781df7afb4 100644 (file)
@@ -268,6 +268,7 @@ void init_proto_http()
        /* memory allocations */
        pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
        pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED);
+       pool2_uniqueid = create_pool("uniqueid", UNIQUEID_LEN, MEM_F_SHARED);
 }
 
 /*
@@ -858,6 +859,7 @@ extern const char sess_fin_state[8];
 extern const char *monthname[12];
 struct pool_head *pool2_requri;
 struct pool_head *pool2_capture;
+struct pool_head *pool2_uniqueid;
 
 /*
  * Capture headers from message starting at <som> according to header list
@@ -2397,6 +2399,10 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit)
                }
        }
 
+               if (!LIST_ISEMPTY(&s->fe->format_unique_id)) {
+                       s->unique_id = pool_alloc2(pool2_uniqueid);
+               }
+
        /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
        if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(req, msg, txn))
                goto return_bad_req;
@@ -3274,6 +3280,19 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit)
                get_srv_from_appsession(s, msg->sol + msg->sl.rq.u, msg->sl.rq.u_l);
        }
 
+       /* add unique-id if "header-unique-id" is specified */
+
+       if (!LIST_ISEMPTY(&s->fe->format_unique_id))
+               build_logline(s, s->unique_id, UNIQUEID_LEN, &s->fe->format_unique_id);
+
+       if (s->fe->header_unique_id && s->unique_id) {
+               int ret = snprintf(trash, global.tune.bufsize, "%s: %s", s->fe->header_unique_id, s->unique_id);
+               if (ret < 0 || ret > global.tune.bufsize)
+                       goto return_bad_req;
+               if(unlikely(http_header_add_tail(req, &txn->req, &txn->hdr_idx, trash) < 0))
+                  goto return_bad_req;
+       }
+
        /*
         * 9: add X-Forwarded-For if either the frontend or the backend
         * asks for it.
@@ -7381,7 +7400,9 @@ void http_end_txn(struct session *s)
        pool_free2(pool2_capture, txn->cli_cookie);
        pool_free2(pool2_capture, txn->srv_cookie);
        pool_free2(apools.sessid, txn->sessid);
+       pool_free2(pool2_uniqueid, s->unique_id);
 
+       s->unique_id = NULL;
        txn->sessid = NULL;
        txn->uri = NULL;
        txn->srv_cookie = NULL;
index 7f15bb26540b7d1dd0d8e574f655cecd9d5c4c73..bb9fe5733da5831276850592badbaa8e5df76856 100644 (file)
@@ -439,6 +439,7 @@ void init_new_proxy(struct proxy *p)
        LIST_INIT(&p->listener_queue);
        LIST_INIT(&p->logsrvs);
        LIST_INIT(&p->logformat);
+       LIST_INIT(&p->format_unique_id);
 
        /* Timeouts are defined as -1 */
        proxy_reset_timeouts(p);