#include <haproxy/applet-t.h>
#include <haproxy/stick_table-t.h>
#include <haproxy/vars-t.h>
+#include <haproxy/log-t.h>
struct session;
struct stream;
struct {
int i; /* integer param (status, nice, loglevel, ..) */
struct ist str; /* string param (reason, header name, ...) */
- struct list fmt; /* log-format compatible expression */
+ struct lf_expr fmt; /* log-format compatible expression */
struct my_regex *re; /* used by replace-header/value/uri/path */
} http; /* args used by some HTTP rules */
struct http_reply *http_reply; /* HTTP response to be used by return/deny/tarpit rules */
struct redirect_rule *redir; /* redirect rule or "http-request redirect" */
struct {
char *ref; /* MAP or ACL file name to update */
- struct list key; /* pattern to retrieve MAP or ACL key */
- struct list value; /* pattern to retrieve MAP value */
+ struct lf_expr key; /* pattern to retrieve MAP or ACL key */
+ struct lf_expr value; /* pattern to retrieve MAP value */
} map;
struct sample_expr *expr;
struct {
} timeout;
struct hlua_rule *hlua_rule;
struct {
- struct list fmt; /* log-format compatible expression */
+ struct lf_expr fmt; /* log-format compatible expression */
struct sample_expr *expr;
uint64_t name_hash;
enum vars_scope scope;
#include <haproxy/acl-t.h>
#include <haproxy/api-t.h>
#include <haproxy/arg-t.h>
+#include <haproxy/log-t.h>
#include <haproxy/fcgi.h>
#include <haproxy/filters-t.h>
#include <haproxy/regex-t.h>
struct fcgi_rule {
enum fcgi_rule_type type;
struct ist name; /* name of the parameter/header */
- struct list value; /* log-format compatible expression, may be empty */
+ struct lf_expr value; /* log-format compatible expression, may be empty */
struct acl_cond *cond; /* acl condition to set the param */
struct list list;
};
/* parameter rule to set/unset a param at the end of the analyzis */
struct fcgi_param_rule {
struct ist name;
- struct list *value; /* if empty , unset the parameter */
+ struct lf_expr *value; /* if empty , unset the parameter */
struct ebpt_node node;
};
#include <haproxy/buf-t.h>
#include <haproxy/http-t.h>
+#include <haproxy/log-t.h>
#include <haproxy/htx-t.h>
/* Context used to find/remove an HTTP header. */
/* Structure used to build the header list of an HTTP reply */
struct http_reply_hdr {
- struct ist name; /* the header name */
- struct list value; /* the log-format string value */
- struct list list; /* header chained list */
+ struct ist name; /* the header name */
+ struct lf_expr value; /* the log-format string value */
+ struct list list; /* header linked list */
};
#define HTTP_REPLY_EMPTY 0x00 /* the reply has no payload */
char *ctype; /* The response content-type, may be NULL */
struct list hdrs; /* A list of http_reply_hdr */
union {
- struct list fmt; /* A log-format string (type = HTTP_REPLY_LOGFMT) */
+ struct lf_expr fmt; /* A log-format string (type = HTTP_REPLY_LOGFMT) */
struct buffer obj; /* A raw string (type = HTTP_REPLY_RAW) */
struct buffer *errmsg; /* The error message to use as response (type = HTTP_REPLY_ERRMSG).
* may be NULL, if so rely on the proxy error messages */
const struct logformat_tag *tag; // set if ->type == LOG_FMT_TAG
};
+/* a full logformat expr made of one or multiple logformat nodes */
+struct lf_expr {
+ struct list nodes; /* logformat_node list */
+};
+
/* Range of indexes for log sampling. */
struct smp_log_range {
unsigned int low; /* Low limit of the indexes of this range. */
int init_log_buffers(void);
void deinit_log_buffers(void);
+void lf_expr_init(struct lf_expr *expr);
+void lf_expr_xfer(struct lf_expr *src, struct lf_expr *dst);
+void lf_expr_deinit(struct lf_expr *expr);
+static inline int lf_expr_isempty(const struct lf_expr *expr)
+{
+ return LIST_ISEMPTY(&expr->nodes);
+}
+
/* Deinitialize log buffers used for syslog messages */
void free_logformat_list(struct list *fmt);
void free_logformat_node(struct logformat_node *node);
/* build a log line for the session and an optional stream */
-int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t maxsize, struct list *list_format);
+int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t maxsize, struct lf_expr *lf_expr);
/*
* send a log for the stream when we have enough info about it.
/*
* add to the logformat linked list
*/
-int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err);
+int add_to_logformat_list(char *start, char *end, int type, struct lf_expr *lf_expr, char **err);
ssize_t syslog_applet_append_event(void *ctx, struct ist v1, struct ist v2, size_t ofs, size_t len);
* Tag name are preceded by % and composed by characters [a-zA-Z0-9]* : %tagname
* You can set arguments using { } : %{many arguments}tagname
*/
-int parse_logformat_string(const char *str, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err);
+int parse_logformat_string(const char *str, struct proxy *curproxy, struct lf_expr *lf_expr, int options, int cap, char **err);
int postresolve_logger_list(struct list *loggers, const char *section, const char *section_name);
/*
* Builds a log line for the stream (must be valid).
*/
-static inline int build_logline(struct stream *s, char *dst, size_t maxsize, struct list *list_format)
+static inline int build_logline(struct stream *s, char *dst, size_t maxsize, struct lf_expr *lf_expr)
{
- return sess_build_logline(strm_sess(s), s, dst, maxsize, list_format);
+ return sess_build_logline(strm_sess(s), s, dst, maxsize, lf_expr);
}
struct ist *build_log_header(struct log_header hdr, size_t *nbelem);
struct proxy *next_stkt_ref; /* Link to the list of proxies which refer to the same stick-table. */
struct list loggers; /* one per 'log' directive */
- struct list logformat; /* log_format linked list */
- struct list logformat_sd; /* log_format linked list for the RFC5424 structured-data part */
- struct list logformat_error; /* log_format linked list used in case of connection error on the frontend */
+ struct lf_expr logformat; /* log_format linked list */
+ struct lf_expr logformat_sd; /* log_format linked list for the RFC5424 structured-data part */
+ struct lf_expr logformat_error; /* log_format linked list used in case of connection error on the frontend */
struct buffer log_tag; /* override default syslog tag */
struct ist header_unique_id; /* unique-id header */
- struct list format_unique_id; /* unique-id format */
+ struct lf_expr format_unique_id; /* unique-id format */
int to_log; /* things to be logged (LW_*) */
int nb_req_cap, nb_rsp_cap; /* # of headers to be captured */
struct cap_hdr *req_cap; /* chained list of request headers to be captured */
union {
struct proxy *backend; /* target backend */
char *name; /* target backend name during config parsing */
- struct list expr; /* logformat expression to use for dynamic rules */
+ struct lf_expr expr; /* logformat expression to use for dynamic rules */
} be;
char *file;
int line;
struct server *ptr; /* target server */
char *name; /* target server name during config parsing */
} srv;
- struct list expr; /* logformat expression to use for dynamic rules */
+ struct lf_expr expr; /* logformat expression to use for dynamic rules */
char *file;
int line;
};
int type;
int rdr_len;
char *rdr_str;
- struct list rdr_fmt;
+ struct lf_expr rdr_fmt;
int code;
unsigned int flags;
int cookie_len;
#include <haproxy/task-t.h>
#include <haproxy/thread-t.h>
#include <haproxy/event_hdl-t.h>
+#include <haproxy/log-t.h>
#include <haproxy/tools-t.h>
*/
struct srv_pp_tlv_list {
struct list list;
- struct list fmt;
+ struct lf_expr fmt;
char *fmt_string;
unsigned char type;
};
void stream_dump_and_crash(enum obj_type *obj, int rate);
void strm_dump_to_buffer(struct buffer *buf, const struct stream *strm, const char *pfx, uint32_t anon_key);
-struct ist stream_generate_unique_id(struct stream *strm, struct list *format);
+struct ist stream_generate_unique_id(struct stream *strm, struct lf_expr *format);
void stream_process_counters(struct stream *s);
void sess_change_server(struct stream *strm, struct server *newsrv);
};
struct tcpcheck_http_hdr {
- struct ist name; /* the header name */
- struct list value; /* the log-format string value */
- struct list list; /* header chained list */
+ struct ist name; /* the header name */
+ struct lf_expr value; /* the log-format string value */
+ struct list list; /* header linked list */
};
struct tcpcheck_codes {
struct tcpcheck_send {
enum tcpcheck_send_type type;
union {
- struct ist data; /* an ASCII string or a binary sequence */
- struct list fmt; /* an ASCII or hexa log-format string */
+ struct ist data; /* an ASCII string or a binary sequence */
+ struct lf_expr fmt; /* an ASCII or hexa log-format string */
struct {
unsigned int flags; /* TCPCHK_SND_HTTP_FL_* */
struct http_meth meth; /* the HTTP request method */
union {
struct ist uri; /* the HTTP request uri is a string */
- struct list uri_fmt; /* or a log-format string */
+ struct lf_expr uri_fmt; /* or a log-format string */
};
struct ist vsn; /* the HTTP request version string */
struct list hdrs; /* the HTTP request header list */
union {
struct ist body; /* the HTTP request payload is a string */
- struct list body_fmt; /* or a log-format string */
+ struct lf_expr body_fmt;/* or a log-format string */
};
} http; /* Info about the HTTP request to send */
};
struct ist data; /* Matching a literal string / binary anywhere in the response. */
struct my_regex *regex; /* Matching a regex pattern. */
struct tcpcheck_codes codes; /* Matching a list of codes */
- struct list fmt; /* Matching a log-format string / binary */
+ struct lf_expr fmt; /* Matching a log-format string / binary */
struct {
union {
struct ist name;
- struct list name_fmt;
+ struct lf_expr name_fmt;
struct my_regex *name_re;
};
union {
struct ist value;
- struct list value_fmt;
+ struct lf_expr value_fmt;
struct my_regex *value_re;
};
} hdr; /* Matching a header pattern */
enum healthcheck_status ok_status; /* The healthcheck status to use on success (default: L7OKD) */
enum healthcheck_status err_status; /* The healthcheck status to use on error (default: L7RSP) */
enum healthcheck_status tout_status; /* The healthcheck status to use on timeout (default: L7TOUT) */
- struct list onerror_fmt; /* log-format string to use as comment on error */
- struct list onsuccess_fmt; /* log-format string to use as comment on success (if last rule) */
- struct sample_expr *status_expr; /* sample expr to determine the check status code */
+ struct lf_expr onerror_fmt; /* log-format string to use as comment on error */
+ struct lf_expr onsuccess_fmt; /* log-format string to use as comment on success (if last rule) */
+ struct sample_expr *status_expr; /* sample expr to determine the check status code */
};
struct tcpcheck_action_kw {
* parsing is cancelled and be.name is restored to be resolved.
*/
pxname = rule->be.name;
- LIST_INIT(&rule->be.expr);
+ lf_expr_init(&rule->be.expr);
curproxy->conf.args.ctx = ARGC_UBK;
curproxy->conf.args.file = rule->file;
curproxy->conf.args.line = rule->line;
cfgerr++;
continue;
}
- node = LIST_NEXT(&rule->be.expr, struct logformat_node *, list);
+ node = LIST_NEXT(&rule->be.expr.nodes, struct logformat_node *, list);
- if (!LIST_ISEMPTY(&rule->be.expr)) {
- if (node->type != LOG_FMT_TEXT || node->list.n != &rule->be.expr) {
+ if (!lf_expr_isempty(&rule->be.expr)) {
+ if (node->type != LOG_FMT_TEXT || node->list.n != &rule->be.expr.nodes) {
rule->dynamic = 1;
free(pxname);
/* backend is not yet known so we cannot assume its type,
/* Only one element in the list, a simple string: free the expression and
* fall back to static rule
*/
- LIST_DELETE(&node->list);
- free_logformat_node(node);
+ lf_expr_deinit(&rule->be.expr);
}
rule->dynamic = 0;
* to a static rule, thus the parsing is cancelled and we fall back to setting srv.ptr.
*/
server_name = srule->srv.name;
- LIST_INIT(&srule->expr);
+ lf_expr_init(&srule->expr);
curproxy->conf.args.ctx = ARGC_USRV;
err = NULL;
if (!parse_logformat_string(server_name, curproxy, &srule->expr, 0, SMP_VAL_FE_HRQ_HDR, &err)) {
cfgerr++;
continue;
}
- node = LIST_NEXT(&srule->expr, struct logformat_node *, list);
+ node = LIST_NEXT(&srule->expr.nodes, struct logformat_node *, list);
- if (!LIST_ISEMPTY(&srule->expr)) {
- if (node->type != LOG_FMT_TEXT || node->list.n != &srule->expr) {
+ if (!lf_expr_isempty(&srule->expr)) {
+ if (node->type != LOG_FMT_TEXT || node->list.n != &srule->expr.nodes) {
srule->dynamic = 1;
free(server_name);
continue;
/* Only one element in the list, a simple string: free the expression and
* fall back to static rule
*/
- LIST_DELETE(&node->list);
- free_logformat_node(node);
+ lf_expr_deinit(&srule->expr);
}
srule->dynamic = 0;
if (!(curproxy->cap & PR_CAP_INT) && (curproxy->mode == PR_MODE_TCP || curproxy->mode == PR_MODE_HTTP) &&
(curproxy->cap & PR_CAP_FE) && LIST_ISEMPTY(&curproxy->loggers) &&
- (!LIST_ISEMPTY(&curproxy->logformat) || !LIST_ISEMPTY(&curproxy->logformat_sd))) {
+ (!lf_expr_isempty(&curproxy->logformat) || !lf_expr_isempty(&curproxy->logformat_sd))) {
ha_warning("log format ignored for %s '%s' since it has no log address.\n",
proxy_type_str(curproxy), curproxy->id);
err_code |= ERR_WARN;
pendconn_free(s);
/* let's do a final log if we need it */
- if (!LIST_ISEMPTY(&fe->logformat) && s->logs.logwait &&
+ if (!lf_expr_isempty(&fe->logformat) && s->logs.logwait &&
!(s->flags & SF_MONITOR) &&
(!(fe->options & PR_O_NULLNOLOG) || s->req.total)) {
s->do_log(s);
/* Users will always need to provide a value, in case of forwarding, they should use fc_pp_tlv.
* for generic types. Otherwise, we will send an empty TLV.
*/
- if (!LIST_ISEMPTY(&srv_tlv->fmt)) {
+ if (!lf_expr_isempty(&srv_tlv->fmt)) {
replace = alloc_trash_chunk();
if (unlikely(!replace))
return 0;
if (!rule)
return;
- free_logformat_list(&rule->value);
+ lf_expr_deinit(&rule->value);
/* ->cond and ->name are not owned by the rule */
free(rule);
}
rule->type = crule->type;
rule->name = ist(crule->name);
rule->cond = crule->cond;
- LIST_INIT(&rule->value);
+ lf_expr_init(&rule->value);
if (crule->value) {
if (!parse_logformat_string(crule->value, px, &rule->value, LOG_OPT_HTTP,
if ((fe->mode == PR_MODE_TCP || fe->mode == PR_MODE_HTTP)
&& (!LIST_ISEMPTY(&fe->loggers))) {
- if (likely(!LIST_ISEMPTY(&fe->logformat))) {
+ if (likely(!lf_expr_isempty(&fe->logformat))) {
/* we have the client ip */
if (s->logs.logwait & LW_CLIP)
if (!(s->logs.logwait &= ~(LW_CLIP|LW_INIT)))
istfree(&rule->arg.http.str);
if (rule->arg.http.re)
regex_free(rule->arg.http.re);
- free_logformat_list(&rule->arg.http.fmt);
+ lf_expr_deinit(&rule->arg.http.fmt);
}
/* Release memory allocated by HTTP actions relying on an http reply. Concretly,
}
rule->action_ptr = http_action_set_req_line;
rule->release_ptr = release_http_action;
- LIST_INIT(&rule->arg.http.fmt);
+ lf_expr_init(&rule->arg.http.fmt);
if (!*args[cur_arg] ||
(*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
rule->action_ptr = http_action_replace_uri;
rule->release_ptr = release_http_action;
- LIST_INIT(&rule->arg.http.fmt);
+ lf_expr_init(&rule->arg.http.fmt);
if (!*args[cur_arg] || !*args[cur_arg+1] ||
(*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
rule->action = ACT_CUSTOM;
rule->action_ptr = action_http_set_status;
rule->release_ptr = release_http_action;
- LIST_INIT(&rule->arg.http.fmt);
+ lf_expr_init(&rule->arg.http.fmt);
/* Check if an argument is available */
if (!*args[*orig_arg]) {
rule->flags |= ACT_FLAG_FINAL;
rule->action_ptr = http_action_auth;
rule->release_ptr = release_http_action;
- LIST_INIT(&rule->arg.http.fmt);
+ lf_expr_init(&rule->arg.http.fmt);
cur_arg = *orig_arg;
if (strcmp(args[cur_arg], "realm") == 0) {
rule->action_ptr = http_action_set_header;
}
rule->release_ptr = release_http_action;
- LIST_INIT(&rule->arg.http.fmt);
+ lf_expr_init(&rule->arg.http.fmt);
cur_arg = *orig_arg;
if (!*args[cur_arg] || !*args[cur_arg+1]) {
rule->action = 1; // replace-value
rule->action_ptr = http_action_replace_header;
rule->release_ptr = release_http_action;
- LIST_INIT(&rule->arg.http.fmt);
+ lf_expr_init(&rule->arg.http.fmt);
cur_arg = *orig_arg;
if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2]) {
rule->action = PAT_MATCH_STR;
rule->action_ptr = http_action_del_header;
rule->release_ptr = release_http_action;
- LIST_INIT(&rule->arg.http.fmt);
+ lf_expr_init(&rule->arg.http.fmt);
cur_arg = *orig_arg;
if (!*args[cur_arg]) {
static void release_http_map(struct act_rule *rule)
{
free(rule->arg.map.ref);
- free_logformat_list(&rule->arg.map.key);
+ lf_expr_deinit(&rule->arg.map.key);
if (rule->action == 1)
- free_logformat_list(&rule->arg.map.value);
+ lf_expr_deinit(&rule->arg.map.value);
}
/* Parse a "add-acl", "del-acl", "set-map" or "del-map" actions. It takes one or
}
/* key pattern */
- LIST_INIT(&rule->arg.map.key);
+ lf_expr_init(&rule->arg.map.key);
if (!parse_logformat_string(args[cur_arg], px, &rule->arg.map.key, LOG_OPT_HTTP, cap, err)) {
free(rule->arg.map.ref);
return ACT_RET_PRS_ERR;
if (rule->action == 1) {
/* value pattern for set-map only */
cur_arg++;
- LIST_INIT(&rule->arg.map.value);
+ lf_expr_init(&rule->arg.map.value);
if (!parse_logformat_string(args[cur_arg], px, &rule->arg.map.value, LOG_OPT_HTTP, cap, err)) {
free(rule->arg.map.ref);
return ACT_RET_PRS_ERR;
* A unique ID is generated even when it is not sent to ensure that the ID can make use of
* fetches only available in the HTTP request processing stage.
*/
- if (!LIST_ISEMPTY(&sess->fe->format_unique_id)) {
+ if (!lf_expr_isempty(&sess->fe->format_unique_id)) {
struct ist unique_id = stream_generate_unique_id(s, &sess->fe->format_unique_id);
if (!isttest(unique_id)) {
* bytes from the server, then this is the right moment. We have
* to temporarily assign bytes_out to log what we currently have.
*/
- if (!LIST_ISEMPTY(&sess->fe->logformat) && !(s->logs.logwait & LW_BYTES)) {
+ if (!lf_expr_isempty(&sess->fe->logformat) && !(s->logs.logwait & LW_BYTES)) {
s->logs.t_close = s->logs.t_data; /* to get a valid end date */
s->logs.bytes_out = htx->data;
s->do_log(s);
#include <haproxy/sample.h>
#include <haproxy/sc_strm.h>
#include <haproxy/stream.h>
+#include <haproxy/log.h>
#include <haproxy/tools.h>
#include <haproxy/version.h>
{
struct ist unique_id;
- if (LIST_ISEMPTY(&smp->sess->fe->format_unique_id))
+ if (lf_expr_isempty(&smp->sess->fe->format_unique_id))
return 0;
if (!smp->strm)
ha_free(&http_reply->ctype);
list_for_each_entry_safe(hdr, hdrb, &http_reply->hdrs, list) {
LIST_DELETE(&hdr->list);
- free_logformat_list(&hdr->value);
+ lf_expr_deinit(&hdr->value);
istfree(&hdr->name);
free(hdr);
}
else if (http_reply->type == HTTP_REPLY_RAW)
chunk_destroy(&http_reply->body.obj);
else if (http_reply->type == HTTP_REPLY_LOGFMT)
- free_logformat_list(&http_reply->body.fmt);
+ lf_expr_deinit(&http_reply->body.fmt);
free(http_reply);
}
fd = -1;
obj[objlen] = '\0';
reply->type = HTTP_REPLY_LOGFMT;
- LIST_INIT(&reply->body.fmt);
+ lf_expr_init(&reply->body.fmt);
cur_arg++;
}
else if (strcmp(args[cur_arg], "lf-string") == 0) {
obj = strdup(args[cur_arg]);
objlen = strlen(args[cur_arg]);
reply->type = HTTP_REPLY_LOGFMT;
- LIST_INIT(&reply->body.fmt);
+ lf_expr_init(&reply->body.fmt);
cur_arg++;
}
else if (strcmp(args[cur_arg], "hdr") == 0) {
goto error;
}
LIST_APPEND(&reply->hdrs, &hdr->list);
- LIST_INIT(&hdr->value);
+ lf_expr_init(&hdr->value);
hdr->name = ist(strdup(args[cur_arg]));
if (!isttest(hdr->name)) {
memprintf(errmsg, "out of memory");
px->conf.args.file, px->conf.args.line);
list_for_each_entry_safe(hdr, hdrb, &reply->hdrs, list) {
LIST_DELETE(&hdr->list);
- free_logformat_list(&hdr->value);
+ lf_expr_deinit(&hdr->value);
istfree(&hdr->name);
free(hdr);
}
}
}
else if (reply->type == HTTP_REPLY_LOGFMT) { /* log-format payload using 'lf-file' of 'lf-string' parameter */
- LIST_INIT(&reply->body.fmt);
+ lf_expr_init(&reply->body.fmt);
if ((reply->status == 204 || reply->status == 304)) {
memprintf(errmsg, "No body expected for %d responses", reply->status);
goto error;
free_acl_cond(rdr->cond);
free(rdr->rdr_str);
free(rdr->cookie_str);
- free_logformat_list(&rdr->rdr_fmt);
+ lf_expr_deinit(&rdr->rdr_fmt);
free(rdr);
}
if (!rule)
goto out_of_memory;
rule->cond = cond;
- LIST_INIT(&rule->rdr_fmt);
+ lf_expr_init(&rule->rdr_fmt);
if (!use_fmt) {
/* old-style static redirect rule */
* ignored when arg_len is 0. Neither <tag> nor <tag_len> may be null.
* Returns false in error case and err is filled, otherwise returns true.
*/
-int parse_logformat_tag(char *arg, int arg_len, char *name, int name_len, int typecast, char *tag, int tag_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
+int parse_logformat_tag(char *arg, int arg_len, char *name, int name_len, int typecast, char *tag, int tag_len, struct proxy *curproxy, struct lf_expr *lf_expr, int *defoptions, char **err)
{
int j;
+ struct list *list_format= &lf_expr->nodes;
struct logformat_node *node = NULL;
for (j = 0; logformat_tags[j].name; j++) { // search a log type
* start: start pointer
* end: end text pointer
* type: string type
- * list_format: destination list
+ * lf_expr: destination logformat expr (list of fmt nodes)
*
* LOG_TEXT: copy chars from start to end excluding end.
*
*/
-int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
+int add_to_logformat_list(char *start, char *end, int type, struct lf_expr *lf_expr, char **err)
{
+ struct list *list_format = &lf_expr->nodes;
char *str;
if (type == LF_TEXT) { /* type text */
}
/*
- * Parse the sample fetch expression <text> and add a node to <list_format> upon
+ * Parse the sample fetch expression <text> and add a node to <lf_expr> upon
* success. The curpx->conf.args.ctx must be set by the caller. If an end pointer
* is passed in <endptr>, it will be updated with the pointer to the first character
* not part of the sample expression.
*
* In error case, the function returns 0, otherwise it returns 1.
*/
-int add_sample_to_logformat_list(char *text, char *name, int name_len, int typecast, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err, char **endptr)
+int add_sample_to_logformat_list(char *text, char *name, int name_len, int typecast, char *arg, int arg_len, struct proxy *curpx, struct lf_expr *lf_expr, int options, int cap, char **err, char **endptr)
{
char *cmd[2];
+ struct list *list_format = &lf_expr->nodes;
struct sample_expr *expr = NULL;
struct logformat_node *node = NULL;
int cmd_arg;
*
* fmt: the string to parse
* curproxy: the proxy affected
- * list_format: the destination list
+ * lf_expr: the destination logformat expression (logformat_node list)
* options: LOG_OPT_* to force on every node
* cap: all SMP_VAL_* flags supported by the consumer
*
* The function returns 1 in success case, otherwise, it returns 0 and err is filled.
*/
-int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err)
+int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct lf_expr *lf_expr, int options, int cap, char **err)
{
char *sp, *str, *backfmt; /* start pointer for text parts */
char *arg = NULL; /* start pointer for args */
}
curproxy->to_log |= LW_INIT;
- /* flush the list first. */
- free_logformat_list(list_format);
+ /* reset the old expr first (if previously defined) */
+ lf_expr_deinit(lf_expr);
for (cformat = LF_INIT; cformat != LF_END; str++) {
pformat = cformat;
* part of the expression, which MUST be the trailing
* angle bracket.
*/
- if (!add_sample_to_logformat_list(tag, name, name_len, typecast, arg, arg_len, curproxy, list_format, options, cap, err, &str))
+ if (!add_sample_to_logformat_list(tag, name, name_len, typecast, arg, arg_len, curproxy, lf_expr, options, cap, err, &str))
goto fail;
if (*str == ']') {
if (cformat != pformat || pformat == LF_SEPARATOR) {
switch (pformat) {
case LF_TAG:
- if (!parse_logformat_tag(arg, arg_len, name, name_len, typecast, tag, tag_len, curproxy, list_format, &options, err))
+ if (!parse_logformat_tag(arg, arg_len, name, name_len, typecast, tag, tag_len, curproxy, lf_expr, &options, err))
goto fail;
break;
case LF_TEXT:
case LF_SEPARATOR:
- if (!add_to_logformat_list(sp, str, pformat, list_format, err))
+ if (!add_to_logformat_list(sp, str, pformat, lf_expr, err))
goto fail;
break;
}
}
}
-/* Builds a log line in <dst> based on <list_format>, and stops before reaching
+/* Prepares log-format expression struct */
+void lf_expr_init(struct lf_expr *expr)
+{
+ LIST_INIT(&expr->nodes);
+}
+
+/* Releases and resets a log-format expression */
+void lf_expr_deinit(struct lf_expr *expr)
+{
+ free_logformat_list(&expr->nodes);
+ lf_expr_init(expr);
+}
+
+/* Transfer log-format expression from <src> to <dst>
+ * at the end of the operation, <src> is reset
+ */
+void lf_expr_xfer(struct lf_expr *src, struct lf_expr *dst)
+{
+ struct logformat_node *lf, *lfb;
+
+ /* first, reset any existing expr */
+ lf_expr_deinit(dst);
+
+ /* then proceed with transfer between <src> and <dst> */
+ list_for_each_entry_safe(lf, lfb, &src->nodes, list) {
+ LIST_DELETE(&lf->list);
+ LIST_APPEND(&dst->nodes, &lf->list);
+ }
+
+ /* src is now empty, perform an explicit reset */
+ lf_expr_init(src);
+}
+
+/* Builds a log line in <dst> based on <lf_expr>, and stops before reaching
* <maxsize> characters. Returns the size of the output string in characters,
* not counting the trailing zero which is always added if the resulting size
* is not zero. It requires a valid session and optionally a stream. If the
* stream is NULL, default values will be assumed for the stream part.
*/
-int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t maxsize, struct list *list_format)
+int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t maxsize, struct lf_expr *lf_expr)
{
struct proxy *fe = sess->fe;
struct proxy *be;
struct http_txn *txn;
const struct strm_logs *logs;
struct connection *fe_conn, *be_conn;
+ struct list *list_format = &lf_expr->nodes;
unsigned int s_flags;
unsigned int uniq_id;
struct buffer chunk;
tmplog = dst;
/* fill logbuffer */
- if (LIST_ISEMPTY(list_format))
+ if (lf_expr_isempty(lf_expr))
return 0;
list_for_each_entry(tmp, list_format, list) {
}
/* if unique-id was not generated */
- if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
+ if (!isttest(s->unique_id) && !lf_expr_isempty(&sess->fe->format_unique_id)) {
stream_generate_unique_id(s, &sess->fe->format_unique_id);
}
- if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
+ if (!lf_expr_isempty(&sess->fe->logformat_sd)) {
sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
&sess->fe->logformat_sd);
}
if (sess->fe->options2 & PR_O2_LOGERRORS)
level = LOG_ERR;
- if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
+ if (!lf_expr_isempty(&sess->fe->logformat_sd)) {
sd_size = sess_build_logline(sess, NULL,
logline_rfc5424, global.max_syslog_len,
&sess->fe->logformat_sd);
}
- if (!LIST_ISEMPTY(&sess->fe->logformat_error))
+ if (!lf_expr_isempty(&sess->fe->logformat_error))
size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat_error);
else
size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
list_for_each_entry_safe(srule, sruleb, srules, list) {
LIST_DELETE(&srule->list);
free_acl_cond(srule->cond);
- free_logformat_list(&srule->expr);
+ lf_expr_deinit(&srule->expr);
free(srule->file);
free(srule);
}
LIST_DELETE(&rule->list);
free_acl_cond(rule->cond);
if (rule->dynamic)
- free_logformat_list(&rule->be.expr);
+ lf_expr_deinit(&rule->be.expr);
free(rule->file);
free(rule);
}
free_logger(log);
}
- free_logformat_list(&p->logformat);
- free_logformat_list(&p->logformat_sd);
- free_logformat_list(&p->format_unique_id);
- free_logformat_list(&p->logformat_error);
+ lf_expr_deinit(&p->logformat);
+ lf_expr_deinit(&p->logformat_sd);
+ lf_expr_deinit(&p->format_unique_id);
+ lf_expr_deinit(&p->logformat_error);
free_act_rules(&p->tcp_req.inspect_rules);
free_act_rules(&p->tcp_rep.inspect_rules);
LIST_INIT(&p->tcp_req.l5_rules);
MT_LIST_INIT(&p->listener_queue);
LIST_INIT(&p->loggers);
- LIST_INIT(&p->logformat);
- LIST_INIT(&p->logformat_sd);
- LIST_INIT(&p->format_unique_id);
- LIST_INIT(&p->logformat_error);
+ lf_expr_init(&p->logformat);
+ lf_expr_init(&p->logformat_sd);
+ lf_expr_init(&p->format_unique_id);
+ lf_expr_init(&p->logformat_error);
LIST_INIT(&p->conf.bind);
LIST_INIT(&p->conf.listeners);
LIST_INIT(&p->conf.errors);
}
list_for_each_entry(srv_tlv, &srv->pp_tlvs, list) {
- LIST_INIT(&srv_tlv->fmt);
+ lf_expr_init(&srv_tlv->fmt);
if (srv_tlv->fmt_string && unlikely(!parse_logformat_string(srv_tlv->fmt_string,
srv->proxy, &srv_tlv->fmt, 0, SMP_VAL_BE_SRV_CON, &errmsg))) {
if (errmsg) {
conn->err_code = CO_ER_SSL_TIMEOUT;
}
- if(!LIST_ISEMPTY(&sess->fe->logformat_error)) {
+ if(!lf_expr_isempty(&sess->fe->logformat_error)) {
/* Display a log line following the configured error-log-format. */
sess_log(sess);
}
if (!IS_HTX_STRM(s)) { /* let's allow immediate data connection in this case */
/* if the user wants to log as soon as possible, without counting
* bytes from the server, then this is the right moment. */
- if (!LIST_ISEMPTY(&strm_fe(s)->logformat) && !(s->logs.logwait & LW_BYTES)) {
+ if (!lf_expr_isempty(&strm_fe(s)->logformat) && !(s->logs.logwait & LW_BYTES)) {
/* note: no pend_pos here, session is established */
s->logs.t_close = s->logs.t_connect; /* to get a valid end date */
s->do_log(s);
}
/* let's do a final log if we need it */
- if (!LIST_ISEMPTY(&sess->fe->logformat) && s->logs.logwait &&
+ if (!lf_expr_isempty(&sess->fe->logformat) && s->logs.logwait &&
!(s->flags & SF_MONITOR) &&
(!(sess->fe->options & PR_O_NULLNOLOG) || req->total)) {
/* we may need to know the position in the queue */
* If an ID is already stored within the stream nothing happens existing unique ID is
* returned.
*/
-struct ist stream_generate_unique_id(struct stream *strm, struct list *format)
+struct ist stream_generate_unique_id(struct stream *strm, struct lf_expr *format)
{
if (isttest(strm->unique_id)) {
return strm->unique_id;
if (!hdr)
return;
- free_logformat_list(&hdr->value);
+ lf_expr_deinit(&hdr->value);
istfree(&hdr->name);
free(hdr);
}
break;
case TCPCHK_SEND_STRING_LF:
case TCPCHK_SEND_BINARY_LF:
- free_logformat_list(&rule->send.fmt);
+ lf_expr_deinit(&rule->send.fmt);
break;
case TCPCHK_SEND_HTTP:
free(rule->send.http.meth.str.area);
if (!(rule->send.http.flags & TCPCHK_SND_HTTP_FL_URI_FMT))
istfree(&rule->send.http.uri);
else
- free_logformat_list(&rule->send.http.uri_fmt);
+ lf_expr_deinit(&rule->send.http.uri_fmt);
istfree(&rule->send.http.vsn);
free_tcpcheck_http_hdrs(&rule->send.http.hdrs);
if (!(rule->send.http.flags & TCPCHK_SND_HTTP_FL_BODY_FMT))
istfree(&rule->send.http.body);
else
- free_logformat_list(&rule->send.http.body_fmt);
+ lf_expr_deinit(&rule->send.http.body_fmt);
break;
case TCPCHK_SEND_UNDEF:
break;
}
break;
case TCPCHK_ACT_EXPECT:
- free_logformat_list(&rule->expect.onerror_fmt);
- free_logformat_list(&rule->expect.onsuccess_fmt);
+ lf_expr_deinit(&rule->expect.onerror_fmt);
+ lf_expr_deinit(&rule->expect.onsuccess_fmt);
release_sample_expr(rule->expect.status_expr);
switch (rule->expect.type) {
case TCPCHK_EXPECT_HTTP_STATUS:
case TCPCHK_EXPECT_STRING_LF:
case TCPCHK_EXPECT_BINARY_LF:
case TCPCHK_EXPECT_HTTP_BODY_LF:
- free_logformat_list(&rule->expect.fmt);
+ lf_expr_deinit(&rule->expect.fmt);
break;
case TCPCHK_EXPECT_HTTP_HEADER:
if (rule->expect.flags & TCPCHK_EXPT_FL_HTTP_HNAME_REG)
regex_free(rule->expect.hdr.name_re);
else if (rule->expect.flags & TCPCHK_EXPT_FL_HTTP_HNAME_FMT)
- free_logformat_list(&rule->expect.hdr.name_fmt);
+ lf_expr_deinit(&rule->expect.hdr.name_fmt);
else
istfree(&rule->expect.hdr.name);
if (rule->expect.flags & TCPCHK_EXPT_FL_HTTP_HVAL_REG)
regex_free(rule->expect.hdr.value_re);
else if (rule->expect.flags & TCPCHK_EXPT_FL_HTTP_HVAL_FMT)
- free_logformat_list(&rule->expect.hdr.value_fmt);
+ lf_expr_deinit(&rule->expect.hdr.value_fmt);
else if (!(rule->expect.flags & TCPCHK_EXPT_FL_HTTP_HVAL_NONE))
istfree(&rule->expect.hdr.value);
break;
chunk_istcat(msg, info);
goto comment;
}
- else if (!LIST_ISEMPTY(&rule->expect.onerror_fmt)) {
+ else if (!lf_expr_isempty(&rule->expect.onerror_fmt)) {
msg->data += sess_build_logline(check->sess, NULL, b_tail(msg), b_room(msg), &rule->expect.onerror_fmt);
goto comment;
}
*/
if (istlen(info))
chunk_istcat(msg, info);
- if (!LIST_ISEMPTY(&rule->expect.onsuccess_fmt))
+ if (!lf_expr_isempty(&rule->expect.onsuccess_fmt))
msg->data += sess_build_logline(check->sess, NULL, b_tail(msg), b_room(msg),
&rule->expect.onsuccess_fmt);
else if (check->type == PR_O2_TCPCHK_CHK &&
/* Set status and description in case of error */
status = ((status != HCHK_STATUS_UNKNOWN) ? status : HCHK_STATUS_L7STS);
- if (LIST_ISEMPTY(&expect->onerror_fmt))
+ if (lf_expr_isempty(&expect->onerror_fmt))
desc = htx_sl_res_reason(sl);
break;
case TCPCHK_EXPECT_HTTP_STATUS_REGEX:
/* Set status and description in case of error */
status = ((status != HCHK_STATUS_UNKNOWN) ? status : HCHK_STATUS_L7STS);
- if (LIST_ISEMPTY(&expect->onerror_fmt))
+ if (lf_expr_isempty(&expect->onerror_fmt))
desc = htx_sl_res_reason(sl);
break;
end_of_match:
status = ((status != HCHK_STATUS_UNKNOWN) ? status : HCHK_STATUS_L7STS);
- if (LIST_ISEMPTY(&expect->onerror_fmt))
+ if (lf_expr_isempty(&expect->onerror_fmt))
desc = htx_sl_res_reason(sl);
break;
}
goto wait_more_data;
}
status = ((status != HCHK_STATUS_UNKNOWN) ? status : HCHK_STATUS_L7RSP);
- if (LIST_ISEMPTY(&expect->onerror_fmt))
+ if (lf_expr_isempty(&expect->onerror_fmt))
desc = ist("HTTP content check could not find a response body");
TRACE_ERROR("no response boduy found while expected", CHK_EV_TCPCHK_EXP|CHK_EV_TCPCHK_ERR, check);
goto error;
/* Set status and description in case of error */
status = ((status != HCHK_STATUS_UNKNOWN) ? status : HCHK_STATUS_L7RSP);
- if (LIST_ISEMPTY(&expect->onerror_fmt))
+ if (lf_expr_isempty(&expect->onerror_fmt))
desc = (inverse
? ist("HTTP check matched unwanted content")
: ist("HTTP content check did not match"));
}
case TCPCHK_SEND_STRING_LF:
case TCPCHK_SEND_BINARY_LF:
- LIST_INIT(&chk->send.fmt);
+ lf_expr_init(&chk->send.fmt);
px->conf.args.ctx = ARGC_SRV;
if (!parse_logformat_string(data, px, &chk->send.fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
memprintf(errmsg, "'%s' invalid log-format string (%s).\n", data, *errmsg);
}
if (uri) {
if (chk->send.http.flags & TCPCHK_SND_HTTP_FL_URI_FMT) {
- LIST_INIT(&chk->send.http.uri_fmt);
+ lf_expr_init(&chk->send.http.uri_fmt);
px->conf.args.ctx = ARGC_SRV;
if (!parse_logformat_string(uri, px, &chk->send.http.uri_fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
memprintf(errmsg, "'%s' invalid log-format string (%s).\n", uri, *errmsg);
memprintf(errmsg, "out of memory");
goto error;
}
- LIST_INIT(&hdr->value);
+ lf_expr_init(&hdr->value);
hdr->name = istdup(hdrs[i].n);
if (!isttest(hdr->name)) {
memprintf(errmsg, "out of memory");
if (body) {
if (chk->send.http.flags & TCPCHK_SND_HTTP_FL_BODY_FMT) {
- LIST_INIT(&chk->send.http.body_fmt);
+ lf_expr_init(&chk->send.http.body_fmt);
px->conf.args.ctx = ARGC_SRV;
if (!parse_logformat_string(body, px, &chk->send.http.body_fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
memprintf(errmsg, "'%s' invalid log-format string (%s).\n", body, *errmsg);
goto error;
}
chk->action = TCPCHK_ACT_EXPECT;
- LIST_INIT(&chk->expect.onerror_fmt);
- LIST_INIT(&chk->expect.onsuccess_fmt);
+ lf_expr_init(&chk->expect.onerror_fmt);
+ lf_expr_init(&chk->expect.onsuccess_fmt);
chk->comment = comment; comment = NULL;
chk->expect.type = type;
chk->expect.min_recv = min_recv;
case TCPCHK_EXPECT_STRING_LF:
case TCPCHK_EXPECT_BINARY_LF:
case TCPCHK_EXPECT_HTTP_BODY_LF:
- LIST_INIT(&chk->expect.fmt);
+ lf_expr_init(&chk->expect.fmt);
px->conf.args.ctx = ARGC_SRV;
if (!parse_logformat_string(pattern, px, &chk->expect.fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
memprintf(errmsg, "'%s' invalid log-format string (%s).\n", pattern, *errmsg);
}
else if (chk->expect.flags & TCPCHK_EXPT_FL_HTTP_HNAME_FMT) {
px->conf.args.ctx = ARGC_SRV;
- LIST_INIT(&chk->expect.hdr.name_fmt);
+ lf_expr_init(&chk->expect.hdr.name_fmt);
if (!parse_logformat_string(npat, px, &chk->expect.hdr.name_fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
memprintf(errmsg, "'%s' invalid log-format string (%s).\n", npat, *errmsg);
goto error;
}
else if (chk->expect.flags & TCPCHK_EXPT_FL_HTTP_HVAL_FMT) {
px->conf.args.ctx = ARGC_SRV;
- LIST_INIT(&chk->expect.hdr.value_fmt);
+ lf_expr_init(&chk->expect.hdr.value_fmt);
if (!parse_logformat_string(vpat, px, &chk->expect.hdr.value_fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
memprintf(errmsg, "'%s' invalid log-format string (%s).\n", npat, *errmsg);
goto error;
*/
void tcpcheck_overwrite_send_http_rule(struct tcpcheck_rule *old, struct tcpcheck_rule *new)
{
- struct logformat_node *lf, *lfb;
struct tcpcheck_http_hdr *hdr, *bhdr;
if (!(old->send.http.flags & TCPCHK_SND_HTTP_FL_URI_FMT))
istfree(&old->send.http.uri);
else
- free_logformat_list(&old->send.http.uri_fmt);
+ lf_expr_deinit(&old->send.http.uri_fmt);
old->send.http.flags &= ~TCPCHK_SND_HTTP_FL_URI_FMT;
old->send.http.uri = new->send.http.uri;
new->send.http.uri = IST_NULL;
}
- else if ((new->send.http.flags & TCPCHK_SND_HTTP_FL_URI_FMT) && !LIST_ISEMPTY(&new->send.http.uri_fmt)) {
+ else if ((new->send.http.flags & TCPCHK_SND_HTTP_FL_URI_FMT) && !lf_expr_isempty(&new->send.http.uri_fmt)) {
if (!(old->send.http.flags & TCPCHK_SND_HTTP_FL_URI_FMT))
istfree(&old->send.http.uri);
else
- free_logformat_list(&old->send.http.uri_fmt);
+ lf_expr_deinit(&old->send.http.uri_fmt);
old->send.http.flags |= TCPCHK_SND_HTTP_FL_URI_FMT;
- LIST_INIT(&old->send.http.uri_fmt);
- list_for_each_entry_safe(lf, lfb, &new->send.http.uri_fmt, list) {
- LIST_DELETE(&lf->list);
- LIST_APPEND(&old->send.http.uri_fmt, &lf->list);
- }
+ lf_expr_init(&old->send.http.uri_fmt);
+ lf_expr_xfer(&new->send.http.uri_fmt, &old->send.http.uri_fmt);
}
if (isttest(new->send.http.vsn)) {
if (!(old->send.http.flags & TCPCHK_SND_HTTP_FL_BODY_FMT))
istfree(&old->send.http.body);
else
- free_logformat_list(&old->send.http.body_fmt);
+ lf_expr_deinit(&old->send.http.body_fmt);
old->send.http.flags &= ~TCPCHK_SND_HTTP_FL_BODY_FMT;
old->send.http.body = new->send.http.body;
new->send.http.body = IST_NULL;
}
- else if ((new->send.http.flags & TCPCHK_SND_HTTP_FL_BODY_FMT) && !LIST_ISEMPTY(&new->send.http.body_fmt)) {
+ else if ((new->send.http.flags & TCPCHK_SND_HTTP_FL_BODY_FMT) && !lf_expr_isempty(&new->send.http.body_fmt)) {
if (!(old->send.http.flags & TCPCHK_SND_HTTP_FL_BODY_FMT))
istfree(&old->send.http.body);
else
- free_logformat_list(&old->send.http.body_fmt);
+ lf_expr_deinit(&old->send.http.body_fmt);
old->send.http.flags |= TCPCHK_SND_HTTP_FL_BODY_FMT;
- LIST_INIT(&old->send.http.body_fmt);
- list_for_each_entry_safe(lf, lfb, &new->send.http.body_fmt, list) {
- LIST_DELETE(&lf->list);
- LIST_APPEND(&old->send.http.body_fmt, &lf->list);
- }
+ lf_expr_init(&old->send.http.body_fmt);
+ lf_expr_xfer(&new->send.http.body_fmt, &old->send.http.body_fmt);
}
}
expect = &tcpcheck->expect;
expect->type = TCPCHK_EXPECT_STRING;
- LIST_INIT(&expect->onerror_fmt);
- LIST_INIT(&expect->onsuccess_fmt);
+ lf_expr_init(&expect->onerror_fmt);
+ lf_expr_init(&expect->onsuccess_fmt);
expect->ok_status = HCHK_STATUS_L7OKD;
expect->err_status = HCHK_STATUS_L7RSP;
expect->tout_status = HCHK_STATUS_L7TOUT;
/* Process the expression. */
memset(&smp, 0, sizeof(smp));
- if (!LIST_ISEMPTY(&rule->arg.vars.fmt)) {
+ if (!lf_expr_isempty(&rule->arg.vars.fmt)) {
/* a format-string is used */
fmtstr = alloc_trash_chunk();
static void release_store_rule(struct act_rule *rule)
{
- free_logformat_list(&rule->arg.vars.fmt);
+ lf_expr_deinit(&rule->arg.vars.fmt);
release_sample_expr(rule->arg.vars.expr);
}
condition = istsplit(&var, ',');
}
- LIST_INIT(&rule->arg.vars.fmt);
+ lf_expr_init(&rule->arg.vars.fmt);
if (!vars_hash_name(var_name, var_len, &rule->arg.vars.scope, &rule->arg.vars.name_hash, err))
return ACT_RET_PRS_ERR;