diff --git a/doc/configuration.txt b/doc/configuration.txt index 6733e650b..596cfb5da 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -25739,6 +25739,14 @@ Flags are : * X: hexadecimal representation (IPs, Ports, %Ts, %rt, %pid) * E: escape characters '"', '\' and ']' in a string with '\' as prefix (intended purpose is for the RFC5424 structured-data log formats) + * bin: try to preserve binary data, this can be useful with sample + expressions that output binary data in order to preserve the original + data. Be careful however, because it can obviously generate non- + printable chars, including NULL-byte, which most syslog endpoints + don't expect. Thus it is mainly intended for use with set-var-fmt, + rings and binary-capable log endpoints. + This option can only be set globally (with %o), it will be ignored + if set on an individual node's options. Example: diff --git a/include/haproxy/log-t.h b/include/haproxy/log-t.h index 657454213..de6edab23 100644 --- a/include/haproxy/log-t.h +++ b/include/haproxy/log-t.h @@ -47,6 +47,7 @@ #define LOG_OPT_HTTP 0x00000020 #define LOG_OPT_ESC 0x00000040 #define LOG_OPT_MERGE_SPACES 0x00000080 +#define LOG_OPT_BIN 0x00000100 /* Fields that need to be extracted from the incoming connection or request for diff --git a/src/log.c b/src/log.c index 491304692..742d4a801 100644 --- a/src/log.c +++ b/src/log.c @@ -327,6 +327,7 @@ struct logformat_tag_args tag_args_list[] = { { "Q", LOG_OPT_QUOTE }, { "X", LOG_OPT_HEXA }, { "E", LOG_OPT_ESC }, + { "bin", LOG_OPT_BIN }, { 0, 0 } }; @@ -1748,8 +1749,10 @@ static inline void lf_buildctx_prepare(struct lf_buildctx *ctx, if (node) { /* per-node options are only considered if not already set * globally + * + * Also, ignore LOG_OPT_BIN since it is a global-only option */ - ctx->options |= node->options; + ctx->options |= (node->options & ~LOG_OPT_BIN); /* consider node's typecast setting */ ctx->typecast = node->typecast; @@ -3237,18 +3240,35 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t type = SMP_T_STR; // default + if (key && key->data.type == SMP_T_BIN && + (ctx.options & LOG_OPT_BIN)) { + /* output type is binary, and binary option is set: + * preserve output type unless typecast is set to + * force output type to string + */ + if (ctx.typecast != SMP_T_STR) + type = SMP_T_BIN; + } + if (key && !sample_convert(key, type)) key = NULL; if (ctx.options & LOG_OPT_HTTP) ret = lf_encode_chunk(tmplog, dst + maxsize, '%', http_encode_map, key ? &key->data.u.str : &empty, &ctx); - else - ret = lf_text_len(tmplog, - key ? key->data.u.str.area : NULL, - key ? key->data.u.str.data : 0, - dst + maxsize - tmplog, - &ctx); + else { + if (key && type == SMP_T_BIN) + ret = lf_encode_chunk(tmplog, dst + maxsize, + 0, no_escape_map, + &key->data.u.str, + &ctx); + else + ret = lf_text_len(tmplog, + key ? key->data.u.str.area : NULL, + key ? key->data.u.str.data : 0, + dst + maxsize - tmplog, + &ctx); + } if (ret == NULL) goto out; tmplog = ret;