]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: otel: added CLI commands for runtime filter management
authorMiroslav Zagorac <mzagorac@haproxy.com>
Sun, 12 Apr 2026 09:31:30 +0000 (11:31 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Mon, 13 Apr 2026 07:23:26 +0000 (09:23 +0200)
Added HAProxy CLI commands that allow runtime inspection and modification
of OTel filter settings without requiring a configuration reload.

The new cli.c module registers CLI keywords under the "otel" prefix and
implements the following commands: flt_otel_cli_parse_status() displays a
comprehensive status report of all OTel filter instances including filter
ID, proxy, disabled state, hard-error mode, logging state, rate limit,
analyzer bits, and SDK diagnostic message count;
flt_otel_cli_parse_disabled() enables or disables filtering across all
instances; flt_otel_cli_parse_option() toggles the hard-error mode that
controls whether errors disable the filter for a stream or are silently
ignored; flt_otel_cli_parse_logging() manages the logging state with
support for off, on, and dontlog-normal modes; flt_otel_cli_parse_rate()
adjusts the sampling rate limit as a floating-point percentage; and
flt_otel_cli_parse_debug() sets the debug verbosity level in debug builds.
All modifications are applied atomically across every OTel filter instance
in every proxy.

The CLI initialization is called from flt_otel_ops_init() during filter
startup via flt_otel_cli_init(), which registers the keyword table through
cli_register_kw().

Supporting changes include the FLT_OTEL_U32_FLOAT macro for converting the
internal uint32_t rate representation to a human-readable percentage, the
FLT_OTEL_PROXIES_LIST_START/END iteration macros for traversing all OTel
filter instances across the proxy list, and flt_otel_filters_dump() for
debug logging of filter instances.

addons/otel/Makefile
addons/otel/include/cli.h [new file with mode: 0644]
addons/otel/include/define.h
addons/otel/include/include.h
addons/otel/include/util.h
addons/otel/src/cli.c [new file with mode: 0644]
addons/otel/src/filter.c
addons/otel/src/util.c

index 74af20708016a2e9eb9e9968fa64bc2875a73a69..7e246ae34dfc3c0287066f5392721bb5c84c8cd4 100644 (file)
@@ -52,6 +52,7 @@ $(error OpenTelemetry C wrapper : can't find library)
 endif
 
 OPTIONS_OBJS += \
+       addons/otel/src/cli.o    \
        addons/otel/src/conf.o   \
        addons/otel/src/event.o  \
        addons/otel/src/filter.o \
diff --git a/addons/otel/include/cli.h b/addons/otel/include/cli.h
new file mode 100644 (file)
index 0000000..fa5fe04
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#ifndef _OTEL_CLI_H_
+#define _OTEL_CLI_H_
+
+#define FLT_OTEL_CLI_CMD                 "flt-otel"
+
+#define FLT_OTEL_CLI_LOGGING_OFF         "off"
+#define FLT_OTEL_CLI_LOGGING_ON          "on"
+#define FLT_OTEL_CLI_LOGGING_NOLOGNORM   "dontlog-normal"
+#define FLT_OTEL_CLI_LOGGING_STATE(a)    (((a) & FLT_OTEL_LOGGING_ON) ? (((a) & FLT_OTEL_LOGGING_NOLOGNORM) ? "enabled, " FLT_OTEL_CLI_LOGGING_NOLOGNORM : "enabled") : "disabled")
+
+#define FLT_OTEL_CLI_MSG_CAT(a)          (((a) == NULL) ? "" : (a)), (((a) == NULL) ? "" : "\n")
+
+
+/* Register CLI keywords for the OTel filter. */
+void flt_otel_cli_init(void);
+
+#endif /* _OTEL_CLI_H_ */
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
index a4a8130b6f2e8001881fe5c8afdcf1e3ad937036..085869f50f0a29b27654e6feffc59c096a860efc 100644 (file)
@@ -9,9 +9,16 @@
 /* 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 uint32_t rate value to a floating-point percentage. */
+#define FLT_OTEL_U32_FLOAT(a)        ((a) * 100.0 / UINT32_MAX)
+
 /* 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))
 
+#define FLT_OTEL_STR_DASH_72         "------------------------------------------------------------------------"
+#define FLT_OTEL_STR_DASH_78         FLT_OTEL_STR_DASH_72 "------"
+#define FLT_OTEL_STR_FLAG_YN(a)      ((a) ? "yes" : "no")
+
 /* Compile-time string length excluding the null terminator. */
 #define FLT_OTEL_STR_SIZE(a)         (sizeof(a) - 1)
 
index e4047d2f13b7b7788923f176f87042881e756fe7..e59fec4008e29b761a17c7f09a281998e89b9bd6 100644 (file)
@@ -28,6 +28,7 @@
 #include "config.h"
 #include "debug.h"
 #include "define.h"
+#include "cli.h"
 #include "event.h"
 #include "conf.h"
 #include "conf_funcs.h"
index aba8722f0ba5bd0e83d27d749359f9320a41c47b..96ee282b1092915df0301a6ec282802985b08736 100644 (file)
        FLT_OTEL_HTTP_METH_DEF(TRACE)   \
        FLT_OTEL_HTTP_METH_DEF(CONNECT)
 
+/* Iterate over all OTel filter configurations across all proxies. */
+#define FLT_OTEL_PROXIES_LIST_START()                                           \
+       do {                                                                    \
+               struct flt_conf *fconf;                                         \
+               struct proxy    *px;                                            \
+                                                                               \
+               for (px = proxies_list; px != NULL; px = px->next)              \
+                       list_for_each_entry(fconf, &(px->filter_configs), list) \
+                               if (fconf->id == otel_flt_id) {                 \
+                                       struct flt_otel_conf *conf = fconf->conf;
+#define FLT_OTEL_PROXIES_LIST_END() \
+                               }   \
+       } while (0)
+
 #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
 #endif
 
 
-#ifdef DEBUG_OTEL
+#ifndef DEBUG_OTEL
+#  define flt_otel_filters_dump()   while (0)
+#else
 /* Dump configuration arguments for debugging. */
 void        flt_otel_args_dump(const char **args);
 
+/* Dump all OTel filter configurations across all proxies. */
+void        flt_otel_filters_dump(void);
+
 /* Return a label string identifying a channel direction. */
 const char *flt_otel_chn_label(const struct channel *chn);
 
diff --git a/addons/otel/src/cli.c b/addons/otel/src/cli.c
new file mode 100644 (file)
index 0000000..2eda9d4
--- /dev/null
@@ -0,0 +1,455 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "../include/include.h"
+
+
+/***
+ * NAME
+ *   flt_otel_cli_set_msg - CLI response message setter
+ *
+ * SYNOPSIS
+ *   static int flt_otel_cli_set_msg(struct appctx *appctx, char *err, char *msg)
+ *
+ * ARGUMENTS
+ *   appctx - CLI application context
+ *   err    - error message string (or NULL)
+ *   msg    - informational message string (or NULL)
+ *
+ * DESCRIPTION
+ *   Sets the CLI response message and state for the given <appctx>.  If <err>
+ *   is non-NULL, it is passed to cli_dynerr() and <msg> is freed; otherwise
+ *   <msg> is passed to cli_dynmsg() at LOG_INFO severity.  When neither message
+ *   is available, the function returns 0 without changing state.
+ *
+ * RETURN VALUE
+ *   Returns 1 when a message was set, or 0 when both pointers were NULL.
+ */
+static int flt_otel_cli_set_msg(struct appctx *appctx, char *err, char *msg)
+{
+       OTELC_FUNC("%p, %p, %p", appctx, err, msg);
+
+       if ((appctx == NULL) || ((err == NULL) && (msg == NULL)))
+               OTELC_RETURN_INT(0);
+
+       if (err != NULL) {
+               OTELC_DBG(INFO, "err(%d): \"%s\"", appctx->st0, err);
+
+               OTELC_SFREE(msg);
+               OTELC_RETURN_INT(cli_dynerr(appctx, err));
+       }
+
+       OTELC_DBG(INFO, "msg(%d): \"%s\"", appctx->st0, msg);
+
+       OTELC_RETURN_INT(cli_dynmsg(appctx, LOG_INFO, msg));
+}
+
+
+#ifdef DEBUG_OTEL
+
+/***
+ * NAME
+ *   flt_otel_cli_parse_debug - CLI debug level handler
+ *
+ * SYNOPSIS
+ *   static int flt_otel_cli_parse_debug(char **args, char *payload, struct appctx *appctx, void *private)
+ *
+ * ARGUMENTS
+ *   args    - CLI command arguments array
+ *   payload - CLI command payload string
+ *   appctx  - CLI application context
+ *   private - unused private data pointer
+ *
+ * DESCRIPTION
+ *   Handles the "otel debug [level]" CLI command.  When a level argument is
+ *   provided in <args[2]>, parses it as an integer in the range
+ *   [0, OTELC_DBG_LEVEL_MASK] and atomically stores it as the global debug
+ *   level.  Setting a level requires admin access level.  When no argument is
+ *   given, reports the current debug level.  The response message includes the
+ *   debug level in both decimal and hexadecimal format.
+ *
+ * RETURN VALUE
+ *   Returns 1, or 0 on memory allocation failure.
+ */
+static int flt_otel_cli_parse_debug(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       char *err = NULL, *msg = NULL;
+
+       OTELC_FUNC("%p, \"%s\", %p, %p", args, OTELC_STR_ARG(payload), appctx, private);
+
+       FLT_OTEL_ARGS_DUMP();
+
+       if (FLT_OTEL_ARG_ISVALID(2)) {
+               int64_t value;
+
+               if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+                       OTELC_RETURN_INT(1);
+
+               if (flt_otel_strtoll(args[2], &value, 0, OTELC_DBG_LEVEL_MASK, &err)) {
+                       _HA_ATOMIC_STORE(&otelc_dbg_level, (int)value);
+
+                       (void)memprintf(&msg, FLT_OTEL_CLI_CMD " : debug level set to %d (0x%04x)", (int)value, (int)value);
+               }
+       } else {
+               int value = _HA_ATOMIC_LOAD(&otelc_dbg_level);
+
+               (void)memprintf(&msg, FLT_OTEL_CLI_CMD " : current debug level is %d (0x%04x)", value, value);
+       }
+
+       OTELC_RETURN_INT(flt_otel_cli_set_msg(appctx, err, msg));
+}
+
+#endif /* DEBUG_OTEL */
+
+
+/***
+ * NAME
+ *   flt_otel_cli_parse_disabled - CLI enable/disable handler
+ *
+ * SYNOPSIS
+ *   static int flt_otel_cli_parse_disabled(char **args, char *payload, struct appctx *appctx, void *private)
+ *
+ * ARGUMENTS
+ *   args    - CLI command arguments array
+ *   payload - CLI command payload string
+ *   appctx  - CLI application context
+ *   private - boolean flag cast to pointer (1 = disable, 0 = enable)
+ *
+ * DESCRIPTION
+ *   Handles the "otel enable" and "otel disable" CLI commands.  The <private>
+ *   parameter determines the action: a value of 1 disables the filter, 0
+ *   enables it.  Requires admin access level.  The flag_disabled field is
+ *   atomically updated for all OTel filter instances across all proxies.
+ *
+ * RETURN VALUE
+ *   Returns 1, or 0 if no OTel filter instances are configured or on memory
+ *   allocation failure.
+ */
+static int flt_otel_cli_parse_disabled(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       char *msg = NULL;
+       bool  value = (uintptr_t)private;
+
+       OTELC_FUNC("%p, \"%s\", %p, %p", args, OTELC_STR_ARG(payload), appctx, private);
+
+       FLT_OTEL_ARGS_DUMP();
+
+       if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+               OTELC_RETURN_INT(1);
+
+       FLT_OTEL_PROXIES_LIST_START() {
+               _HA_ATOMIC_STORE(&(conf->instr->flag_disabled), value);
+
+               (void)memprintf(&msg, "%s%s" FLT_OTEL_CLI_CMD " : filter %sabled", FLT_OTEL_CLI_MSG_CAT(msg), value ? "dis" : "en");
+       } FLT_OTEL_PROXIES_LIST_END();
+
+       OTELC_RETURN_INT(flt_otel_cli_set_msg(appctx, NULL, msg));
+}
+
+
+/***
+ * NAME
+ *   flt_otel_cli_parse_option - CLI error mode handler
+ *
+ * SYNOPSIS
+ *   static int flt_otel_cli_parse_option(char **args, char *payload, struct appctx *appctx, void *private)
+ *
+ * ARGUMENTS
+ *   args    - CLI command arguments array
+ *   payload - CLI command payload string
+ *   appctx  - CLI application context
+ *   private - boolean flag cast to pointer (1 = hard-errors, 0 = soft-errors)
+ *
+ * DESCRIPTION
+ *   Handles the "otel hard-errors" and "otel soft-errors" CLI commands.  The
+ *   <private> parameter determines the error mode: a value of 1 enables
+ *   hard-error mode (filter failure aborts the stream), 0 enables soft-error
+ *   mode (failures are silently ignored).  Requires admin access level.  The
+ *   flag_harderr field is atomically updated for all OTel filter instances
+ *   across all proxies.
+ *
+ * RETURN VALUE
+ *   Returns 1, or 0 if no OTel filter instances are configured or on memory
+ *   allocation failure.
+ */
+static int flt_otel_cli_parse_option(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       char *msg = NULL;
+       bool  value = (uintptr_t)private;
+
+       OTELC_FUNC("%p, \"%s\", %p, %p", args, OTELC_STR_ARG(payload), appctx, private);
+
+       FLT_OTEL_ARGS_DUMP();
+
+       if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+               OTELC_RETURN_INT(1);
+
+       FLT_OTEL_PROXIES_LIST_START() {
+               _HA_ATOMIC_STORE(&(conf->instr->flag_harderr), value);
+
+               (void)memprintf(&msg, "%s%s" FLT_OTEL_CLI_CMD " : filter set %s-errors", FLT_OTEL_CLI_MSG_CAT(msg), value ? "hard" : "soft");
+       } FLT_OTEL_PROXIES_LIST_END();
+
+       OTELC_RETURN_INT(flt_otel_cli_set_msg(appctx, NULL, msg));
+}
+
+
+/***
+ * NAME
+ *   flt_otel_cli_parse_logging - CLI logging state handler
+ *
+ * SYNOPSIS
+ *   static int flt_otel_cli_parse_logging(char **args, char *payload, struct appctx *appctx, void *private)
+ *
+ * ARGUMENTS
+ *   args    - CLI command arguments array
+ *   payload - CLI command payload string
+ *   appctx  - CLI application context
+ *   private - unused private data pointer
+ *
+ * DESCRIPTION
+ *   Handles the "otel logging [state]" CLI command.  When a state argument is
+ *   provided in <args[2]>, it is matched against "off", "on", or "nolognorm"
+ *   and the logging field is atomically updated for all OTel filter instances.
+ *   Setting a value requires admin access level.  When no argument is given,
+ *   reports the current logging state for all instances.  Invalid values
+ *   produce an error with the accepted options listed.
+ *
+ * RETURN VALUE
+ *   Returns 1, or 0 if no OTel filter instances are configured (and no error
+ *   occurred) or on memory allocation failure.
+ */
+static int flt_otel_cli_parse_logging(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       char    *err = NULL, *msg = NULL;
+       bool     flag_set = false;
+       uint8_t  value;
+
+       OTELC_FUNC("%p, \"%s\", %p, %p", args, OTELC_STR_ARG(payload), appctx, private);
+
+       FLT_OTEL_ARGS_DUMP();
+
+       if (FLT_OTEL_ARG_ISVALID(2)) {
+               if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+                       OTELC_RETURN_INT(1);
+
+               if (strcasecmp(args[2], FLT_OTEL_CLI_LOGGING_OFF) == 0) {
+                       flag_set = true;
+                       value    = FLT_OTEL_LOGGING_OFF;
+               }
+               else if (strcasecmp(args[2], FLT_OTEL_CLI_LOGGING_ON) == 0) {
+                       flag_set = true;
+                       value    = FLT_OTEL_LOGGING_ON;
+               }
+               else if (strcasecmp(args[2], FLT_OTEL_CLI_LOGGING_NOLOGNORM) == 0) {
+                       flag_set = true;
+                       value    = FLT_OTEL_LOGGING_ON | FLT_OTEL_LOGGING_NOLOGNORM;
+               }
+               else {
+                       (void)memprintf(&err, "'%s' : invalid value, use <" FLT_OTEL_CLI_LOGGING_OFF " | " FLT_OTEL_CLI_LOGGING_ON " | " FLT_OTEL_CLI_LOGGING_NOLOGNORM ">", args[2]);
+               }
+
+               if (flag_set) {
+                       FLT_OTEL_PROXIES_LIST_START() {
+                               _HA_ATOMIC_STORE(&(conf->instr->logging), value);
+
+                               (void)memprintf(&msg, "%s%s" FLT_OTEL_CLI_CMD " : logging is %s", FLT_OTEL_CLI_MSG_CAT(msg), FLT_OTEL_CLI_LOGGING_STATE(value));
+                       } FLT_OTEL_PROXIES_LIST_END();
+               }
+       } else {
+               FLT_OTEL_PROXIES_LIST_START() {
+                       value = _HA_ATOMIC_LOAD(&(conf->instr->logging));
+
+                       (void)memprintf(&msg, "%s%s" FLT_OTEL_CLI_CMD " : logging is currently %s", FLT_OTEL_CLI_MSG_CAT(msg), FLT_OTEL_CLI_LOGGING_STATE(value));
+               } FLT_OTEL_PROXIES_LIST_END();
+       }
+
+       OTELC_RETURN_INT(flt_otel_cli_set_msg(appctx, err, msg));
+}
+
+
+/***
+ * NAME
+ *   flt_otel_cli_parse_rate - CLI rate limit handler
+ *
+ * SYNOPSIS
+ *   static int flt_otel_cli_parse_rate(char **args, char *payload, struct appctx *appctx, void *private)
+ *
+ * ARGUMENTS
+ *   args    - CLI command arguments array
+ *   payload - CLI command payload string
+ *   appctx  - CLI application context
+ *   private - unused private data pointer
+ *
+ * DESCRIPTION
+ *   Handles the "otel rate [value]" CLI command.  When a value argument is
+ *   provided in <args[2]>, it is parsed as a floating-point number in the
+ *   range [0.0, 100.0], converted to a fixed-point uint32_t representation,
+ *   and atomically stored as the rate limit for all OTel filter instances.
+ *   Setting a value requires admin access level.  When no argument is given,
+ *   reports the current rate limit percentage for all instances.
+ *
+ * RETURN VALUE
+ *   Returns 1, or 0 if no OTel filter instances are configured (and no error
+ *   occurred) or on memory allocation failure.
+ */
+static int flt_otel_cli_parse_rate(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       char *err = NULL, *msg = NULL;
+
+       OTELC_FUNC("%p, \"%s\", %p, %p", args, OTELC_STR_ARG(payload), appctx, private);
+
+       FLT_OTEL_ARGS_DUMP();
+
+       if (FLT_OTEL_ARG_ISVALID(2)) {
+               double value;
+
+               if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+                       OTELC_RETURN_INT(1);
+
+               if (flt_otel_strtod(args[2], &value, 0.0, 100.0, &err)) {
+                       FLT_OTEL_PROXIES_LIST_START() {
+                               _HA_ATOMIC_STORE(&(conf->instr->rate_limit), FLT_OTEL_FLOAT_U32(value));
+
+                               (void)memprintf(&msg, "%s%s" FLT_OTEL_CLI_CMD " : rate limit set to %.2f", FLT_OTEL_CLI_MSG_CAT(msg), value);
+                       } FLT_OTEL_PROXIES_LIST_END();
+               }
+       } else {
+               FLT_OTEL_PROXIES_LIST_START() {
+                       uint32_t value = _HA_ATOMIC_LOAD(&(conf->instr->rate_limit));
+
+                       (void)memprintf(&msg, "%s%s" FLT_OTEL_CLI_CMD " : current rate limit is %.2f", FLT_OTEL_CLI_MSG_CAT(msg), FLT_OTEL_U32_FLOAT(value));
+               } FLT_OTEL_PROXIES_LIST_END();
+       }
+
+       OTELC_RETURN_INT(flt_otel_cli_set_msg(appctx, err, msg));
+}
+
+
+/***
+ * NAME
+ *   flt_otel_cli_parse_status - CLI status display handler
+ *
+ * SYNOPSIS
+ *   static int flt_otel_cli_parse_status(char **args, char *payload, struct appctx *appctx, void *private)
+ *
+ * ARGUMENTS
+ *   args    - CLI command arguments array
+ *   payload - CLI command payload string
+ *   appctx  - CLI application context
+ *   private - unused private data pointer
+ *
+ * DESCRIPTION
+ *   Handles the "otel status" CLI command.  Builds a formatted status report
+ *   for all OTel filter instances across all proxies.  The report includes
+ *   the library version, proxy name, configuration file path, group and scope
+ *   counts, disable counts, instrumentation ID, tracer state, rate limit, error
+ *   mode, disabled state, logging state, and analyzer bits.  When DEBUG_OTEL is
+ *   enabled, the current debug level is also included.
+ *
+ * RETURN VALUE
+ *   Returns 1, or 0 on memory allocation failure.
+ */
+static int flt_otel_cli_parse_status(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       const char *nl = "";
+       char       *msg = NULL;
+
+       OTELC_FUNC("%p, \"%s\", %p, %p", args, OTELC_STR_ARG(payload), appctx, private);
+
+       FLT_OTEL_ARGS_DUMP();
+       flt_otel_filters_dump();
+
+       (void)memprintf(&msg, " " FLT_OTEL_OPT_NAME " filter status\n" FLT_OTEL_STR_DASH_78 "\n");
+       (void)memprintf(&msg, "%s   library:       C++ " OTELCPP_VERSION ", C wrapper %s\n", msg, otelc_version());
+#ifdef DEBUG_OTEL
+       (void)memprintf(&msg, "%s   debug level:   0x%02hhx\n", msg, otelc_dbg_level);
+#endif
+       (void)memprintf(&msg, "%s   dropped count: %" PRId64 "/%" PRId64 " %" PRIu64 "\n", msg, otelc_processor_dropped_count(0), otelc_processor_dropped_count(1), _HA_ATOMIC_LOAD(&flt_otel_drop_cnt));
+
+       FLT_OTEL_PROXIES_LIST_START() {
+               struct flt_otel_conf_group *grp;
+               struct flt_otel_conf_scope *scp;
+               int                         n_groups = 0, n_scopes = 0;
+
+               list_for_each_entry(grp, &(conf->groups), list)
+                       n_groups++;
+               list_for_each_entry(scp, &(conf->scopes), list)
+                       n_scopes++;
+
+               (void)memprintf(&msg, "%s\n%s   proxy %s, filter %s\n", msg, nl, px->id, conf->id);
+               (void)memprintf(&msg, "%s     configuration: %s\n", msg, conf->cfg_file);
+               (void)memprintf(&msg, "%s     groups/scopes: %d/%d\n\n", msg, n_groups, n_scopes);
+               (void)memprintf(&msg, "%s       instrumentation %s\n", msg, conf->instr->id);
+               (void)memprintf(&msg, "%s       configuration: %s\n", msg, conf->instr->config);
+               (void)memprintf(&msg, "%s       tracer:        %s\n", msg, (conf->instr->tracer != NULL) ? "active" : "not initialized");
+               (void)memprintf(&msg, "%s       rate limit:    %.2f %%\n", msg, FLT_OTEL_U32_FLOAT(_HA_ATOMIC_LOAD(&(conf->instr->rate_limit))));
+               (void)memprintf(&msg, "%s       hard errors:   %s\n", msg, FLT_OTEL_STR_FLAG_YN(_HA_ATOMIC_LOAD(&(conf->instr->flag_harderr))));
+               (void)memprintf(&msg, "%s       disabled:      %s\n", msg, FLT_OTEL_STR_FLAG_YN(_HA_ATOMIC_LOAD(&(conf->instr->flag_disabled))));
+               (void)memprintf(&msg, "%s       logging:       %s\n", msg, FLT_OTEL_CLI_LOGGING_STATE(_HA_ATOMIC_LOAD(&(conf->instr->logging))));
+               (void)memprintf(&msg, "%s       analyzers:     %08x", msg, conf->instr->analyzers);
+#ifdef FLT_OTEL_USE_COUNTERS
+               (void)memprintf(&msg, "%s\n\n     counters\n", msg);
+               (void)memprintf(&msg, "%s       attached: %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", msg, conf->cnt.attached[0], conf->cnt.attached[1], conf->cnt.attached[2], conf->cnt.attached[3]);
+               (void)memprintf(&msg, "%s       disabled: %" PRIu64 " %" PRIu64, msg, conf->cnt.disabled[0], conf->cnt.disabled[1]);
+#endif
+
+               nl = "\n";
+       } FLT_OTEL_PROXIES_LIST_END();
+
+       OTELC_RETURN_INT(flt_otel_cli_set_msg(appctx, NULL, msg));
+}
+
+
+/* CLI command table for the OTel filter. */
+static struct cli_kw_list cli_kws = { { }, {
+#ifdef DEBUG_OTEL
+       { { FLT_OTEL_CLI_CMD, "debug", NULL }, FLT_OTEL_CLI_CMD " debug [level]                  : set the OTEL filter debug level (default: get current debug level)", flt_otel_cli_parse_debug, NULL, NULL, NULL, ACCESS_LVL_ADMIN },
+#endif
+       { { FLT_OTEL_CLI_CMD, "disable", NULL }, FLT_OTEL_CLI_CMD " disable                        : disable the OTEL filter", flt_otel_cli_parse_disabled, NULL, NULL, (void *)1, ACCESS_LVL_ADMIN },
+       { { FLT_OTEL_CLI_CMD, "enable", NULL }, FLT_OTEL_CLI_CMD " enable                         : enable the OTEL filter", flt_otel_cli_parse_disabled, NULL, NULL, (void *)0, ACCESS_LVL_ADMIN },
+       { { FLT_OTEL_CLI_CMD, "soft-errors", NULL }, FLT_OTEL_CLI_CMD " soft-errors                    : disable hard-errors mode", flt_otel_cli_parse_option, NULL, NULL, (void *)0, ACCESS_LVL_ADMIN },
+       { { FLT_OTEL_CLI_CMD, "hard-errors", NULL }, FLT_OTEL_CLI_CMD " hard-errors                    : enable hard-errors mode", flt_otel_cli_parse_option, NULL, NULL, (void *)1, ACCESS_LVL_ADMIN },
+       { { FLT_OTEL_CLI_CMD, "logging",  NULL }, FLT_OTEL_CLI_CMD " logging [state]                : set logging state (default: get current logging state)", flt_otel_cli_parse_logging, NULL, NULL, NULL, ACCESS_LVL_ADMIN },
+       { { FLT_OTEL_CLI_CMD, "rate", NULL }, FLT_OTEL_CLI_CMD " rate [value]                   : set the rate limit (default: get current rate value)", flt_otel_cli_parse_rate, NULL, NULL, NULL, ACCESS_LVL_ADMIN },
+       { { FLT_OTEL_CLI_CMD, "status", NULL }, FLT_OTEL_CLI_CMD " status                         : show the OTEL filter status", flt_otel_cli_parse_status, NULL, NULL, NULL, 0 },
+       { /* END */ }
+}};
+
+
+/***
+ * NAME
+ *   flt_otel_cli_init - CLI keyword registration
+ *
+ * SYNOPSIS
+ *   void flt_otel_cli_init(void)
+ *
+ * ARGUMENTS
+ *   This function takes no arguments.
+ *
+ * DESCRIPTION
+ *   Registers the OTel filter CLI keywords with the HAProxy CLI subsystem.
+ *   The keywords include commands for enable/disable, error mode, logging,
+ *   rate limit, status display, and (when DEBUG_OTEL is defined) debug level
+ *   management.
+ *
+ * RETURN VALUE
+ *   This function does not return a value.
+ */
+void flt_otel_cli_init(void)
+{
+       OTELC_FUNC("");
+
+       /* Register CLI keywords. */
+       cli_register_kw(&cli_kws);
+
+       OTELC_RETURN();
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
index 939909201a878a94a52d1ce14ed48c4c0cd9c9e5..de4a19a68f4199c773e6c0aa65c30f86e6919967 100644 (file)
@@ -367,6 +367,8 @@ static int flt_otel_ops_init(struct proxy *p, struct flt_conf *fconf)
        if (conf == NULL)
                OTELC_RETURN_INT(retval);
 
+       flt_otel_cli_init();
+
        /*
         * Initialize the OpenTelemetry library.
         */
index 20cdbad24d34c39aed0ec04f58522ff2b5c71633..c54e741e5572ff9a08ae4639d10160af40c8176b 100644 (file)
@@ -38,6 +38,45 @@ void flt_otel_args_dump(const char **args)
 }
 
 
+/***
+ * NAME
+ *   flt_otel_filters_dump - debug OTel filter instances dump
+ *
+ * SYNOPSIS
+ *   void flt_otel_filters_dump(void)
+ *
+ * ARGUMENTS
+ *   This function takes no arguments.
+ *
+ * DESCRIPTION
+ *   Dumps all OTel filter instances across all proxies.  Iterates the global
+ *   proxy list, logging each proxy name and its associated OTel filter IDs.
+ *
+ * RETURN VALUE
+ *   This function does not return a value.
+ */
+void flt_otel_filters_dump(void)
+{
+       struct flt_conf *fconf;
+       struct proxy    *px;
+
+       OTELC_FUNC("");
+
+       for (px = proxies_list; px != NULL; px = px->next) {
+               OTELC_DBG(NOTICE, "proxy '%s'", px->id);
+
+               list_for_each_entry(fconf, &(px->filter_configs), list)
+                       if (fconf->id == otel_flt_id) {
+                               struct flt_otel_conf *conf = fconf->conf;
+
+                               OTELC_DBG(NOTICE, "  OTEL filter '%s'", conf->id);
+                       }
+       }
+
+       OTELC_RETURN();
+}
+
+
 /***
  * NAME
  *   flt_otel_chn_label - channel direction label