mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 15:17:01 +02:00
MINOR: log: add +cbor encoding option
In this patch, we make use of the CBOR (RFC8949) encode helper functions from the previous commit to implement '+cbor' encoding option for log- formats. The logic behind it is pretty similar to '+json' encoding option, except that the produced output is a CBOR payload written in HEX format so that it remains compatible to use this with regular syslog endpoints. Example: log-format "%{+cbor}o %[int(4)] test %(named_field)[str(ok)]" Will produce: BF6B6E616D65645F6669656C64626F6BFF Detailed view (from cbor.me): BF # map(*) 6B # text(11) 6E616D65645F6669656C64 # "named_field" 62 # text(2) 6F6B # "ok" FF # primitive(*) If the option isn't set globally, but on a specific node instead, then only the value will be encoded according to CBOR specification. Example: log-format "test cbor bool: %{+cbor}[bool(true)]" Will produce: test cbor bool: F5
This commit is contained in:
parent
810303e3e6
commit
c614fd3b9f
@ -25752,6 +25752,13 @@ Flags are :
|
|||||||
Incomplete numerical values (e.g.: '%B' when logasap is used),
|
Incomplete numerical values (e.g.: '%B' when logasap is used),
|
||||||
which are normally prefixed with '+' without encoding, will be
|
which are normally prefixed with '+' without encoding, will be
|
||||||
encoded as-is. Also, '+E' option will be ignored.
|
encoded as-is. Also, '+E' option will be ignored.
|
||||||
|
* cbor: automatically encode value in CBOR format
|
||||||
|
(when set globally, only named format variables are considered)
|
||||||
|
By default, cbor encoded data is represented in HEX form so
|
||||||
|
that it remains printable on stdout an can be used with usual
|
||||||
|
syslog endpoints.
|
||||||
|
As with json encoding, incomplete numerical values will be encoded
|
||||||
|
as-is and '+E' option will be ignored.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -25761,6 +25768,7 @@ Flags are :
|
|||||||
log-format-sd %{+Q,+E}o\ [exampleSDID@1234\ header=%[capture.req.hdr(0)]]
|
log-format-sd %{+Q,+E}o\ [exampleSDID@1234\ header=%[capture.req.hdr(0)]]
|
||||||
|
|
||||||
log-format "%{+json}o %(request)r %(custom_expr)[str(custom)]"
|
log-format "%{+json}o %(request)r %(custom_expr)[str(custom)]"
|
||||||
|
log-format "%{+cbor}o %(request)r %(custom_expr)[str(custom)]"
|
||||||
|
|
||||||
Please refer to the table below for currently defined variables :
|
Please refer to the table below for currently defined variables :
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
#define LOG_OPT_BIN 0x00000100
|
#define LOG_OPT_BIN 0x00000100
|
||||||
/* unused: 0x00000200 ... 0x00000800 */
|
/* unused: 0x00000200 ... 0x00000800 */
|
||||||
#define LOG_OPT_ENCODE_JSON 0x00001000
|
#define LOG_OPT_ENCODE_JSON 0x00001000
|
||||||
/* unused encode: 0x00002000 */
|
#define LOG_OPT_ENCODE_CBOR 0x00002000
|
||||||
#define LOG_OPT_ENCODE 0x00003000
|
#define LOG_OPT_ENCODE 0x00003000
|
||||||
|
|
||||||
|
|
||||||
|
329
src/log.c
329
src/log.c
@ -330,6 +330,7 @@ struct logformat_tag_args tag_args_list[] = {
|
|||||||
{ "E", LOG_OPT_ESC },
|
{ "E", LOG_OPT_ESC },
|
||||||
{ "bin", LOG_OPT_BIN },
|
{ "bin", LOG_OPT_BIN },
|
||||||
{ "json", LOG_OPT_ENCODE_JSON },
|
{ "json", LOG_OPT_ENCODE_JSON },
|
||||||
|
{ "cbor", LOG_OPT_ENCODE_CBOR },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1743,8 +1744,41 @@ struct lf_buildctx {
|
|||||||
int options; /* LOG_OPT_* options */
|
int options; /* LOG_OPT_* options */
|
||||||
int typecast;/* same as logformat_node->typecast */
|
int typecast;/* same as logformat_node->typecast */
|
||||||
int in_text; /* inside variable-length text */
|
int in_text; /* inside variable-length text */
|
||||||
|
union {
|
||||||
|
struct cbor_encode_ctx cbor; /* cbor-encode specific ctx */
|
||||||
|
} encode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* helper to encode a single byte in hex form
|
||||||
|
*
|
||||||
|
* Returns the position of the last written byte on success and NULL on
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
static char *_encode_byte_hex(char *start, char *stop, unsigned char byte)
|
||||||
|
{
|
||||||
|
/* hex form requires 2 bytes */
|
||||||
|
if ((stop - start) < 2)
|
||||||
|
return NULL;
|
||||||
|
*start++ = hextab[(byte >> 4) & 15];
|
||||||
|
*start++ = hextab[byte & 15];
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lf cbor function ptr used to encode a single byte according to RFC8949
|
||||||
|
*
|
||||||
|
* for now only hex form is supported.
|
||||||
|
*
|
||||||
|
* Returns the position of the last written byte on success and NULL on
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
static char *_lf_cbor_encode_byte(struct cbor_encode_ctx *cbor_ctx,
|
||||||
|
char *start, char *stop, unsigned char byte)
|
||||||
|
{
|
||||||
|
__maybe_unused struct lf_buildctx *ctx = cbor_ctx->e_byte_fct_ctx;
|
||||||
|
|
||||||
|
return _encode_byte_hex(start, stop, byte);
|
||||||
|
}
|
||||||
|
|
||||||
/* helper function to prepare lf_buildctx struct based on global options
|
/* helper function to prepare lf_buildctx struct based on global options
|
||||||
* and current node settings (may be NULL)
|
* and current node settings (may be NULL)
|
||||||
*/
|
*/
|
||||||
@ -1778,9 +1812,16 @@ static inline void lf_buildctx_prepare(struct lf_buildctx *ctx,
|
|||||||
if (ctx->options & LOG_OPT_HTTP)
|
if (ctx->options & LOG_OPT_HTTP)
|
||||||
ctx->options &= ~LOG_OPT_ENCODE;
|
ctx->options &= ~LOG_OPT_ENCODE;
|
||||||
|
|
||||||
/* when encoding is set, ignore +E option */
|
if (ctx->options & LOG_OPT_ENCODE) {
|
||||||
if (ctx->options & LOG_OPT_ENCODE)
|
/* when encoding is set, ignore +E option */
|
||||||
ctx->options &= ~LOG_OPT_ESC;
|
ctx->options &= ~LOG_OPT_ESC;
|
||||||
|
|
||||||
|
if (ctx->options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
/* prepare cbor-specific encode ctx */
|
||||||
|
ctx->encode.cbor.e_byte_fct = _lf_cbor_encode_byte;
|
||||||
|
ctx->encode.cbor.e_byte_fct_ctx = ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* helper function for _lf_encode_bytes() to escape a single byte
|
/* helper function for _lf_encode_bytes() to escape a single byte
|
||||||
@ -1798,6 +1839,27 @@ static inline char *_lf_escape_byte(char *start, char *stop,
|
|||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* helper function for _lf_encode_bytes() to escape a single byte
|
||||||
|
* with <escape> and deal with cbor-specific encoding logic
|
||||||
|
*/
|
||||||
|
static inline char *_lf_cbor_escape_byte(char *start, char *stop,
|
||||||
|
char byte, const char escape,
|
||||||
|
uint8_t cbor_string_prefix,
|
||||||
|
struct lf_buildctx *ctx)
|
||||||
|
{
|
||||||
|
char escaped_byte[3];
|
||||||
|
|
||||||
|
escaped_byte[0] = escape;
|
||||||
|
escaped_byte[1] = hextab[(byte >> 4) & 15];
|
||||||
|
escaped_byte[2] = hextab[byte & 15];
|
||||||
|
|
||||||
|
start = cbor_encode_bytes_prefix(&ctx->encode.cbor, start, stop,
|
||||||
|
escaped_byte, 3,
|
||||||
|
cbor_string_prefix);
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
/* helper function for _lf_encode_bytes() to encode a single byte
|
/* helper function for _lf_encode_bytes() to encode a single byte
|
||||||
* and escape it with <escape> if found in <map>
|
* and escape it with <escape> if found in <map>
|
||||||
*
|
*
|
||||||
@ -1809,6 +1871,7 @@ static inline char *_lf_escape_byte(char *start, char *stop,
|
|||||||
static inline char *_lf_map_escape_byte(char *start, char *stop,
|
static inline char *_lf_map_escape_byte(char *start, char *stop,
|
||||||
const char *byte,
|
const char *byte,
|
||||||
const char escape, const long *map,
|
const char escape, const long *map,
|
||||||
|
const char **pending, uint8_t cbor_string_prefix,
|
||||||
struct lf_buildctx *ctx)
|
struct lf_buildctx *ctx)
|
||||||
{
|
{
|
||||||
if (!ha_bit_test((unsigned char)(*byte), map))
|
if (!ha_bit_test((unsigned char)(*byte), map))
|
||||||
@ -1819,6 +1882,50 @@ static inline char *_lf_map_escape_byte(char *start, char *stop,
|
|||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* helper function for _lf_encode_bytes() to encode a single byte
|
||||||
|
* and escape it with <escape> if found in <map> and deal with
|
||||||
|
* cbor-specific encoding logic.
|
||||||
|
*
|
||||||
|
* The function assumes that at least 1 byte is available for writing
|
||||||
|
*
|
||||||
|
* Returns the address of the last written byte on success, or NULL
|
||||||
|
* on error
|
||||||
|
*/
|
||||||
|
static inline char *_lf_cbor_map_escape_byte(char *start, char *stop,
|
||||||
|
const char *byte,
|
||||||
|
const char escape, const long *map,
|
||||||
|
const char **pending, uint8_t cbor_string_prefix,
|
||||||
|
struct lf_buildctx *ctx)
|
||||||
|
{
|
||||||
|
/* We try our best to minimize the number of chunks produced for the
|
||||||
|
* indefinite-length byte string as each chunk has an extra overhead
|
||||||
|
* as per RFC8949.
|
||||||
|
*
|
||||||
|
* To achieve that, we try to emit consecutive bytes together
|
||||||
|
*/
|
||||||
|
if (!ha_bit_test((unsigned char)(*byte), map)) {
|
||||||
|
/* do nothing and let the caller continue seeking data,
|
||||||
|
* pending data will be flushed later
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
/* first, flush pending unescaped bytes */
|
||||||
|
start = cbor_encode_bytes_prefix(&ctx->encode.cbor, start, stop,
|
||||||
|
*pending, (byte - *pending),
|
||||||
|
cbor_string_prefix);
|
||||||
|
if (start == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*pending = byte + 1;
|
||||||
|
|
||||||
|
/* escape current matching byte */
|
||||||
|
start = _lf_cbor_escape_byte(start, stop, *byte, escape,
|
||||||
|
cbor_string_prefix,
|
||||||
|
ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
/* helper function for _lf_encode_bytes() to encode a single byte
|
/* helper function for _lf_encode_bytes() to encode a single byte
|
||||||
* and escape it with <escape> if found in <map> or escape it with
|
* and escape it with <escape> if found in <map> or escape it with
|
||||||
* '\' if found in rfc5424_escape_map
|
* '\' if found in rfc5424_escape_map
|
||||||
@ -1831,6 +1938,7 @@ static inline char *_lf_map_escape_byte(char *start, char *stop,
|
|||||||
static inline char *_lf_rfc5424_escape_byte(char *start, char *stop,
|
static inline char *_lf_rfc5424_escape_byte(char *start, char *stop,
|
||||||
const char *byte,
|
const char *byte,
|
||||||
const char escape, const long *map,
|
const char escape, const long *map,
|
||||||
|
const char **pending, uint8_t cbor_string_prefix,
|
||||||
struct lf_buildctx *ctx)
|
struct lf_buildctx *ctx)
|
||||||
{
|
{
|
||||||
if (!ha_bit_test((unsigned char)(*byte), map)) {
|
if (!ha_bit_test((unsigned char)(*byte), map)) {
|
||||||
@ -1861,6 +1969,7 @@ static inline char *_lf_rfc5424_escape_byte(char *start, char *stop,
|
|||||||
static inline char *_lf_json_escape_byte(char *start, char *stop,
|
static inline char *_lf_json_escape_byte(char *start, char *stop,
|
||||||
const char *byte,
|
const char *byte,
|
||||||
const char escape, const long *map,
|
const char escape, const long *map,
|
||||||
|
const char **pending, uint8_t cbor_string_prefix,
|
||||||
struct lf_buildctx *ctx)
|
struct lf_buildctx *ctx)
|
||||||
{
|
{
|
||||||
if (!ha_bit_test((unsigned char)(*byte), map)) {
|
if (!ha_bit_test((unsigned char)(*byte), map)) {
|
||||||
@ -1892,6 +2001,9 @@ static inline char *_lf_json_escape_byte(char *start, char *stop,
|
|||||||
* When using json encoding, string will be escaped according to
|
* When using json encoding, string will be escaped according to
|
||||||
* json escape map
|
* json escape map
|
||||||
*
|
*
|
||||||
|
* When using cbor encoding, escape option is ignored. However bytes found
|
||||||
|
* in <map> will still be escaped with <escape>.
|
||||||
|
*
|
||||||
* Return the address of the \0 character, or NULL on error
|
* Return the address of the \0 character, or NULL on error
|
||||||
*/
|
*/
|
||||||
static char *_lf_encode_bytes(char *start, char *stop,
|
static char *_lf_encode_bytes(char *start, char *stop,
|
||||||
@ -1900,27 +2012,54 @@ static char *_lf_encode_bytes(char *start, char *stop,
|
|||||||
struct lf_buildctx *ctx)
|
struct lf_buildctx *ctx)
|
||||||
{
|
{
|
||||||
char *ret;
|
char *ret;
|
||||||
|
const char *pending;
|
||||||
|
uint8_t cbor_string_prefix = 0;
|
||||||
char *(*encode_byte)(char *start, char *stop,
|
char *(*encode_byte)(char *start, char *stop,
|
||||||
const char *byte,
|
const char *byte,
|
||||||
const char escape, const long *map,
|
const char escape, const long *map,
|
||||||
|
const char **pending, uint8_t cbor_string_prefix,
|
||||||
struct lf_buildctx *ctx);
|
struct lf_buildctx *ctx);
|
||||||
|
|
||||||
if (ctx->options & LOG_OPT_ENCODE_JSON)
|
if (ctx->options & LOG_OPT_ENCODE_JSON)
|
||||||
encode_byte = _lf_json_escape_byte;
|
encode_byte = _lf_json_escape_byte;
|
||||||
|
else if (ctx->options & LOG_OPT_ENCODE_CBOR)
|
||||||
|
encode_byte = _lf_cbor_map_escape_byte;
|
||||||
else if (ctx->options & LOG_OPT_ESC)
|
else if (ctx->options & LOG_OPT_ESC)
|
||||||
encode_byte = _lf_rfc5424_escape_byte;
|
encode_byte = _lf_rfc5424_escape_byte;
|
||||||
else
|
else
|
||||||
encode_byte = _lf_map_escape_byte;
|
encode_byte = _lf_map_escape_byte;
|
||||||
|
|
||||||
|
if (ctx->options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
if (!bytes_stop) {
|
||||||
|
/* printable chars: use cbor text */
|
||||||
|
cbor_string_prefix = 0x60;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* non printable chars: use cbor byte string */
|
||||||
|
cbor_string_prefix = 0x40;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (start < stop) {
|
if (start < stop) {
|
||||||
stop--; /* reserve one byte for the final '\0' */
|
stop--; /* reserve one byte for the final '\0' */
|
||||||
|
|
||||||
|
if ((ctx->options & LOG_OPT_ENCODE_CBOR) && !ctx->in_text) {
|
||||||
|
/* start indefinite-length cbor byte string or text */
|
||||||
|
start = _lf_cbor_encode_byte(&ctx->encode.cbor, start, stop,
|
||||||
|
(cbor_string_prefix | 0x1F));
|
||||||
|
if (start == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pending = bytes;
|
||||||
|
|
||||||
/* we have 2 distinct loops to keep checks outside of the loop
|
/* we have 2 distinct loops to keep checks outside of the loop
|
||||||
* for better performance
|
* for better performance
|
||||||
*/
|
*/
|
||||||
if (bytes && !bytes_stop) {
|
if (bytes && !bytes_stop) {
|
||||||
while (start < stop && *bytes != '\0') {
|
while (start < stop && *bytes != '\0') {
|
||||||
ret = encode_byte(start, stop, bytes, escape, map, ctx);
|
ret = encode_byte(start, stop, bytes, escape, map,
|
||||||
|
&pending, cbor_string_prefix,
|
||||||
|
ctx);
|
||||||
if (ret == NULL)
|
if (ret == NULL)
|
||||||
break;
|
break;
|
||||||
start = ret;
|
start = ret;
|
||||||
@ -1928,13 +2067,33 @@ static char *_lf_encode_bytes(char *start, char *stop,
|
|||||||
}
|
}
|
||||||
} else if (bytes) {
|
} else if (bytes) {
|
||||||
while (start < stop && bytes < bytes_stop) {
|
while (start < stop && bytes < bytes_stop) {
|
||||||
ret = encode_byte(start, stop, bytes, escape, map, ctx);
|
ret = encode_byte(start, stop, bytes, escape, map,
|
||||||
|
&pending, cbor_string_prefix,
|
||||||
|
ctx);
|
||||||
if (ret == NULL)
|
if (ret == NULL)
|
||||||
break;
|
break;
|
||||||
start = ret;
|
start = ret;
|
||||||
bytes++;
|
bytes++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
if (pending != bytes) {
|
||||||
|
/* flush pending unescaped bytes */
|
||||||
|
start = cbor_encode_bytes_prefix(&ctx->encode.cbor, start, stop,
|
||||||
|
pending, (bytes - pending),
|
||||||
|
cbor_string_prefix);
|
||||||
|
if (start == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!ctx->in_text) {
|
||||||
|
/* cbor break (to end indefinite-length text or byte string) */
|
||||||
|
start = _lf_cbor_encode_byte(&ctx->encode.cbor, start, stop, 0xFF);
|
||||||
|
if (start == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*start = '\0';
|
*start = '\0';
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
@ -1974,12 +2133,15 @@ static char *lf_encode_chunk(char *start, char *stop,
|
|||||||
* When using json encoding, string will be escaped according
|
* When using json encoding, string will be escaped according
|
||||||
* to json escape map
|
* to json escape map
|
||||||
*
|
*
|
||||||
|
* When using cbor encoding, escape option is ignored.
|
||||||
|
*
|
||||||
* Return the address of the \0 character, or NULL on error
|
* Return the address of the \0 character, or NULL on error
|
||||||
*/
|
*/
|
||||||
static inline char *_lf_text_len(char *dst, const char *src,
|
static inline char *_lf_text_len(char *dst, const char *src,
|
||||||
size_t len, size_t size, struct lf_buildctx *ctx)
|
size_t len, size_t size, struct lf_buildctx *ctx)
|
||||||
{
|
{
|
||||||
const long *escape_map = NULL;
|
const long *escape_map = NULL;
|
||||||
|
char *ret;
|
||||||
|
|
||||||
if (ctx->options & LOG_OPT_ENCODE_JSON)
|
if (ctx->options & LOG_OPT_ENCODE_JSON)
|
||||||
escape_map = json_escape_map;
|
escape_map = json_escape_map;
|
||||||
@ -1987,10 +2149,24 @@ static inline char *_lf_text_len(char *dst, const char *src,
|
|||||||
escape_map = rfc5424_escape_map;
|
escape_map = rfc5424_escape_map;
|
||||||
|
|
||||||
if (src && len) {
|
if (src && len) {
|
||||||
|
if (ctx->options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
/* it's actually less costly to compute the actual text size to
|
||||||
|
* write a single fixed length text at once rather than emitting
|
||||||
|
* indefinite length text in cbor, because indefinite-length text
|
||||||
|
* has to be made of multiple chunks of known size as per RFC8949...
|
||||||
|
*/
|
||||||
|
len = strnlen(src, len);
|
||||||
|
|
||||||
|
ret = cbor_encode_text(&ctx->encode.cbor, dst, dst + size, src, len);
|
||||||
|
if (ret == NULL)
|
||||||
|
return NULL;
|
||||||
|
len = ret - dst;
|
||||||
|
}
|
||||||
|
|
||||||
/* escape_string and strlcpy2 will both try to add terminating NULL-byte
|
/* escape_string and strlcpy2 will both try to add terminating NULL-byte
|
||||||
* to dst
|
* to dst
|
||||||
*/
|
*/
|
||||||
if (escape_map) {
|
else if (escape_map) {
|
||||||
char *ret;
|
char *ret;
|
||||||
|
|
||||||
ret = escape_string(dst, dst + size, '\\', escape_map, src, src + len);
|
ret = escape_string(dst, dst + size, '\\', escape_map, src, src + len);
|
||||||
@ -2056,7 +2232,8 @@ static char *lf_text_len(char *dst, const char *src, size_t len, size_t size, st
|
|||||||
{
|
{
|
||||||
if ((ctx->options & (LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON)))
|
if ((ctx->options & (LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON)))
|
||||||
return _lf_quotetext_len(dst, src, len, size, ctx);
|
return _lf_quotetext_len(dst, src, len, size, ctx);
|
||||||
else if (src && len)
|
else if ((ctx->options & LOG_OPT_ENCODE_CBOR) ||
|
||||||
|
(src && len))
|
||||||
return _lf_text_len(dst, src, len, size, ctx);
|
return _lf_text_len(dst, src, len, size, ctx);
|
||||||
|
|
||||||
if (size < 2)
|
if (size < 2)
|
||||||
@ -2169,6 +2346,11 @@ static char *lf_bool_encode(char *dst, size_t size, uint8_t value,
|
|||||||
ret += iret;
|
ret += iret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
if (ctx->options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
if (value)
|
||||||
|
return _lf_cbor_encode_byte(&ctx->encode.cbor, dst, dst + size, 0xF5);
|
||||||
|
return _lf_cbor_encode_byte(&ctx->encode.cbor, dst, dst + size, 0xF4);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL; /* not supported */
|
return NULL; /* not supported */
|
||||||
}
|
}
|
||||||
@ -2206,6 +2388,12 @@ static char *lf_int_encode(char *dst, size_t size, int64_t value,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
else if (ctx->options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
/* Always print as a regular int64 number (STR typecast isn't
|
||||||
|
* supported)
|
||||||
|
*/
|
||||||
|
return cbor_encode_int64(&ctx->encode.cbor, dst, dst + size, value);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL; /* not supported */
|
return NULL; /* not supported */
|
||||||
}
|
}
|
||||||
@ -2921,30 +3109,63 @@ const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found a
|
|||||||
Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
|
Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
|
||||||
Set-cookie Updated, unknown, unknown */
|
Set-cookie Updated, unknown, unknown */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try to write a cbor byte if there is enough space, or goto out
|
||||||
|
*/
|
||||||
|
#define LOG_CBOR_BYTE(x) do { \
|
||||||
|
ret = _lf_cbor_encode_byte(&ctx.encode.cbor, \
|
||||||
|
tmplog, \
|
||||||
|
dst + maxsize, \
|
||||||
|
(x)); \
|
||||||
|
if (ret == NULL) \
|
||||||
|
goto out; \
|
||||||
|
tmplog = ret; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* try to write a character if there is enough space, or goto out
|
* try to write a character if there is enough space, or goto out
|
||||||
*/
|
*/
|
||||||
#define LOGCHAR(x) do { \
|
#define LOGCHAR(x) do { \
|
||||||
if (tmplog < dst + maxsize - 1) { \
|
if ((ctx.options & LOG_OPT_ENCODE_CBOR) && \
|
||||||
*(tmplog++) = (x); \
|
ctx.in_text) { \
|
||||||
} else { \
|
char _x[1]; \
|
||||||
goto out; \
|
/* encode the char as text chunk since we \
|
||||||
} \
|
* cannot just throw random bytes and expect \
|
||||||
|
* cbor decoder to know how to handle them \
|
||||||
|
*/ \
|
||||||
|
_x[0] = (x); \
|
||||||
|
ret = cbor_encode_text(&ctx.encode.cbor, \
|
||||||
|
tmplog, \
|
||||||
|
dst + maxsize, \
|
||||||
|
_x, sizeof(_x)); \
|
||||||
|
tmplog = ret; \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
if (tmplog < dst + maxsize - 1) { \
|
||||||
|
*(tmplog++) = (x); \
|
||||||
|
} else { \
|
||||||
|
goto out; \
|
||||||
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/* indicate that a new variable-length text is starting, sets in_text
|
/* indicate that a new variable-length text is starting, sets in_text
|
||||||
* variable to indicate that a var text was started and deals with
|
* variable to indicate that a var text was started and deals with
|
||||||
* encoding and options to know if some special treatment is needed.
|
* encoding and options to know if some special treatment is needed.
|
||||||
*/
|
*/
|
||||||
#define LOG_VARTEXT_START() do { \
|
#define LOG_VARTEXT_START() do { \
|
||||||
ctx.in_text = 1; \
|
ctx.in_text = 1; \
|
||||||
/* put the text within quotes if JSON encoding \
|
if (ctx.options & LOG_OPT_ENCODE_CBOR) { \
|
||||||
* is used or quoting is enabled \
|
/* start indefinite-length cbor text */ \
|
||||||
*/ \
|
LOG_CBOR_BYTE(0x7F); \
|
||||||
if (ctx.options & \
|
break; \
|
||||||
(LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON)) { \
|
} \
|
||||||
LOGCHAR('"'); \
|
/* put the text within quotes if JSON encoding \
|
||||||
} \
|
* is used or quoting is enabled \
|
||||||
|
*/ \
|
||||||
|
if (ctx.options & \
|
||||||
|
(LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON)) { \
|
||||||
|
LOGCHAR('"'); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* properly finish a variable text that was started using LOG_VARTEXT_START
|
/* properly finish a variable text that was started using LOG_VARTEXT_START
|
||||||
@ -2952,17 +3173,22 @@ const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found a
|
|||||||
* deals with encoding and options to know if some special treatment is
|
* deals with encoding and options to know if some special treatment is
|
||||||
* needed.
|
* needed.
|
||||||
*/
|
*/
|
||||||
#define LOG_VARTEXT_END() do { \
|
#define LOG_VARTEXT_END() do { \
|
||||||
if (!ctx.in_text) \
|
if (!ctx.in_text) \
|
||||||
break; \
|
break; \
|
||||||
ctx.in_text = 0; \
|
ctx.in_text = 0; \
|
||||||
/* add the ending quote if JSON encoding is \
|
if (ctx.options & LOG_OPT_ENCODE_CBOR) { \
|
||||||
* used or quoting is enabled \
|
/* end indefinite-length cbor text with break*/\
|
||||||
*/ \
|
LOG_CBOR_BYTE(0xFF); \
|
||||||
if (ctx.options & \
|
break; \
|
||||||
(LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON)) { \
|
} \
|
||||||
LOGCHAR('"'); \
|
/* add the ending quote if JSON encoding is \
|
||||||
} \
|
* used or quoting is enabled \
|
||||||
|
*/ \
|
||||||
|
if (ctx.options & \
|
||||||
|
(LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON)) { \
|
||||||
|
LOGCHAR('"'); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Prints additional logvalue hint represented by <chr>.
|
/* Prints additional logvalue hint represented by <chr>.
|
||||||
@ -2980,10 +3206,16 @@ const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found a
|
|||||||
#define LOG_STRARRAY_START() do { \
|
#define LOG_STRARRAY_START() do { \
|
||||||
if (ctx.options & LOG_OPT_ENCODE_JSON) \
|
if (ctx.options & LOG_OPT_ENCODE_JSON) \
|
||||||
LOGCHAR('['); \
|
LOGCHAR('['); \
|
||||||
|
if (ctx.options & LOG_OPT_ENCODE_CBOR) { \
|
||||||
|
/* start indefinite-length array */ \
|
||||||
|
LOG_CBOR_BYTE(0x9F); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* indicate that a new element is added to the string array */
|
/* indicate that a new element is added to the string array */
|
||||||
#define LOG_STRARRAY_NEXT() do { \
|
#define LOG_STRARRAY_NEXT() do { \
|
||||||
|
if (ctx.options & LOG_OPT_ENCODE_CBOR) \
|
||||||
|
break; \
|
||||||
if (ctx.options & LOG_OPT_ENCODE_JSON) { \
|
if (ctx.options & LOG_OPT_ENCODE_JSON) { \
|
||||||
LOGCHAR(','); \
|
LOGCHAR(','); \
|
||||||
LOGCHAR(' '); \
|
LOGCHAR(' '); \
|
||||||
@ -2996,6 +3228,10 @@ const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found a
|
|||||||
#define LOG_STRARRAY_END() do { \
|
#define LOG_STRARRAY_END() do { \
|
||||||
if (ctx.options & LOG_OPT_ENCODE_JSON) \
|
if (ctx.options & LOG_OPT_ENCODE_JSON) \
|
||||||
LOGCHAR(']'); \
|
LOGCHAR(']'); \
|
||||||
|
if (ctx.options & LOG_OPT_ENCODE_CBOR) { \
|
||||||
|
/* cbor break */ \
|
||||||
|
LOG_CBOR_BYTE(0xFF); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Initializes some log data at boot */
|
/* Initializes some log data at boot */
|
||||||
@ -3359,6 +3595,10 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
|
|||||||
|
|
||||||
if (ctx.options & LOG_OPT_ENCODE_JSON)
|
if (ctx.options & LOG_OPT_ENCODE_JSON)
|
||||||
LOGCHAR('{');
|
LOGCHAR('{');
|
||||||
|
else if (ctx.options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
/* start indefinite-length map */
|
||||||
|
LOG_CBOR_BYTE(0xBF);
|
||||||
|
}
|
||||||
|
|
||||||
list_for_each_entry(tmp, list_format, list) {
|
list_for_each_entry(tmp, list_format, list) {
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
@ -3400,6 +3640,14 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
|
|||||||
LOGCHAR(':');
|
LOGCHAR(':');
|
||||||
LOGCHAR(' ');
|
LOGCHAR(' ');
|
||||||
}
|
}
|
||||||
|
else if (ctx.options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
ret = cbor_encode_text(&ctx.encode.cbor, tmplog,
|
||||||
|
dst + maxsize, tmp->name,
|
||||||
|
strlen(tmp->name));
|
||||||
|
if (ret == NULL)
|
||||||
|
goto out;
|
||||||
|
tmplog = ret;
|
||||||
|
}
|
||||||
|
|
||||||
first_node = 0;
|
first_node = 0;
|
||||||
}
|
}
|
||||||
@ -3455,6 +3703,10 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
|
|||||||
/* if encoding is set, try to preserve output type
|
/* if encoding is set, try to preserve output type
|
||||||
* with respect to typecast settings
|
* with respect to typecast settings
|
||||||
* (ie: str, sint, bool)
|
* (ie: str, sint, bool)
|
||||||
|
*
|
||||||
|
* Special case for cbor encoding: we also try to
|
||||||
|
* preserve bin output type since cbor encoders
|
||||||
|
* know how to deal with binary data.
|
||||||
*/
|
*/
|
||||||
if (ctx.options & LOG_OPT_ENCODE) {
|
if (ctx.options & LOG_OPT_ENCODE) {
|
||||||
if (ctx.typecast == SMP_T_STR ||
|
if (ctx.typecast == SMP_T_STR ||
|
||||||
@ -3465,7 +3717,9 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
|
|||||||
}
|
}
|
||||||
else if (key &&
|
else if (key &&
|
||||||
(key->data.type == SMP_T_SINT ||
|
(key->data.type == SMP_T_SINT ||
|
||||||
key->data.type == SMP_T_BOOL)) {
|
key->data.type == SMP_T_BOOL ||
|
||||||
|
((ctx.options & LOG_OPT_ENCODE_CBOR) &&
|
||||||
|
key->data.type == SMP_T_BIN))) {
|
||||||
/* preserve type */
|
/* preserve type */
|
||||||
type = key->data.type;
|
type = key->data.type;
|
||||||
}
|
}
|
||||||
@ -4474,6 +4728,13 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
|
|||||||
goto out;
|
goto out;
|
||||||
tmplog += iret;
|
tmplog += iret;
|
||||||
}
|
}
|
||||||
|
if (ctx.options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
/* for CBOR, we have the '22' primitive which is known as
|
||||||
|
* NULL
|
||||||
|
*/
|
||||||
|
LOG_CBOR_BYTE(0xF6);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if variable text was started for the current node data, we need
|
/* if variable text was started for the current node data, we need
|
||||||
@ -4489,6 +4750,10 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
|
|||||||
|
|
||||||
if (ctx.options & LOG_OPT_ENCODE_JSON)
|
if (ctx.options & LOG_OPT_ENCODE_JSON)
|
||||||
LOGCHAR('}');
|
LOGCHAR('}');
|
||||||
|
else if (ctx.options & LOG_OPT_ENCODE_CBOR) {
|
||||||
|
/* end indefinite-length map */
|
||||||
|
LOG_CBOR_BYTE(0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
/* *tmplog is a unused character */
|
/* *tmplog is a unused character */
|
||||||
|
Loading…
Reference in New Issue
Block a user