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),
|
||||
which are normally prefixed with '+' without encoding, will be
|
||||
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:
|
||||
|
||||
@ -25761,6 +25768,7 @@ Flags are :
|
||||
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 "%{+cbor}o %(request)r %(custom_expr)[str(custom)]"
|
||||
|
||||
Please refer to the table below for currently defined variables :
|
||||
|
||||
|
@ -50,7 +50,7 @@
|
||||
#define LOG_OPT_BIN 0x00000100
|
||||
/* unused: 0x00000200 ... 0x00000800 */
|
||||
#define LOG_OPT_ENCODE_JSON 0x00001000
|
||||
/* unused encode: 0x00002000 */
|
||||
#define LOG_OPT_ENCODE_CBOR 0x00002000
|
||||
#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 },
|
||||
{ "bin", LOG_OPT_BIN },
|
||||
{ "json", LOG_OPT_ENCODE_JSON },
|
||||
{ "cbor", LOG_OPT_ENCODE_CBOR },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@ -1743,8 +1744,41 @@ struct lf_buildctx {
|
||||
int options; /* LOG_OPT_* options */
|
||||
int typecast;/* same as logformat_node->typecast */
|
||||
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
|
||||
* 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)
|
||||
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;
|
||||
|
||||
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
|
||||
@ -1798,6 +1839,27 @@ static inline char *_lf_escape_byte(char *start, char *stop,
|
||||
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
|
||||
* 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,
|
||||
const char *byte,
|
||||
const char escape, const long *map,
|
||||
const char **pending, uint8_t cbor_string_prefix,
|
||||
struct lf_buildctx *ctx)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* and escape it with <escape> if found in <map> or escape it with
|
||||
* '\' 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,
|
||||
const char *byte,
|
||||
const char escape, const long *map,
|
||||
const char **pending, uint8_t cbor_string_prefix,
|
||||
struct lf_buildctx *ctx)
|
||||
{
|
||||
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,
|
||||
const char *byte,
|
||||
const char escape, const long *map,
|
||||
const char **pending, uint8_t cbor_string_prefix,
|
||||
struct lf_buildctx *ctx)
|
||||
{
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
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)
|
||||
{
|
||||
char *ret;
|
||||
const char *pending;
|
||||
uint8_t cbor_string_prefix = 0;
|
||||
char *(*encode_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);
|
||||
|
||||
if (ctx->options & LOG_OPT_ENCODE_JSON)
|
||||
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)
|
||||
encode_byte = _lf_rfc5424_escape_byte;
|
||||
else
|
||||
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) {
|
||||
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
|
||||
* for better performance
|
||||
*/
|
||||
if (bytes && !bytes_stop) {
|
||||
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)
|
||||
break;
|
||||
start = ret;
|
||||
@ -1928,13 +2067,33 @@ static char *_lf_encode_bytes(char *start, char *stop,
|
||||
}
|
||||
} else if (bytes) {
|
||||
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)
|
||||
break;
|
||||
start = ret;
|
||||
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';
|
||||
return start;
|
||||
}
|
||||
@ -1974,12 +2133,15 @@ static char *lf_encode_chunk(char *start, char *stop,
|
||||
* When using json encoding, string will be escaped according
|
||||
* to json escape map
|
||||
*
|
||||
* When using cbor encoding, escape option is ignored.
|
||||
*
|
||||
* Return the address of the \0 character, or NULL on error
|
||||
*/
|
||||
static inline char *_lf_text_len(char *dst, const char *src,
|
||||
size_t len, size_t size, struct lf_buildctx *ctx)
|
||||
{
|
||||
const long *escape_map = NULL;
|
||||
char *ret;
|
||||
|
||||
if (ctx->options & LOG_OPT_ENCODE_JSON)
|
||||
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;
|
||||
|
||||
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
|
||||
* to dst
|
||||
*/
|
||||
if (escape_map) {
|
||||
else if (escape_map) {
|
||||
char *ret;
|
||||
|
||||
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)))
|
||||
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);
|
||||
|
||||
if (size < 2)
|
||||
@ -2169,6 +2346,11 @@ static char *lf_bool_encode(char *dst, size_t size, uint8_t value,
|
||||
ret += iret;
|
||||
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 */
|
||||
}
|
||||
@ -2206,6 +2388,12 @@ static char *lf_int_encode(char *dst, size_t size, int64_t value,
|
||||
|
||||
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 */
|
||||
}
|
||||
@ -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 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
|
||||
*/
|
||||
#define LOGCHAR(x) do { \
|
||||
if (tmplog < dst + maxsize - 1) { \
|
||||
*(tmplog++) = (x); \
|
||||
} else { \
|
||||
goto out; \
|
||||
} \
|
||||
if ((ctx.options & LOG_OPT_ENCODE_CBOR) && \
|
||||
ctx.in_text) { \
|
||||
char _x[1]; \
|
||||
/* 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)
|
||||
|
||||
/* indicate that a new variable-length text is starting, sets in_text
|
||||
* variable to indicate that a var text was started and deals with
|
||||
* encoding and options to know if some special treatment is needed.
|
||||
*/
|
||||
#define LOG_VARTEXT_START() do { \
|
||||
ctx.in_text = 1; \
|
||||
/* 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('"'); \
|
||||
} \
|
||||
#define LOG_VARTEXT_START() do { \
|
||||
ctx.in_text = 1; \
|
||||
if (ctx.options & LOG_OPT_ENCODE_CBOR) { \
|
||||
/* start indefinite-length cbor text */ \
|
||||
LOG_CBOR_BYTE(0x7F); \
|
||||
break; \
|
||||
} \
|
||||
/* 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)
|
||||
|
||||
/* 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
|
||||
* needed.
|
||||
*/
|
||||
#define LOG_VARTEXT_END() do { \
|
||||
if (!ctx.in_text) \
|
||||
break; \
|
||||
ctx.in_text = 0; \
|
||||
/* add the ending quote if JSON encoding is \
|
||||
* used or quoting is enabled \
|
||||
*/ \
|
||||
if (ctx.options & \
|
||||
(LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON)) { \
|
||||
LOGCHAR('"'); \
|
||||
} \
|
||||
#define LOG_VARTEXT_END() do { \
|
||||
if (!ctx.in_text) \
|
||||
break; \
|
||||
ctx.in_text = 0; \
|
||||
if (ctx.options & LOG_OPT_ENCODE_CBOR) { \
|
||||
/* end indefinite-length cbor text with break*/\
|
||||
LOG_CBOR_BYTE(0xFF); \
|
||||
break; \
|
||||
} \
|
||||
/* 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)
|
||||
|
||||
/* 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 { \
|
||||
if (ctx.options & LOG_OPT_ENCODE_JSON) \
|
||||
LOGCHAR('['); \
|
||||
if (ctx.options & LOG_OPT_ENCODE_CBOR) { \
|
||||
/* start indefinite-length array */ \
|
||||
LOG_CBOR_BYTE(0x9F); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* indicate that a new element is added to the string array */
|
||||
#define LOG_STRARRAY_NEXT() do { \
|
||||
if (ctx.options & LOG_OPT_ENCODE_CBOR) \
|
||||
break; \
|
||||
if (ctx.options & LOG_OPT_ENCODE_JSON) { \
|
||||
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 { \
|
||||
if (ctx.options & LOG_OPT_ENCODE_JSON) \
|
||||
LOGCHAR(']'); \
|
||||
if (ctx.options & LOG_OPT_ENCODE_CBOR) { \
|
||||
/* cbor break */ \
|
||||
LOG_CBOR_BYTE(0xFF); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* 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)
|
||||
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) {
|
||||
#ifdef USE_OPENSSL
|
||||
@ -3400,6 +3640,14 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
|
||||
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;
|
||||
}
|
||||
@ -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
|
||||
* with respect to typecast settings
|
||||
* (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.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 &&
|
||||
(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 */
|
||||
type = key->data.type;
|
||||
}
|
||||
@ -4474,6 +4728,13 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
|
||||
goto out;
|
||||
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
|
||||
@ -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)
|
||||
LOGCHAR('}');
|
||||
else if (ctx.options & LOG_OPT_ENCODE_CBOR) {
|
||||
/* end indefinite-length map */
|
||||
LOG_CBOR_BYTE(0xFF);
|
||||
}
|
||||
|
||||
out:
|
||||
/* *tmplog is a unused character */
|
||||
|
Loading…
Reference in New Issue
Block a user