mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 15:17:01 +02:00
MINOR: log: explicit typecasting for logformat nodes
Add the ability to manually specify desired output type after a custom field name for logformat nodes. Forcing the type can be useful to ensure value is stored with the proper type representation. (i.e.: forcing numerical to string to work around the limited resolution of JS number types) By default, type is set to SMP_T_SAME, which means the original type will be preserved. Currently supported types are: bool, str, sint
This commit is contained in:
parent
0cfcc64b79
commit
1448478d62
@ -201,6 +201,7 @@ enum {
|
|||||||
LF_VAR, // variable name, after '%' or '%{..}'
|
LF_VAR, // variable name, after '%' or '%{..}'
|
||||||
LF_STARTVAR, // % in text
|
LF_STARTVAR, // % in text
|
||||||
LF_STONAME, // after '%(' and before ')'
|
LF_STONAME, // after '%(' and before ')'
|
||||||
|
LF_STOTYPE, // after ':' while in STONAME
|
||||||
LF_EDONAME, // ')' after '%('
|
LF_EDONAME, // ')' after '%('
|
||||||
LF_STARG, // after '%{' and berore '}'
|
LF_STARG, // after '%{' and berore '}'
|
||||||
LF_EDARG, // '}' after '%{'
|
LF_EDARG, // '}' after '%{'
|
||||||
@ -214,6 +215,7 @@ struct logformat_node {
|
|||||||
struct list list;
|
struct list list;
|
||||||
int type; // LOG_FMT_*
|
int type; // LOG_FMT_*
|
||||||
int options; // LOG_OPT_*
|
int options; // LOG_OPT_*
|
||||||
|
int typecast; // explicit typecasting for printing purposes (SMP_T_{SAME,BOOL,STR,SINT})
|
||||||
char *name; // printable name for output types that require named fields (ie: json)
|
char *name; // printable name for output types that require named fields (ie: json)
|
||||||
char *arg; // text for LOG_FMT_TEXT, arg for others
|
char *arg; // text for LOG_FMT_TEXT, arg for others
|
||||||
void *expr; // for use with LOG_FMT_EXPR
|
void *expr; // for use with LOG_FMT_EXPR
|
||||||
|
36
src/log.c
36
src/log.c
@ -306,7 +306,7 @@ int parse_logformat_var_args(char *args, struct logformat_node *node, char **err
|
|||||||
* ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
|
* ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
|
||||||
* Returns false in error case and err is filled, otherwise returns true.
|
* Returns false in error case and err is filled, otherwise returns true.
|
||||||
*/
|
*/
|
||||||
int parse_logformat_var(char *arg, int arg_len, char *name, int name_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
|
int parse_logformat_var(char *arg, int arg_len, char *name, int name_len, int typecast, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
struct logformat_node *node = NULL;
|
struct logformat_node *node = NULL;
|
||||||
@ -321,6 +321,7 @@ int parse_logformat_var(char *arg, int arg_len, char *name, int name_len, char *
|
|||||||
goto error_free;
|
goto error_free;
|
||||||
}
|
}
|
||||||
node->type = logformat_keywords[j].type;
|
node->type = logformat_keywords[j].type;
|
||||||
|
node->typecast = typecast;
|
||||||
if (name)
|
if (name)
|
||||||
node->name = my_strndup(name, name_len);
|
node->name = my_strndup(name, name_len);
|
||||||
node->options = *defoptions;
|
node->options = *defoptions;
|
||||||
@ -412,7 +413,7 @@ int add_to_logformat_list(char *start, char *end, int type, struct list *list_fo
|
|||||||
*
|
*
|
||||||
* In error case, the function returns 0, otherwise it returns 1.
|
* In error case, the function returns 0, otherwise it returns 1.
|
||||||
*/
|
*/
|
||||||
int add_sample_to_logformat_list(char *text, char *name, int name_len, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err, char **endptr)
|
int add_sample_to_logformat_list(char *text, char *name, int name_len, int typecast, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err, char **endptr)
|
||||||
{
|
{
|
||||||
char *cmd[2];
|
char *cmd[2];
|
||||||
struct sample_expr *expr = NULL;
|
struct sample_expr *expr = NULL;
|
||||||
@ -438,6 +439,7 @@ int add_sample_to_logformat_list(char *text, char *name, int name_len, char *arg
|
|||||||
if (name)
|
if (name)
|
||||||
node->name = my_strndup(name, name_len);
|
node->name = my_strndup(name, name_len);
|
||||||
node->type = LOG_FMT_EXPR;
|
node->type = LOG_FMT_EXPR;
|
||||||
|
node->typecast = typecast;
|
||||||
node->expr = expr;
|
node->expr = expr;
|
||||||
node->options = options;
|
node->options = options;
|
||||||
|
|
||||||
@ -506,9 +508,11 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
|
|||||||
char *arg = NULL; /* start pointer for args */
|
char *arg = NULL; /* start pointer for args */
|
||||||
char *var = NULL; /* start pointer for vars */
|
char *var = NULL; /* start pointer for vars */
|
||||||
char *name = NULL; /* token name (optional) */
|
char *name = NULL; /* token name (optional) */
|
||||||
|
char *typecast_str = NULL; /* token output type (if custom name is set) */
|
||||||
int arg_len = 0;
|
int arg_len = 0;
|
||||||
int var_len = 0;
|
int var_len = 0;
|
||||||
int name_len = 0;
|
int name_len = 0;
|
||||||
|
int typecast = SMP_T_SAME; /* relaxed by default */
|
||||||
int cformat; /* current token format */
|
int cformat; /* current token format */
|
||||||
int pformat; /* previous token format */
|
int pformat; /* previous token format */
|
||||||
struct logformat_node *tmplf, *back;
|
struct logformat_node *tmplf, *back;
|
||||||
@ -544,6 +548,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
|
|||||||
arg = NULL; var = NULL;
|
arg = NULL; var = NULL;
|
||||||
name = NULL;
|
name = NULL;
|
||||||
name_len = 0;
|
name_len = 0;
|
||||||
|
typecast = SMP_T_SAME;
|
||||||
arg_len = var_len = 0;
|
arg_len = var_len = 0;
|
||||||
if (*str == '(') { // custom output name
|
if (*str == '(') { // custom output name
|
||||||
cformat = LF_STONAME;
|
cformat = LF_STONAME;
|
||||||
@ -554,9 +559,26 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case LF_STONAME: // text immediately following '%('
|
case LF_STONAME: // text immediately following '%('
|
||||||
if (*str == ')') { // end of custom output name
|
case LF_STOTYPE:
|
||||||
|
if (cformat == LF_STONAME && *str == ':') { // start custom output type
|
||||||
|
cformat = LF_STOTYPE;
|
||||||
|
name_len = str -name;
|
||||||
|
typecast_str = str + 1;
|
||||||
|
}
|
||||||
|
else if (*str == ')') { // end of custom output name
|
||||||
|
if (cformat == LF_STONAME)
|
||||||
|
name_len = str - name;
|
||||||
|
else {
|
||||||
|
/* custom type */
|
||||||
|
*str = 0; // so that typecast_str is 0 terminated
|
||||||
|
typecast = type_to_smp(typecast_str);
|
||||||
|
if (typecast != SMP_T_STR && typecast != SMP_T_SINT &&
|
||||||
|
typecast != SMP_T_BOOL) {
|
||||||
|
memprintf(err, "unexpected output type '%.*s' at position %d line : '%s'. Supported types are: str, sint, bool", (int)(str - typecast_str), typecast_str, (int)(typecast_str - backfmt), fmt);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
cformat = LF_EDONAME;
|
cformat = LF_EDONAME;
|
||||||
name_len = str - name;
|
|
||||||
} else if (!isalnum((unsigned char)*str) && *str != '_' && *str != '-') {
|
} else if (!isalnum((unsigned char)*str) && *str != '_' && *str != '-') {
|
||||||
memprintf(err, "invalid character in custom name near '%c' at position %d line : '%s'",
|
memprintf(err, "invalid character in custom name near '%c' at position %d line : '%s'",
|
||||||
*str, (int)(str - backfmt), fmt);
|
*str, (int)(str - backfmt), fmt);
|
||||||
@ -623,7 +645,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
|
|||||||
* part of the expression, which MUST be the trailing
|
* part of the expression, which MUST be the trailing
|
||||||
* angle bracket.
|
* angle bracket.
|
||||||
*/
|
*/
|
||||||
if (!add_sample_to_logformat_list(var, name, name_len, arg, arg_len, curproxy, list_format, options, cap, err, &str))
|
if (!add_sample_to_logformat_list(var, name, name_len, typecast, arg, arg_len, curproxy, list_format, options, cap, err, &str))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (*str == ']') {
|
if (*str == ']') {
|
||||||
@ -669,7 +691,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
|
|||||||
if (cformat != pformat || pformat == LF_SEPARATOR) {
|
if (cformat != pformat || pformat == LF_SEPARATOR) {
|
||||||
switch (pformat) {
|
switch (pformat) {
|
||||||
case LF_VAR:
|
case LF_VAR:
|
||||||
if (!parse_logformat_var(arg, arg_len, name, name_len, var, var_len, curproxy, list_format, &options, err))
|
if (!parse_logformat_var(arg, arg_len, name, name_len, typecast, var, var_len, curproxy, list_format, &options, err))
|
||||||
goto fail;
|
goto fail;
|
||||||
break;
|
break;
|
||||||
case LF_TEXT:
|
case LF_TEXT:
|
||||||
@ -682,7 +704,7 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR || pformat == LF_STONAME || pformat == LF_EDONAME) {
|
if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR || pformat == LF_STONAME || pformat == LF_STOTYPE || pformat == LF_EDONAME) {
|
||||||
memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
|
memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user