]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: otel: added flt_otel_sample_eval and exposed flt_otel_sample_add_kv
authorMiroslav Zagorac <mzagorac@haproxy.com>
Thu, 2 Apr 2026 14:03:12 +0000 (16:03 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Mon, 13 Apr 2026 07:23:26 +0000 (09:23 +0200)
Factored the sample evaluation logic out of flt_otel_sample_add() into a
new flt_otel_sample_eval() function that evaluates a sample definition
into an otelc_value.  Both the log-format path and the bare sample
expression path are handled, with a flag_native parameter controlling
native type preservation for single-expression samples.
flt_otel_sample_add() now calls flt_otel_sample_eval() and dispatches the
result.

Made flt_otel_sample_add_kv() non-static so callers outside util.c can
add key-value pairs directly to a bare flt_otel_scope_data_kv without
requiring the full flt_otel_scope_data structure.

addons/otel/README-func
addons/otel/include/util.h
addons/otel/src/util.c

index be53a0accde8c13c3efe3b72f8cb173510be9f19..be47b5e86ff32c167484bea8d748a877f4a12b93 100644 (file)
@@ -401,8 +401,8 @@ generated by the FLT_OTEL_CONF_FUNC_INIT and FLT_OTEL_CONF_FUNC_FREE macros.
       Frees a conf_instrument structure and removes it from its list.
 
   flt_otel_conf_log_record_init
-      Allocates and initializes a conf_log_record structure with an empty
-      samples list.
+      Allocates and initializes a conf_log_record structure with empty
+      attributes and samples lists.
 
   flt_otel_conf_log_record_free
       Frees a conf_log_record structure: event_name, span, attributes and
@@ -686,9 +686,16 @@ Utility and conversion functions.
       Adds a sample value as a key-value attribute or baggage entry.
       Dynamically grows the key-value array.
 
+  flt_otel_sample_eval
+      Evaluates all sample expressions for a configured sample definition and
+      stores the result in an otelc_value.  Supports both log-format and bare
+      sample expression paths.  When flag_native is true and the sample has
+      exactly one expression, the native HAProxy sample type is preserved;
+      otherwise results are concatenated into a string.
+
   flt_otel_sample_add
-      Top-level sample evaluator.  Processes all sample expressions for a
-      configured sample, converts results, and dispatches to the appropriate
+      Top-level sample evaluator and dispatcher.  Calls flt_otel_sample_eval()
+      to evaluate the sample, then dispatches the result to the appropriate
       handler (attribute, event, baggage, status).
 
 
index 663e2ba5577aaa029df37f0a782b0f406241511f..cf05f3b5e30975fe5509859a1a08caa8614e3c41 100644 (file)
@@ -83,6 +83,12 @@ int         flt_otel_sample_to_str(const struct sample_data *data, char *value,
 /* Convert sample data to an OTel value. */
 int         flt_otel_sample_to_value(const char *key, const struct sample_data *data, struct otelc_value *value, char **err);
 
+/* Add a key-value pair to a growable key-value array. */
+int         flt_otel_sample_add_kv(struct flt_otel_scope_data_kv *kv, const char *key, const struct otelc_value *value);
+
+/* Evaluate a sample definition into an OTel value. */
+int         flt_otel_sample_eval(struct stream *s, uint dir, struct flt_otel_conf_sample *sample, bool flag_native, struct otelc_value *value, char **err);
+
 /* Evaluate a sample expression and add the result to scope data. */
 int         flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample *sample, struct flt_otel_scope_data *data, int type, char **err);
 
index 05108572dfffb6fcfee8628fdf1c0e54ebf53dee..fb8ff76ded4b6d6dface98f6d7734af31515be62 100644 (file)
@@ -799,7 +799,7 @@ static int flt_otel_sample_set_status(struct flt_otel_scope_data_status *status,
  *   flt_otel_sample_add_kv - key-value attribute addition
  *
  * SYNOPSIS
- *   static int flt_otel_sample_add_kv(struct flt_otel_scope_data_kv *kv, const char *key, const struct otelc_value *value)
+ *   int flt_otel_sample_add_kv(struct flt_otel_scope_data_kv *kv, const char *key, const struct otelc_value *value)
  *
  * ARGUMENTS
  *   kv    - key-value storage (attributes or baggage)
@@ -816,7 +816,7 @@ static int flt_otel_sample_set_status(struct flt_otel_scope_data_status *status,
  * RETURN VALUE
  *   Returns the current element count, or FLT_OTEL_RET_ERROR on failure.
  */
-static int flt_otel_sample_add_kv(struct flt_otel_scope_data_kv *kv, const char *key, const struct otelc_value *value)
+int flt_otel_sample_add_kv(struct flt_otel_scope_data_kv *kv, const char *key, const struct otelc_value *value)
 {
        struct otelc_kv *attr = NULL;
 
@@ -858,46 +858,49 @@ static int flt_otel_sample_add_kv(struct flt_otel_scope_data_kv *kv, const char
 
 /***
  * NAME
- *   flt_otel_sample_add - top-level sample evaluator
+ *   flt_otel_sample_eval - sample expression evaluation
  *
  * SYNOPSIS
- *   int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample *sample, struct flt_otel_scope_data *data, int type, char **err)
+ *   int flt_otel_sample_eval(struct stream *s, uint dir, struct flt_otel_conf_sample *sample, bool flag_native, struct otelc_value *value, char **err)
  *
  * ARGUMENTS
- *   s      - current stream
- *   dir    - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
- *   sample - configured sample definition
- *   data   - scope data to populate
- *   type   - sample type (FLT_OTEL_EVENT_SAMPLE_*)
- *   err    - indirect pointer to error message string
+ *   s           - current stream
+ *   dir         - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
+ *   sample      - configured sample definition
+ *   flag_native - preserve native types for single-expression samples
+ *   value       - evaluated result (caller-owned)
+ *   err         - indirect pointer to error message string
  *
  * DESCRIPTION
- *   Processes all sample expressions for a configured sample definition,
- *   converts the results, and dispatches to the appropriate handler.  For
- *   single-expression attributes and events, native type preservation is
- *   attempted via flt_otel_sample_to_value().  For multi-expression samples,
- *   all results are concatenated into a string buffer.  The final value is
- *   dispatched to flt_otel_sample_add_kv() for attributes and baggage,
- *   flt_otel_sample_add_event() for events, or flt_otel_sample_set_status()
- *   for status.
+ *   Evaluates all sample expressions for a configured sample definition and
+ *   stores the result in <value>.  Two evaluation paths are supported:
+ *   log-format expressions (sample->lf_used) are evaluated via build_logline();
+ *   bare sample expressions are evaluated via sample_process().
+ *
+ *   When <flag_native> is true and the sample has exactly one expression, the
+ *   native HAProxy sample type is preserved via flt_otel_sample_to_value()
+ *   (e.g. bool, int64).  Otherwise, all expression results are concatenated
+ *   into a string (OTELC_VALUE_DATA).
+ *
+ *   On success, ownership of any dynamically allocated data within <value>
+ *   (value->u.value_data for OTELC_VALUE_DATA) is transferred to the caller.
+ *   On error, no cleanup is required.
  *
  * RETURN VALUE
- *   Returns a negative value if an error occurs, 0 if it needs to wait,
- *   any other value otherwise.
+ *   Returns FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
  */
-int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample *sample, struct flt_otel_scope_data *data, int type, char **err)
+int flt_otel_sample_eval(struct stream *s, uint dir, struct flt_otel_conf_sample *sample, bool flag_native, struct otelc_value *value, char **err)
 {
        const struct flt_otel_conf_sample_expr *expr;
        struct sample                           smp;
-       struct otelc_value                      value;
        struct buffer                           buffer;
        int                                     idx = 0, rc, retval = FLT_OTEL_RET_OK;
 
-       OTELC_FUNC("%p, %u, %p, %p, %d, %p:%p", s, dir, sample, data, type, OTELC_DPTR_ARGS(err));
+       OTELC_FUNC("%p, %u, %p, %hhu, %p, %p:%p", s, dir, sample, flag_native, value, OTELC_DPTR_ARGS(err));
 
        FLT_OTEL_DBG_CONF_SAMPLE("sample ", sample);
 
-       (void)memset(&value, 0, sizeof(value));
+       (void)memset(value, 0, sizeof(*value));
        (void)memset(&buffer, 0, sizeof(buffer));
 
        /* Evaluate the sample: log-format path or expression list path. */
@@ -914,8 +917,8 @@ int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample
                } else {
                        buffer.data = build_logline(s, buffer.area, buffer.size, &(sample->lf_expr));
 
-                       value.u_type       = OTELC_VALUE_DATA;
-                       value.u.value_data = buffer.area;
+                       value->u_type       = OTELC_VALUE_DATA;
+                       value->u.value_data = buffer.area;
                }
        } else {
                list_for_each_entry(expr, &(sample->exprs), list) {
@@ -947,8 +950,8 @@ int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample
                         * 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)
+                       if ((sample->num_exprs == 1) && flag_native) {
+                               if (flt_otel_sample_to_value(sample->key, &(smp.data), value, err) == FLT_OTEL_RET_ERROR)
                                        retval = FLT_OTEL_RET_ERROR;
                        } else {
                                if (buffer.area == NULL) {
@@ -969,14 +972,65 @@ int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample
                                        buffer.data += rc;
 
                                        if (sample->num_exprs == ++idx) {
-                                               value.u_type       = OTELC_VALUE_DATA;
-                                               value.u.value_data = buffer.area;
+                                               value->u_type       = OTELC_VALUE_DATA;
+                                               value->u.value_data = buffer.area;
                                        }
                                }
                        }
                }
        }
 
+       /* On error, free any dynamically allocated value data. */
+       if (retval == FLT_OTEL_RET_ERROR) {
+               if (buffer.area != NULL)
+                       OTELC_SFREE(buffer.area);
+               else if (value->u_type == OTELC_VALUE_DATA)
+                       OTELC_SFREE(value->u.value_data);
+
+               (void)memset(value, 0, sizeof(*value));
+       }
+
+       OTELC_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ *   flt_otel_sample_add - top-level sample evaluator and dispatcher
+ *
+ * SYNOPSIS
+ *   int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample *sample, struct flt_otel_scope_data *data, int type, char **err)
+ *
+ * ARGUMENTS
+ *   s      - current stream
+ *   dir    - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
+ *   sample - configured sample definition
+ *   data   - scope data to populate
+ *   type   - sample type (FLT_OTEL_EVENT_SAMPLE_*)
+ *   err    - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ *   Evaluates all sample expressions for a configured sample definition via
+ *   flt_otel_sample_eval(), then dispatches the result to the appropriate
+ *   handler: flt_otel_sample_add_kv() for attributes and baggage,
+ *   flt_otel_sample_add_event() for events, or flt_otel_sample_set_status()
+ *   for status.
+ *
+ * RETURN VALUE
+ *   Returns a negative value if an error occurs, 0 if it needs to wait,
+ *   any other value otherwise.
+ */
+int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample *sample, struct flt_otel_scope_data *data, int type, char **err)
+{
+       struct otelc_value value;
+       bool               flag_native;
+       int                retval;
+
+       OTELC_FUNC("%p, %u, %p, %p, %d, %p:%p", s, dir, sample, data, type, OTELC_DPTR_ARGS(err));
+
+       flag_native = ((type == FLT_OTEL_EVENT_SAMPLE_ATTRIBUTE) || (type == FLT_OTEL_EVENT_SAMPLE_EVENT));
+       retval = flt_otel_sample_eval(s, dir, sample, flag_native, &value, err);
+
        /* Dispatch the evaluated value to the appropriate collection. */
        if (retval == FLT_OTEL_RET_ERROR) {
                /* Do nothing. */
@@ -1015,8 +1069,6 @@ int flt_otel_sample_add(struct stream *s, uint dir, struct flt_otel_conf_sample
         */
        if ((retval != FLT_OTEL_RET_ERROR) && (type != FLT_OTEL_EVENT_SAMPLE_STATUS))
                /* Do nothing. */;
-       else if (buffer.area != NULL)
-               OTELC_SFREE(buffer.area);
        else if (value.u_type == OTELC_VALUE_DATA)
                OTELC_SFREE(value.u.value_data);