endif
OPTIONS_OBJS += \
+ addons/otel/src/conf.o \
addons/otel/src/filter.o \
- addons/otel/src/parser.o
+ addons/otel/src/parser.o \
+ addons/otel/src/util.o
OTEL_CFLAGS := $(OTEL_CFLAGS) -Iaddons/otel/include $(OTEL_DEFINE)
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#ifndef _OTEL_CONF_H_
+#define _OTEL_CONF_H_
+
+/* Extract the OTel filter configuration from a filter instance. */
+#define FLT_OTEL_CONF(f) ((struct flt_otel_conf *)FLT_CONF(f))
+
+/* Expand to a string pointer and its length for a named member. */
+#define FLT_OTEL_STR_HDR_ARGS(p,m) (p)->m, (p)->m##_len
+/***
+ * It should be noted that the macro FLT_OTEL_CONF_HDR_ARGS() does not have
+ * all the parameters defined that would correspond to the format found in
+ * the FLT_OTEL_CONF_HDR_FMT macro (first pointer is missing).
+ *
+ * This is because during the expansion of the OTELC_DBG_STRUCT() macro, an
+ * incorrect conversion is performed and instead of the first correct code,
+ * a second incorrect code is generated:
+ *
+ * do {
+ * if ((p) == NULL)
+ * ..
+ * } while (0)
+ *
+ * do {
+ * if ((p), (int) (p)->id_len, (p)->id, (p)->id_len, (p)->cfg_line == NULL)
+ * ..
+ * } while (0)
+ *
+ */
+#define FLT_OTEL_CONF_HDR_FMT "%p:{ { '%.*s' %zu %d } "
+#define FLT_OTEL_CONF_HDR_ARGS(p,m) (int)(p)->m##_len, (p)->m, (p)->m##_len, (p)->cfg_line
+
+#define FLT_OTEL_CONF_STR_CMP(s,S) ((s##_len == S##_len) && (memcmp(s, S, S##_len) == 0))
+
+#define FLT_OTEL_DBG_CONF_SAMPLE_EXPR(h,p) \
+ 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), \
+ (p)->key, (p)->fmt_string, otelc_value_dump(&((p)->extra), ""), \
+ flt_otel_list_dump(&((p)->exprs)), (p)->num_exprs)
+
+#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))
+
+#define FLT_OTEL_DBG_CONF_CONTEXT(h,p) \
+ OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "0x%02hhx }", (p), FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->flags)
+
+#define FLT_OTEL_DBG_CONF_SPAN(h,p) \
+ OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "'%s' %zu %s' %zu %hhu 0x%02hhx %s %s %s %s }", \
+ (p), FLT_OTEL_CONF_HDR_ARGS(p, id), FLT_OTEL_STR_HDR_ARGS(p, ref_id), \
+ FLT_OTEL_STR_HDR_ARGS(p, ctx_id), (p)->flag_root, (p)->ctx_flags, \
+ flt_otel_list_dump(&((p)->attributes)), flt_otel_list_dump(&((p)->events)), \
+ flt_otel_list_dump(&((p)->baggages)), flt_otel_list_dump(&((p)->statuses)))
+
+#define FLT_OTEL_DBG_CONF_SCOPE(h,p) \
+ OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%hhu %d %u %s %p %s %s %s }", (p), \
+ FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->flag_used, (p)->event, (p)->idle_timeout, \
+ flt_otel_list_dump(&((p)->acls)), (p)->cond, flt_otel_list_dump(&((p)->contexts)), \
+ flt_otel_list_dump(&((p)->spans)), flt_otel_list_dump(&((p)->spans_to_finish)))
+
+#define FLT_OTEL_DBG_CONF_GROUP(h,p) \
+ OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%hhu %s }", (p), \
+ FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->flag_used, flt_otel_list_dump(&((p)->ph_scopes)))
+
+#define FLT_OTEL_DBG_CONF_PH(h,p) \
+ OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%p }", (p), FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->ptr)
+
+#define FLT_OTEL_DBG_CONF_INSTR(h,p) \
+ OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "'%s' %p %u %hhu %hhu 0x%02hhx %p:%s 0x%08x %u %s %s %s }", (p), \
+ FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->config, (p)->tracer, (p)->rate_limit, (p)->flag_harderr, \
+ (p)->flag_disabled, (p)->logging, &((p)->proxy_log), flt_otel_list_dump(&((p)->proxy_log.loggers)), \
+ (p)->analyzers, (p)->idle_timeout, flt_otel_list_dump(&((p)->acls)), flt_otel_list_dump(&((p)->ph_groups)), \
+ flt_otel_list_dump(&((p)->ph_scopes)))
+
+#define FLT_OTEL_DBG_CONF(h,p) \
+ OTELC_DBG(DEBUG, h "%p:{ %p '%s' '%s' %p %s %s }", (p), \
+ (p)->proxy, (p)->id, (p)->cfg_file, (p)->instr, \
+ flt_otel_list_dump(&((p)->groups)), flt_otel_list_dump(&((p)->scopes)))
+
+/* Anonymous struct containing a string pointer and its length. */
+#define FLT_OTEL_CONF_STR(p) \
+ struct { \
+ char *p; \
+ size_t p##_len; \
+ }
+
+/* Common header embedded in all configuration structures. */
+#define FLT_OTEL_CONF_HDR(p) \
+ struct { \
+ FLT_OTEL_CONF_STR(p); \
+ int cfg_line; \
+ struct list list; \
+ }
+
+
+/* Generic configuration header used for simple named list entries. */
+struct flt_otel_conf_hdr {
+ FLT_OTEL_CONF_HDR(id); /* A list containing header names. */
+};
+
+/* flt_otel_conf_sample->exprs */
+struct flt_otel_conf_sample_expr {
+ FLT_OTEL_CONF_HDR(fmt_expr); /* The original sample expression format string. */
+ struct sample_expr *expr; /* The sample expression. */
+};
+
+/*
+ * flt_otel_conf_span->attributes
+ * flt_otel_conf_span->events (event_name -> OTELC_VALUE_STR(&extra))
+ * flt_otel_conf_span->baggages
+ * flt_otel_conf_span->statuses (status_code -> extra.u.value_int32)
+ */
+struct flt_otel_conf_sample {
+ FLT_OTEL_CONF_HDR(key); /* The list containing sample names. */
+ char *fmt_string; /* All sample-expression arguments are combined into a single string. */
+ struct otelc_value extra; /* Optional supplementary data. */
+ struct list exprs; /* Used to chain sample expressions. */
+ int num_exprs; /* Number of defined expressions. */
+};
+
+/*
+ * flt_otel_conf_scope->spans_to_finish
+ *
+ * It can be seen that this structure is actually identical to the structure
+ * flt_otel_conf_hdr.
+ */
+struct flt_otel_conf_str {
+ FLT_OTEL_CONF_HDR(str); /* A list containing character strings. */
+};
+
+/* flt_otel_conf_scope->contexts */
+struct flt_otel_conf_context {
+ FLT_OTEL_CONF_HDR(id); /* The name of the context. */
+ uint8_t flags; /* The type of storage from which the span context is extracted. */
+};
+
+/*
+ * Span configuration within a scope.
+ * flt_otel_conf_scope->spans
+ */
+struct flt_otel_conf_span {
+ FLT_OTEL_CONF_HDR(id); /* The name of the span. */
+ FLT_OTEL_CONF_STR(ref_id); /* The reference name, if used. */
+ FLT_OTEL_CONF_STR(ctx_id); /* The span context name, if used. */
+ uint8_t ctx_flags; /* The type of storage used for the span context. */
+ bool flag_root; /* Whether this is a root span. */
+ struct list attributes; /* The set of key:value attributes. */
+ struct list events; /* The set of events with key-value attributes. */
+ struct list baggages; /* The set of key:value baggage items. */
+ struct list statuses; /* Span status code and description (only one per list). */
+};
+
+/* Configuration for a single event scope. */
+struct flt_otel_conf_scope {
+ FLT_OTEL_CONF_HDR(id); /* The scope name. */
+ bool flag_used; /* The indication that the scope is being used. */
+ int event; /* FLT_OTEL_EVENT_* */
+ uint idle_timeout; /* Idle timeout interval in milliseconds (0 = off). */
+ struct list acls; /* ACLs declared on this scope. */
+ struct acl_cond *cond; /* ACL condition to meet. */
+ struct list contexts; /* Declared contexts. */
+ struct list spans; /* Declared spans. */
+ struct list spans_to_finish; /* The list of spans scheduled for finishing. */
+};
+
+/* Configuration for a named group of scopes. */
+struct flt_otel_conf_group {
+ FLT_OTEL_CONF_HDR(id); /* The group name. */
+ bool flag_used; /* The indication that the group is being used. */
+ struct list ph_scopes; /* List of all used scopes. */
+};
+
+/* Placeholder referencing a scope or group by name. */
+struct flt_otel_conf_ph {
+ FLT_OTEL_CONF_HDR(id); /* The scope/group name. */
+ void *ptr; /* Pointer to real placeholder structure. */
+};
+#define flt_otel_conf_ph_group flt_otel_conf_ph
+#define flt_otel_conf_ph_scope flt_otel_conf_ph
+
+/* Top-level OTel instrumentation settings (tracer, options). */
+struct flt_otel_conf_instr {
+ FLT_OTEL_CONF_HDR(id); /* The OpenTelemetry instrumentation name. */
+ char *config; /* The OpenTelemetry configuration file name. */
+ struct otelc_tracer *tracer; /* The OpenTelemetry tracer handle. */
+ uint32_t rate_limit; /* [0 2^32-1] <-> [0.0 100.0] */
+ bool flag_harderr; /* [0 1] */
+ bool flag_disabled; /* [0 1] */
+ uint8_t logging; /* [0 1 3] */
+ struct proxy proxy_log; /* The log server list. */
+ uint analyzers; /* Defined channel analyzers. */
+ uint idle_timeout; /* Minimum idle timeout across scopes (ms, 0 = off). */
+ struct list acls; /* ACLs declared on this tracer. */
+ struct list ph_groups; /* List of all used groups. */
+ struct list ph_scopes; /* List of all used scopes. */
+};
+
+/* The OpenTelemetry filter configuration. */
+struct flt_otel_conf {
+ struct proxy *proxy; /* Proxy owning the filter. */
+ char *id; /* The OpenTelemetry filter id. */
+ char *cfg_file; /* The OpenTelemetry filter configuration file name. */
+ struct flt_otel_conf_instr *instr; /* The OpenTelemetry instrumentation settings. */
+ struct list groups; /* List of all available groups. */
+ struct list scopes; /* List of all available scopes. */
+ struct list smp_args; /* Deferred OTEL sample fetch args to resolve. */
+};
+
+
+/* Allocate and initialize a sample from parsed arguments. */
+struct flt_otel_conf_sample *flt_otel_conf_sample_init_ex(const char **args, int idx, int n, const struct otelc_value *extra, int line, struct list *head, char **err);
+
+/* Allocate and initialize the top-level OTel filter configuration. */
+struct flt_otel_conf *flt_otel_conf_init(struct proxy *px);
+
+/* Free the top-level OTel filter configuration. */
+void flt_otel_conf_free(struct flt_otel_conf **ptr);
+
+#endif /* _OTEL_CONF_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#ifndef _OTEL_CONF_FUNCS_H_
+#define _OTEL_CONF_FUNCS_H_
+
+/*
+ * Macro that generates a flt_otel_conf_<type>_init() function. The generated
+ * function allocates and initializes a configuration structure of the given
+ * type, checks for duplicate names in the list, and optionally runs a custom
+ * initializer body.
+ */
+#define FLT_OTEL_CONF_FUNC_INIT(_type_, _id_, _func_) \
+ struct flt_otel_conf_##_type_ *flt_otel_conf_##_type_##_init(const char *id, int line, struct list *head, char **err) \
+ { \
+ struct flt_otel_conf_##_type_ *retptr = NULL; \
+ struct flt_otel_conf_##_type_ *ptr; \
+ size_t _id_##_len; \
+ \
+ OTELC_FUNC("\"%s\", %d, %p, %p:%p", OTELC_STR_ARG(id), line, head, OTELC_DPTR_ARGS(err)); \
+ \
+ if ((id == NULL) || (*id == '\0')) { \
+ FLT_OTEL_ERR("name not set"); \
+ \
+ OTELC_RETURN_PTR(retptr); \
+ } \
+ \
+ _id_##_len = strlen(id); \
+ if (_id_##_len >= FLT_OTEL_ID_MAXLEN) { \
+ FLT_OTEL_ERR("'%s' : name too long", id); \
+ \
+ OTELC_RETURN_PTR(retptr); \
+ } \
+ \
+ if (head != NULL) \
+ list_for_each_entry(ptr, head, list) \
+ if (strcmp(ptr->_id_, id) == 0) { \
+ FLT_OTEL_ERR("'%s' : already defined", id); \
+ \
+ OTELC_RETURN_PTR(retptr); \
+ } \
+ \
+ retptr = OTELC_CALLOC(1, sizeof(*retptr)); \
+ if (retptr != NULL) { \
+ retptr->cfg_line = line; \
+ retptr->_id_##_len = _id_##_len; \
+ retptr->_id_ = OTELC_STRDUP(id); \
+ if (retptr->_id_ != NULL) { \
+ if (head != NULL) \
+ LIST_APPEND(head, &(retptr->list)); \
+ \
+ FLT_OTEL_DBG_CONF_HDR("- conf_" #_type_ " init ", retptr, _id_); \
+ } \
+ else \
+ OTELC_SFREE_CLEAR(retptr); \
+ } \
+ \
+ if (retptr != NULL) { \
+ _func_ \
+ } \
+ \
+ if (retptr == NULL) \
+ FLT_OTEL_ERR("out of memory"); \
+ \
+ OTELC_RETURN_PTR(retptr); \
+ }
+
+/*
+ * Macro that generates a flt_otel_conf_<type>_free() function. The generated
+ * function runs a custom cleanup body, then frees the name string, removes the
+ * structure from its list, and frees the structure.
+ */
+#define FLT_OTEL_CONF_FUNC_FREE(_type_, _id_, _func_) \
+ void flt_otel_conf_##_type_##_free(struct flt_otel_conf_##_type_ **ptr) \
+ { \
+ OTELC_FUNC("%p:%p", OTELC_DPTR_ARGS(ptr)); \
+ \
+ if ((ptr == NULL) || (*ptr == NULL)) \
+ OTELC_RETURN(); \
+ \
+ { _func_ } \
+ \
+ OTELC_SFREE((*ptr)->_id_); \
+ FLT_OTEL_LIST_DEL(&((*ptr)->list)); \
+ OTELC_SFREE_CLEAR(*ptr); \
+ \
+ OTELC_RETURN(); \
+ }
+
+
+/* The FLT_OTEL_LIST_DESTROY() macro uses the following two definitions. */
+#define flt_otel_conf_ph_group_free flt_otel_conf_ph_free
+#define flt_otel_conf_ph_scope_free flt_otel_conf_ph_free
+
+/* Declare init/free function prototypes for a configuration type. */
+#define FLT_OTEL_CONF_FUNC_DECL(_type_) \
+ struct flt_otel_conf_##_type_ *flt_otel_conf_##_type_##_init(const char *id, int line, struct list *head, char **err); \
+ void flt_otel_conf_##_type_##_free(struct flt_otel_conf_##_type_ **ptr);
+
+FLT_OTEL_CONF_FUNC_DECL(hdr)
+FLT_OTEL_CONF_FUNC_DECL(str)
+FLT_OTEL_CONF_FUNC_DECL(ph)
+FLT_OTEL_CONF_FUNC_DECL(sample_expr)
+FLT_OTEL_CONF_FUNC_DECL(sample)
+FLT_OTEL_CONF_FUNC_DECL(context)
+FLT_OTEL_CONF_FUNC_DECL(span)
+FLT_OTEL_CONF_FUNC_DECL(scope)
+FLT_OTEL_CONF_FUNC_DECL(group)
+FLT_OTEL_CONF_FUNC_DECL(instr)
+
+#endif /* _OTEL_CONF_FUNCS_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
#ifndef _OTEL_CONFIG_H_
#define _OTEL_CONFIG_H_
+#define FLT_OTEL_ID_MAXLEN 64 /* Maximum identifier length. */
#define FLT_OTEL_DEBUG_LEVEL 0b11101111111 /* Default debug bitmask. */
#endif /* _OTEL_CONFIG_H_ */
#ifndef _OTEL_DEFINE_H_
#define _OTEL_DEFINE_H_
+/* Check whether argument at index n is in range, non-NULL and non-empty. */
+#define FLT_OTEL_ARG_ISVALID(n) ({ typeof(n) _n = (n); OTELC_IN_RANGE(_n, 0, MAX_LINE_ARGS - 1) && (args[_n] != NULL) && (*args[_n] != '\0'); })
+
+/* Convert a floating-point percentage to a uint32_t rate value. */
+#define FLT_OTEL_FLOAT_U32(a) ((uint32_t)((a) / 100.0 * UINT32_MAX + 0.5))
+
+/* Compile-time string length excluding the null terminator. */
+#define FLT_OTEL_STR_SIZE(a) (sizeof(a) - 1)
+
/* Execute a statement exactly once across all invocations. */
#define FLT_OTEL_RUN_ONCE(f) do { static bool _f = 1; if (_f) { _f = 0; { f; } } } while (0)
+/* Check whether a list head has been initialized. */
+#define FLT_OTEL_LIST_ISVALID(a) ({ typeof(a) _a = (a); (_a != NULL) && (_a->n != NULL) && (_a->p != NULL); })
+
+/* Safely delete a list element if its list head is valid. */
+#define FLT_OTEL_LIST_DEL(a) do { if (FLT_OTEL_LIST_ISVALID(a)) LIST_DELETE(a); } while (0)
+
+/* Destroy all elements in a typed configuration list. */
+#define FLT_OTEL_LIST_DESTROY(t,h) \
+ do { \
+ struct flt_otel_conf_##t *_ptr, *_back; \
+ \
+ if (!FLT_OTEL_LIST_ISVALID(h) || LIST_ISEMPTY(h)) \
+ break; \
+ \
+ OTELC_DBG(NOTICE, "- deleting " #t " list %s", flt_otel_list_dump(h)); \
+ \
+ list_for_each_entry_safe(_ptr, _back, (h), list) \
+ flt_otel_conf_##t##_free(&_ptr); \
+ } while (0)
+
+/* Declare a rotating thread-local string buffer pool. */
+#define FLT_OTEL_BUFFER_THR(b,m,n,p) \
+ static THREAD_LOCAL char b[m][n]; \
+ static THREAD_LOCAL size_t __idx = 0; \
+ char *p = b[__idx]; \
+ __idx = (__idx + 1) % (m)
+
+/* Format an error message if none has been set yet. */
+#define FLT_OTEL_ERR(f, ...) \
+ do { \
+ if ((err != NULL) && (*err == NULL)) { \
+ (void)memprintf(err, f, ##__VA_ARGS__); \
+ \
+ OTELC_DBG(DEBUG, "err: '%s'", *err); \
+ } \
+ } while (0)
+/* Append to an existing error message unconditionally. */
+#define FLT_OTEL_ERR_APPEND(f, ...) \
+ do { \
+ if (err != NULL) \
+ (void)memprintf(err, f, ##__VA_ARGS__); \
+ } while (0)
+/* Log an error message and free its memory. */
+#define FLT_OTEL_ERR_FREE(p) \
+ do { \
+ if ((p) == NULL) \
+ break; \
+ \
+ OTELC_DBG(LOG, "%s:%d: ERROR: %s", __func__, __LINE__, (p)); \
+ OTELC_SFREE_CLEAR(p); \
+ } while (0)
+
#endif /* _OTEL_DEFINE_H_ */
/*
#include "config.h"
#include "define.h"
+#include "conf.h"
+#include "conf_funcs.h"
#include "filter.h"
#include "parser.h"
+#include "util.h"
#endif /* _OTEL_INCLUDE_H_ */
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#ifndef _OTEL_UTIL_H_
+#define _OTEL_UTIL_H_
+
+#define FLT_OTEL_HTTP_METH_DEFINES \
+ FLT_OTEL_HTTP_METH_DEF(OPTIONS) \
+ FLT_OTEL_HTTP_METH_DEF(GET) \
+ FLT_OTEL_HTTP_METH_DEF(HEAD) \
+ FLT_OTEL_HTTP_METH_DEF(POST) \
+ FLT_OTEL_HTTP_METH_DEF(PUT) \
+ FLT_OTEL_HTTP_METH_DEF(DELETE) \
+ FLT_OTEL_HTTP_METH_DEF(TRACE) \
+ FLT_OTEL_HTTP_METH_DEF(CONNECT)
+
+#ifdef DEBUG_OTEL
+# define FLT_OTEL_ARGS_DUMP() do { if (otelc_dbg_level & (1 << OTELC_DBG_LEVEL_LOG)) flt_otel_args_dump((const char **)args); } while (0)
+#else
+# define FLT_OTEL_ARGS_DUMP() while (0)
+#endif
+
+
+#ifdef DEBUG_OTEL
+/* Dump configuration arguments for debugging. */
+void flt_otel_args_dump(const char **args);
+
+/* Dump a linked list of configuration items as a string. */
+const char *flt_otel_list_dump(const struct list *head);
+#endif
+
+/* Count the number of non-NULL arguments in an argument array. */
+int flt_otel_args_count(const char **args);
+
+/* Concatenate argument array elements into a single string. */
+int flt_otel_args_concat(const char **args, int idx, int n, char **str);
+
+/* Convert sample data to a string representation. */
+int flt_otel_sample_to_str(const struct sample_data *data, char *value, size_t size, char **err);
+
+#endif /* _OTEL_UTIL_H_ */
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "../include/include.h"
+
+
+/***
+ * NAME
+ * flt_otel_conf_hdr_init - conf_hdr structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_hdr *flt_otel_conf_hdr_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_hdr structure. The <id> string is
+ * duplicated and stored as the header identifier. If <head> is non-NULL,
+ * the structure is appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(hdr, id, )
+
+
+/***
+ * NAME
+ * flt_otel_conf_hdr_free - conf_hdr structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_hdr_free(struct flt_otel_conf_hdr **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_hdr structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(hdr, id,
+ FLT_OTEL_DBG_CONF_HDR("- conf_hdr free ", *ptr, id);
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_str_init - conf_str structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_str *flt_otel_conf_str_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_str structure. The <id> string is
+ * duplicated and stored as the string value. If <head> is non-NULL, the
+ * structure is appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(str, str, )
+
+
+/***
+ * NAME
+ * flt_otel_conf_str_free - conf_str structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_str_free(struct flt_otel_conf_str **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_str structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(str, str,
+ FLT_OTEL_DBG_CONF_HDR("- conf_str free ", *ptr, str);
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_ph_init - conf_ph placeholder structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_ph *flt_otel_conf_ph_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_ph (placeholder) structure. The <id>
+ * string is duplicated and stored as the placeholder identifier. If <head>
+ * is non-NULL, the structure is appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(ph, id, )
+
+
+/***
+ * NAME
+ * flt_otel_conf_ph_free - conf_ph structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_ph_free(struct flt_otel_conf_ph **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_ph structure and its contents,
+ * then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(ph, id,
+ FLT_OTEL_DBG_CONF_HDR("- conf_ph free ", *ptr, id);
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_sample_expr_init - conf_sample_expr structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_sample_expr *flt_otel_conf_sample_expr_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_sample_expr structure. The <id> string is
+ * duplicated and stored as the expression value. If <head> is non-NULL, the
+ * structure is appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(sample_expr, fmt_expr, )
+
+
+/***
+ * NAME
+ * flt_otel_conf_sample_expr_free - conf_sample_expr structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_sample_expr_free(struct flt_otel_conf_sample_expr **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_sample_expr structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(sample_expr, fmt_expr,
+ FLT_OTEL_DBG_CONF_SAMPLE_EXPR("- conf_sample_expr free ", *ptr);
+
+ release_sample_expr((*ptr)->expr);
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_sample_init - conf_sample structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_sample *flt_otel_conf_sample_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_sample structure. The <id> string is
+ * duplicated and stored as the sample key. If <head> is non-NULL, the
+ * structure is appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(sample, key,
+ LIST_INIT(&(retptr->exprs));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_sample_init_ex - extended sample initialization
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_sample *flt_otel_conf_sample_init_ex(const char **args, int idx, int n, const struct otelc_value *extra, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * args - configuration line arguments array
+ * idx - position where sample value starts
+ * n - maximum number of arguments to concatenate (0 means all)
+ * extra - optional extra data (event name or status code)
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Creates and initializes a conf_sample structure with extended data. Calls
+ * flt_otel_conf_sample_init() with <args[idx - 1]> as the sample key to
+ * create the base structure, copies <extra> data (event name string or status
+ * code integer), concatenates the remaining arguments into the sample value
+ * string, and counts the number of sample expressions.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+struct flt_otel_conf_sample *flt_otel_conf_sample_init_ex(const char **args, int idx, int n, const struct otelc_value *extra, int line, struct list *head, char **err)
+{
+ struct flt_otel_conf_sample *retptr = NULL;
+
+ OTELC_FUNC("%p, %d, %d, %p, %d, %p, %p:%p", args, idx, n, extra, line, head, OTELC_DPTR_ARGS(err));
+
+ OTELC_DBG_VALUE(DEBUG, "extra ", extra);
+
+ /* Ensure the sample value is present in the args[] array. */
+ if (flt_otel_args_count(args) <= idx) {
+ FLT_OTEL_ERR("'%s' : too few arguments", args[0]);
+
+ OTELC_RETURN_PTR(retptr);
+ }
+
+ /* The sample key is located at the idx location of the args[] field. */
+ retptr = flt_otel_conf_sample_init(args[idx - 1], line, head, err);
+ if (retptr == NULL)
+ OTELC_RETURN_PTR(retptr);
+
+ if ((extra == NULL) || (extra->u_type == OTELC_VALUE_NULL)) {
+ /*
+ * Do nothing - sample extra data is not set or initialized,
+ * which means it is not used.
+ */
+ }
+ else if (extra->u_type == OTELC_VALUE_STRING) {
+ retptr->extra.u_type = OTELC_VALUE_DATA;
+ retptr->extra.u.value_data = OTELC_STRDUP(extra->u.value_string);
+ if (retptr->extra.u.value_data == NULL) {
+ FLT_OTEL_ERR("out of memory");
+ flt_otel_conf_sample_free(&retptr);
+
+ OTELC_RETURN_PTR(retptr);
+ }
+ }
+ else if (extra->u_type == OTELC_VALUE_INT32) {
+ retptr->extra.u_type = extra->u_type;
+ retptr->extra.u.value_int32 = extra->u.value_int32;
+ }
+ else {
+ FLT_OTEL_ERR("invalid sample extra data type: %d", extra->u_type);
+ flt_otel_conf_sample_free(&retptr);
+
+ OTELC_RETURN_PTR(retptr);
+ }
+
+ /* The sample value starts in the args[] array after the key. */
+ retptr->num_exprs = flt_otel_args_concat(args, idx, n, &(retptr->fmt_string));
+ if (retptr->num_exprs == FLT_OTEL_RET_ERROR) {
+ FLT_OTEL_ERR("out of memory");
+ flt_otel_conf_sample_free(&retptr);
+
+ OTELC_RETURN_PTR(retptr);
+ }
+
+ FLT_OTEL_DBG_CONF_SAMPLE("- conf_sample init ", retptr);
+
+ OTELC_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_otel_conf_sample_free - conf_sample structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_sample_free(struct flt_otel_conf_sample **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_sample structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(sample, key,
+ FLT_OTEL_DBG_CONF_SAMPLE("- conf_sample free ", *ptr);
+
+ OTELC_SFREE((*ptr)->fmt_string);
+ if ((*ptr)->extra.u_type == OTELC_VALUE_DATA)
+ OTELC_SFREE((*ptr)->extra.u.value_data);
+ FLT_OTEL_LIST_DESTROY(sample_expr, &((*ptr)->exprs));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_context_init - conf_context structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_context *flt_otel_conf_context_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_context structure. The <id> string is
+ * duplicated and stored as the context identifier. If <head> is non-NULL,
+ * the structure is appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(context, id, )
+
+
+/***
+ * NAME
+ * flt_otel_conf_context_free - conf_context structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_context_free(struct flt_otel_conf_context **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_context structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(context, id,
+ FLT_OTEL_DBG_CONF_HDR("- conf_context free ", *ptr, id);
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_span_init - conf_span structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_span *flt_otel_conf_span_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_span structure with empty lists for links,
+ * attributes, events, baggages, and statuses. The <id> string is duplicated
+ * and stored as the span name. If <head> is non-NULL, the structure is
+ * appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(span, id,
+ LIST_INIT(&(retptr->attributes));
+ LIST_INIT(&(retptr->events));
+ LIST_INIT(&(retptr->baggages));
+ LIST_INIT(&(retptr->statuses));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_span_free - conf_span structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_span_free(struct flt_otel_conf_span **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_span structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(span, id,
+ FLT_OTEL_DBG_CONF_HDR("- conf_span free ", *ptr, id);
+
+ OTELC_SFREE((*ptr)->ref_id);
+ OTELC_SFREE((*ptr)->ctx_id);
+ FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->attributes));
+ FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->events));
+ FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->baggages));
+ FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->statuses));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_scope_init - conf_scope structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_scope *flt_otel_conf_scope_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_scope structure with empty lists for ACLs,
+ * contexts, spans, spans_to_finish, and instruments. The <id> string is
+ * duplicated and stored as the scope name. If <head> is non-NULL, the
+ * structure is appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(scope, id,
+ LIST_INIT(&(retptr->acls));
+ LIST_INIT(&(retptr->contexts));
+ LIST_INIT(&(retptr->spans));
+ LIST_INIT(&(retptr->spans_to_finish));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_scope_free - conf_scope structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_scope_free(struct flt_otel_conf_scope **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_scope structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(scope, id,
+ struct acl *acl;
+ struct acl *aclback;
+
+ FLT_OTEL_DBG_CONF_SCOPE("- conf_scope free ", *ptr);
+
+ list_for_each_entry_safe(acl, aclback, &((*ptr)->acls), list) {
+ prune_acl(acl);
+ FLT_OTEL_LIST_DEL(&(acl->list));
+ OTELC_SFREE(acl);
+ }
+ free_acl_cond((*ptr)->cond);
+ FLT_OTEL_LIST_DESTROY(context, &((*ptr)->contexts));
+ FLT_OTEL_LIST_DESTROY(span, &((*ptr)->spans));
+ FLT_OTEL_LIST_DESTROY(str, &((*ptr)->spans_to_finish));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_group_init - conf_group structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_group *flt_otel_conf_group_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_group structure with an empty placeholder
+ * scope list. The <id> string is duplicated and stored as the group name.
+ * If <head> is non-NULL, the structure is appended to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(group, id,
+ LIST_INIT(&(retptr->ph_scopes));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_group_free - conf_group structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_group_free(struct flt_otel_conf_group **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_group structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(group, id,
+ FLT_OTEL_DBG_CONF_GROUP("- conf_group free ", *ptr);
+
+ FLT_OTEL_LIST_DESTROY(ph_scope, &((*ptr)->ph_scopes));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_instr_init - conf_instr structure allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf_instr *flt_otel_conf_instr_init(const char *id, int line, struct list *head, char **err)
+ *
+ * ARGUMENTS
+ * id - identifier string to duplicate
+ * line - configuration file line number
+ * head - list to append to (or NULL)
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Allocates and initializes a conf_instr (instrumentation) structure. Sets
+ * the default rate limit to 100%, initializes the proxy_log for logger
+ * support, and creates empty lists for ACLs, placeholder groups, and
+ * placeholder scopes. The <id> string is duplicated and stored as the
+ * instrumentation name. If <head> is non-NULL, the structure is appended
+ * to the list.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+FLT_OTEL_CONF_FUNC_INIT(instr, id,
+ retptr->rate_limit = FLT_OTEL_FLOAT_U32(100.0);
+ init_new_proxy(&(retptr->proxy_log));
+ LIST_INIT(&(retptr->acls));
+ LIST_INIT(&(retptr->ph_groups));
+ LIST_INIT(&(retptr->ph_scopes));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_instr_free - conf_instr structure deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_instr_free(struct flt_otel_conf_instr **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf_instr structure and its
+ * contents, then removes it from the list of structures of that type.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+FLT_OTEL_CONF_FUNC_FREE(instr, id,
+ struct acl *acl;
+ struct acl *aclback;
+ struct logger *logger;
+ struct logger *loggerback;
+
+ FLT_OTEL_DBG_CONF_INSTR("- conf_instr free ", *ptr);
+
+ OTELC_SFREE((*ptr)->config);
+ OTELC_DBG(NOTICE, "- deleting acls list %s", flt_otel_list_dump(&((*ptr)->acls)));
+ list_for_each_entry_safe(acl, aclback, &((*ptr)->acls), list) {
+ prune_acl(acl);
+ FLT_OTEL_LIST_DEL(&(acl->list));
+ OTELC_SFREE(acl);
+ }
+ OTELC_DBG(NOTICE, "- deleting proxy_log.loggers list %s", flt_otel_list_dump(&((*ptr)->proxy_log.loggers)));
+ list_for_each_entry_safe(logger, loggerback, &((*ptr)->proxy_log.loggers), list) {
+ LIST_DELETE(&(logger->list));
+ ha_free(&logger);
+ }
+ FLT_OTEL_LIST_DESTROY(ph_group, &((*ptr)->ph_groups));
+ FLT_OTEL_LIST_DESTROY(ph_scope, &((*ptr)->ph_scopes));
+)
+
+
+/***
+ * NAME
+ * flt_otel_conf_init - top-level filter configuration allocation
+ *
+ * SYNOPSIS
+ * struct flt_otel_conf *flt_otel_conf_init(struct proxy *px)
+ *
+ * ARGUMENTS
+ * px - proxy instance to associate with
+ *
+ * DESCRIPTION
+ * Allocates and initializes the top-level flt_otel_conf structure. Stores
+ * the <px> proxy reference and creates empty group and scope lists.
+ *
+ * RETURN VALUE
+ * Returns a pointer to the initialized structure, or NULL on failure.
+ */
+struct flt_otel_conf *flt_otel_conf_init(struct proxy *px)
+{
+ struct flt_otel_conf *retptr;
+
+ OTELC_FUNC("%p", px);
+
+ retptr = OTELC_CALLOC(1, sizeof(*retptr));
+ if (retptr == NULL)
+ OTELC_RETURN_PTR(retptr);
+
+ retptr->proxy = px;
+ LIST_INIT(&(retptr->groups));
+ LIST_INIT(&(retptr->scopes));
+ LIST_INIT(&(retptr->smp_args));
+
+ FLT_OTEL_DBG_CONF("- conf init ", retptr);
+
+ OTELC_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_otel_conf_free - top-level filter configuration deallocation
+ *
+ * SYNOPSIS
+ * void flt_otel_conf_free(struct flt_otel_conf **ptr)
+ *
+ * ARGUMENTS
+ * ptr - a pointer to the address of a structure
+ *
+ * DESCRIPTION
+ * Deallocates memory used by the flt_otel_conf structure and its contents.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_otel_conf_free(struct flt_otel_conf **ptr)
+{
+ struct arg_list *cur, *back;
+
+ OTELC_FUNC("%p:%p", OTELC_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ OTELC_RETURN();
+
+ FLT_OTEL_DBG_CONF("- conf free ", *ptr);
+
+ OTELC_SFREE((*ptr)->id);
+ OTELC_SFREE((*ptr)->cfg_file);
+ flt_otel_conf_instr_free(&((*ptr)->instr));
+ FLT_OTEL_LIST_DESTROY(group, &((*ptr)->groups));
+ FLT_OTEL_LIST_DESTROY(scope, &((*ptr)->scopes));
+ /* Free any unresolved OTEL sample fetch args (error path). */
+ list_for_each_entry_safe(cur, back, &((*ptr)->smp_args), list) {
+ LIST_DELETE(&(cur->list));
+ ha_free(&cur);
+ }
+ OTELC_SFREE_CLEAR(*ptr);
+
+ OTELC_RETURN();
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
);
#endif
+ FLT_OTEL_ARGS_DUMP();
+
OTELC_RETURN_INT(retval);
}
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "../include/include.h"
+
+
+#ifdef DEBUG_OTEL
+
+/***
+ * NAME
+ * flt_otel_args_dump - debug configuration arguments dump
+ *
+ * SYNOPSIS
+ * void flt_otel_args_dump(const char **args)
+ *
+ * ARGUMENTS
+ * args - configuration line arguments array
+ *
+ * DESCRIPTION
+ * Dumps all configuration arguments to stderr. Counts the number of valid
+ * arguments via flt_otel_args_count() and prints each one surrounded by
+ * single quotes.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_otel_args_dump(const char **args)
+{
+ int i, argc;
+
+ argc = flt_otel_args_count(args);
+
+ (void)fprintf(stderr, OTELC_DBG_FMT("args[%d]: { '%s' "), argc, args[0]);
+
+ for (i = 1; i < argc; i++)
+ (void)fprintf(stderr, "'%s' ", args[i]);
+
+ (void)fprintf(stderr, "}\n");
+}
+
+
+/***
+ * NAME
+ * flt_otel_list_dump - debug list summary
+ *
+ * SYNOPSIS
+ * const char *flt_otel_list_dump(const struct list *head)
+ *
+ * ARGUMENTS
+ * head - list head to summarize
+ *
+ * DESCRIPTION
+ * Returns a concise summary string describing the state of a linked list.
+ * For NULL or empty lists, returns a descriptive label. For single-element
+ * lists, returns the element pointer. For multi-element lists, returns the
+ * first and last pointers along with the element count. Uses a rotating
+ * thread-local buffer for the return value.
+ *
+ * RETURN VALUE
+ * Returns a pointer to a thread-local string describing the list.
+ */
+const char *flt_otel_list_dump(const struct list *head)
+{
+ FLT_OTEL_BUFFER_THR(retbuf, 4, 64, retptr);
+
+ if ((head == NULL) || LIST_ISEMPTY(head)) {
+ (void)strncpy(retptr, (head == NULL) ? "{ null list }" : "{ empty list }", sizeof(retbuf[0]));
+ }
+ else if (head->p == head->n) {
+ (void)snprintf(retptr, sizeof(retbuf[0]), "{ %p * 1 }", head->p);
+ }
+ else {
+ const struct list *ptr;
+ size_t count = 0;
+
+ for (ptr = head->n; ptr != head; ptr = ptr->n, count++);
+
+ (void)snprintf(retptr, sizeof(retbuf[0]), "{ %p %p %zu }", head->p, head->n, count);
+ }
+
+ return (retptr);
+}
+
+#endif /* DEBUG_OTEL */
+
+
+/***
+ * NAME
+ * flt_otel_args_count - argument count
+ *
+ * SYNOPSIS
+ * int flt_otel_args_count(const char **args)
+ *
+ * ARGUMENTS
+ * args - configuration line arguments array
+ *
+ * DESCRIPTION
+ * Counts the number of valid (non-NULL) arguments in <args>. Scans up to
+ * MAX_LINE_ARGS entries, handling gaps from blank arguments by returning the
+ * index of the last valid argument incremented by one.
+ *
+ * RETURN VALUE
+ * Returns the number of valid arguments.
+ */
+int flt_otel_args_count(const char **args)
+{
+ int i, retval = 0;
+
+ if (args == NULL)
+ return retval;
+
+ /*
+ * It is possible that some arguments within the configuration line
+ * are not specified; that is, they are set to a blank string.
+ *
+ * For example:
+ * keyword '' arg_2
+ *
+ * In that case the content of the args field will be like this:
+ * args[0]: 'keyword'
+ * args[1]: NULL pointer
+ * args[2]: 'arg_2'
+ * args[3 .. MAX_LINE_ARGS): NULL pointers
+ *
+ * The total number of arguments is the index of the last argument
+ * (increased by 1) that is not a NULL pointer.
+ */
+ for (i = 0; i < MAX_LINE_ARGS; i++)
+ if (FLT_OTEL_ARG_ISVALID(i))
+ retval = i + 1;
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * flt_otel_args_concat - argument concatenation
+ *
+ * SYNOPSIS
+ * int flt_otel_args_concat(const char **args, int idx, int n, char **str)
+ *
+ * ARGUMENTS
+ * args - configuration line arguments array
+ * idx - starting index for concatenation
+ * n - maximum number of arguments to concatenate (0 means all)
+ * str - indirect pointer to the result string
+ *
+ * DESCRIPTION
+ * Concatenates arguments starting from index <idx> into a single
+ * space-separated string. The result is built via memprintf() into <*str>.
+ * NULL arguments within the range are treated as empty strings.
+ *
+ * RETURN VALUE
+ * Returns the number of concatenated arguments, or FLT_OTEL_RET_ERROR on
+ * failure.
+ */
+int flt_otel_args_concat(const char **args, int idx, int n, char **str)
+{
+ int i, argc;
+
+ if ((args == NULL) || (str == NULL))
+ return FLT_OTEL_RET_ERROR;
+ else if ((idx < 0) || (n < 0))
+ return FLT_OTEL_RET_ERROR;
+
+ argc = (n == 0) ? flt_otel_args_count(args) : OTELC_MIN(flt_otel_args_count(args), idx + n);
+
+ for (i = idx; i < argc; i++)
+ (void)memprintf(str, "%s%s%s", (*str == NULL) ? "" : *str, (i == idx) ? "" : " ", (args[i] == NULL) ? "" : args[i]);
+
+ OTELC_DBG(DEBUG, "args[%d, %d]: '%s'", idx, argc, (*str == NULL) ? "" : *str);
+
+ return (*str == NULL) ? FLT_OTEL_RET_ERROR : (i - idx);
+}
+
+
+/***
+ * NAME
+ * flt_otel_sample_to_str - sample data to string conversion
+ *
+ * SYNOPSIS
+ * int flt_otel_sample_to_str(const struct sample_data *data, char *value, size_t size, char **err)
+ *
+ * ARGUMENTS
+ * data - sample data to convert
+ * value - output buffer for the string representation
+ * size - output buffer size
+ * err - indirect pointer to error message string
+ *
+ * DESCRIPTION
+ * Converts sample data to its string representation. Handles bool, sint,
+ * IPv4, IPv6, str, and HTTP method types. Boolean values are written as
+ * "0" or "1". Integer values use snprintf(). IP addresses are converted
+ * via inet_ntop(). String values are copied directly. HTTP methods are
+ * resolved to their standard string names; the HTTP_METH_OTHER type uses
+ * the method's raw string data. Binary and unknown types produce an error.
+ *
+ * RETURN VALUE
+ * Returns the number of characters written to <value>,
+ * or FLT_OTEL_RET_ERROR on failure.
+ */
+int flt_otel_sample_to_str(const struct sample_data *data, char *value, size_t size, char **err)
+{
+ int retval = FLT_OTEL_RET_ERROR;
+
+ OTELC_FUNC("%p, %p, %zu, %p:%p", data, value, size, OTELC_DPTR_ARGS(err));
+
+ if ((data == NULL) || (value == NULL) || (size == 0))
+ OTELC_RETURN_INT(retval);
+
+ *value = '\0';
+
+ /* Convert the sample value to a string based on its type. */
+ if (data->type == SMP_T_ANY) {
+ FLT_OTEL_ERR("invalid sample data type %d", data->type);
+ }
+ else if (data->type == SMP_T_BOOL) {
+ value[0] = data->u.sint ? '1' : '0';
+ value[1] = '\0';
+
+ retval = 1;
+ }
+ else if (data->type == SMP_T_SINT) {
+ retval = snprintf(value, size, "%lld", data->u.sint);
+ }
+ else if (data->type == SMP_T_ADDR) {
+ /* This type is never used to qualify a sample. */
+ }
+ else if (data->type == SMP_T_IPV4) {
+ if (INET_ADDRSTRLEN > size)
+ FLT_OTEL_ERR("sample data size too large");
+ else if (inet_ntop(AF_INET, &(data->u.ipv4), value, INET_ADDRSTRLEN) == NULL)
+ FLT_OTEL_ERR("invalid IPv4 address");
+ else
+ retval = strlen(value);
+ }
+ else if (data->type == SMP_T_IPV6) {
+ if (INET6_ADDRSTRLEN > size)
+ FLT_OTEL_ERR("sample data size too large");
+ else if (inet_ntop(AF_INET6, &(data->u.ipv6), value, INET6_ADDRSTRLEN) == NULL)
+ FLT_OTEL_ERR("invalid IPv6 address");
+ else
+ retval = strlen(value);
+ }
+ else if (data->type == SMP_T_STR) {
+ if (data->u.str.data >= size) {
+ FLT_OTEL_ERR("sample data size too large");
+ }
+ else if (data->u.str.data > 0) {
+ retval = data->u.str.data;
+ (void)memcpy(value, data->u.str.area, retval);
+ value[retval] = '\0';
+ }
+ else {
+ /*
+ * There is no content to add but we will still return
+ * the correct status.
+ */
+ retval = 0;
+ }
+ }
+ else if (data->type == SMP_T_BIN) {
+ FLT_OTEL_ERR("invalid sample data type %d", data->type);
+ }
+ else if (data->type != SMP_T_METH) {
+ FLT_OTEL_ERR("invalid sample data type %d", data->type);
+ }
+ else if (OTELC_IN_RANGE(data->u.meth.meth, HTTP_METH_OPTIONS, HTTP_METH_CONNECT)) {
+#define FLT_OTEL_HTTP_METH_DEF(a) { #a, FLT_OTEL_STR_SIZE(#a) },
+ static const struct {
+ const char *str;
+ size_t len;
+ } http_meth_str[] = { FLT_OTEL_HTTP_METH_DEFINES };
+#undef FLT_OTEL_HTTP_METH_DEF
+
+ retval = http_meth_str[data->u.meth.meth].len;
+ (void)memcpy(value, http_meth_str[data->u.meth.meth].str, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_OTHER) {
+ if (data->u.meth.str.data >= size) {
+ FLT_OTEL_ERR("sample data size too large");
+ } else {
+ retval = data->u.meth.str.data;
+ (void)memcpy(value, data->u.meth.str.area, retval);
+ value[retval] = '\0';
+ }
+ }
+ else {
+ FLT_OTEL_ERR("invalid HTTP method");
+ }
+
+ if (retval != FLT_OTEL_RET_ERROR)
+ OTELC_DBG(DEBUG, "sample value (%d): '%.*s' %d", data->type, retval, value, retval);
+
+ OTELC_RETURN_INT(retval);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */