mirror of
https://github.com/haproxy/haproxy.git
synced 2026-04-13 21:06:13 -04:00
MINOR: otel: added log-format support to the sample parser and runtime
Extended flt_otel_parse_cfg_sample() to accept log-format strings in addition to bare sample expressions. Added lf_expr and lf_used fields to flt_otel_conf_sample. Extended flt_otel_sample_add() to evaluate log-format expressions when lf_used was set.
This commit is contained in:
parent
40ac0fd932
commit
bc6402f609
4 changed files with 103 additions and 51 deletions
|
|
@ -37,9 +37,9 @@
|
|||
OTELC_DBG(DEBUG, h "%p:{ '%s' %p }", (p), (p)->fmt_expr, (p)->expr)
|
||||
|
||||
#define FLT_OTEL_DBG_CONF_SAMPLE(h,p) \
|
||||
OTELC_DBG(DEBUG, h "%p:{ '%s' '%s' %s %s %d }", (p), \
|
||||
OTELC_DBG(DEBUG, h "%p:{ '%s' '%s' %s %s %d %p %hhu }", (p), \
|
||||
(p)->key, (p)->fmt_string, otelc_value_dump(&((p)->extra), ""), \
|
||||
flt_otel_list_dump(&((p)->exprs)), (p)->num_exprs)
|
||||
flt_otel_list_dump(&((p)->exprs)), (p)->num_exprs, &((p)->lf_expr), (p)->lf_used)
|
||||
|
||||
#define FLT_OTEL_DBG_CONF_HDR(h,p,i) \
|
||||
OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "}", (p), FLT_OTEL_CONF_HDR_ARGS(p, i))
|
||||
|
|
@ -118,6 +118,8 @@ struct flt_otel_conf_sample {
|
|||
struct otelc_value extra; /* Optional supplementary data. */
|
||||
struct list exprs; /* Used to chain sample expressions. */
|
||||
int num_exprs; /* Number of defined expressions. */
|
||||
struct lf_expr lf_expr; /* The log-format expression. */
|
||||
bool lf_used; /* Whether lf_expr is used instead of exprs. */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ FLT_OTEL_CONF_FUNC_FREE(sample_expr, fmt_expr,
|
|||
*/
|
||||
FLT_OTEL_CONF_FUNC_INIT(sample, key,
|
||||
LIST_INIT(&(retptr->exprs));
|
||||
lf_expr_init(&(retptr->lf_expr));
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -327,6 +328,7 @@ FLT_OTEL_CONF_FUNC_FREE(sample, key,
|
|||
if ((*ptr)->extra.u_type == OTELC_VALUE_DATA)
|
||||
OTELC_SFREE((*ptr)->extra.u.value_data);
|
||||
FLT_OTEL_LIST_DESTROY(sample_expr, &((*ptr)->exprs));
|
||||
lf_expr_deinit(&((*ptr)->lf_expr));
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -317,10 +317,21 @@ static int flt_otel_parse_cfg_sample_expr(const char *file, int line, char **arg
|
|||
* err - indirect pointer to error message string
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Parses a complete sample definition starting at index <idx> in <args>.
|
||||
* Creates a conf_sample structure with optional <extra> data (event name or
|
||||
* status code), then parses sample expressions. When <n> is 0, all remaining
|
||||
* arguments are parsed; otherwise at most <n> expressions are parsed.
|
||||
* Parses a complete sample definition starting at index <idx> in the
|
||||
* <args> array. A new conf_sample structure is allocated and initialized
|
||||
* via flt_otel_conf_sample_init_ex() with the optional <extra> data (an
|
||||
* event name or a status code), then the sample expressions are parsed.
|
||||
*
|
||||
* When <args>[<idx>] contains the "%[" sequence, the argument is parsed
|
||||
* as a log-format string via parse_logformat_string(): the lf_used flag
|
||||
* is set and the result is stored in the lf_expr member while the exprs
|
||||
* list remains empty. Otherwise the arguments are treated as bare sample
|
||||
* expressions: the proxy configuration context is set and the function
|
||||
* calls flt_otel_parse_cfg_sample_expr() in a loop to populate exprs.
|
||||
*
|
||||
* When <n> is 0 all remaining valid arguments are consumed; otherwise at
|
||||
* most <n> expressions are parsed. On error the allocated conf_sample
|
||||
* structure is freed before returning.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns ERR_NONE (== 0) in case of success, or a combination of ERR_* flags
|
||||
|
|
@ -338,7 +349,25 @@ static int flt_otel_parse_cfg_sample(const char *file, int line, char **args, in
|
|||
if (sample == NULL)
|
||||
FLT_OTEL_PARSE_ERR(err, "'%s' : out of memory", args[0]);
|
||||
|
||||
if (!(retval & ERR_CODE)) {
|
||||
if (retval & ERR_CODE) {
|
||||
/* Do nothing. */
|
||||
}
|
||||
else if (strstr(args[idx], "%[") != NULL) {
|
||||
/*
|
||||
* Log-format path: parse the single argument as a log-format
|
||||
* string into the sample structure.
|
||||
*/
|
||||
sample->lf_used = 1;
|
||||
|
||||
if (parse_logformat_string(args[idx], flt_otel_current_config->proxy, &(sample->lf_expr), LOG_OPT_HTTP, SMP_VAL_FE_LOG_END, err) == 0)
|
||||
retval |= ERR_ABORT | ERR_ALERT;
|
||||
else
|
||||
OTELC_DBG(DEBUG, "sample '%s' -> log-format '%s' added", sample->key, sample->fmt_string);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Bare sample expression path.
|
||||
*/
|
||||
flt_otel_current_config->proxy->conf.args.ctx = ARGC_OTEL;
|
||||
flt_otel_current_config->proxy->conf.args.file = file;
|
||||
flt_otel_current_config->proxy->conf.args.line = line;
|
||||
|
|
|
|||
|
|
@ -887,59 +887,78 @@ int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample
|
|||
(void)memset(&value, 0, sizeof(value));
|
||||
(void)memset(&buffer, 0, sizeof(buffer));
|
||||
|
||||
list_for_each_entry(expr, &(sample->exprs), list) {
|
||||
FLT_OTEL_DBG_CONF_SAMPLE_EXPR("sample expression ", expr);
|
||||
|
||||
(void)memset(&smp, 0, sizeof(smp));
|
||||
|
||||
if (sample_process(s->be, s->sess, s, dir | SMP_OPT_FINAL, expr->expr, &smp) != NULL) {
|
||||
OTELC_DBG(DEBUG, "data type %d: '%s'", smp.data.type, expr->fmt_expr);
|
||||
} else {
|
||||
OTELC_DBG(NOTICE, "WARNING: failed to fetch '%s' value", expr->fmt_expr);
|
||||
|
||||
/*
|
||||
* In case the fetch failed, we will set the result
|
||||
* (sample) to an empty static string.
|
||||
*/
|
||||
(void)memset(&(smp.data), 0, sizeof(smp.data));
|
||||
smp.data.type = SMP_T_STR;
|
||||
smp.data.u.str.area = "";
|
||||
}
|
||||
|
||||
/* Evaluate the sample: log-format path or expression list path. */
|
||||
if (sample->lf_used) {
|
||||
/*
|
||||
* If we have only one expression to process, then the data
|
||||
* type that is the result of the expression is converted to
|
||||
* an equivalent data type (if possible) that is written to
|
||||
* the tracer.
|
||||
*
|
||||
* If conversion is not possible, or if we have multiple
|
||||
* expressions to process, then the result is converted to
|
||||
* a string and as such sent to the tracer.
|
||||
* Log-format path: evaluate the log-format expression into a
|
||||
* dynamically allocated buffer.
|
||||
*/
|
||||
if ((sample->num_exprs == 1) && ((type == FLT_OTEL_EVENT_SAMPLE_ATTRIBUTE) || (type == FLT_OTEL_EVENT_SAMPLE_EVENT))) {
|
||||
if (flt_otel_sample_to_value(sample->key, &(smp.data), &value, err) == FLT_OTEL_RET_ERROR)
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
chunk_init(&buffer, OTELC_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
|
||||
if (buffer.area == NULL) {
|
||||
FLT_OTEL_ERR("out of memory");
|
||||
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
} else {
|
||||
if (buffer.area == NULL) {
|
||||
chunk_init(&buffer, OTELC_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
|
||||
if (buffer.area == NULL) {
|
||||
FLT_OTEL_ERR("out of memory");
|
||||
buffer.data = build_logline(s, buffer.area, buffer.size, &(sample->lf_expr));
|
||||
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
value.u_type = OTELC_VALUE_DATA;
|
||||
value.u.value_data = buffer.area;
|
||||
}
|
||||
} else {
|
||||
list_for_each_entry(expr, &(sample->exprs), list) {
|
||||
FLT_OTEL_DBG_CONF_SAMPLE_EXPR("sample expression ", expr);
|
||||
|
||||
break;
|
||||
}
|
||||
(void)memset(&smp, 0, sizeof(smp));
|
||||
|
||||
if (sample_process(s->be, s->sess, s, dir | SMP_OPT_FINAL, expr->expr, &smp) != NULL) {
|
||||
OTELC_DBG(DEBUG, "data type %d: '%s'", smp.data.type, expr->fmt_expr);
|
||||
} else {
|
||||
OTELC_DBG(NOTICE, "WARNING: failed to fetch '%s' value", expr->fmt_expr);
|
||||
|
||||
/*
|
||||
* In case the fetch failed, we will set the result
|
||||
* (sample) to an empty static string.
|
||||
*/
|
||||
(void)memset(&(smp.data), 0, sizeof(smp.data));
|
||||
smp.data.type = SMP_T_STR;
|
||||
smp.data.u.str.area = "";
|
||||
}
|
||||
|
||||
rc = flt_otel_sample_to_str(&(smp.data), buffer.area + buffer.data, buffer.size - buffer.data, err);
|
||||
if (rc == FLT_OTEL_RET_ERROR) {
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
/*
|
||||
* If we have only one expression to process, then the data
|
||||
* type that is the result of the expression is converted to
|
||||
* an equivalent data type (if possible) that is written to
|
||||
* the tracer.
|
||||
*
|
||||
* If conversion is not possible, or if we have multiple
|
||||
* expressions to process, then the result is converted to
|
||||
* a string and as such sent to the tracer.
|
||||
*/
|
||||
if ((sample->num_exprs == 1) && ((type == FLT_OTEL_EVENT_SAMPLE_ATTRIBUTE) || (type == FLT_OTEL_EVENT_SAMPLE_EVENT))) {
|
||||
if (flt_otel_sample_to_value(sample->key, &(smp.data), &value, err) == FLT_OTEL_RET_ERROR)
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
} else {
|
||||
buffer.data += rc;
|
||||
if (buffer.area == NULL) {
|
||||
chunk_init(&buffer, OTELC_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
|
||||
if (buffer.area == NULL) {
|
||||
FLT_OTEL_ERR("out of memory");
|
||||
|
||||
if (sample->num_exprs == ++idx) {
|
||||
value.u_type = OTELC_VALUE_DATA;
|
||||
value.u.value_data = buffer.area;
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = flt_otel_sample_to_str(&(smp.data), buffer.area + buffer.data, buffer.size - buffer.data, err);
|
||||
if (rc == FLT_OTEL_RET_ERROR) {
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
} else {
|
||||
buffer.data += rc;
|
||||
|
||||
if (sample->num_exprs == ++idx) {
|
||||
value.u_type = OTELC_VALUE_DATA;
|
||||
value.u.value_data = buffer.area;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue