us_ltime(format[,offset]) integer string
us_utime(format[,offset]) integer string
utime(format[,offset]) integer string
+when(condition) any same
word(index,delimiters[,count]) string string
wt6([avalanche]) binary integer
x509_v_err_str integer string
# e.g. 20140710162350 127.0.0.1:57325
log-format %[date,utime(%Y%m%d%H%M%S)]\ %ci:%cp
+when(<condition>)
+ 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:
+
+ - "error" returns true when an error was encountered during the processing
+ of the request or stream. It uses the same rules as "dontlog-normal"
+ (e.g. a successful redispatch counts as an error).
+
+ - "forwarded" returns true when the request was forwarded to a backend
+ server
+
+ - "normal" returns true when no error happened (this is equivalent to
+ "!error").
+
+ - "processed" returns true when the request was either forwarded to a
+ backend server, or processed by an applet.
+
+ - "stopping" returns true if the process is currently stopping when the
+ rule is evaluated
+
+ - "toapplet" returns true when the request was processed by an applet.
+
+ 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.
+
+ An example would be to add backend stream debugging information in the logs
+ only when an error was encountered during processing, or logging extra
+ information when stopping, etc.
+
+ Example:
+ # log "dbg={-}" when fine, or "dbg={... debug info ...}" on error:
+ log-format "$HAPROXY_HTTP_LOG_FMT dbg={%[bs.debug_str,when(!normal)]}"
+
+ Here, the "dbg" field in the log will only contain an dash ('-') to
+ indicate a missing content when the rule is not validated, and will emit a
+ whole debugging block when it is.
+
+ Example
+ # only emit the backend src/port when a real connection was issued:
+ log-format "$HAPROXY_HTTP_LOG_FMT \
+ src=[%[bc_src,when(forwarded)]:%[bc_src_port,when(forwarded)]]"
+
+ Since it kills the evaluation of the expression when it is not true, it is
+ also possible to use it to stop a subsequent converter from being called.
+ This may for example be used to call the debug() converter only upon error,
+ to log an element only when absolutely necessary.
+
+ Example:
+ # emit the whole response headers list to stderr only on error and only
+ # when the output is a connection. We abuse a dummy variable here.
+ http-after-response set-var(res.test) \
+ res.hdrs,when(error),when(forwarded),debug(hdrs,stderr)
+
+ See also: debug converter
+
word(<index>,<delimiters>[,<count>])
Extracts the nth word counting from the beginning (positive index) or from
the end (negative index) considering given delimiters from an input string.
#include <haproxy/global.h>
#include <haproxy/hash.h>
#include <haproxy/http.h>
+#include <haproxy/http_ana-t.h>
#include <haproxy/istbuf.h>
#include <haproxy/mqtt.h>
#include <haproxy/net_helper.h>
#include <haproxy/proxy.h>
#include <haproxy/regex.h>
#include <haproxy/sample.h>
+#include <haproxy/sc_strm.h>
#include <haproxy/sink.h>
#include <haproxy/stick_table.h>
#include <haproxy/time.h>
return 1;
}
+enum {
+ WHEN_COND_STOPPING,
+ WHEN_COND_NORMAL,
+ WHEN_COND_ERROR,
+ WHEN_COND_FORWARDED,
+ WHEN_COND_TOAPPLET,
+ WHEN_COND_PROCESSED,
+ WHEN_COND_CONDITIONS
+};
+
+const char *when_cond_kw[WHEN_COND_CONDITIONS] = {
+ [WHEN_COND_STOPPING] = "stopping",
+ [WHEN_COND_NORMAL] = "normal",
+ [WHEN_COND_ERROR] = "error",
+ [WHEN_COND_FORWARDED] = "forwarded",
+ [WHEN_COND_TOAPPLET] = "toapplet",
+ [WHEN_COND_PROCESSED] = "processed",
+};
+
+/* Evaluates a condition and decides whether or not to pass the input sample
+ * to the output. The purpose is to hide some info when certain conditions are
+ * (not) met. These conditions belong to a fixed list that can verify internal
+ * states (debug mode, too high load, reloading, server down, stream in error
+ * etc). The condition's sign is placed in arg_p[0].data.int. 0=direct, 1=inv.
+ * The condition keyword is in arg_p[1].data.int (WHEN_COND_*).
+ */
+static int sample_conv_when(const struct arg *arg_p, struct sample *smp, void *private)
+{
+ struct session *sess = smp->sess;
+ struct stream *strm = smp->strm;
+ int neg = arg_p[0].data.sint;
+ int cond = arg_p[1].data.sint;
+ int ret = 0;
+
+ switch (cond) {
+ case WHEN_COND_STOPPING:
+ ret = !!stopping;
+ break;
+
+ case WHEN_COND_NORMAL:
+ neg = !neg;
+ __fallthrough;
+
+ case WHEN_COND_ERROR:
+ if (strm &&
+ ((strm->flags & SF_REDISP) ||
+ ((strm->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
+ (((strm->flags & SF_ERR_MASK) == SF_ERR_NONE) && strm->conn_retries) ||
+ ((sess->fe->mode == PR_MODE_HTTP) && strm->txn && strm->txn->status >= 500)))
+ ret = 1;
+ break;
+
+ case WHEN_COND_FORWARDED: // true if forwarded to a connection
+ ret = !!sc_conn(smp->strm->scb);
+ break;
+
+ case WHEN_COND_TOAPPLET: // true if handled as an applet
+ ret = !!sc_appctx(smp->strm->scb);
+ break;
+
+ case WHEN_COND_PROCESSED: // true if forwarded or appctx
+ ret = sc_conn(smp->strm->scb) || sc_appctx(smp->strm->scb);
+ break;
+ }
+
+ ret = !!ret ^ !!neg;
+ if (!ret) {
+ /* kill the sample */
+ return 0;
+ }
+
+ /* pass the sample as-is */
+ return 1;
+}
+
+/* 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.
+ */
+static int check_when_cond(struct arg *args, struct sample_conv *conv,
+ const char *file, int line, char **err)
+{
+ const char *kw;
+ int neg = 0;
+ int i;
+
+ kw = args[0].data.str.area;
+ if (*kw == '!') {
+ kw++;
+ neg = 1;
+ }
+
+ for (i = 0; i < WHEN_COND_CONDITIONS; i++) {
+ if (strcmp(kw, when_cond_kw[i]) == 0)
+ break;
+ }
+
+ if (i == WHEN_COND_CONDITIONS) {
+ memprintf(err, "expects a supported keyword among {");
+ for (i = 0; i < WHEN_COND_CONDITIONS; i++)
+ memprintf(err, "%s%s%s", *err, when_cond_kw[i], (i == WHEN_COND_CONDITIONS - 1) ? "}" : ",");
+ memprintf(err, "%s but got '%s'", *err, kw);
+ return 0;
+ }
+
+ chunk_destroy(&args[0].data.str);
+ // store condition
+ args[0].type = ARGT_SINT;
+ args[0].data.sint = neg; // '!' present
+
+ // and keyword
+ args[1].type = ARGT_SINT;
+ args[1].data.sint = i;
+ return 1;
+}
+
#define GRPC_MSG_COMPRESS_FLAG_SZ 1 /* 1 byte */
#define GRPC_MSG_LENGTH_SZ 4 /* 4 bytes */
#define GRPC_MSG_HEADER_SZ (GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ)
{ "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 },
{ NULL, NULL, 0, 0, 0 },
}};