# e.g. 20140710162350 127.0.0.1:57325
log-format %[date,utime(%Y%m%d%H%M%S)]\ %ci:%cp
-when(<condition>)
+when(<condition>[,<args>...])
Evaluates the condition and when true, passes the input sample as-is to the
output, otherwise return nothing. This is designed specifically to produce
some rarely needed data that should only be emitted under certain conditions,
such as debugging information when an error is met.
The condition is made of a keyword among the list below, optionally preceeded
- by an exclamation mark ('!') to negate it:
+ by an exclamation mark ('!') to negate it, and optionally suffixed by some
+ arguments specific to that condition:
- "error" returns true when an error was encountered during the processing
of the request or stream. It uses the same rules as "dontlog-normal"
- "toapplet" returns true when the request was processed by an applet.
+ - "acl" returns true when the ACL designated by the next argument evaluates
+ to true. Note that the ACL is evaluated inline by the converter, so that
+ what it refers to must be valid in that context. A particular use case
+ consists in evaluating if the total transfer time is too long or not
+ before deciding to log detauls from abnormally long transfers.
+
Note that the content is evaluated in any case, so doing this does not avoid
the generation of that information. It's only meant to avoid producing that
information.
indicate a missing content when the rule is not validated, and will emit a
whole debugging block when it is.
+ Example
+ # log "dbg={-}" when fine, or "dbg={... debug info ...}" on slow transfers
+ acl slow_xfer res.timer.data ge 10000 # more than 10s is slow
+ log-format "$HAPROXY_HTTP_LOG_FMT \
+ fsdbg={%[fs.debug_str,when(acl,slow_xfer)]} \
+ bsdbg={%[bs.debug_str,when(acl,slow_xfer)]}"
+
Example
# only emit the backend src/port when a real connection was issued:
log-format "$HAPROXY_HTTP_LOG_FMT \
#include <import/mjson.h>
#include <import/sha1.h>
+#include <haproxy/acl.h>
#include <haproxy/api.h>
#include <haproxy/arg.h>
#include <haproxy/auth.h>
#include <haproxy/base64.h>
#include <haproxy/buf.h>
+#include <haproxy/cfgparse.h>
#include <haproxy/chunk.h>
#include <haproxy/clock.h>
#include <haproxy/errors.h>
WHEN_COND_FORWARDED,
WHEN_COND_TOAPPLET,
WHEN_COND_PROCESSED,
+ WHEN_COND_ACL,
WHEN_COND_CONDITIONS
};
[WHEN_COND_FORWARDED] = "forwarded",
[WHEN_COND_TOAPPLET] = "toapplet",
[WHEN_COND_PROCESSED] = "processed",
+ [WHEN_COND_ACL] = "acl",
};
/* Evaluates a condition and decides whether or not to pass the input sample
struct stream *strm = smp->strm;
int neg = arg_p[0].data.sint;
int cond = arg_p[1].data.sint;
+ struct acl_sample *acl_sample;
int ret = 0;
switch (cond) {
case WHEN_COND_PROCESSED: // true if forwarded or appctx
ret = sc_conn(smp->strm->scb) || sc_appctx(smp->strm->scb);
break;
+
+ case WHEN_COND_ACL: // true if the ACL pointed to by args[2] evaluates to true
+ acl_sample = arg_p[2].data.ptr;
+ ret = acl_exec_cond(&acl_sample->cond, smp->px, smp->sess, smp->strm, smp->opt) == ACL_TEST_PASS;
+ break;
}
ret = !!ret ^ !!neg;
/* checks and resolves the type of the argument passed to when().
* It supports an optional '!' to negate the condition, followed by
- * a keyword among the list above.
+ * a keyword among the list above. Note that we're purposely declaring
+ * one extra arg because the first one will be split into two.
*/
static int check_when_cond(struct arg *args, struct sample_conv *conv,
const char *file, int line, char **err)
{
+ struct acl_sample *acl_sample;
const char *kw;
int neg = 0;
int i;
return 0;
}
+ if (i == WHEN_COND_ACL) {
+ if (args[1].type != ARGT_STR || !*args[1].data.str.area) {
+ memprintf(err, "'acl' selector requires an extra argument with the ACL name");
+ return 0;
+ }
+
+ if (!curproxy) {
+ memprintf(err, "'acl' selector may only be used in the context of a proxy");
+ return 0;
+ }
+
+ acl_sample = calloc(1, sizeof(struct acl_sample) + sizeof(struct acl_term));
+ if (!acl_sample) {
+ memprintf(err, "not enough memory for 'acl' selector");
+ return 0;
+ }
+
+ LIST_INIT(&acl_sample->suite.terms);
+ LIST_INIT(&acl_sample->cond.suites);
+ LIST_APPEND(&acl_sample->cond.suites, &acl_sample->suite.list);
+ LIST_APPEND(&acl_sample->suite.terms, &acl_sample->terms[0].list);
+ acl_sample->cond.val = ~0U; // the keyword is valid everywhere for now.
+
+ /* build one term based on the ACL kw */
+ if (!(acl_sample->terms[0].acl = find_acl_by_name(args[1].data.str.area, &curproxy->acl)) &&
+ !(acl_sample->terms[0].acl = find_acl_default(args[1].data.str.area, &curproxy->acl, err, NULL, NULL, 0))) {
+ memprintf(err, "ACL '%s' not found", args[1].data.str.area);
+ return 0;
+ }
+
+ acl_sample->cond.use |= acl_sample->terms[0].acl->use;
+ acl_sample->cond.val &= acl_sample->terms[0].acl->val;
+
+ args[2].type = ARGT_PTR;
+ args[2].unresolved = 0;
+ args[2].resolve_ptr = NULL;
+ args[2].data.ptr = acl_sample;
+ }
+
chunk_destroy(&args[0].data.str);
+ if (args[1].type == ARGT_STR)
+ chunk_destroy(&args[1].data.str);
+
+ if (args[2].type == ARGT_STR)
+ chunk_destroy(&args[2].data.str);
+
// store condition
args[0].type = ARGT_SINT;
args[0].data.sint = neg; // '!' present
{ "jwt_payload_query", sample_conv_jwt_payload_query, ARG2(0,STR,STR), sample_conv_jwt_query_check, SMP_T_BIN, SMP_T_ANY },
{ "jwt_verify", sample_conv_jwt_verify, ARG2(2,STR,STR), sample_conv_jwt_verify_check, SMP_T_BIN, SMP_T_SINT },
#endif
- { "when", sample_conv_when, ARG1(1,STR), check_when_cond, SMP_T_ANY, SMP_T_ANY },
+ { "when", sample_conv_when, ARG3(1,STR,STR,STR), check_when_cond, SMP_T_ANY, SMP_T_ANY },
{ NULL, NULL, 0, 0, 0 },
}};