From: William Lallemand Date: Mon, 12 Mar 2012 11:48:57 +0000 (+0100) Subject: MEDIUM: log: Unique ID X-Git-Tag: v1.5-dev9~108 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a73203e3dc1a675b9fce8ffd5f918ad23d5954c0;p=thirdparty%2Fhaproxy.git MEDIUM: log: Unique ID 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. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 66b61ff25a..8f502132be 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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 + Generate a unique ID for each request. + May be used in sections : defaults | frontend | listen | backend + yes | yes | yes | no + Arguments : + 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 + Add a unique ID header in the HTTP request. + May be used in sections : defaults | frontend | listen | backend + yes | yes | yes | no + Arguments : + 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 if use_backend unless @@ -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 | diff --git a/include/proto/log.h b/include/proto/log.h index 0e41ecab9e..5adf6740e7 100644 --- a/include/proto/log.h +++ b/include/proto/log.h @@ -33,6 +33,7 @@ #include extern struct pool_head *pool2_requri; +extern struct pool_head *pool2_uniqueid; extern char *log_format; extern char default_tcp_log_format[]; diff --git a/include/types/log.h b/include/types/log.h index ad96e9a1a3..269fb46326 100644 --- a/include/types/log.h +++ b/include/types/log.h @@ -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 */ diff --git a/include/types/proxy.h b/include/types/proxy.h index d69a91416c..aa6cec82c6 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -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 */ diff --git a/include/types/session.h b/include/types/session.h index 5678e5c069..7539c0cd83 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -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 */ diff --git a/src/cfgparse.c b/src/cfgparse.c index aa57b9b55a..1267cd7eeb 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -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]); diff --git a/src/log.c b/src/log.c index af2aee97b1..130d627ba4 100644 --- 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; + } } diff --git a/src/proto_http.c b/src/proto_http.c index 2f9d3e8eec..dd2f0d07d8 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -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 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; diff --git a/src/proxy.c b/src/proxy.c index 7f15bb2654..bb9fe5733d 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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);