]> git.kaiwu.me - haproxy.git/commitdiff
CLEANUP: otel: move opentelemetry outside haproxy sources
authorWilliam Lallemand <wlallemand@haproxy.com>
Mon, 4 May 2026 12:18:40 +0000 (14:18 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Mon, 4 May 2026 12:18:40 +0000 (14:18 +0200)
The opentelemetry addons now live outside haproxy sources and is
available at https://github.com/haproxytech/haproxy-opentelemetry/

The addon must be built using the EXTRA_MAKE option from HAProxy
Makefile:

$ PKG_CONFIG_PATH=/opt/lib/pkgconfig make -j8 TARGET=linux-glibc
  EXTRA_MAKE="/tmp/a/a/haproxy-opentelemetry" OTEL_DEBUG=1 OTEL_USE_VARS=1

83 files changed:
addons/otel/AUTHORS [deleted file]
addons/otel/MAINTAINERS [deleted file]
addons/otel/Makefile [deleted file]
addons/otel/README [deleted file]
addons/otel/README-conf [deleted file]
addons/otel/README-configuration [deleted file]
addons/otel/README-design [deleted file]
addons/otel/README-func [deleted file]
addons/otel/README-implementation [deleted file]
addons/otel/README-misc [deleted file]
addons/otel/README.md [deleted file]
addons/otel/include/cli.h [deleted file]
addons/otel/include/conf.h [deleted file]
addons/otel/include/conf_funcs.h [deleted file]
addons/otel/include/config.h [deleted file]
addons/otel/include/debug.h [deleted file]
addons/otel/include/define.h [deleted file]
addons/otel/include/event.h [deleted file]
addons/otel/include/filter.h [deleted file]
addons/otel/include/group.h [deleted file]
addons/otel/include/http.h [deleted file]
addons/otel/include/include.h [deleted file]
addons/otel/include/otelc.h [deleted file]
addons/otel/include/parser.h [deleted file]
addons/otel/include/pool.h [deleted file]
addons/otel/include/scope.h [deleted file]
addons/otel/include/util.h [deleted file]
addons/otel/include/vars.h [deleted file]
addons/otel/src/cli.c [deleted file]
addons/otel/src/conf.c [deleted file]
addons/otel/src/event.c [deleted file]
addons/otel/src/filter.c [deleted file]
addons/otel/src/group.c [deleted file]
addons/otel/src/http.c [deleted file]
addons/otel/src/otelc.c [deleted file]
addons/otel/src/parser.c [deleted file]
addons/otel/src/pool.c [deleted file]
addons/otel/src/scope.c [deleted file]
addons/otel/src/util.c [deleted file]
addons/otel/src/vars.c [deleted file]
addons/otel/test/README-cmp [deleted file]
addons/otel/test/README-ctx [deleted file]
addons/otel/test/README-empty [deleted file]
addons/otel/test/README-fe-be [deleted file]
addons/otel/test/README-full [deleted file]
addons/otel/test/README-sa [deleted file]
addons/otel/test/README-speed-cmp [deleted file]
addons/otel/test/README-speed-ctx [deleted file]
addons/otel/test/README-speed-fe-be [deleted file]
addons/otel/test/README-speed-sa [deleted file]
addons/otel/test/README-test-speed [deleted file]
addons/otel/test/be/haproxy.cfg [deleted file]
addons/otel/test/be/otel.cfg [deleted file]
addons/otel/test/be/otel.yml [deleted file]
addons/otel/test/cmp/haproxy.cfg [deleted file]
addons/otel/test/cmp/otel.cfg [deleted file]
addons/otel/test/cmp/otel.yml [deleted file]
addons/otel/test/copy-yml.sh [deleted file]
addons/otel/test/ctx/haproxy.cfg [deleted file]
addons/otel/test/ctx/otel.cfg [deleted file]
addons/otel/test/ctx/otel.yml [deleted file]
addons/otel/test/empty/haproxy.cfg [deleted file]
addons/otel/test/empty/otel.cfg [deleted file]
addons/otel/test/empty/otel.yml [deleted file]
addons/otel/test/fe/haproxy.cfg [deleted file]
addons/otel/test/fe/otel.cfg [deleted file]
addons/otel/test/fe/otel.yml [deleted file]
addons/otel/test/full/haproxy.cfg [deleted file]
addons/otel/test/full/otel.cfg [deleted file]
addons/otel/test/full/otel.yml [deleted file]
addons/otel/test/haproxy-common.cfg [deleted file]
addons/otel/test/index.html [deleted file]
addons/otel/test/run-cmp.sh [deleted symlink]
addons/otel/test/run-ctx.sh [deleted symlink]
addons/otel/test/run-empty.sh [deleted symlink]
addons/otel/test/run-fe-be.sh [deleted file]
addons/otel/test/run-full.sh [deleted symlink]
addons/otel/test/run-sa.sh [deleted symlink]
addons/otel/test/run-test-config.sh [deleted file]
addons/otel/test/sa/haproxy.cfg [deleted file]
addons/otel/test/sa/otel.cfg [deleted file]
addons/otel/test/sa/otel.yml [deleted file]
addons/otel/test/test-speed.sh [deleted file]

diff --git a/addons/otel/AUTHORS b/addons/otel/AUTHORS
deleted file mode 100644 (file)
index 92b2831..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Miroslav Zagorac <mzagorac@haproxy.com>
diff --git a/addons/otel/MAINTAINERS b/addons/otel/MAINTAINERS
deleted file mode 100644 (file)
index 92b2831..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Miroslav Zagorac <mzagorac@haproxy.com>
diff --git a/addons/otel/Makefile b/addons/otel/Makefile
deleted file mode 100644 (file)
index 28ed896..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-# USE_OTEL      : enable the OpenTelemetry filter
-# OTEL_DEBUG    : compile the OpenTelemetry filter in debug mode
-# OTEL_INC      : force the include path to libopentelemetry-c-wrapper
-# OTEL_LIB      : force the lib path to libopentelemetry-c-wrapper
-# OTEL_RUNPATH  : add libopentelemetry-c-wrapper RUNPATH to haproxy executable
-# OTEL_USE_VARS : allows the use of variables for the OpenTelemetry context
-
-OTEL_DEFINE    =
-OTEL_CFLAGS    =
-OTEL_LDFLAGS   =
-OTEL_DEBUG_EXT =
-OTEL_PKGSTAT   =
-OTELC_WRAPPER  = opentelemetry-c-wrapper
-
-ifneq ($(OTEL_DEBUG:0=),)
-OTEL_DEBUG_EXT = _dbg
-OTEL_DEFINE    = -DDEBUG_OTEL
-endif
-
-ifeq ($(OTEL_INC),)
-OTEL_PKGSTAT = $(shell pkg-config --exists $(OTELC_WRAPPER)$(OTEL_DEBUG_EXT); echo $$?)
-OTEL_CFLAGS  = $(shell pkg-config --silence-errors --cflags $(OTELC_WRAPPER)$(OTEL_DEBUG_EXT))
-else
-ifneq ($(wildcard $(OTEL_INC)/$(OTELC_WRAPPER)/.*),)
-OTEL_CFLAGS = -I$(OTEL_INC) $(if $(OTEL_DEBUG),-DOTELC_DBG_MEM)
-endif
-endif
-
-ifeq ($(OTEL_PKGSTAT),)
-ifeq ($(OTEL_CFLAGS),)
-$(error OpenTelemetry C wrapper : can't find headers)
-endif
-else
-ifneq ($(OTEL_PKGSTAT),0)
-$(error OpenTelemetry C wrapper : can't find package)
-endif
-endif
-
-ifeq ($(OTEL_LIB),)
-OTEL_LDFLAGS = $(shell pkg-config --silence-errors --libs $(OTELC_WRAPPER)$(OTEL_DEBUG_EXT))
-else
-ifneq ($(wildcard $(OTEL_LIB)/lib$(OTELC_WRAPPER).*),)
-OTEL_LDFLAGS = -L$(OTEL_LIB) -l$(OTELC_WRAPPER)$(OTEL_DEBUG_EXT)
-ifneq ($(OTEL_RUNPATH),)
-OTEL_LDFLAGS += -Wl,--rpath,$(OTEL_LIB)
-endif
-endif
-endif
-
-ifeq ($(OTEL_LDFLAGS),)
-$(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 \
-       addons/otel/src/group.o  \
-       addons/otel/src/http.o   \
-       addons/otel/src/otelc.o  \
-       addons/otel/src/parser.o \
-       addons/otel/src/pool.o   \
-       addons/otel/src/scope.o  \
-       addons/otel/src/util.o
-
-ifneq ($(OTEL_USE_VARS:0=),)
-OTEL_DEFINE  += -DUSE_OTEL_VARS
-OPTIONS_OBJS += addons/otel/src/vars.o
-
-# Auto-detect whether struct var has a 'name' member.  When present,
-# prefix-based variable scanning can be used instead of the tracking
-# buffer approach.
-OTEL_VAR_HAS_NAME := $(shell awk '/^struct var \{/,/^\}/' include/haproxy/vars-t.h 2>/dev/null | grep -q '[*]name;' && echo 1)
-ifneq ($(OTEL_VAR_HAS_NAME),)
-OTEL_DEFINE += -DUSE_OTEL_VARS_NAME
-endif
-endif
-
-OTEL_CFLAGS := $(OTEL_CFLAGS) -Iaddons/otel/include $(OTEL_DEFINE)
diff --git a/addons/otel/README b/addons/otel/README
deleted file mode 100644 (file)
index f74cd40..0000000
+++ /dev/null
@@ -1,1172 +0,0 @@
-                   -----------------------------------------
-                      The HAProxy OpenTelemetry filter (OTel)
-                                  Version 1.0
-                          ( Last update: 2026-03-18 )
-                   -----------------------------------------
-                           Author : Miroslav Zagorac
-                     Contact : mzagorac at haproxy dot com
-
-
-SUMMARY
---------
-
-  0.    Terms
-  1.    Introduction
-  2.    Build instructions
-  3.    Basic concepts in OpenTelemetry
-  4.    OTel configuration
-  4.1.    OTel scope
-  4.2.    "otel-instrumentation" section
-  4.3.    "otel-scope" section
-  4.4.    "otel-group" section
-  5.    Examples
-  5.1.    Benchmarking results
-  6.    OTel CLI
-  7.    Known bugs and limitations
-
-
-0. Terms
----------
-
-* OTel: The HAProxy OpenTelemetry filter
-
-OTel is the HAProxy filter that allows you to send telemetry data (traces,
-metrics and logs) to observability backends via the OpenTelemetry protocol.
-
-
-1. Introduction
-----------------
-
-Nowadays there is a growing need to divide a process into microservices and
-there is a problem of monitoring the work of the same process.  One way to solve
-this problem is to use a distributed tracing service in a central location.
-
-The OTel filter is the successor to the OpenTracing (OT) filter and is built on
-the OpenTelemetry standard, which unifies distributed tracing, metrics and
-logging into a single observability framework.  Unlike the older OpenTracing
-filter which relied on vendor-specific tracer plugins, the OTel filter uses the
-OpenTelemetry protocol (OTLP) to export data directly to any compatible backend.
-
-The OTel filter is a standard HAProxy filter, so what applies to others also
-applies to this one (of course, by that I mean what is described in the
-documentation, more precisely in the doc/internals/filters.txt file).
-
-The OTel filter activation is done explicitly by specifying it in the HAProxy
-configuration.  If this is not done, the OTel filter in no way participates in
-the work of HAProxy.
-
-As for the impact on HAProxy speed, this is documented with test results located
-in the test directory (see section 5.1).  The speed of operation depends on the
-way the filter is used and the complexity of the configuration.  In typical
-production use with a rate limit of 10% or less, the performance impact should
-be negligible (see the 'rate-limit' keyword).
-
-The OTel filter allows intensive use of ACLs, which can be defined anywhere in
-the configuration.  Thus, it is possible to use the filter only for those
-connections that are of interest to us.
-
-
-2. Build instructions
-----------------------
-
-OTel is the HAProxy filter and as such is compiled together with HAProxy.
-
-To communicate with an OpenTelemetry compatible backend, the OTel filter uses
-the OpenTelemetry C Wrapper library (which again uses the OpenTelemetry C++
-SDK).  This means that we must have the library installed on the system on which
-we want to compile or use HAProxy.
-
-Instructions for compiling and installing the required library can be found at
-https://github.com/haproxytech/opentelemetry-c-wrapper .
-
-The OTel filter can be more easily compiled using the pkg-config tool, if we
-have the OpenTelemetry C Wrapper library installed so that it contains
-pkg-config files (which have the .pc extension).  If the pkg-config tool cannot
-be used, then the path to the directory where the include files and libraries
-are located can be explicitly specified.
-
-Below are examples of the two ways to compile HAProxy with the OTel filter, the
-first using the pkg-config tool and the second explicitly specifying the path to
-the OpenTelemetry C Wrapper include and library.
-
-Note: prompt '%' indicates that the command is executed under an unprivileged
-      user, while prompt '#' indicates that the command is executed under the
-      root user.
-
-Example of compiling HAProxy using the pkg-config tool (assuming the
-OpenTelemetry C Wrapper library is installed in the /opt directory):
-
-  % PKG_CONFIG_PATH=/opt/lib/pkgconfig make -j8 USE_OTEL=1 TARGET=linux-glibc
-
-The OTel filter can also be compiled in debug mode as follows:
-
-  % PKG_CONFIG_PATH=/opt/lib/pkgconfig make -j8 USE_OTEL=1 OTEL_DEBUG=1 TARGET=linux-glibc
-
-HAProxy compilation example explicitly specifying path to the OpenTelemetry C
-Wrapper include and library:
-
-  % make -j8 USE_OTEL=1 OTEL_INC=/opt/include OTEL_LIB=/opt/lib TARGET=linux-glibc
-
-In case we want to use debug mode, then it looks like this:
-
-  % make -j8 USE_OTEL=1 OTEL_DEBUG=1 OTEL_INC=/opt/include OTEL_LIB=/opt/lib TARGET=linux-glibc
-
-To enable OpenTelemetry context propagation via HAProxy variables (in addition
-to HTTP headers), add the OTEL_USE_VARS=1 option:
-
-  % PKG_CONFIG_PATH=/opt/lib/pkgconfig make -j8 USE_OTEL=1 OTEL_USE_VARS=1 TARGET=linux-glibc
-
-If the library we want to use is not installed on a unix system, then a locally
-installed library can be used (say, which is compiled and installed in the user
-home directory).  In this case instead of /opt/include and /opt/lib the
-equivalent paths to the local installation should be specified.  Of course, in
-that case the pkg-config tool can also be used if we have a complete
-installation (with .pc files).
-
-Last but not least, if the pkg-config tool is not used when compiling, then the
-HAProxy executable may not be able to find the OpenTelemetry C Wrapper library
-at startup.  This can be solved in several ways, for example using the
-LD_LIBRARY_PATH environment variable which should be set to the path where the
-library is located before starting the HAProxy.
-
-  % LD_LIBRARY_PATH=/opt/lib /path-to/haproxy ...
-
-Another way is to add RUNPATH to HAProxy executable that contains the path to
-the library in question.
-
-  % make -j8 USE_OTEL=1 OTEL_RUNPATH=1 OTEL_INC=/opt/include OTEL_LIB=/opt/lib TARGET=linux-glibc
-
-After HAProxy is compiled, we can check if the OTel filter is enabled:
-
-  % ./haproxy -vv | grep opentelemetry
-  --- command output ----------
-          [  OTel] opentelemetry
-  --- command output ----------
-
-A summary of all OTel build options:
-
-  USE_OTEL      - enable the OpenTelemetry filter
-  OTEL_DEBUG    - compile the filter in debug mode
-  OTEL_INC      - force path to opentelemetry-c-wrapper include files
-  OTEL_LIB      - force path to opentelemetry-c-wrapper library
-  OTEL_RUNPATH  - add opentelemetry-c-wrapper RUNPATH to executable
-  OTEL_USE_VARS - enable context propagation via HAProxy variables
-
-
-3. Basic concepts in OpenTelemetry
------------------------------------
-
-Basic concepts of OpenTelemetry can be read on the OpenTelemetry documentation
-website https://opentelemetry.io/docs/concepts/ .
-
-Here we will list only the most important elements of distributed tracing.
-
-A 'trace' is a description of the complete transaction we want to record in the
-tracing system.  A 'span' is an operation that represents a unit of work that is
-recorded in a tracing system.  A 'span context' is a group of information
-related to a particular span that is passed on to the system (from service to
-service).  Using this context, we can add new spans to already open trace (or
-supplement data in already open spans).
-
-An individual span may contain one or more attributes, events, links and baggage
-items.
-
-An 'attribute' is a key-value element that is valid for the entire span.
-Attributes describe properties of the span such as HTTP method, URL, status
-code, and so on.
-
-A span 'event' is a named key-value element that allows you to write some data
-at a certain time within the span's lifetime.  It can be used for debugging or
-recording notable occurrences.
-
-A 'link' is a reference to another span (possibly in a different trace) that is
-causally related to the current span.  Unlike the parent-child relationship,
-links represent non-hierarchical associations between spans.
-
-A 'baggage' item is a key-value data pair that can be used for the duration of
-an entire trace, from the moment it is added to the span.
-
-A span 'status' indicates the outcome of the operation: unset (default), ok
-(successful) or error (failed).  An optional description string can accompany
-the error status.
-
-
-4. OTel configuration
-----------------------
-
-The OTel filter must also be included in the HAProxy configuration, in the
-proxy section (frontend / listen / backend):
-
-   frontend otel-test
-     ...
-     filter opentelemetry [id <id>] config <file>
-     ...
-
-If no filter id is specified, 'otel-filter' is used as default.  The 'config'
-parameter must be specified and it contains the path of the OTel filter
-configuration file.  This file defines the OTel scopes, groups and
-instrumentation sections (see section 4.1).  The YAML configuration for the
-OpenTelemetry SDK is a separate file, referenced by the 'config' keyword inside
-the "otel-instrumentation" section (see section 4.2).
-
-
-4.1 OTel scope
----------------
-
-If the filter id is defined for the OTel filter, then the OTel scope with the
-same name should be defined in the configuration file.  In the same
-configuration file we can have several defined OTel scopes.
-
-Each OTel scope must have a defined (only one) "otel-instrumentation" section
-that is used to configure the operation of the OTel filter and define the used
-groups and scopes.
-
-OTel scope starts with the id of the filter specified in square brackets and
-ends with the end of the file or when a new OTel scope is defined.
-
-For example, this defines two OTel scopes in the same configuration file:
-  [my-first-otel-filter]
-    otel-instrumentation instrumentation1
-    ...
-    otel-group group1
-    ...
-    otel-scope scope1
-    ...
-
-  [my-second-otel-filter]
-    ...
-
-
-4.2. "otel-instrumentation" section
--------------------------------------
-
-Only one "otel-instrumentation" section must be defined for each OTel scope.
-
-The mandatory 'config' keyword defines the YAML configuration file for the
-OpenTelemetry SDK.  This file specifies the telemetry pipeline: exporters,
-processors, samplers, providers and signals.
-
-Through optional keywords can be defined ACLs, logging, rate limit, and groups
-and scopes that define the tracing model.
-
-
-otel-instrumentation <name>
-  A new OTel instrumentation with the name <name> is created.
-
-  Arguments :
-    name - the name of the OpenTelemetry instrumentation section
-
-
-  The following keywords are supported in this section:
-    - mandatory keywords:
-      - config
-
-    - optional keywords:
-      - acl
-      - debug-level
-      - groups
-      - [no] log
-      - [no] option disabled
-      - [no] option dontlog-normal
-      - [no] option hard-errors
-      - rate-limit
-      - scopes
-
-
-acl <aclname> <criterion> [flags] [operator] <value> ...
-  Declare or complete an access list.
-
-  To configure and use the ACL, see section 7 of the HAProxy Configuration
-  Manual.
-
-
-config <file>
-  The mandatory keyword associated with the OTel instrumentation configuration.
-  This keyword sets the path of the YAML configuration file for the
-  OpenTelemetry SDK.  The YAML file defines the complete telemetry pipeline
-  including exporters, samplers, processors, providers and signal routing.
-
-  The YAML configuration file supports the following top-level sections:
-
-  'exporters' - defines telemetry data destinations.  Supported exporter types
-  are:
-    - otlp_grpc     : export via OTLP over gRPC
-    - otlp_http     : export via OTLP over HTTP (JSON or Protobuf)
-    - otlp_file     : export to local files in OTLP format
-    - zipkin        : export to Zipkin-compatible backends
-    - elasticsearch : export to Elasticsearch
-    - ostream       : write to a file (text output, useful for debugging)
-    - memory        : in-memory buffer (useful for testing)
-
-  'samplers' - defines trace sampling strategies.  Supported types:
-    - always_on            : sample every trace
-    - always_off           : sample no traces
-    - trace_id_ratio_based : sample a fraction of traces (set by ratio)
-    - parent_based         : sampling decision based on parent span
-
-  'processors' - defines how telemetry data is processed before export:
-    - batch  : batch spans before exporting (configurable queue size, export
-               interval and batch size)
-    - single : export each span individually
-
-  'readers' - defines metric readers with configurable export interval and
-  timeout.
-
-  'providers' - defines resource attributes (service name, version, instance ID,
-  namespace, etc.) that are attached to all telemetry data.
-
-  'signals' - binds the above components together for each signal type (traces,
-  metrics, logs), specifying which exporter, sampler, processor, reader and
-  provider to use.
-
-  Arguments :
-    file - the path of the YAML configuration file
-
-
-debug-level <value>
-  This keyword sets the value of the debug level related to the display of debug
-  messages in the OTel filter.  The 'debug-level' value is a bitmask, ie a
-  single value bit enables or disables the display of the corresponding debug
-  message that uses that bit.  The default value is set via the
-  FLT_OTEL_DEBUG_LEVEL macro in the include/config.h file.  Debug level value is
-  used only if the OTel filter is compiled with the debug mode enabled,
-  otherwise it is ignored.
-
-  Arguments :
-    value - bitmask value (hexadecimal notation, e.g. 0x77f)
-
-
-groups <name> ...
-  A list of "otel-group" groups used for the currently defined instrumentation
-  is declared.  Several groups can be specified in one line.
-
-  Arguments :
-    name - the name of the OTel group
-
-
-log global
-log <addr> [len <len>] [format <fmt>] <facility> [<level> [<minlevel>]]
-no log
-  Enable per-instance logging of events and traffic.
-
-  To configure and use the logging system, see section 4.2 of the HAProxy
-  Configuration Manual.
-
-
-option disabled
-no option disabled
-  Keyword which turns the operation of the OTel filter on or off.  By default
-  the filter is on.
-
-
-option dontlog-normal
-no option dontlog-normal
-  Enable or disable logging of normal, successful processing.  By default, this
-  option is disabled.  For this option to be considered, logging must be turned
-  on.
-
-  See also: 'log' keyword description.
-
-
-option hard-errors
-no option hard-errors
-  During the operation of the filter, some errors may occur, caused by incorrect
-  configuration of the instrumentation or some error related to the operation of
-  HAProxy.  By default, such an error will not interrupt the filter operation
-  for the stream in which the error occurred.  If the 'hard-errors' option is
-  enabled, the operation error prohibits all further processing of events and
-  groups in the stream in which the error occurred.
-
-
-rate-limit <value>
-  This option allows limiting the use of the OTel filter, ie it can be
-  influenced whether the OTel filter is activated for a stream or not.
-  Determining whether or not a filter is activated depends on the value of this
-  option that is compared to a randomly selected value when attaching the filter
-  to the stream.  By default, the value of this option is set to 100.0, ie the
-  OTel filter is activated for each stream.
-
-  Arguments :
-    value - floating point value ranging from 0.0 to 100.0
-
-
-scopes <name> ...
-  This keyword declares a list of "otel-scope" definitions used for the
-  currently defined instrumentation.  Multiple scopes can be specified in the
-  same line.
-
-  Arguments :
-    name - the name of the OTel scope
-
-
-4.3. "otel-scope" section
---------------------------
-
-Stream processing begins with filter attachment, then continues with the
-processing of a number of defined events and groups, and ends with filter
-detachment.  The "otel-scope" section is used to define actions related to
-individual events.  However, this section may be part of a group, so the event
-does not have to be part of the definition.
-
-
-otel-scope <name>
-  Creates a new OTel scope definition named <name>.
-
-  Arguments :
-    name - the name of the OTel scope
-
-
-  The following keywords are supported in this section:
-    - acl
-    - attribute
-    - baggage
-    - event
-    - extract
-    - finish
-    - idle-timeout
-    - inject
-    - instrument
-    - link
-    - log-record
-    - otel-event
-    - span
-    - status
-
-
-acl <aclname> <criterion> [flags] [operator] <value> ...
-  Declare or complete an access list.
-
-  To configure and use the ACL, see section 7 of the HAProxy Configuration
-  Manual.
-
-
-attribute <key> <sample> ...
-  This keyword allows setting an attribute for the currently active span.  The
-  first argument is the name of the attribute (key) and the rest are its value.
-  A value can consist of one or more sample expressions.  If the value is only
-  one sample, then the type of that data depends on the type of the HAProxy
-  sample.  If the value contains more samples, then the data type is string.
-  The data conversion table is below:
-
-   HAProxy sample data type | the OpenTelemetry data type
-  --------------------------+----------------------------
-            NULL            |        NULL
-            BOOL            |        BOOL
-            INT32           |        INT64
-            UINT32          |        UINT64
-            INT64           |        INT64
-            UINT64          |        UINT64
-            IPV4            |        STRING
-            IPV6            |        STRING
-            STRING          |        STRING
-            BINARY          |        UNSUPPORTED
-  --------------------------+----------------------------
-
-  Arguments :
-    key    - key part of a data pair (attribute name)
-    sample - sample expression (value part of a data pair), at least
-             one sample must be present
-
-
-baggage <key> <sample> ...
-  Baggage items allow the propagation of data between spans, ie allow the
-  assignment of metadata that is propagated to future children spans.  This data
-  is formatted in the style of key-value pairs and is part of the context that
-  can be transferred between processes that are part of a server architecture.
-
-  This keyword allows setting the baggage for the currently active span.  The
-  data type is always a string, ie any sample type is converted to a string.
-  The exception is a binary value that is not supported by the OTel filter.
-
-  See the 'attribute' keyword description for the data type conversion table.
-
-  Arguments :
-    key    - key part of a data pair
-    sample - sample expression (value part of a data pair), at least one sample
-             must be present
-
-
-event <name> <key> <sample> ...
-  This keyword allows adding a span event to the currently active span.  A span
-  event is a named, timestamped annotation with optional attributes.  The data
-  type is always a string, ie any sample type is converted to a string.
-
-  See the 'attribute' keyword description for the data type conversion table.
-
-  Arguments :
-    name   - name of the span event
-    key    - key part of a data pair (attribute name within the event)
-    sample - sample expression (value part of a data pair), at least one sample
-             must be present
-
-
-extract <name-prefix> [use-vars | use-headers]
-  For a more detailed description of the propagation process of the span
-  context, see the description of the keyword 'inject'.  Only the process of
-  extracting data from the carrier is described here.
-
-  The default carrier is HTTP headers.  If OTEL_USE_VARS is enabled at compile
-  time, the 'use-vars' option can be used instead to extract context from
-  HAProxy variables.
-
-  Arguments :
-    name-prefix - data name prefix (ie key element prefix)
-    use-vars    - data is extracted from HAProxy variables
-    use-headers - data is extracted from the HTTP header
-
-
-  Below is an example of using HAProxy variables to transfer span context data:
-
-  --- test/ctx/otel.cfg -----------------------------------------------
-      ...
-      otel-scope client_session_start_2
-          extract "otel_ctx_1" use-vars
-          span "Client session" parent "otel_ctx_1"
-      ...
-  ---------------------------------------------------------------------
-
-
-finish <name> ...
-  Closing a particular span or span context.  Instead of the name of the span,
-  there are several specially predefined names with which we can finish certain
-  groups of spans.  So it can be used as the name '*req*' for all open spans
-  related to the request channel, '*res*' for all open spans related to the
-  response channel and '*' for all open spans regardless of which channel they
-  are related to.  Several spans and/or span contexts can be specified in one
-  line.
-
-  Arguments :
-    name - the name of the span or span context
-
-
-inject <name-prefix> [use-vars] [use-headers]
-  In OpenTelemetry, the transfer of data related to the tracing process between
-  microservices that are part of a larger service is done through the
-  propagation of the span context.  The basic operations that allow us to access
-  and transfer this data are 'inject' and 'extract'.
-
-  'inject' allows us to extract span context so that the obtained data can be
-  forwarded to another process (microservice) via the selected carrier. 'inject'
-  in the name actually means inject data into carrier.  Carrier is an interface
-  here (ie a data structure) that allows us to transfer tracing state from one
-  process to another.
-
-  Data transfer can take place via one of two selected storage methods, the
-  first is by adding data to the HTTP header and the second is by using HAProxy
-  variables (the latter requires OTEL_USE_VARS=1 at compile time).  Only data
-  transfer via HTTP header can be used to transfer data to another process (ie
-  microservice).  All data is organized in the form of key-value data pairs.
-
-  No matter which data transfer method you use, we need to specify a prefix for
-  the key element.  All alphanumerics (lowercase only) and underline character
-  can be used to construct the data name prefix.  Uppercase letters can actually
-  be used, but they will be converted to lowercase when creating the prefix.
-  The special prefix '-' can be used to generate the name automatically from the
-  scope's event name or the span name.
-
-  Arguments :
-    name-prefix - data name prefix (ie key element prefix), or '-' for automatic
-                  naming
-    use-vars    - HAProxy variables are used to store and transfer data
-                  (requires OTEL_USE_VARS=1)
-    use-headers - HTTP headers are used to store and transfer data
-
-
-  Below is an example of using HTTP headers and variables to propagate the span
-  context.
-
-  --- test/ctx/otel.cfg -----------------------------------------------
-      ...
-      otel-scope client_session_start_1
-          span "HAProxy session" root
-              inject "otel_ctx_1" use-headers use-vars
-      ...
-  ---------------------------------------------------------------------
-
-  Because HAProxy does not allow the '-' character in the variable name (which
-  is automatically generated by the OpenTelemetry API and on which we have no
-  influence), it is converted to the letter 'D'.  We can see that there is no
-  such conversion in the name of the HTTP header because the '-' sign is allowed
-  there.  Due to this conversion, initially all uppercase letters are converted
-  to lowercase because otherwise we would not be able to distinguish whether the
-  disputed sign '-' is used or not.
-
-  Thus created HTTP headers and variables are deleted when executing the
-  'finish' keyword or when detaching the stream from the filter.
-
-
-instrument { update <name> [<attr>] | <type> <name> [<aggr>] [<desc>] [<unit>] <value> [<bounds>] }
-  This keyword allows creating or updating metric instruments within the scope.
-  Metric instruments record numerical measurements that are exported alongside
-  traces.
-
-  To create a new instrument, specify the instrument type, a name, and a sample
-  expression providing the measurement value (preceded by the 'value' keyword).
-  Optionally, a human-readable description (preceded by 'desc') and a unit
-  string (preceded by 'unit') can be added.
-
-  An aggregation type can be specified using the 'aggr' keyword followed by one
-  of the supported aggregation types listed below.  When specified, a metrics
-  view is registered with the given aggregation strategy.  If no aggregation
-  type is specified, the SDK default is used.
-
-  For histogram instruments (hist_int), optional bucket boundaries can be
-  specified using the 'bounds' keyword followed by a double-quoted string of
-  space-separated integers in strictly ascending order.  When bounds are
-  specified without an explicit aggregation type, histogram aggregation is
-  used automatically.
-
-  To update an existing instrument (previously created in another scope), use
-  'update' followed by the name of the instrument.  Optional attributes can be
-  added using the 'attr' keyword followed by a key and a sample expression
-  evaluated at runtime.
-
-  Supported instrument types:
-    - cnt_int   : counter (uint64)
-    - hist_int  : histogram (uint64)
-    - udcnt_int : up-down counter (int64)
-    - gauge_int : gauge (int64)
-
-  Supported aggregation types:
-    - drop          : measurements are discarded
-    - histogram     : explicit bucket histogram
-    - last_value    : last recorded value
-    - sum           : sum of recorded values
-    - default       : SDK default for the instrument type
-    - exp_histogram : base-2 exponential histogram
-
-  Observable (asynchronous) instruments are not supported.  The OpenTelemetry
-  SDK invokes their callbacks from an external background thread that is not
-  a HAProxy thread.  HAProxy sample fetches rely on internal per-thread-group
-  state and return incorrect results when called from a non-HAProxy thread.
-
-  Double-precision types are not supported because HAProxy sample fetches do
-  not return double values.
-
-  For example:
-    instrument cnt_int  "my_counter" desc "Counter" value int(1)
-    instrument hist_int "my_hist" aggr exp_histogram desc "Latency" value lat_ns_tot unit "ns"
-    instrument hist_int "my_hist2" desc "Latency" value lat_ns_tot unit "ns" bounds "100 1000 10000 100000"
-    instrument update "my_counter" attr "key1" str("val1")
-
-  Arguments :
-    type   - the instrument type (see list above)
-    name   - the name of the instrument
-    aggr   - optional aggregation type (see list above)
-    desc   - optional human-readable description of the instrument
-    unit   - optional unit string for the instrument
-    value  - sample expression providing the measurement value
-    bounds - optional histogram bucket boundaries (hist_int only)
-    attr   - attribute key and sample expression (update form only)
-
-
-log-record <severity> [id <integer>] [event <name>] [span <span-name>] [attr <key> <sample>] ... <sample> ...
-  This keyword emits an OpenTelemetry log record within the scope.  The first
-  argument is a required severity level.  Optional keywords follow in any order
-  before the trailing sample expressions that form the log record body:
-
-    id <integer>        - numeric event identifier
-    event <name>        - event name string
-    span <span-name>    - associate the log record with an open span
-    attr <key> <sample> - add an attribute evaluated at runtime (repeatable)
-
-  The remaining arguments at the end are sample fetch expressions.  A single
-  sample preserves its native type; multiple samples are concatenated as a
-  string.
-
-  Supported severity levels follow the OpenTelemetry specification:
-    trace, trace2, trace3, trace4, debug, debug2, debug3, debug4,
-    info, info2, info3, info4, warn, warn2, warn3, warn4,
-    error, error2, error3, error4, fatal, fatal2, fatal3, fatal4
-
-  The log record is only emitted when the logger is enabled for the configured
-  severity.  If a 'span' reference is given but the named span is not found at
-  runtime, the log record is emitted without span correlation.
-
-  For example:
-    log-record info str("heartbeat")
-    log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" method method url
-    log-record trace id 1000 event "session-start" span "Client session" attr "src_ip" src src str(":") src_port
-    log-record warn event "server-unavailable" str("503 Service Unavailable")
-
-  Arguments :
-    severity - the log severity level (see list above)
-    id       - optional numeric event identifier
-    event    - optional event name
-    span     - optional name of an open span to associate with
-    attr     - optional attribute key-value pairs (repeatable)
-    sample   - sample fetch expression(s) forming the log record body
-
-
-link <span> ...
-  This keyword adds span links to the currently active span.  A span link
-  represents a causal relationship to another span without establishing a
-  parent-child hierarchy.  Links are useful for connecting spans across
-  different traces or for associating related spans within the same trace.
-
-  Multiple span names can be specified in one line.  Each name is resolved at
-  runtime by searching for an active span or an extracted context with that
-  name.  If a referenced span or context cannot be found, the link is silently
-  skipped.
-
-  Arguments :
-    span - the name of a span or span context to link to
-
-
-otel-event <name> [{ if | unless } <condition>]
-  Set the event that triggers the 'otel-scope' to which it is assigned.
-  Optionally, it can be followed by an ACL-based condition, in which case it
-  will only be evaluated if the condition is true.
-
-  ACL-based conditions are executed in the context of a stream that processes
-  the client and server connections.  To configure and use the ACL, see section
-  7 of the HAProxy Configuration Manual.
-
-  Arguments :
-    name      - the event name
-    condition - a standard ACL-based condition
-
-  Supported events are (the table gives the names of the events in the OTel
-  filter and the corresponding equivalent in the SPOE filter):
-
-    -------------------------------------|------------------------------
-      the OTel filter                    |  the SPOE filter
-    -------------------------------------|------------------------------
-      on-stream-start                    |  -
-      on-stream-stop                     |  -
-      on-idle-timeout                    |  -
-      on-backend-set                     |  -
-    -------------------------------------|------------------------------
-      on-client-session-start            |  on-client-session
-      on-frontend-tcp-request            |  on-frontend-tcp-request
-      on-http-wait-request               |  -
-      on-http-body-request               |  -
-      on-frontend-http-request           |  on-frontend-http-request
-      on-switching-rules-request         |  -
-      on-backend-tcp-request             |  on-backend-tcp-request
-      on-backend-http-request            |  on-backend-http-request
-      on-process-server-rules-request    |  -
-      on-http-process-request            |  -
-      on-tcp-rdp-cookie-request          |  -
-      on-process-sticking-rules-request  |  -
-      on-http-headers-request            |  -
-      on-http-end-request                |  -
-      on-client-session-end              |  -
-      on-server-unavailable              |  -
-    -------------------------------------|------------------------------
-      on-server-session-start            |  on-server-session
-      on-tcp-response                    |  on-tcp-response
-      on-http-wait-response              |  -
-      on-process-store-rules-response    |  -
-      on-http-response                   |  on-http-response
-      on-http-headers-response           |  -
-      on-http-end-response               |  -
-      on-http-reply                      |  -
-      on-server-session-end              |  -
-    -------------------------------------|------------------------------
-
-  --- Stream lifecycle events (not tied to a channel analyzer) ---
-
-  The on-stream-start and on-stream-stop events fire from the stream_start and
-  stream_stop filter callbacks respectively, before any channel processing
-  begins and after all channel processing ends.  No channel is available at
-  that point, so context injection/extraction via HTTP headers cannot be used
-  in scopes bound to these events.  Sample fetches in these scopes are not
-  direction-constrained.
-
-  The on-idle-timeout event fires periodically when the stream has no data
-  transfer activity.  It requires the 'idle-timeout' keyword to set the
-  interval.  This event is useful for heartbeat spans, idle-time metrics, and
-  idle-time log records.  It fires from the check_timeouts filter callback
-  using HAProxy's tick-based timer infrastructure.
-
-  The on-backend-set event fires from the stream_set_backend filter callback
-  when a backend is assigned to the stream.  It is not called if the frontend
-  and the backend are the same proxy.
-
-
-  --- Request channel events ---
-
-  Analyzer events (tied to AN_REQ_* bits):
-
-  The on-frontend-tcp-request event fires during frontend TCP content inspection
-  (AN_REQ_INSPECT_FE).
-
-  The on-http-wait-request event fires after the complete HTTP request has been
-  received (AN_REQ_WAIT_HTTP).  This is a post-analyzer event.
-
-  The on-http-body-request event fires when the HTTP request body is available
-  for inspection (AN_REQ_HTTP_BODY).
-
-  The on-frontend-http-request event fires during frontend HTTP request
-  processing: header rules, monitoring, statistics and redirects
-  (AN_REQ_HTTP_PROCESS_FE).
-
-  The on-switching-rules-request event fires when backend switching rules are
-  evaluated (AN_REQ_SWITCHING_RULES).
-
-  The on-backend-tcp-request event fires during backend TCP content inspection
-  (AN_REQ_INSPECT_BE).
-
-  The on-backend-http-request event fires during backend HTTP request processing
-  (AN_REQ_HTTP_PROCESS_BE).
-
-  The on-process-server-rules-request event fires when use-server rules are
-  evaluated (AN_REQ_SRV_RULES).
-
-  The on-http-process-request event fires during inner HTTP request processing
-  (AN_REQ_HTTP_INNER).
-
-  The on-tcp-rdp-cookie-request event fires when RDP cookie persistence is
-  evaluated (AN_REQ_PRST_RDP_COOKIE).
-
-  The on-process-sticking-rules-request event fires when stick-table persistence
-  matching rules are evaluated (AN_REQ_STICKING_RULES).
-
-  Non-analyzer events (not tied to AN_REQ_* bits):
-
-  The on-client-session-start event fires when the request channel analysis
-  begins.  It corresponds to the start of a new client session.
-
-  The on-http-headers-request event fires from the http_headers filter callback
-  after all HTTP request headers have been parsed and analyzed.
-
-  The on-http-end-request event fires from the http_end filter callback when all
-  HTTP request data has been processed and forwarded.
-
-  The on-client-session-end event fires when the request channel analysis ends.
-
-  The on-server-unavailable event fires during request channel end-analysis when
-  response analyzers were configured but never executed because the server was
-  not reached.
-
-
-  --- Response channel events ---
-
-  Analyzer events (tied to AN_RES_* bits):
-
-  The on-tcp-response event fires during TCP response content inspection
-  (AN_RES_INSPECT).
-
-  The on-http-wait-response event fires after the complete HTTP response has
-  been received (AN_RES_WAIT_HTTP).  This is a post-analyzer event.
-
-  The on-process-store-rules-response event fires when stick-table store rules
-  are evaluated (AN_RES_STORE_RULES).
-
-  The on-http-response event fires during backend HTTP response processing
-  (AN_RES_HTTP_PROCESS_BE).
-
-  Non-analyzer events (not tied to AN_RES_* bits):
-
-  The on-server-session-start event fires when the response channel analysis
-  begins, after a server connection has been established.
-
-  The on-http-headers-response event fires from the http_headers filter callback
-  after all HTTP response headers have been parsed and analyzed.
-
-  The on-http-end-response event fires from the http_end filter callback when
-  all HTTP response data has been processed and forwarded.
-
-  The on-http-reply event fires from the http_reply filter callback when HAProxy
-  generates an internal reply (error page, deny response, redirect).  It always
-  fires on the response channel.
-
-  The on-server-session-end event fires when the response channel analysis ends.
-
-
-idle-timeout <time>
-  Set the idle timeout interval for a scope bound to the 'on-idle-timeout'
-  event.  The timer fires periodically at the given interval when the stream
-  is idle.  This keyword is mandatory for scopes using the 'on-idle-timeout'
-  event and cannot be used with any other event.
-
-  The <time> argument accepts the standard HAProxy time format: a number
-  followed by a unit suffix (ms, s, m, h, d).  A value of zero is not
-  permitted.
-
-  Arguments :
-    time - the idle timeout interval (e.g. 5s, 500ms, 1m)
-
-  Example :
-    scopes on_idle_timeout
-    ..
-    otel-scope on_idle_timeout
-        idle-timeout 5s
-        span "heartbeat" root
-            attribute "idle.elapsed" str("idle-check")
-        instrument cnt_int "idle.count" value int(1)
-        log-record info str("heartbeat")
-        otel-event on-idle-timeout
-
-
-span <name> [<reference>] [<link>] [root]
-  Creating a new span (or referencing an already opened one).  If a new span is
-  created, it can have a parent reference to another span or context, an inline
-  link to another span, or be marked as a root span.  If no reference is
-  specified, the new span will become a root span.  We need to pay attention to
-  the fact that in one trace there can be only one root span.  If a non-existent
-  span is specified as a reference, a new span will not be created.
-
-  The parent reference is set using the 'parent' keyword followed by the name of
-  an existing span or extracted context.  An inline link is set using the 'link'
-  keyword followed by a span or context name.  The 'root' keyword explicitly
-  marks the span as a root span.
-
-  For example:
-    span "HAProxy session" root
-    span "Client session" parent "HAProxy session"
-    span "HTTP request" parent "TCP request" link "HAProxy session"
-    span "Client session" parent "otel_ctx_1"
-
-  Only one inline link can be specified per 'span' declaration.  For multiple
-  links, use the standalone 'link' keyword described above.
-
-  Arguments :
-    name      - the name of the span being created or referenced
-                (operation name)
-    reference - 'parent <name>' or 'link <name>' or 'root'
-
-
-status <code> [<sample> ...]
-  This keyword sets the status for the currently active span.  The status
-  indicates the outcome of the operation represented by the span.
-
-  The status code is one of the following predefined values:
-    - ignore : do not set any status (default)
-    - unset  : explicitly mark status as unset
-    - ok     : the operation completed successfully
-    - error  : the operation resulted in an error
-
-  An optional description can follow the status code, consisting of one or more
-  sample expressions whose values are concatenated as a string.  The description
-  is typically used with the 'error' status to provide additional context about
-  the failure.
-
-  For example:
-    status "ok"
-    status "error" str("http.status_code: ") status
-
-  Arguments :
-    code   - the status code (ignore, unset, ok, error)
-    sample - optional sample expression(s) for the status description
-
-
-4.4. "otel-group" section
---------------------------
-
-This section allows us to define a group of OTel scopes, that is not activated
-via an event but is triggered from TCP or HTTP rules.  More precisely, these are
-the following rules: 'tcp-request', 'tcp-response', 'http-request',
-'http-response' and 'http-after-response'.  These rules can be defined in the
-HAProxy configuration file.
-
-The action keyword used in these rules is 'otel-group', and it takes the filter
-id and the group name as arguments:
-
-  http-response otel-group <filter-id> <group-name> [{ if | unless } ...]
-
-
-otel-group <name>
-  Creates a new OTel group definition named <name>.
-
-  Arguments :
-    name - the name of the OTel group
-
-
-  The following keywords are supported in this section:
-    - scopes
-
-
-scopes <name> ...
-  'otel-scope' sections that are part of the specified group are defined.  If
-  the mentioned 'otel-scope' sections are used only in some OTel group, they do
-  not have to have defined events.  Several 'otel-scope' sections can be
-  specified in one line.
-
-  Arguments :
-    name - the name of the 'otel-scope' section
-
-
-5. Examples
-------------
-
-Several examples of the OTel filter configuration can be found in the test
-directory.  A brief description of the prepared configurations follows:
-
-cmp   - a configuration made for comparison purposes with other tracing
-        implementations.
-
-sa    - a standalone configuration in which all possible events are used.  This
-        is the most comprehensive example demonstrating spans, attributes,
-        events, links, baggage, status and other features.
-
-ctx   - a configuration similar to 'sa', with the difference that the spans are
-        opened using extracted span contexts as references instead of direct
-        parent span names.  This demonstrates the inject/extract context
-        propagation mechanism using HAProxy variables.
-
-fe be - a more complex example of the OTel filter configuration that uses two
-        cascaded HAProxy services (frontend and backend).  The span context
-        between HAProxy processes is transmitted via the HTTP header using
-        inject/extract.
-
-empty - an empty configuration in which the OTel filter is initialized but no
-        event is triggered.  It is not very usable, except to check the behavior
-        of the OTel filter in the case of a similar configuration.
-
-
-The OTel filter does not use tracer plugins.  Instead, telemetry data is
-exported using the OpenTelemetry protocol (OTLP) directly to any compatible
-backend.  The backend is configured through the YAML configuration file
-specified by the 'config' keyword.
-
-In order to be able to collect and view trace data we need an OpenTelemetry
-compatible backend.  There are many options available, including:
-
-  - Jaeger  : https://www.jaegertracing.io/
-  - Grafana : https://grafana.com/oss/tempo/
-  - Zipkin  : https://zipkin.io/
-  - SigNoz  : https://signoz.io/
-  - Datadog : https://www.datadoghq.com/
-
-For quick testing, a simple setup using the OpenTelemetry Collector and Jaeger
-can be started with Docker:
-
-  # docker run -d --name jaeger -p 4317:4317 -p 4318:4318 -p 16686:16686 jaegertracing/all-in-one:latest
-
-This starts Jaeger with OTLP/gRPC on port 4317, OTLP/HTTP on port 4318 and the
-web UI on port 16686.  If we want to use that container later, it can be started
-and stopped using the 'docker container start/stop' commands.
-
-The test configurations use a YAML file that defines an OTLP/HTTP exporter
-sending data to localhost:4318.  A typical minimal YAML configuration looks like
-this:
-
-  --- otel.yml --------------------------------------------------------
-  exporters:
-    my_exporter:
-      type:     otlp_http
-      endpoint: "http://localhost:4318/v1/traces"
-
-  samplers:
-    my_sampler:
-      type: always_on
-
-  processors:
-    my_processor:
-      type: batch
-
-  providers:
-    my_provider:
-      resources:
-        - service.name: "haproxy"
-
-  signals:
-    traces:
-      scope_name: "HAProxy OTel"
-      exporters:  my_exporter
-      samplers:   my_sampler
-      processors: my_processor
-      providers:  my_provider
-  ---------------------------------------------------------------------
-
-In order to use any of the configurations from the test directory, we can run
-one of the pre-configured scripts:
-
-  % ./run-sa.sh
-  % ./run-ctx.sh
-  % ./run-cmp.sh
-  % ./run-fe-be.sh
-
-
-5.1. Benchmarking results
---------------------------
-
-To check the performance impact of the OTel filter, test configurations located
-in the test directory have been benchmarked.  The test results (with the names
-README-speed-xxx, where xxx is the name of the configuration being tested) are
-also in the test directory.
-
-Testing was done with the wrk utility using 8 threads, 8 connections and a
-5-minute test duration.  Detailed results and methodology are documented in the
-test/README-test-speed file.
-
-Below is a summary of the 'sa' (standalone) configuration results, which uses
-all possible events and demonstrates the worst-case scenario:
-
-  ---------------------------------------------------------------
-   rate-limit     req/s     avg latency     overhead
-  ---------------------------------------------------------------
-      100.0%     38,202       213.08 us       21.6%
-       50.0%     42,777       190.49 us       12.2%
-       25.0%     45,302       180.46 us        7.0%
-       10.0%     46,879       174.69 us        3.7%
-        2.5%     47,993       170.58 us        1.4%
-     disabled    48,788       167.74 us          ~0
-     off         48,697       168.00 us      baseline
-  ---------------------------------------------------------------
-
-The 'off' baseline is measured with the 'filter opentelemetry' directive
-commented out, so the filter is not loaded at all.  The 'disabled' level has
-the filter loaded but disabled via 'option disabled', so the initialization
-overhead is included but no events are processed.
-
-As the table shows, with the rate limit set to 25% the overhead is about 7%.
-At 10% the overhead drops to 3.7%.  In typical production use with a rate limit
-of 10% or less, the performance impact should be negligible.
-
-
-6. OTel CLI
-------------
-
-Via the HAProxy CLI interface we can find out the current status of the OTel
-filter and change several of its settings.
-
-All supported CLI commands can be found in the following way, using the socat
-utility with the assumption that the HAProxy CLI socket path is set to
-/tmp/haproxy.sock (of course, instead of socat, nc or other utility can be used
-with a change in arguments when running the same):
-
-  % echo "help" | socat - UNIX-CONNECT:/tmp/haproxy.sock | grep flt-otel
-  --- command output ----------
-  flt-otel debug [level]   : set the OTel filter debug level
-  flt-otel disable         : disable the OTel filter
-  flt-otel enable          : enable the OTel filter
-  flt-otel soft-errors     : turning off hard-errors mode
-  flt-otel hard-errors     : enabling hard-errors mode
-  flt-otel logging [state] : set logging state
-  flt-otel rate [value]    : set the rate limit
-  flt-otel status          : show the OTel filter status
-  --- command output ----------
-
-'flt-otel debug' can only be used in case the OTel filter is compiled with the
-debug mode enabled.  When invoked without arguments, these commands display the
-current value of the respective setting.
-
-
-7. Known bugs and limitations
--------------------------------
-
-The name of the span context definition can contain only letters, numbers and
-characters '_' and '-'.  Also, all uppercase letters in the name are converted
-to lowercase.  The character '-' is converted internally to the 'D' character,
-and since a HAProxy variable is generated from that name, this should be taken
-into account if we want to use it somewhere in the HAProxy configuration.  The
-above mentioned span context is used in the 'inject' and 'extract' keywords.
-
-An inline span link (using the 'link' keyword within a 'span' declaration) is
-limited to a single link per span declaration due to the fixed argument count
-(maximum 7 arguments).  For multiple links, use the standalone 'link' keyword
-instead.
-
-Let's look a little at the example test/fe-be (configurations are in the
-test/fe and test/be directories, 'fe' is here the abbreviation for frontend and
-'be' for backend).  In case we have the 'rate-limit' set to a value less than
-100.0, then distributed tracing will not be started with each new HTTP request.
-It also means that the span context will not be delivered (via the HTTP header)
-to the backend HAProxy process.  The 'rate-limit' on the backend HAProxy must be
-set to 100.0, but because the frontend HAProxy does not send a span context
-every time, all such cases will cause an error to be reported on the backend
-server.  Therefore, the 'hard-errors' option must be set on the backend server,
-so that processing on that stream is stopped as soon as the first error occurs.
diff --git a/addons/otel/README-conf b/addons/otel/README-conf
deleted file mode 100644 (file)
index f8c1ac8..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-OpenTelemetry Filter Configuration Structures
-==============================================================================
-
-1  Overview
-------------------------------------------------------------------------------
-
-The OpenTelemetry filter configuration is a tree of C structures that mirrors
-the hierarchical layout of the filter's configuration file.  Each structure type
-carries a common header macro, and its allocation and deallocation are performed
-by macro-generated init/free function pairs defined in conf_funcs.h.
-
-The root of the tree is flt_otel_conf, which owns the instrumentation settings,
-groups, and scopes.  Scopes contain the actual tracing and metrics definitions:
-contexts, spans, instruments, and their sample expressions.
-
-Source files:
-  include/conf.h        Structure definitions and debug macros.
-  include/conf_funcs.h  Init/free macro templates and declarations.
-  src/conf.c            Init/free implementations for all types.
-
-
-2  Common Macros
-------------------------------------------------------------------------------
-
-Two macros provide the building blocks embedded in every configuration
-structure.
-
-2.1  FLT_OTEL_CONF_STR(p)
-
-Expands to an anonymous struct containing a string pointer and its cached
-length:
-
-  struct {
-      char   *p;
-      size_t  p_len;
-  };
-
-Used for auxiliary string fields that do not need list linkage (e.g. ref_id and
-ctx_id in flt_otel_conf_span).
-
-2.2  FLT_OTEL_CONF_HDR(p)
-
-Expands to an anonymous struct that extends FLT_OTEL_CONF_STR with a
-configuration file line number and an intrusive list node:
-
-  struct {
-      char        *p;
-      size_t       p_len;
-      int          cfg_line;
-      struct list  list;
-  };
-
-Every configuration structure embeds FLT_OTEL_CONF_HDR as its first member.
-The <p> parameter names the identifier field (e.g. "id", "key", "str", "span",
-"fmt_expr").  The list node chains the structure into its parent's list.
-The cfg_line records the source line for error reporting.
-
-
-3  Structure Hierarchy
-------------------------------------------------------------------------------
-
-The complete ownership tree, from root to leaves:
-
-  flt_otel_conf
-  +-- flt_otel_conf_instr                    (one, via pointer)
-  |   +-- flt_otel_conf_ph                   (ph_groups list)
-  |   +-- flt_otel_conf_ph                   (ph_scopes list)
-  |   +-- struct acl                         (acls list, HAProxy-owned type)
-  |   +-- struct logger                      (proxy_log.loggers, HAProxy type)
-  +-- flt_otel_conf_group                    (groups list)
-  |   +-- flt_otel_conf_ph                   (ph_scopes list)
-  +-- flt_otel_conf_scope                    (scopes list)
-      +-- flt_otel_conf_context              (contexts list)
-      +-- flt_otel_conf_span                 (spans list)
-      |   +-- flt_otel_conf_link             (links list)
-      |   +-- flt_otel_conf_sample           (attributes list)
-      |   |   +-- flt_otel_conf_sample_expr  (exprs list)
-      |   +-- flt_otel_conf_sample           (events list)
-      |   |   +-- flt_otel_conf_sample_expr  (exprs list)
-      |   +-- flt_otel_conf_sample           (baggages list)
-      |   |   +-- flt_otel_conf_sample_expr  (exprs list)
-      |   +-- flt_otel_conf_sample           (statuses list)
-      |       +-- flt_otel_conf_sample_expr  (exprs list)
-      +-- flt_otel_conf_str                  (spans_to_finish list)
-      +-- flt_otel_conf_instrument           (instruments list)
-      |   +-- flt_otel_conf_sample           (samples list)
-      |       +-- flt_otel_conf_sample_expr  (exprs list)
-      +-- flt_otel_conf_log_record           (log_records list)
-          +-- flt_otel_conf_sample           (attributes list)
-          |   +-- flt_otel_conf_sample_expr  (exprs list)
-          +-- flt_otel_conf_sample           (samples list)
-              +-- flt_otel_conf_sample_expr  (exprs list)
-
-All child lists use HAProxy's intrusive doubly-linked list (struct list)
-threaded through the FLT_OTEL_CONF_HDR embedded in each child structure.
-
-3.1  Placeholder Structures
-
-The flt_otel_conf_ph structure serves as an indirection node.  During parsing,
-placeholder entries record names of groups and scopes.  At check time
-(flt_otel_check), these names are resolved to pointers to the actual
-flt_otel_conf_group or flt_otel_conf_scope structures via the ptr field.
-Two type aliases exist for clarity:
-
-  #define flt_otel_conf_ph_group  flt_otel_conf_ph
-  #define flt_otel_conf_ph_scope  flt_otel_conf_ph
-
-Corresponding free aliases ensure the FLT_OTEL_LIST_DESTROY macro can locate
-the correct free function:
-
-  #define flt_otel_conf_ph_group_free  flt_otel_conf_ph_free
-  #define flt_otel_conf_ph_scope_free  flt_otel_conf_ph_free
-
-
-4  Structure Definitions
-------------------------------------------------------------------------------
-
-4.1  flt_otel_conf (root)
-
-  proxy      Proxy owning the filter.
-  id         The OpenTelemetry filter id.
-  cfg_file   The OpenTelemetry filter configuration file name.
-  instr      The OpenTelemetry instrumentation settings (pointer).
-  groups     List of all available groups.
-  scopes     List of all available scopes.
-  cnt        Various counters related to filter operation.
-  smp_args   Deferred sample fetch arguments to resolve at check time.
-
-This structure does not use FLT_OTEL_CONF_HDR because it is not part of any
-list -- it is the unique root, owned by the filter instance.
-
-4.2  flt_otel_conf_instr (instrumentation)
-
-  FLT_OTEL_CONF_HDR(id)  The OpenTelemetry instrumentation name.
-  config                 The OpenTelemetry configuration file name.
-  tracer                 The OpenTelemetry tracer handle.
-  meter                  The OpenTelemetry meter handle.
-  logger                 The OpenTelemetry logger handle.
-  rate_limit             Rate limit as uint32 ([0..2^32-1] maps [0..100]%).
-  flag_harderr           Hard-error mode flag.
-  flag_disabled          Disabled flag.
-  logging                Logging mode (0, 1, or 3).
-  proxy_log              The log server list (HAProxy proxy structure).
-  analyzers              Defined channel analyzers bitmask.
-  idle_timeout           Minimum idle timeout across scopes (ms, 0 = off).
-  acls                   ACLs declared on this tracer.
-  ph_groups              List of all used groups (placeholders).
-  ph_scopes              List of all used scopes (placeholders).
-
-Exactly one instrumentation block is allowed per filter instance.  The parser
-stores a pointer to it in flt_otel_conf.instr.
-
-4.3  flt_otel_conf_group
-
-  FLT_OTEL_CONF_HDR(id)  The group name.
-  flag_used              The indication that the group is being used.
-  ph_scopes              List of all used scopes (placeholders).
-
-Groups bundle scopes for use with the "otel-group" HAProxy action.
-
-4.4  flt_otel_conf_scope
-
-  FLT_OTEL_CONF_HDR(id)  The scope name.
-  flag_used              The indication that the scope is being used.
-  event                  FLT_OTEL_EVENT_* identifier.
-  idle_timeout           Idle timeout interval in milliseconds (0 = off).
-  acls                   ACLs declared on this scope.
-  cond                   ACL condition to meet.
-  contexts               Declared contexts.
-  spans                  Declared spans.
-  spans_to_finish        The list of spans scheduled for finishing.
-  instruments            The list of metric instruments.
-  log_records            The list of log records.
-
-Each scope binds to a single HAProxy analyzer event (or none, if used only
-through groups).
-
-4.5  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.
-  ctx_flags                  The type of storage used for the span context.
-  flag_root                  Whether this is a root span.
-  links                      The set of linked span names.
-  attributes                 The set of key:value attributes.
-  events                     The set of events with key-value attributes.
-  baggages                   The set of key:value baggage items.
-  statuses                   Span status code and description.
-
-The ref_id and ctx_id fields use FLT_OTEL_CONF_STR because they are simple name
-strings without list linkage.
-
-4.6  flt_otel_conf_instrument
-
-  FLT_OTEL_CONF_HDR(id)  The name of the instrument.
-  idx                    Meter instrument index: UNSET (-1) before creation,
-                         PENDING (-2) while another thread is creating, or >= 0
-                         for the actual meter index.
-  type                   Instrument type (or UPDATE).
-  aggr_type              Aggregation type for the view (create only).
-  description            Instrument description (create only).
-  unit                   Instrument unit (create only).
-  samples                Sample expressions for the value.
-  bounds                 Histogram bucket boundaries (create only).
-  bounds_num             Number of histogram bucket boundaries.
-  attributes             Instrument attributes (update only, flt_otel_conf_sample).
-  ref                    Resolved create-form instrument (update only).
-
-Instruments come in two forms: create-form (defines a new metric with type,
-description, unit, and optional histogram bounds) and update-form (references
-an existing instrument via the ref pointer).  Update-form attributes are stored
-as flt_otel_conf_sample entries and evaluated at runtime.
-
-4.7  flt_otel_conf_log_record
-
-  FLT_OTEL_CONF_HDR(id)  Required by macro; member <id> is not used directly.
-  severity               The severity level.
-  event_id               Optional event identifier.
-  event_name             Optional event name.
-  span                   Optional span reference.
-  attributes             Log record attributes (flt_otel_conf_sample list).
-  samples                Sample expressions for the body.
-
-Log records are emitted via the OTel logger at the configured severity.  The
-optional span reference associates the log record with an open span at runtime.
-Attributes are stored as flt_otel_conf_sample entries added via the 'attr'
-keyword, which can be repeated.  Attribute values are HAProxy sample expressions
-evaluated at runtime.
-
-4.8  flt_otel_conf_context
-
-  FLT_OTEL_CONF_HDR(id)  The name of the context.
-  flags                  Storage type from which the span context is extracted.
-
-4.9  flt_otel_conf_sample
-
-  FLT_OTEL_CONF_HDR(key)  The list containing sample names.
-  fmt_string              Combined sample-expression arguments string.
-  extra                   Optional supplementary data.
-  exprs                   Used to chain sample expressions.
-  num_exprs               Number of defined expressions.
-  lf_expr                 The log-format expression.
-  lf_used                 Whether lf_expr is used instead of exprs.
-
-The extra field carries type-specific data: event name strings (OTELC_VALUE_DATA)
-for span events, status code integers (OTELC_VALUE_INT32) for span statuses.
-
-When the sample value argument contains the "%[" sequence, the parser treats
-it as a log-format string: the lf_used flag is set and the compiled result is
-stored in lf_expr, while the exprs list remains empty.  At runtime, if lf_used
-is true, the log-format expression is evaluated via build_logline() instead of
-the sample expression list.
-
-4.10  flt_otel_conf_sample_expr
-
-  FLT_OTEL_CONF_HDR(fmt_expr)  The original expression format string.
-  expr                         The sample expression (struct sample_expr).
-
-4.11  Simple Types
-
-  flt_otel_conf_hdr   Generic header; used for simple named entries.
-  flt_otel_conf_str   String holder (identical to conf_hdr in layout, but the
-                      HDR field is named "str" instead of "id"); used for
-                      spans_to_finish.
-  flt_otel_conf_link  Span link reference; HDR field named "span".
-  flt_otel_conf_ph    Placeholder; carries a ptr field resolved at check time.
-
-
-5  Initialization
-------------------------------------------------------------------------------
-
-5.1  Macro-Generated Init Functions
-
-The FLT_OTEL_CONF_FUNC_INIT macro (conf_funcs.h) generates a function with the
-following signature for each configuration type:
-
-  struct flt_otel_conf_<type> *flt_otel_conf_<type>_init(const char *id, int line, struct list *head, char **err);
-
-The generated function performs these steps:
-
-  1. Validates that <id> is non-NULL and non-empty.
-  2. Checks the identifier length against FLT_OTEL_ID_MAXLEN (64).
-  3. If <head> is non-NULL, iterates the list to reject duplicate identifiers
-     (strcmp match).
-  4. Allocates the structure with OTELC_CALLOC (zeroed memory).
-  5. Records the configuration line number in cfg_line.
-  6. Duplicates the identifier string with OTELC_STRDUP.
-  7. If <head> is non-NULL, appends the structure to the list via LIST_APPEND.
-  8. Executes any custom initialization body provided as the third macro
-     argument.
-
-If any step fails, the function sets an error message via FLT_OTEL_ERR and
-returns NULL.
-
-5.2  Custom Initialization Bodies
-
-Several structure types require additional setup beyond what the macro template
-provides.  The custom init body runs after the base allocation and list
-insertion succeed:
-
-  conf_sample:
-    LIST_INIT for exprs.  Calls lf_expr_init for lf_expr.
-
-  conf_span:
-    LIST_INIT for links, attributes, events, baggages, statuses.
-
-  conf_scope:
-    LIST_INIT for acls, contexts, spans, spans_to_finish, instruments,
-    log_records.
-
-  conf_group:
-    LIST_INIT for ph_scopes.
-
-  conf_instrument:
-    Sets idx and type to OTELC_METRIC_INSTRUMENT_UNSET, aggr_type to
-    OTELC_METRIC_AGGREGATION_UNSET.  LIST_INIT for samples.
-
-  conf_log_record:
-    LIST_INIT for samples.
-
-  conf_instr:
-    Sets rate_limit to FLT_OTEL_FLOAT_U32(100.0) (100%).  Calls init_new_proxy
-    for proxy_log.  LIST_INIT for acls, ph_groups, ph_scopes.
-
-Types with no custom body (hdr, str, link, ph, sample_expr, context) rely
-entirely on the zeroed OTELC_CALLOC allocation.
-
-5.3  Extended Sample Initialization
-
-The flt_otel_conf_sample_init_ex function (conf.c) provides a higher-level
-initialization for sample structures:
-
-  1. Verifies sufficient arguments in the args[] array.
-  2. Calls flt_otel_conf_sample_init with the sample key.
-  3. Copies extra data (event name string or status code integer).
-  4. Concatenates remaining arguments into the fmt_string via
-     flt_otel_args_concat.
-  5. Counts the number of sample expressions.
-
-This function is used by the parser for span attributes, events, baggages,
-statuses, and instrument samples.
-
-5.4  Top-Level Initialization
-
-The flt_otel_conf_init function (conf.c) is hand-written rather than
-macro-generated because the root structure does not follow the standard header
-pattern:
-
-  1. Allocates flt_otel_conf with OTELC_CALLOC.
-  2. Stores the proxy reference.
-  3. Initializes the groups and scopes lists.
-
-
-6  Deallocation
-------------------------------------------------------------------------------
-
-6.1  Macro-Generated Free Functions
-
-The FLT_OTEL_CONF_FUNC_FREE macro (conf_funcs.h) generates a function with the
-following signature:
-
-  void flt_otel_conf_<type>_free(struct flt_otel_conf_<type> **ptr);
-
-The generated function performs these steps:
-
-  1. Checks that both <ptr> and <*ptr> are non-NULL.
-  2. Executes any custom cleanup body provided as the third macro argument.
-  3. Frees the identifier string with OTELC_SFREE.
-  4. Removes the structure from its list with FLT_OTEL_LIST_DEL.
-  5. Frees the structure with OTELC_SFREE_CLEAR and sets <*ptr> to NULL.
-
-6.2  Custom Cleanup Bodies
-
-Custom cleanup runs before the base teardown, allowing child structures to be
-freed while the parent is still valid:
-
-  conf_sample:
-    Frees fmt_string.  If extra is OTELC_VALUE_DATA, frees the data pointer.
-    Destroys the exprs list (sample_expr entries).  Deinitializes lf_expr via
-    lf_expr_deinit.
-
-  conf_sample_expr:
-    Releases the HAProxy sample expression via release_sample_expr.
-
-  conf_span:
-    Frees ref_id and ctx_id strings.
-    Destroys links, attributes, events, baggages, and statuses lists.
-
-  conf_instrument:
-    Frees description, unit, and bounds.  Destroys the samples list.
-    Destroys the attr key-value array via otelc_kv_destroy.
-
-  conf_log_record:
-    Frees event_name and span strings.  Destroys the attr key-value array via
-    otelc_kv_destroy.  Destroys the samples list.
-
-  conf_scope:
-    Prunes and frees each ACL entry.  Frees the ACL condition via free_acl_cond.
-    Destroys contexts, spans, spans_to_finish, instruments, and log_records
-    lists.
-
-  conf_group:
-    Destroys the ph_scopes list.
-
-  conf_instr:
-    Frees the config string.  Prunes and frees each ACL entry.  Frees each
-    logger entry from proxy_log.loggers.  Destroys the ph_groups and ph_scopes
-    lists.
-
-Types with no custom cleanup (hdr, str, link, ph, context) only run the base
-teardown: free the identifier, unlink, free the structure.
-
-6.3  List Destruction
-
-The FLT_OTEL_LIST_DESTROY(type, head) macro (defined in define.h) iterates a
-list and calls flt_otel_conf_<type>_free for each entry.  This macro drives the
-recursive teardown from parent to leaf.
-
-6.4  Top-Level Deallocation
-
-The flt_otel_conf_free function (conf.c) is hand-written:
-
-  1. Frees the id and cfg_file strings.
-  2. Calls flt_otel_conf_instr_free for the instrumentation.
-  3. Destroys the groups list (which recursively frees placeholders).
-  4. Destroys the scopes list (which recursively frees contexts, spans,
-     instruments, log records, and all their children).
-  5. Frees the root structure and sets the pointer to NULL.
-
-
-7  Summary of Init/Free Pairs
-------------------------------------------------------------------------------
-
-The following table lists all configuration types and their init/free function
-pairs.  Types marked "macro" are generated by the FLT_OTEL_CONF_FUNC_(INIT|FREE)
-macros.  The HDR field column shows which member name is used for the common
-header.
-
-  Type             HDR field  Source  Custom init body
-  ---------------  ---------  ------  -------------------------
-  conf             (none)     manual  groups, scopes
-  conf_hdr         id         macro   (none)
-  conf_str         str        macro   (none)
-  conf_link        span       macro   (none)
-  conf_ph          id         macro   (none)
-  conf_sample_expr fmt_expr   macro   (none)
-  conf_sample      key        macro   exprs, lf_expr
-  conf_sample (ex) key        manual  extra, fmt_string, exprs
-  conf_context     id         macro   (none)
-  conf_span        id         macro   5 sub-lists
-  conf_instrument  id         macro   idx, type, samples
-  conf_log_record  id         macro   samples
-  conf_scope       id         macro   6 sub-lists
-  conf_group       id         macro   ph_scopes
-  conf_instr       id         macro   rate_limit, proxy_log, acls, ph_groups, ph_scopes
diff --git a/addons/otel/README-configuration b/addons/otel/README-configuration
deleted file mode 100644 (file)
index a723d48..0000000
+++ /dev/null
@@ -1,949 +0,0 @@
-                   -----------------------------------------
-                    HAProxy OTel filter configuration guide
-                                Version 1.0
-                        ( Last update: 2026-03-18 )
-                   -----------------------------------------
-                         Author : Miroslav Zagorac
-                   Contact : mzagorac at haproxy dot com
-
-
-SUMMARY
---------
-
-  1.    Overview
-  2.    HAProxy filter declaration
-  3.    OTel configuration file structure
-  3.1.    OTel scope (top-level)
-  3.2.    "otel-instrumentation" section
-  3.3.    "otel-scope" section
-  3.4.    "otel-group" section
-  4.    YAML configuration file
-  4.1.    Exporters
-  4.2.    Samplers
-  4.3.    Processors
-  4.4.    Readers
-  4.5.    Providers
-  4.6.    Signals
-  5.    HAProxy rule integration
-  6.    Complete examples
-  6.1.    Standalone example (sa)
-  6.2.    Frontend / backend example (fe/be)
-  6.3.    Context propagation example (ctx)
-  6.4.    Comparison example (cmp)
-  6.5.    Empty / minimal example (empty)
-
-
-1. Overview
-------------
-
-The OTel filter configuration consists of two files:
-
-  1) An OTel configuration file (.cfg) that defines the tracing model: scopes,
-     groups, spans, attributes, events, instrumentation and log-records.
-
-  2) A YAML configuration file (.yml) that configures the OpenTelemetry SDK
-     pipeline: exporters, samplers, processors, readers, providers and signal
-     routing.
-
-The OTel configuration file is referenced from the HAProxy configuration using
-the 'filter opentelemetry' directive.  The YAML file is in turn referenced from
-the OTel configuration file using the 'config' keyword inside the
-"otel-instrumentation" section.
-
-
-2. HAProxy filter declaration
-------------------------------
-
-The filter is activated by adding a filter directive in the HAProxy
-configuration, in a proxy section (frontend / listen / backend):
-
-  frontend my-frontend
-    ...
-    filter opentelemetry [id <id>] config <otel-cfg-file>
-    ...
-
-If no filter id is specified, 'otel-filter' is used as default.  The 'config'
-parameter is mandatory and specifies the path to the OTel configuration file.
-
-Example (from test/sa/haproxy.cfg):
-
-  frontend otel-test-sa-frontend
-      bind *:10080
-      default_backend servers-backend
-
-      acl acl-http-status-ok status 100:399
-
-      filter opentelemetry id otel-test-sa config sa/otel.cfg
-
-      http-response otel-group otel-test-sa http_response_group if acl-http-status-ok
-      http-after-response otel-group otel-test-sa http_after_response_group if !acl-http-status-ok
-
-  backend servers-backend
-      server server-1 127.0.0.1:8000
-
-
-3. OTel configuration file structure
---------------------------------------
-
-The OTel configuration file uses a simple section-based format.  It contains
-three types of sections: one "otel-instrumentation" section (mandatory), zero
-or more "otel-scope" sections, and zero or more "otel-group" sections.
-
-
-3.1. OTel scope (top-level)
------------------------------
-
-The file is organized into top-level OTel scopes, each identified by a filter
-id enclosed in square brackets.  The filter id must match the id specified in
-the HAProxy 'filter opentelemetry' directive.
-
-  [<filter-id>]
-      otel-instrumentation <name>
-          ...
-
-      otel-group <name>
-          ...
-
-      otel-scope <name>
-          ...
-
-Multiple OTel scopes (for different filter instances) can coexist in the same
-file:
-
-  [my-first-filter]
-      otel-instrumentation instr1
-          ...
-
-  [my-second-filter]
-      otel-instrumentation instr2
-          ...
-
-
-3.2. "otel-instrumentation" section
--------------------------------------
-
-Exactly one "otel-instrumentation" section must be defined per OTel scope.
-It configures the global behavior of the filter and declares which groups
-and scopes are active.
-
-Syntax:
-
-  otel-instrumentation <name>
-
-Keywords (mandatory):
-
-  config <file>
-      Path to the YAML configuration file for the OpenTelemetry SDK.
-
-Keywords (optional):
-
-  acl <aclname> <criterion> [flags] [operator] <value> ...
-      Declare an ACL.  See section 7 of the HAProxy Configuration Manual.
-
-  debug-level <value>
-      Set the debug level bitmask (e.g. 0x77f).  Only effective when compiled
-      with OTEL_DEBUG=1.
-
-  groups <name> ...
-      Declare one or more "otel-group" sections used by this instrumentation.
-      Can be repeated on multiple lines.
-
-  log global
-  log <addr> [len <len>] [format <fmt>] <facility> [<level> [<minlvl>]]
-  no log
-      Enable per-instance logging.
-
-  option disabled / no option disabled
-      Disable or enable the filter.  Default: enabled.
-
-  option dontlog-normal / no option dontlog-normal
-      Suppress logging for normal (successful) operations.  Default: disabled.
-
-  option hard-errors / no option hard-errors
-      Stop all filter processing in a stream after the first error.  Default:
-      disabled (errors are non-fatal).
-
-  rate-limit <value>
-      Percentage of streams for which the filter is activated.  Floating-point
-      value from 0.0 to 100.0.  Default: 100.0.
-
-  scopes <name> ...
-      Declare one or more "otel-scope" sections used by this instrumentation.
-      Can be repeated on multiple lines.
-
-
-Example (from test/sa/otel.cfg):
-
-  [otel-test-sa]
-      otel-instrumentation otel-test-instrumentation
-          debug-level 0x77f
-          log localhost:514 local7 debug
-          config sa/otel.yml
-          option dontlog-normal
-          option hard-errors
-          no option disabled
-          rate-limit 100.0
-
-          groups http_response_group
-          groups http_after_response_group
-
-          scopes on_stream_start
-          scopes on_stream_stop
-
-          scopes client_session_start
-          scopes frontend_tcp_request
-          ...
-          scopes server_session_end
-
-
-3.3. "otel-scope" section
----------------------------
-
-An "otel-scope" section defines the actions that take place when a particular
-event fires or when a group is triggered.
-
-Syntax:
-
-  otel-scope <name>
-
-Supported keywords:
-
-  span <name> [parent <ref>] [link <ref>] [root]
-      Create a new span or reference an already opened one.
-
-      - 'root' marks this span as the trace root (only one per trace).
-      - 'parent <ref>' sets the parent to an existing span or extracted context
-        name.
-      - 'link <ref>' adds an inline link to another span or context.  Multiple
-        inline links can be specified within the argument limit.
-      - If no reference is given, the span becomes a root span.
-
-      A span declaration opens a "sub-context" within the scope: the keywords
-      'link', 'attribute', 'event', 'baggage', 'status' and 'inject' that follow
-      apply to that span until the next 'span' keyword or the end of the scope.
-
-      Examples:
-        span "HAProxy session" root
-        span "Client session" parent "HAProxy session"
-        span "HTTP request" parent "TCP request" link "HAProxy session"
-        span "Client session" parent "otel_ctx_1"
-
-
-  attribute <key> <sample> ...
-      Set an attribute on the currently active span.  A single sample preserves
-      its native type; multiple samples are concatenated as a string.
-
-      Examples:
-        attribute "http.method" method
-        attribute "http.url" url
-        attribute "http.version" str("HTTP/") req.ver
-
-
-  event <name> <key> <sample> ...
-      Add a span event (timestamped annotation) to the currently active span.
-      The data type is always string.
-
-      Examples:
-        event "event_ip" "src" src str(":") src_port
-        event "event_be" "be" be_id str(" ") be_name
-
-
-  baggage <key> <sample> ...
-      Set baggage on the currently active span.  Baggage propagates to all child
-      spans.  The data type is always string.
-
-      Example:
-        baggage "haproxy_id" var(sess.otel.uuid)
-
-
-  status <code> [<sample> ...]
-      Set the span status.  Valid codes: ignore (default), unset, ok, error.
-      An optional description follows the code.
-
-      Examples:
-        status "ok"
-        status "error" str("http.status_code: ") status
-
-
-  link <span> ...
-      Add non-hierarchical links to the currently active span.  Multiple span
-      names can be specified.  Use this keyword for multiple links (the inline
-      'link' in 'span' is limited to one).
-
-      Example:
-        link "HAProxy session" "Client session"
-
-
-  inject <name-prefix> [use-vars] [use-headers]
-      Inject span context into an HTTP header carrier and/or HAProxy variables.
-      The prefix names the context; the special prefix '-' generates the name
-      automatically.  Default storage: use-headers.  The 'use-vars' option
-      requires OTEL_USE_VARS=1 at compile time.
-
-      Example:
-        span "HAProxy session" root
-            inject "otel_ctx_1" use-headers use-vars
-
-
-  extract <name-prefix> [use-vars | use-headers]
-      Extract a previously injected span context from an HTTP header or HAProxy
-      variables.  The extracted context can then be used as a parent reference
-      in 'span ... parent <name-prefix>'.
-
-      Example:
-        extract "otel_ctx_1" use-vars
-        span "Client session" parent "otel_ctx_1"
-
-
-  finish <name> ...
-      Close one or more spans or span contexts.  Special names:
-        '*'      - finish all open spans
-        '*req*'  - finish all request-channel spans
-        '*res*'  - finish all response-channel spans
-
-      Multiple names can be given on one line.  A quoted context name after a
-      span name finishes the associated context as well.
-
-      Examples:
-        finish "Frontend TCP request"
-        finish "Client session" "otel_ctx_2"
-        finish *
-
-
-  instrument <type> <name> [aggr <aggregation>] [desc <description>] [unit <unit>] value <sample> [bounds <bounds>]
-  instrument update <name> [attr <key> <sample> ...]
-      Create or update a metric instrument.
-
-      Supported types:
-        cnt_int   - counter (uint64)
-        hist_int  - histogram (uint64)
-        udcnt_int - up-down counter (int64)
-        gauge_int - gauge (int64)
-
-      Supported aggregation types:
-        drop           - measurements are discarded
-        histogram      - explicit bucket histogram
-        last_value     - last recorded value
-        sum            - sum of recorded values
-        default        - SDK default for the instrument type
-        exp_histogram  - base-2 exponential histogram
-
-      An aggregation type can be specified using the 'aggr' keyword.  When
-      specified, a metrics view is registered with the given aggregation
-      strategy.  If omitted, the SDK default is used.
-
-      For histogram instruments (hist_int), optional bucket boundaries can be
-      specified using the 'bounds' keyword followed by a double-quoted string
-      of space-separated numbers (order does not matter; values are sorted
-      internally).  When bounds are specified without an explicit aggregation
-      type, histogram aggregation is used automatically.
-
-      Observable (asynchronous) and double-precision types are not supported.
-      Observable instrument callbacks are invoked by the OTel SDK from an
-      external background thread; HAProxy sample fetches rely on internal
-      per-thread-group state and return incorrect results from a non-HAProxy
-      thread.  Double-precision types are not supported because HAProxy sample
-      fetches do not return double values.
-
-      Examples:
-        instrument cnt_int  "name_cnt_int" desc "Integer Counter" value int(1),add(2) unit "unit"
-        instrument hist_int "name_hist" aggr exp_histogram desc "Latency" value lat_ns_tot unit "ns"
-        instrument hist_int "name_hist2" desc "Latency" value lat_ns_tot unit "ns" bounds "100 1000 10000"
-        instrument update "name_cnt_int" attr "attr_1_key" str("attr_1_value")
-
-
-  log-record <severity> [id <integer>] [event <name>] [span <span-name>] [attr <key> <sample>] ... <sample> ...
-      Emit an OpenTelemetry log record.  The first argument is a required
-      severity level.  Optional keywords follow in any order:
-
-        id <integer>        - numeric event identifier
-        event <name>        - event name string
-        span <span-name>    - associate the log record with an open span
-        attr <key> <sample> - add an attribute evaluated at runtime (repeatable)
-
-      The 'attr' keyword takes an attribute name and a single HAProxy sample
-      expression.  The expression is evaluated at runtime, following the same
-      rules as span attributes: a bare sample fetch (e.g. src) or a log-format
-      string (e.g. "%[src]:%[src_port]").
-
-      The remaining arguments at the end are sample fetch expressions that form
-      the log record body.  A single sample preserves its native type; multiple
-      samples are concatenated as a string.
-
-      Supported severity levels follow the OpenTelemetry specification:
-        trace, trace2, trace3, trace4
-        debug, debug2, debug3, debug4
-        info,  info2,  info3,  info4
-        warn,  warn2,  warn3,  warn4
-        error, error2, error3, error4
-        fatal, fatal2, fatal3, fatal4
-
-      The log record is only emitted if the logger is enabled for the configured
-      severity (controlled by the 'min_severity' option in the YAML logs signal
-      configuration).  If a 'span' reference is given but the named span is not
-      found at runtime, the log record is emitted without span correlation.
-
-      Examples:
-        log-record info str("heartbeat")
-        log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" method method url
-        log-record trace id 1000 event "session-start" span "Client session" attr "src_ip" src attr "src_port" src_port src str(":") src_port
-        log-record warn event "server-unavailable" str("503 Service Unavailable")
-        log-record info event "session-stop" str("stream stopped")
-
-
-  acl <aclname> <criterion> [flags] [operator] <value> ...
-      Declare an ACL local to this scope.
-
-      Example:
-        acl acl-test-src-ip src 127.0.0.1
-
-
-  otel-event <name> [{ if | unless } <condition>]
-      Bind this scope to a filter event, optionally with an ACL-based condition.
-
-      Supported events (stream lifecycle):
-        on-stream-start
-        on-stream-stop
-        on-idle-timeout
-        on-backend-set
-
-      Supported events (request channel):
-        on-client-session-start
-        on-frontend-tcp-request
-        on-http-wait-request
-        on-http-body-request
-        on-frontend-http-request
-        on-switching-rules-request
-        on-backend-tcp-request
-        on-backend-http-request
-        on-process-server-rules-request
-        on-http-process-request
-        on-tcp-rdp-cookie-request
-        on-process-sticking-rules-request
-        on-http-headers-request
-        on-http-end-request
-        on-client-session-end
-        on-server-unavailable
-
-      Supported events (response channel):
-        on-server-session-start
-        on-tcp-response
-        on-http-wait-response
-        on-process-store-rules-response
-        on-http-response
-        on-http-headers-response
-        on-http-end-response
-        on-http-reply
-        on-server-session-end
-
-      The on-stream-start event fires from the stream_start filter callback,
-      before any channel processing begins.  The on-stream-stop event fires from
-      the stream_stop callback, after all channel processing ends.  No channel
-      is available at that point, so context injection/extraction via HTTP
-      headers cannot be used in scopes bound to these events.
-
-      The on-idle-timeout event fires periodically when the stream has no data
-      transfer activity.  It requires the 'idle-timeout' keyword to set the
-      interval.  Scopes bound to this event can create heartbeat spans, record
-      idle-time metrics, and emit idle-time log records.
-
-      The on-backend-set event fires when a backend is assigned to the stream.
-      It is not called if the frontend and backend are the same.
-
-      The on-http-headers-request and on-http-headers-response events fire after
-      all HTTP headers have been parsed and analyzed.
-
-      The on-http-end-request and on-http-end-response events fire when all HTTP
-      data has been processed and forwarded.
-
-      The on-http-reply event fires when HAProxy generates an internal reply
-      (error page, deny response, redirect).
-
-      Examples:
-        otel-event on-stream-start if acl-test-src-ip
-        otel-event on-stream-stop
-        otel-event on-client-session-start
-        otel-event on-client-session-start if acl-test-src-ip
-        otel-event on-http-response if !acl-http-status-ok
-        otel-event on-idle-timeout
-
-
-  idle-timeout <time>
-      Set the idle timeout interval for a scope bound to the 'on-idle-timeout'
-      event.  The timer fires periodically at the given interval when the stream
-      has no data transfer activity.  This keyword is mandatory for scopes using
-      the 'on-idle-timeout' event and cannot be used with any other event.
-
-      The <time> argument accepts the standard HAProxy time format: a number
-      followed by a unit suffix (ms, s, m, h, d).  A value of zero is not
-      permitted.
-
-      Example:
-        scopes on_idle_timeout
-        ..
-        otel-scope on_idle_timeout
-            idle-timeout 5s
-            span "heartbeat" root
-                attribute "idle.elapsed" str("idle-check")
-            instrument cnt_int "idle.count" value int(1)
-            log-record info str("heartbeat")
-            otel-event on-idle-timeout
-
-
-3.4. "otel-group" section
----------------------------
-
-An "otel-group" section defines a named collection of scopes that can be
-triggered from HAProxy TCP/HTTP rules rather than from filter events.
-
-Syntax:
-
-  otel-group <name>
-
-Keywords:
-
-  scopes <name> ...
-      List the "otel-scope" sections that belong to this group.  Multiple names
-      can be given on one line.  Scopes that are used only in groups do not need
-      to define an 'otel-event'.
-
-Example (from test/sa/otel.cfg):
-
-  otel-group http_response_group
-      scopes http_response_1
-      scopes http_response_2
-
-  otel-scope http_response_1
-      span "HTTP response"
-          event "event_content" "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes")
-
-  otel-scope http_response_2
-      span "HTTP response"
-          event "event_date" "hdr.date" res.hdr("date") str(" / ") res.hdr("last-modified")
-
-
-4. YAML configuration file
-----------------------------
-
-The YAML configuration file defines the OpenTelemetry SDK pipeline.  It is
-referenced by the 'config' keyword in the "otel-instrumentation" section.
-It contains the following top-level sections: exporters, samplers, processors,
-readers, providers and signals.
-
-
-4.1. Exporters
----------------
-
-Each exporter has a user-chosen name and a 'type' that determines which
-additional options are available.  Options marked with (*) are required.
-
-Supported types:
-
-  otlp_grpc - Export via OTLP over gRPC.
-    type (*)                          "otlp_grpc"
-    thread_name                       exporter thread name (string)
-    endpoint                          OTLP/gRPC endpoint URL (string)
-    use_ssl_credentials               enable SSL channel credentials (boolean)
-    ssl_credentials_cacert_path       CA certificate file path (string)
-    ssl_credentials_cacert_as_string  CA certificate as inline string (string)
-    ssl_client_key_path               client private key file path (string)
-    ssl_client_key_string             client private key as inline string (string)
-    ssl_client_cert_path              client certificate file path (string)
-    ssl_client_cert_string            client certificate as inline string (string)
-    timeout                           export timeout in seconds (integer)
-    user_agent                        User-Agent header value (string)
-    max_threads                       maximum exporter threads (integer)
-    compression                       compression algorithm name (string)
-    max_concurrent_requests           concurrent request limit (integer)
-
-
-  otlp_http - Export via OTLP over HTTP (JSON or Protobuf).
-    type (*)                        "otlp_http"
-    thread_name                     exporter thread name (string)
-    endpoint                        OTLP/HTTP endpoint URL (string)
-    content_type                    payload format: "json" or "protobuf"
-    json_bytes_mapping              binary encoding: "hexid", "utf8" or "base64"
-    debug                           enable debug output (boolean)
-    timeout                         export timeout in seconds (integer)
-    http_headers                    custom HTTP headers (list of key: value)
-    max_concurrent_requests         concurrent request limit (integer)
-    max_requests_per_connection     request limit per connection (integer)
-    background_thread_wait_for      idle timeout for the HTTP background thread
-                                    in milliseconds; 0 means the thread never
-                                    exits on its own (integer, default: 0).  If
-                                    this option is set, 'insecure-fork-wanted'
-                                    must be used in the HAProxy configuration,
-                                    otherwise HAProxy may crash while exporting
-                                    OTel data
-    ssl_insecure_skip_verify        skip TLS certificate verification (boolean)
-    ssl_ca_cert_path                CA certificate file path (string)
-    ssl_ca_cert_string              CA certificate as inline string (string)
-    ssl_client_key_path             client private key file path (string)
-    ssl_client_key_string           client private key as inline string (string)
-    ssl_client_cert_path            client certificate file path (string)
-    ssl_client_cert_string          client certificate as inline string (string)
-    ssl_min_tls                     minimum TLS version (string)
-    ssl_max_tls                     maximum TLS version (string)
-    ssl_cipher                      TLS cipher list (string)
-    ssl_cipher_suite                TLS 1.3 cipher suite list (string)
-    compression                     compression algorithm name (string)
-
-
-  otlp_file - Export to local files in OTLP format.
-    type (*)                        "otlp_file"
-    thread_name                     exporter thread name (string)
-    file_pattern                    output filename pattern (string)
-    alias_pattern                   symlink pattern for latest file (string)
-    flush_interval                  flush interval in microseconds (integer)
-    flush_count                     spans per flush (integer)
-    file_size                       maximum file size in bytes (integer)
-    rotate_size                     number of rotated files to keep (integer)
-
-
-  ostream - Write to a file (text output, useful for debugging).
-    type (*)                        "ostream"
-    filename                        output file path (string)
-
-
-  memory - In-memory buffer (useful for testing).
-    type (*)                        "memory"
-    buffer_size                     maximum buffered items (integer)
-
-
-  zipkin - Export to Zipkin-compatible backends.
-    type (*)                        "zipkin"
-    endpoint                        Zipkin collector URL (string)
-    format                          payload format: "json" or "protobuf"
-    service_name                    service name reported to Zipkin (string)
-    ipv4                            service IPv4 address (string)
-    ipv6                            service IPv6 address (string)
-
-
-  elasticsearch - Export to Elasticsearch.
-    type (*)                        "elasticsearch"
-    host                            Elasticsearch hostname (string)
-    port                            Elasticsearch port (integer)
-    index                           Elasticsearch index name (string)
-    response_timeout                response timeout in seconds (integer)
-    debug                           enable debug output (boolean)
-    http_headers                    custom HTTP headers (list of key: value)
-
-
-4.2. Samplers
---------------
-
-Samplers control which traces are recorded.  Each sampler has a user-chosen
-name and a 'type' that determines its behavior.
-
-Supported types:
-
-  always_on - Sample every trace.
-    type (*)                        "always_on"
-
-
-  always_off - Sample no traces.
-    type (*)                        "always_off"
-
-
-  trace_id_ratio_based - Sample a fraction of traces.
-    type (*)                        "trace_id_ratio_based"
-    ratio                           sampling ratio, 0.0 to 1.0 (float)
-
-
-  parent_based - Inherit sampling decision from parent span.
-    type (*)                        "parent_based"
-    delegate                        fallback sampler name (string)
-
-
-4.3. Processors
-----------------
-
-Processors define how telemetry data is handled before export.  Each
-processor has a user-chosen name and a 'type' that determines its behavior.
-
-Supported types:
-
-  batch - Batch spans before exporting.
-    type (*)                        "batch"
-    thread_name                     processor thread name (string)
-    max_queue_size                  maximum queued spans (integer)
-    schedule_delay                  export interval in milliseconds (integer)
-    max_export_batch_size           maximum spans per export call (integer)
-
-    When the queue reaches half capacity, a preemptive notification triggers
-    an early export.
-
-  single - Export each span individually (no batching).
-    type (*)                        "single"
-
-
-4.4. Readers
--------------
-
-Readers define how metrics are collected and exported.  Each reader has a
-user-chosen name.
-
-    thread_name                     reader thread name (string)
-    export_interval                 collection interval in milliseconds (integer)
-    export_timeout                  export timeout in milliseconds (integer)
-
-
-4.5. Providers
----------------
-
-Providers define resource attributes attached to all telemetry data.  Each
-provider has a user-chosen name.
-
-    resources                       key-value resource attributes (list)
-
-Standard resource attribute keys include service.name, service.version,
-service.instance.id and service.namespace.
-
-
-4.6. Signals
--------------
-
-Signals bind exporters, samplers, processors, readers and providers together
-for each telemetry type.  The supported signal names are "traces", "metrics"
-and "logs".
-
-    scope_name                      instrumentation scope name (string)
-    exporters                       exporter name reference (string)
-    samplers                        sampler name reference (string, traces only)
-    processors                      processor name reference (string, traces/logs)
-    readers                         reader name reference (string, metrics only)
-    providers                       provider name reference (string)
-    min_severity                    minimum log severity level (string, logs only)
-
-The "min_severity" option controls which log records are emitted.  Only log
-records whose severity is equal to or higher than the configured minimum are
-passed to the exporter.  The value is a severity name as listed under the
-"log-record" keyword (e.g. "trace", "debug", "info", "warn", "error", "fatal").
-If omitted, the logger accepts all severity levels.
-
-
-5. HAProxy rule integration
-----------------------------
-
-Groups defined in the OTel configuration file can be triggered from HAProxy
-TCP/HTTP rules using the 'otel-group' action keyword:
-
-  http-request        otel-group <filter-id> <group> [condition]
-  http-response       otel-group <filter-id> <group> [condition]
-  http-after-response otel-group <filter-id> <group> [condition]
-  tcp-request         otel-group <filter-id> <group> [condition]
-  tcp-response        otel-group <filter-id> <group> [condition]
-
-This allows running specific groups of scopes based on ACL conditions defined
-in the HAProxy configuration.
-
-Example (from test/sa/haproxy.cfg):
-
-  acl acl-http-status-ok status 100:399
-
-  filter opentelemetry id otel-test-sa config sa/otel.cfg
-
-  # Run response scopes for successful responses
-  http-response otel-group otel-test-sa http_response_group if acl-http-status-ok
-
-  # Run after-response scopes for error responses
-  http-after-response otel-group otel-test-sa http_after_response_group if !acl-http-status-ok
-
-
-6. Complete examples
----------------------
-
-The test directory contains several complete example configurations.  Each
-subdirectory contains an OTel configuration file (otel.cfg), a YAML file
-(otel.yml) and a HAProxy configuration file (haproxy.cfg).
-
-
-6.1. Standalone example (sa)
-------------------------------
-
-The most comprehensive example.  All possible events are used, with spans,
-attributes, events, links, baggage, status, metrics and groups demonstrated.
-
---- test/sa/otel.cfg (excerpt) -----------------------------------------
-
-[otel-test-sa]
-    otel-instrumentation otel-test-instrumentation
-        config sa/otel.yml
-        option dontlog-normal
-        option hard-errors
-        no option disabled
-        rate-limit 100.0
-
-        groups http_response_group
-        groups http_after_response_group
-
-        scopes on_stream_start
-        scopes on_stream_stop
-        scopes client_session_start
-        scopes frontend_tcp_request
-        ...
-        scopes server_session_end
-
-    otel-group http_response_group
-        scopes http_response_1
-        scopes http_response_2
-
-    otel-scope http_response_1
-        span "HTTP response"
-            event "event_content" "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes")
-
-    otel-scope on_stream_start
-        instrument udcnt_int "haproxy.sessions.active" desc "Active sessions" value int(1) unit "{session}"
-        span "HAProxy session" root
-            baggage "haproxy_id" var(sess.otel.uuid)
-            event "event_ip" "src" src str(":") src_port
-        acl acl-test-src-ip src 127.0.0.1
-        otel-event on-stream-start if acl-test-src-ip
-
-    otel-scope on_stream_stop
-        finish *
-        otel-event on-stream-stop
-
-    otel-scope client_session_start
-        span "Client session" parent "HAProxy session"
-        otel-event on-client-session-start
-
-    otel-scope frontend_http_request
-        span "Frontend HTTP request" parent "HTTP body request" link "HAProxy session"
-            attribute "http.method" method
-            attribute "http.url" url
-            attribute "http.version" str("HTTP/") req.ver
-        finish "HTTP body request"
-        otel-event on-frontend-http-request
-
-    otel-scope server_session_start
-        span "Server session" parent "HAProxy session"
-        link "HAProxy session" "Client session"
-        finish "Process sticking rules request"
-        otel-event on-server-session-start
-
-    otel-scope server_session_end
-        finish *
-        otel-event on-server-session-end
-
----------------------------------------------------------------------
-
-
-6.2. Frontend / backend example (fe/be)
------------------------------------------
-
-Demonstrates distributed tracing across two cascaded HAProxy instances using
-inject/extract to propagate the span context via HTTP headers.
-
-The frontend HAProxy (test/fe) creates the root trace and injects context:
-
---- test/fe/otel.cfg (excerpt) -----------------------------------------
-
-    otel-scope backend_http_request
-        span "Backend HTTP request" parent "Backend TCP request"
-        finish "Backend TCP request"
-        span "HAProxy session"
-            inject "otel-ctx" use-headers
-        otel-event on-backend-http-request
-
----------------------------------------------------------------------
-
-The backend HAProxy (test/be) extracts the context and continues the trace:
-
---- test/be/otel.cfg (excerpt) -----------------------------------------
-
-    otel-scope frontend_http_request
-        extract "otel-ctx" use-headers
-        span "HAProxy session" parent "otel-ctx" root
-            baggage "haproxy_id" var(sess.otel.uuid)
-        span "Client session" parent "HAProxy session"
-        span "Frontend HTTP request" parent "Client session"
-            attribute "http.method" method
-            attribute "http.url" url
-            attribute "http.version" str("HTTP/") req.ver
-        otel-event on-frontend-http-request
-
----------------------------------------------------------------------
-
-
-6.3. Context propagation example (ctx)
-----------------------------------------
-
-Similar to 'sa', but spans are opened using extracted span contexts as parent
-references instead of direct span names.  This demonstrates the inject/extract
-mechanism using HAProxy variables.
-
---- test/ctx/otel.cfg (excerpt) ----------------------------------------
-
-    otel-scope client_session_start_1
-        span "HAProxy session" root
-            inject "otel_ctx_1" use-headers use-vars
-            baggage "haproxy_id" var(sess.otel.uuid)
-        otel-event on-client-session-start
-
-    otel-scope client_session_start_2
-        extract "otel_ctx_1" use-vars
-        span "Client session" parent "otel_ctx_1"
-            inject "otel_ctx_2" use-headers use-vars
-        otel-event on-client-session-start
-
-    otel-scope frontend_tcp_request
-        extract "otel_ctx_2" use-vars
-        span "Frontend TCP request" parent "otel_ctx_2"
-            inject "otel_ctx_3" use-headers use-vars
-        otel-event on-frontend-tcp-request
-
-    otel-scope http_wait_request
-        extract "otel_ctx_3" use-vars
-        span "HTTP wait request" parent "otel_ctx_3"
-        finish "Frontend TCP request" "otel_ctx_3"
-        otel-event on-http-wait-request
-
----------------------------------------------------------------------
-
-
-6.4. Comparison example (cmp)
--------------------------------
-
-A configuration made for comparison purposes with other tracing implementations.
-It uses a simplified span hierarchy without context propagation.
-
---- test/cmp/otel.cfg (excerpt) ----------------------------------------
-
-    otel-scope client_session_start
-        span "HAProxy session" root
-            baggage "haproxy_id" var(sess.otel.uuid)
-        span "Client session" parent "HAProxy session"
-        otel-event on-client-session-start
-
-    otel-scope http_response-error
-        span "HTTP response"
-            status "error" str("!acl-http-status-ok")
-        otel-event on-http-response if !acl-http-status-ok
-
-    otel-scope server_session_end
-        finish "HTTP response" "Server session"
-        otel-event on-http-response
-
-    otel-scope client_session_end
-        finish "*"
-        otel-event on-http-response
-
----------------------------------------------------------------------
-
-
-6.5. Empty / minimal example (empty)
---------------------------------------
-
-The minimal valid OTel configuration.  The filter is initialized but no events
-are triggered:
-
---- test/empty/otel.cfg -------------------------------------------------
-
-  otel-instrumentation otel-test-instrumentation
-      config empty/otel.yml
-
----------------------------------------------------------------------
-
-This is useful for testing the OTel filter initialization behavior without any
-actual telemetry processing.
diff --git a/addons/otel/README-design b/addons/otel/README-design
deleted file mode 100644 (file)
index cd5a925..0000000
+++ /dev/null
@@ -1,725 +0,0 @@
-OpenTelemetry filter -- design patterns
-==========================================================================
-
-This document describes the cross-cutting design patterns used throughout
-the OTel filter implementation.  It complements README-implementation
-(component-by-component architecture) with a pattern-oriented view of the
-mechanisms that span multiple source files.
-
-
-1  X-Macro Code Generation
-----------------------------------------------------------------------
-
-The filter uses X-macro lists extensively to generate enums, keyword tables,
-event metadata and configuration init/free functions from a single definition.
-Each X-macro list is a preprocessor define containing repeated invocations of
-a helper macro whose name is supplied by the expansion context.
-
-1.1  Event Definitions
-
-FLT_OTEL_EVENT_DEFINES (event.h) drives the event system.  Each entry has the
-form:
-
-  FLT_OTEL_EVENT_DEF(NAME, CHANNEL, REQ_AN, RES_AN, HTTP_INJ, "string")
-
-The same list is expanded twice:
-
-  - In enum FLT_OTEL_EVENT_enum (event.h) to produce symbolic constants
-    (FLT_OTEL_EVENT_NONE, FLT_OTEL_EVENT_REQ_STREAM_START, etc.) followed by
-    the FLT_OTEL_EVENT_MAX sentinel.
-
-  - In the flt_otel_event_data[] initializer (event.c) to produce a const table
-    of struct flt_otel_event_data entries carrying the analyzer bit, sample
-    fetch direction, valid fetch locations, HTTP injection flag and event name
-    string.
-
-Adding a new event requires a single line in the X-macro list.
-
-1.2  Parser Keyword Definitions
-
-Three X-macro lists drive the configuration parser:
-
-  FLT_OTEL_PARSE_INSTR_DEFINES   (parser.h, 9 keywords)
-  FLT_OTEL_PARSE_GROUP_DEFINES   (parser.h, 2 keywords)
-  FLT_OTEL_PARSE_SCOPE_DEFINES   (parser.h, 15 keywords)
-
-Each entry has the form:
-
-  FLT_OTEL_PARSE_DEF(ENUM, flag, check, min, max, "name", "usage")
-
-Each list is expanded to:
-
-  - An enum for keyword indices (FLT_OTEL_PARSE_INSTR_ID, etc.).
-  - A static parse_data[] table of struct flt_otel_parse_data entries carrying
-    the keyword index, flag_check_id, check_name type, argument count bounds,
-    keyword name string and usage string.
-
-The section parsers (flt_otel_parse_cfg_instr, _group, _scope) look up args[0]
-in their parse_data table via flt_otel_parse_cfg_check(), which validates
-argument counts and character constraints before dispatching to
-the keyword-specific handler.
-
-Additional X-macro lists generate:
-
-  FLT_OTEL_PARSE_SCOPE_STATUS_DEFINES      Span status codes.
-  FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEFINES  Instrument type keywords.
-  FLT_OTEL_HTTP_METH_DEFINES               HTTP method name table.
-  FLT_OTEL_GROUP_DEFINES                   Group action metadata.
-
-1.3  Configuration Init/Free Generation
-
-Two macros in conf_funcs.h generate init and free functions for all
-configuration structure types:
-
-  FLT_OTEL_CONF_FUNC_INIT(_type_, _id_, _func_)
-  FLT_OTEL_CONF_FUNC_FREE(_type_, _id_, _func_)
-
-The _type_ parameter names the structure (e.g. "span"), _id_ names the
-identifier field within the FLT_OTEL_CONF_HDR (e.g. "id", "key", "str"), and
-_func_ is a brace-enclosed code block executed after the boilerplate allocation
-(for init) or before the boilerplate teardown (for free).
-
-The generated init function:
-  1. Validates the identifier is non-NULL and non-empty.
-  2. Checks the length against FLT_OTEL_ID_MAXLEN (64).
-  3. Detects duplicates in the target list.
-  4. Handles auto-generated IDs (FLT_OTEL_CONF_HDR_SPECIAL prefix).
-  5. Allocates with OTELC_CALLOC, duplicates the ID with OTELC_STRDUP.
-  6. Appends to the parent list via LIST_APPEND.
-  7. Executes the custom _func_ body.
-
-The generated free function:
-  1. Executes the custom _func_ body (typically list destruction).
-  2. Frees the identifier string.
-  3. Removes the node from its list.
-  4. Frees the structure with OTELC_SFREE_CLEAR.
-
-conf.c instantiates these macros for all 13 configuration types: hdr, str, ph,
-sample_expr, sample, link, context, span, scope, instrument, log_record, group,
-instr.  The more complex types (span, scope, instr) carry non-trivial _func_
-bodies that initialize sub-lists or set default values.
-
-
-2  Type-Safe Generic Macros
-----------------------------------------------------------------------
-
-define.h provides utility macros that use typeof() and statement expressions
-for type-safe generic programming without C++ templates.
-
-2.1  Safe Pointer Dereferencing
-
-  FLT_OTEL_PTR_SAFE(a, b)
-    Returns 'a' if non-NULL, otherwise the default value 'b'.  Uses typeof(*(a))
-    to verify type compatibility at compile time.
-
-  FLT_OTEL_DEREF(p, m, v)
-    Safely dereferences p->m, returning 'v' if 'p' is NULL.
-
-  FLT_OTEL_DDEREF(a, m, v)
-    Safely double-dereferences *a->m, returning 'v' if either 'a' or '*a' is
-    NULL.
-
-These macros eliminate repetitive NULL checks while preserving the correct
-pointer types through typeof().
-
-2.2  String Comparison
-
-  FLT_OTEL_STR_CMP(S, s)
-    Compares a runtime string 's' against a compile-time string literal 'S'.
-    Expands to a call with the literal's address and computed length, avoiding
-    repeated strlen() on known constants.
-
-  FLT_OTEL_CONF_STR_CMP(s, S)
-    Compares two configuration strings using their cached length fields (from
-    FLT_OTEL_CONF_STR / FLT_OTEL_CONF_HDR).  Falls through to memcmp() only when
-    lengths match, providing an early-out fast path.
-
-2.3  List Operations
-
-  FLT_OTEL_LIST_ISVALID(a)
-    Checks whether a list head has been initialized (both prev and next are
-    non-NULL).
-
-  FLT_OTEL_LIST_DEL(a)
-    Safely deletes a list element only if the list head is valid.
-
-  FLT_OTEL_LIST_DESTROY(t, h)
-    Destroys all elements in a typed configuration list by iterating with
-    list_for_each_entry_safe and calling flt_otel_conf_<t>_free() for each
-    entry.  The type 't' is used to derive both the structure type and the
-    free function name.
-
-2.4  Thread-Local Rotating Buffers
-
-  FLT_OTEL_BUFFER_THR(b, m, n, p)
-    Declares a thread-local pool of 'n' string buffers, each of size 'm'.
-    The pool index rotates on each invocation, avoiding the need for explicit
-    allocation in debug formatting functions.  Each call returns a pointer to
-    the next buffer via the output parameter 'p'.
-
-    Used primarily in debug-only functions (flt_otel_analyzer,
-    flt_otel_list_dump) where temporary strings must survive until their caller
-    finishes with them.
-
-
-3  Error Handling Architecture
-----------------------------------------------------------------------
-
-3.1  Error Accumulation Macros
-
-Three macros in define.h manage error messages:
-
-  FLT_OTEL_ERR(f, ...)
-    Formats an error message via memprintf() into the caller's char **err
-    pointer, but only if *err is still NULL.  Prevents overwriting the first
-    error with a cascading secondary error.
-
-  FLT_OTEL_ERR_APPEND(f, ...)
-    Unconditionally appends to the error message regardless of prior content.
-    Used when a function must report multiple issues.
-
-  FLT_OTEL_ERR_FREE(p)
-    Logs the accumulated error message at WARNING level via FLT_OTEL_ALERT,
-    then frees the string and NULLs the pointer.
-
-All source functions that can fail accept a char **err parameter.  The
-convention is: set *err on error, leave it alone on success.  Callers check
-both the return value and *err to detect problems.
-
-3.2  Parse-Time Error Reporting
-
-Configuration parsing (parser.c) uses additional macros:
-
-  FLT_OTEL_PARSE_ERR(e, f, ...)
-    Sets the error string and ORs ERR_ABORT | ERR_ALERT into the return value.
-    Used inside section parser switch statements.
-
-  FLT_OTEL_PARSE_ALERT(f, ...)
-    Issues a ha_alert() with the current file and line, then sets the error
-    flags.  Used when the error message should appear immediately.
-
-  FLT_OTEL_POST_PARSE_ALERT(f, ...)
-    Same as PARSE_ALERT but uses cfg_file instead of file, for post-parse
-    validation that runs after the parser has moved on.
-
-  FLT_OTEL_PARSE_IFERR_ALERT()
-    Checks whether *err was set by a called function, and if so, issues an
-    alert and clears the error.  This bridges between functions that use the
-    char **err convention and the parser's own alert mechanism.
-
-3.3  Runtime Error Modes
-
-Two helper functions in filter.c implement the runtime error policy:
-
-  flt_otel_return_int(f, err, retval)
-  flt_otel_return_void(f, err)
-
-If an error is detected (retval == FLT_OTEL_RET_ERROR or *err != NULL):
-
-  Hard-error mode (rt_ctx->flag_harderr):
-    Sets rt_ctx->flag_disabled = 1, disabling the filter for the remainder of
-    the stream.  Atomically increments the disabled counter.  The error is
-    logged as "filter hard-error (disabled)".
-
-  Soft-error mode (default):
-    The error is logged as "filter soft-error" and processing continues.  The
-    tracing data for the current event may be incomplete but the stream is not
-    affected.
-
-In both modes, FLT_OTEL_RET_OK is always returned to HAProxy.  A tracing failure
-never interrupts stream processing.
-
-3.4  Disabled State Checking
-
-flt_otel_is_disabled() (filter.c) is called at the top of every filter callback
-that processes events.  It checks three conditions:
-
-  1. rt_ctx is NULL (filter was never attached or already detached).
-  2. rt_ctx->flag_disabled is set (hard-error disabled the filter).
-  3. conf->instr->flag_disabled is set (globally disabled via CLI).
-
-All three are loaded via _HA_ATOMIC_LOAD() for thread safety.  When disabled,
-the callback returns immediately without processing.
-
-
-4  Thread Safety Model
-----------------------------------------------------------------------
-
-The filter runs within HAProxy's multi-threaded worker model.  Each stream is
-bound to a single thread, so per-stream state (the runtime context, spans and
-contexts) is accessed without locking.  Cross-stream shared state uses atomic
-operations.
-
-4.1  Atomic Fields
-
-The following fields are accessed atomically across threads:
-
-  conf->instr->flag_disabled  Toggled by CLI "otel enable/disable".  Checked in
-                              flt_otel_ops_attach() and flt_otel_is_disabled().
-
-  conf->instr->flag_harderr   Toggled by CLI "otel hard-errors/soft-errors".
-                              Copied to rt_ctx at attach time.
-
-  conf->instr->rate_limit     Set by CLI "otel rate".
-                              Read in flt_otel_ops_attach().
-
-  conf->instr->logging        Set by CLI "otel logging".
-                              Copied to rt_ctx at attach time.
-
-  flt_otel_drop_cnt           Incremented in flt_otel_log_handler_cb().
-                              Read by CLI "otel status".
-
-  conf->cnt.disabled[]        Incremented in flt_otel_return_int/void().
-  conf->cnt.attached[]        Incremented in flt_otel_ops_attach().
-
-All use _HA_ATOMIC_LOAD(), _HA_ATOMIC_STORE(), _HA_ATOMIC_INC() or
-_HA_ATOMIC_ADD() from HAProxy's atomic primitives.
-
-4.2  Metric Instrument Creation (CAS Pattern)
-
-Metric instruments are shared across all threads but created lazily on first
-use.  The creation uses a compare-and-swap pattern to ensure exactly one thread
-performs the creation:
-
-  int64_t expected = OTELC_METRIC_INSTRUMENT_UNSET;  /* -1 */
-  if (HA_ATOMIC_CAS(&instr->idx, &expected, OTELC_METRIC_INSTRUMENT_PENDING)) {
-      /* This thread won the race -- create the instrument. */
-      idx = meter->create_instrument(...);
-      HA_ATOMIC_STORE(&instr->idx, idx);
-  }
-
-The three states are:
-  UNSET   (-1)  Not yet created.  The CAS target.
-  PENDING (-2)  Creation in progress by another thread.
-  >= 0          Valid meter index.  Ready for recording.
-
-Threads that lose the CAS skip creation.  Update-form instruments check that the
-referenced create-form's idx is >= 0 before recording; if it is still PENDING or
-UNSET, the measurement is silently skipped.
-
-4.3  Per-Thread Initialization Guard
-
-flt_otel_ops_init_per_thread() uses the FLT_CFG_FL_HTX flag on fconf as a
-one-shot guard: the tracer, meter and logger background threads are started only
-on the first call.  Subsequent calls from other proxies sharing the same filter
-configuration skip the start sequence.
-
-4.4  CLI Update Propagation
-
-CLI set commands (cli.c) iterate all OTel filter instances across all proxies
-using the FLT_OTEL_PROXIES_LIST_START / FLT_OTEL_PROXIES_LIST_END macros
-(util.h) and atomically update the target field on each instance.  This ensures
-that "otel disable" takes effect globally, not just on one proxy.
-
-
-5  Sample Evaluation Pipeline
-----------------------------------------------------------------------
-
-Sample expressions bridge HAProxy's runtime data (headers, variables, connection
-properties) into OTel attributes, events, baggage, status, metric values and log
-record bodies.
-
-5.1  Two Evaluation Paths
-
-The parser detects which path to use based on the presence of "%[" in the sample
-value argument:
-
-  Log-format path (sample->lf_used == true):
-    The value is parsed via parse_logformat_string() and stored in
-    sample->lf_expr.  At runtime, build_logline() evaluates the expression into
-    a temporary buffer of global.tune.bufsize bytes.  The result is always a
-    string.
-
-  Bare sample path (sample->lf_used == false):
-    Each whitespace-separated token is parsed via sample_parse_expr() and
-    stored as an flt_otel_conf_sample_expr in sample->exprs.  At runtime, each
-    expression is evaluated via sample_process().  If there is exactly one
-    expression, the native HAProxy sample type is preserved (bool, int, IP
-    address, string).  If there are multiple expressions, their string
-    representations are concatenated.
-
-5.2  Type Conversion Chain
-
-flt_otel_sample_to_value() (util.c) converts HAProxy sample types to OTel value
-types:
-
-  SMP_T_BOOL  ->  OTELC_VALUE_BOOL
-  SMP_T_SINT  ->  OTELC_VALUE_INT64
-  Other       ->  OTELC_VALUE_DATA (string, via flt_otel_sample_to_str)
-
-flt_otel_sample_to_str() handles the string conversion for non-trivial types:
-
-  SMP_T_BOOL     "0" or "1"
-  SMP_T_SINT     snprintf decimal
-  SMP_T_IPV4     inet_ntop
-  SMP_T_IPV6     inet_ntop
-  SMP_T_STR      direct copy
-  SMP_T_METH     lookup from static HTTP method table, or raw string for
-                 HTTP_METH_OTHER
-
-For metric instruments, string values are rejected -- the meter requires
-OTELC_VALUE_INT64.  If the sample evaluates to a string, otelc_value_strtonum()
-attempts numeric conversion as a last resort.
-
-5.3  Dispatch to Data Structures
-
-flt_otel_sample_add() (util.c) is the top-level evaluator.  After converting the
-sample to an otelc_value, it dispatches based on type:
-
-  FLT_OTEL_EVENT_SAMPLE_ATTRIBUTE
-    -> flt_otel_sample_add_kv(&data->attributes, key, &value)
-
-  FLT_OTEL_EVENT_SAMPLE_BAGGAGE
-    -> flt_otel_sample_add_kv(&data->baggage, key, &value)
-
-  FLT_OTEL_EVENT_SAMPLE_EVENT
-    -> flt_otel_sample_add_event(&data->events, sample, &value)
-       Groups attributes by event name; creates a new flt_otel_scope_data_event
-       node if the event name is not yet present.
-
-  FLT_OTEL_EVENT_SAMPLE_STATUS
-    -> flt_otel_sample_set_status(&data->status, sample, &value, err)
-       Sets the status code from sample->extra.num and the description from the
-       evaluated value.  Rejects duplicate status settings.
-
-5.4  Growable Key-Value Arrays
-
-Attribute and baggage arrays use a lazy-allocation / grow-on-demand pattern via
-flt_otel_sample_add_kv() (util.c):
-
-  - Initial allocation: FLT_OTEL_ATTR_INIT_SIZE (8) elements via otelc_kv_new().
-  - Growth: FLT_OTEL_ATTR_INC_SIZE (4) additional elements via otelc_kv_resize()
-    when the array is full.
-  - The cnt field tracks used elements; size tracks total capacity.
-
-Event attribute arrays follow the same pattern within each
-flt_otel_scope_data_event node.
-
-
-6  Rate Limiting and Filtering
-----------------------------------------------------------------------
-
-6.1  Rate Limit Representation
-
-The rate limit is configured as a floating-point percentage (0.0 to 100.0) but
-stored internally as a uint32_t for lock-free comparison:
-
-  FLT_OTEL_FLOAT_U32(a)  Converts a percentage to a uint32 value:
-                          (uint32_t)((a / 100.0) * UINT32_MAX)
-
-  FLT_OTEL_U32_FLOAT(a)  Converts back for display:
-                          ((double)(a) / UINT32_MAX) * 100.0
-
-At attach time, the filter compares a fresh ha_random32() value against the
-stored rate_limit.  If the random value exceeds the threshold, the filter
-returns FLT_OTEL_RET_IGNORE and does not attach to the stream.  This provides
-uniform sampling without floating-point arithmetic on the hot path.
-
-6.2  ACL-Based Filtering
-
-Each scope may carry an ACL condition (if/unless) evaluated at scope
-execution time via acl_exec_cond().  ACL references are resolved through
-a priority chain in flt_otel_parse_acl() (parser.c):
-
-  1. Scope-local ACLs (declared within the otel-scope section).
-  2. Instrumentation ACLs (declared in the otel-instrumentation section).
-  3. Proxy ACLs (declared in the HAProxy frontend/backend section).
-
-The first list that produces a successful build_acl_cond() result is used.
-If the condition fails at runtime:
-
-  - If the scope contains a root span, the entire stream is disabled
-    (rt_ctx->flag_disabled = 1) to avoid orphaned child spans.
-  - Otherwise, the scope is simply skipped.
-
-6.3  Global Disable
-
-The filter can be disabled globally via the CLI ("otel disable") or the
-configuration ("option disabled").  The flag_disabled field on the
-instrumentation configuration is checked atomically in flt_otel_ops_attach()
-before any per-stream allocation occurs.
-
-
-7  Memory Management Strategy
-----------------------------------------------------------------------
-
-7.1  Pool-Based Allocation
-
-Four HAProxy memory pools are registered for frequently allocated structures
-(pool.c):
-
-  pool_head_otel_scope_span       Per-stream span entries.
-  pool_head_otel_scope_context    Per-stream context entries.
-  pool_head_otel_runtime_context  Per-stream runtime context.
-  pool_head_otel_span_context     OTel SDK objects (via C wrapper allocator
-                                  callback).
-
-Pool registration is conditional on compile-time flags (USE_POOL_OTEL_* in
-config.h).  flt_otel_pool_alloc() attempts pool allocation first and falls back
-to heap allocation (OTELC_MALLOC) when the pool is NULL or the requested size
-exceeds the pool's element size.
-
-The C wrapper library's memory allocations are redirected through
-flt_otel_mem_malloc() / flt_otel_mem_free() (filter.c), which use the
-otel_span_context pool via otelc_ext_init().  This keeps OTel SDK objects in
-HAProxy's pool allocator for cache-friendly allocation.
-
-7.2  Trash Buffers
-
-flt_otel_trash_alloc() (pool.c) provides temporary scratch buffers of
-global.tune.bufsize bytes.  When USE_TRASH_CHUNK is defined, it uses HAProxy's
-alloc_trash_chunk(); otherwise it manually allocates a buffer structure and data
-area.  Trash buffers are used for:
-
-  - Log-format evaluation in metric recording and log record emission.
-  - HTTP header name construction in flt_otel_http_header_set().
-  - Temporary string assembly in sample evaluation.
-
-7.3  Scope Data Lifecycle
-
-flt_otel_scope_data (scope.h) is initialized and freed within a single span
-processing block in flt_otel_scope_run().  It is stack-conceptual data:
-allocated at the start of each span's processing, populated during sample
-evaluation, consumed by flt_otel_scope_run_span(), and freed immediately after.
-The key-value arrays within it are heap-allocated via otelc_kv_new() and freed
-via otelc_kv_destroy().
-
-
-8  Context Propagation Mechanism
-----------------------------------------------------------------------
-
-8.1  Carrier Abstraction
-
-The OTel C wrapper uses a carrier pattern for context propagation.  Two carrier
-types exist, each with writer and reader variants:
-
-  otelc_text_map_writer / otelc_text_map_reader
-  otelc_http_headers_writer / otelc_http_headers_reader
-
-otelc.c provides callback functions that the C wrapper invokes during
-inject/extract operations:
-
-  Injection (writer callbacks):
-    flt_otel_text_map_writer_set_cb()
-    flt_otel_http_headers_writer_set_cb()
-    Both append key-value pairs to the carrier's text_map via
-    OTELC_TEXT_MAP_ADD.
-
-  Extraction (reader callbacks):
-    flt_otel_text_map_reader_foreach_key_cb()
-    flt_otel_http_headers_reader_foreach_key_cb()
-    Both iterate the text_map's key-value pairs, invoking a handler function
-    for each entry.  Iteration stops early if the handler returns -1.
-
-8.2  HTTP Header Storage
-
-flt_otel_http_headers_get() (http.c) reads headers from the HTX buffer with
-prefix matching.  The prefix is stripped from header names in the returned
-text_map.  A special prefix character ('-') matches all headers without prefix
-filtering.
-
-flt_otel_http_header_set() constructs a "prefix-name" header, removes all
-existing occurrences via an http_find_header / http_remove_header loop, then
-adds the new value via http_add_header.
-
-8.3  Variable Storage
-
-When USE_OTEL_VARS is enabled, span context can also be stored in HAProxy
-transaction-scoped variables.  Variable names are normalized
-(flt_otel_normalize_name in vars.c):
-
-  Dashes    -> 'D'  (FLT_OTEL_VAR_CHAR_DASH)
-  Spaces    -> 'S'  (FLT_OTEL_VAR_CHAR_SPACE)
-  Uppercase -> lowercase
-
-Full variable names are constructed as "scope.prefix.name" with dots as
-component separators.
-
-Two implementation paths exist based on the USE_OTEL_VARS_NAME compile flag:
-
-  With USE_OTEL_VARS_NAME:
-    A binary tracking buffer (stored as a HAProxy variable) records the names
-    of all context variables.  flt_otel_ctx_loop() iterates length-prefixed
-    entries in this buffer, calling a callback for each.  This enables efficient
-    enumeration without scanning the full variable store.
-
-  Without USE_OTEL_VARS_NAME:
-    Direct CEB tree traversal on the HAProxy variable store with prefix
-    matching.  This is simpler but potentially slower for large variable sets.
-
-The choice is auto-detected at build time by checking whether struct var has
-a 'name' member.
-
-
-9  Debug Infrastructure
-----------------------------------------------------------------------
-
-9.1  Conditional Compilation
-
-When OTEL_DEBUG=1 is set at build time, -DDEBUG_OTEL is added to the compiler
-flags.  This enables:
-
-  - Additional flt_ops callbacks: deinit_per_thread, http_payload, http_reset,
-    tcp_payload.  In non-debug builds these are NULL.
-
-  - FLT_OTEL_USE_COUNTERS (config.h), which activates the per-event counters in
-    flt_otel_counters (attached[], disabled[] arrays).
-
-  - Debug-only functions throughout the codebase, marked with [D] in
-    README-func: flt_otel_scope_data_dump, flt_otel_http_headers_dump,
-    flt_otel_vars_dump, flt_otel_args_dump, flt_otel_filters_dump, etc.
-
-  - The OTELC_DBG() macro for level-gated debug output.
-
-9.2  Debug Level Bitmask
-
-The debug level is a uint stored in conf->instr and controllable at runtime via
-"otel debug <level>".  The default value is FLT_OTEL_DEBUG_LEVEL (0b11101111111
-in config.h).  Each bit enables a category of debug output.
-
-9.3  Logging Integration
-
-The FLT_OTEL_LOG macro (debug.h) integrates with HAProxy's send_log() system.
-Its behavior depends on the logging flags:
-
-  FLT_OTEL_LOGGING_OFF (0):
-    No log messages are emitted.
-
-  FLT_OTEL_LOGGING_ON (1 << 0):
-    Log messages are sent to the log servers configured in the instrumentation
-    block via parse_logger().
-
-  FLT_OTEL_LOGGING_NOLOGNORM (1 << 1):
-    Combined with ON, suppresses normal-level messages (only warnings and above
-    are emitted).
-
-These flags are set via the "option dontlog-normal" configuration keyword or the
-"otel logging" CLI command.
-
-9.4  Counter System
-
-When FLT_OTEL_USE_COUNTERS is defined, the flt_otel_counters structure (conf.h)
-maintains:
-
-  attached[4]   Counters for attach outcomes, incremented atomically in
-                flt_otel_ops_attach().
-  disabled[2]   Counters for hard-error disables, incremented atomically in
-                flt_otel_return_int() / flt_otel_return_void().
-
-The counters are reported by the "otel status" CLI command and dumped at deinit
-time in debug builds.
-
-
-10  Idle Timeout Mechanism
-----------------------------------------------------------------------
-
-The idle timeout fires periodic events on idle streams, enabling heartbeat-style
-span updates or metric recordings.
-
-10.1  Configuration
-
-Each otel-scope bound to the "on-idle-timeout" event must declare an
-idle-timeout interval.  At check time (flt_otel_ops_check), the minimum idle
-timeout across all scopes is stored in conf->instr->idle_timeout.
-
-10.2  Initialization
-
-In flt_otel_ops_stream_start(), the runtime context's idle_timeout and idle_exp
-fields are initialized from the precomputed minimum.  The expiration tick is
-merged into the request channel's analyse_exp to ensure the stream task wakes
-at the right time.
-
-10.3  Firing
-
-flt_otel_ops_check_timeouts() checks tick_is_expired(rt_ctx->idle_exp).
-When expired:
-  - The on-idle-timeout event fires via flt_otel_event_run().
-  - The timer is rescheduled for the next interval.
-  - If analyse_exp itself has expired (which would cause a tight loop), it is
-    reset before the new idle_exp is merged.
-  - STRM_EVT_MSG is set on stream->pending_events to ensure the stream is
-    re-evaluated.
-
-
-11  Group Action Integration Pattern
-----------------------------------------------------------------------
-
-The "otel-group" action integrates OTel scopes with HAProxy's rule system
-(http-request, http-response, http-after-response, tcp-request, tcp-response).
-
-11.1  Registration
-
-group.c registers action keywords via INITCALL1 macros for all five action
-contexts.  Each registration points to flt_otel_group_parse() as the parse
-function.
-
-11.2  Parse-Check-Execute Cycle
-
-  Parse (flt_otel_group_parse):
-    Stores the filter ID and group ID as string duplicates in rule->arg.act.p[].
-    Sets the check, action and release callbacks.
-
-  Check (flt_otel_group_check):
-    Resolves the string IDs to configuration pointers by scanning the proxy's
-    filter list.  Replaces the string pointers with resolved flt_conf,
-    flt_otel_conf and flt_otel_conf_ph pointers.  Frees the original string
-    duplicates.
-
-  Execute (flt_otel_group_action):
-    Finds the filter instance in the stream's filter list.  Validates rule->from
-    against the flt_otel_group_data[] table to determine the sample fetch
-    direction and valid fetch locations.  Iterates all scopes in the group and
-    calls flt_otel_scope_run() for each.  Always returns ACT_RET_CONT -- a group
-    action never interrupts rule processing.
-
-11.3  Group Data Table
-
-The flt_otel_group_data[] table (group.c) maps each HAProxy action context
-(ACT_F_*) to:
-
-  act_from     The action context enum value.
-  smp_val      The valid sample fetch location (FE or BE).
-  smp_opt_dir  The sample fetch direction (REQ or RES).
-
-This table is generated from the FLT_OTEL_GROUP_DEFINES X-macro list (group.h).
-
-
-12  CLI Runtime Control Architecture
-----------------------------------------------------------------------
-
-cli.c registers commands under the "otel" prefix.  The command table maps
-keyword sequences to handler functions with access level requirements.
-
-12.1  Command Table
-
-  "otel status"       No access restriction.  Read-only status report.
-  "otel enable"       ACCESS_LVL_ADMIN.  Clears flag_disabled.
-  "otel disable"      ACCESS_LVL_ADMIN.  Sets flag_disabled.
-  "otel hard-errors"  ACCESS_LVL_ADMIN.  Sets flag_harderr.
-  "otel soft-errors"  ACCESS_LVL_ADMIN.  Clears flag_harderr.
-  "otel logging"      ACCESS_LVL_ADMIN for setting; any for reading.
-  "otel rate"         ACCESS_LVL_ADMIN for setting; any for reading.
-  "otel debug"        ACCESS_LVL_ADMIN.  DEBUG_OTEL only.
-
-The "otel enable" and "otel disable" commands share the same handler
-(flt_otel_cli_parse_disabled) with the private argument distinguishing the
-operation (1 for disable, 0 for enable).  The same pattern is used for
-hard-errors / soft-errors.
-
-12.2  Global Propagation
-
-All set operations iterate every OTel filter instance across all proxies using
-FLT_OTEL_PROXIES_LIST_START / FLT_OTEL_PROXIES_LIST_END macros and atomically
-update the target field.  A single "otel disable" command disables the filter
-in every proxy that has it configured.
-
-12.3  Status Report
-
-The "otel status" command assembles a dynamic string via memprintf() containing:
-
-  - Library versions (C++ SDK and C wrapper).
-  - Debug level (DEBUG_OTEL only).
-  - Dropped diagnostic message count.
-  - Per-proxy: config file, group/scope counts, instrumentation details, rate
-    limit, error mode, disabled state, logging state, analyzer bitmask, and
-    counters (if FLT_OTEL_USE_COUNTERS).
diff --git a/addons/otel/README-func b/addons/otel/README-func
deleted file mode 100644 (file)
index acfafc7..0000000
+++ /dev/null
@@ -1,723 +0,0 @@
-OpenTelemetry filter -- function reference
-==========================================================================
-
-Functions are grouped by source file.  Functions marked with [D] are only
-compiled when DEBUG_OTEL is defined.
-
-
-src/filter.c
-----------------------------------------------------------------------
-
-Filter lifecycle callbacks and helpers registered in flt_otel_ops.
-
-  flt_otel_mem_malloc
-      Allocator callback for the OTel C wrapper library.  Uses the HAProxy
-      pool_head_otel_span_context pool.
-
-  flt_otel_mem_free
-      Deallocator callback for the OTel C wrapper library.
-
-  flt_otel_log_handler_cb
-      Diagnostic callback for the OTel C wrapper library.  Counts SDK internal
-      diagnostic messages.
-
-  flt_otel_thread_id
-      Returns the current HAProxy thread ID (tid).
-
-  flt_otel_lib_init
-      Initializes the OTel C wrapper library: verifies the library version,
-      constructs the configuration path, calls otelc_init(), and creates the
-      tracer, meter and logger instances.
-
-  flt_otel_is_disabled
-      Checks whether the filter instance is disabled for the current stream.
-      Logs the event name when DEBUG_OTEL is enabled.
-
-  flt_otel_return_int
-      Error handler for callbacks returning int.  In hard-error mode, disables
-      the filter; in soft-error mode, clears the error and returns OK.
-
-  flt_otel_return_void
-      Error handler for callbacks returning void.  Same logic as
-      flt_otel_return_int but without a return value.
-
-  flt_otel_ops_init
-      Filter init callback (flt_ops.init).  Called once per proxy to initialize
-      the OTel library via flt_otel_lib_init() and register CLI keywords.
-
-  flt_otel_ops_deinit
-      Filter deinit callback (flt_ops.deinit).  Destroys the tracer, meter and
-      logger, frees the configuration, and calls otelc_deinit().
-
-  flt_otel_ops_check
-      Filter check callback (flt_ops.check).  Validates the parsed
-      configuration: checks for duplicate filter IDs, resolves group/scope
-      placeholder references, verifies root span count, and sets analyzer bits.
-
-  flt_otel_ops_init_per_thread
-      Per-thread init callback (flt_ops.init_per_thread).  Starts the OTel
-      tracer thread and enables HTX filtering.
-
-  flt_otel_ops_deinit_per_thread [D]
-      Per-thread deinit callback (flt_ops.deinit_per_thread).
-
-  flt_otel_ops_attach
-      Filter attach callback (flt_ops.attach).  Called when a filter instance is
-      attached to a stream.  Applies rate limiting, creates the runtime context,
-      and sets analyzer bits.
-
-  flt_otel_ops_stream_start
-      Stream start callback (flt_ops.stream_start).  Fires the
-      on-stream-start event before any channel processing begins.  The channel
-      argument is NULL.  After the event, initializes the idle timer in the
-      runtime context from the precomputed minimum idle_timeout in the
-      instrumentation configuration.
-
-  flt_otel_ops_stream_set_backend
-      Stream set-backend callback (flt_ops.stream_set_backend).  Fires the
-      on-backend-set event when a backend is assigned to the stream.
-
-  flt_otel_ops_stream_stop
-      Stream stop callback (flt_ops.stream_stop).  Fires the
-      on-stream-stop event after all channel processing ends.  The channel
-      argument is NULL.
-
-  flt_otel_ops_detach
-      Filter detach callback (flt_ops.detach).  Frees the runtime context when
-      the filter is detached from a stream.
-
-  flt_otel_ops_check_timeouts
-      Timeout callback (flt_ops.check_timeouts).  When the idle-timeout timer
-      has expired, fires the on-idle-timeout event and reschedules the timer
-      for the next interval.  Sets the STRM_EVT_MSG pending event flag on the
-      stream.
-
-  flt_otel_ops_channel_start_analyze
-      Channel start-analyze callback.  Registers analyzers on the channel and
-      runs the client/server session start event.  Propagates the idle-timeout
-      expiry to the channel's analyse_exp so the stream task keeps waking.
-
-  flt_otel_ops_channel_pre_analyze
-      Channel pre-analyze callback.  Maps the analyzer bit to an event index and
-      runs the corresponding event.
-
-  flt_otel_ops_channel_post_analyze
-      Channel post-analyze callback.  Non-resumable; called once when a
-      filterable analyzer finishes.
-
-  flt_otel_ops_channel_end_analyze
-      Channel end-analyze callback.  Runs the client/server session end event.
-      For the request channel, also fires the server-unavailable event if no
-      response was processed.
-
-  flt_otel_ops_http_headers
-      HTTP headers callback (flt_ops.http_headers).  Fires
-      on-http-headers-request or on-http-headers-response depending on the
-      channel direction.
-
-  flt_otel_ops_http_payload [D]
-      HTTP payload callback (flt_ops.http_payload).
-
-  flt_otel_ops_http_end
-      HTTP end callback (flt_ops.http_end).  Fires on-http-end-request or
-      on-http-end-response depending on the channel direction.
-
-  flt_otel_ops_http_reset [D]
-      HTTP reset callback (flt_ops.http_reset).
-
-  flt_otel_ops_http_reply
-      HTTP reply callback (flt_ops.http_reply).  Fires the on-http-reply event
-      when HAProxy generates an internal reply.
-
-  flt_otel_ops_tcp_payload [D]
-      TCP payload callback (flt_ops.tcp_payload).
-
-
-src/event.c
-----------------------------------------------------------------------
-
-Event dispatching, metrics recording and scope/span execution engine.
-
-  flt_otel_scope_run_instrument_record
-      Records a measurement for a synchronous metric instrument.  Evaluates
-      update-form attributes via flt_otel_sample_eval() and
-      flt_otel_sample_add_kv(), evaluates the sample expression from the
-      create-form instrument (instr_ref), and submits the value to the meter
-      via update_instrument_kv_n().
-
-  flt_otel_scope_run_instrument
-      Processes all metric instruments for a scope.  Runs in two passes: the
-      first lazily creates create-form instruments via the meter, using
-      HA_ATOMIC_CAS to guarantee thread-safe one-time initialization; the second
-      iterates update-form instruments and records measurements via
-      flt_otel_scope_run_instrument_record().  Instruments whose index is still
-      negative (UNUSED or PENDING) are skipped.
-
-  flt_otel_scope_run_log_record
-      Emits log records for a scope.  Iterates over the configured log-record
-      list, skipping entries whose severity is below the logger threshold.
-      Evaluates the body from sample fetch expressions or a log-format string,
-      optionally resolves a span reference against the runtime context, and
-      emits the record via the logger.  A missing span is non-fatal -- the
-      record is emitted without span correlation.
-
-  flt_otel_scope_run_span
-      Executes a single span: creates the OTel span on first call, adds links,
-      baggage, attributes, events and status, then injects the context into HTTP
-      headers or HAProxy variables.
-
-  flt_otel_scope_run
-      Executes a complete scope: evaluates ACL conditions, extracts contexts,
-      iterates over configured spans (resolving links, evaluating sample
-      expressions), calls flt_otel_scope_run_span for each, processes metric
-      instruments via flt_otel_scope_run_instrument(), emits log records via
-      flt_otel_scope_run_log_record(), then marks and finishes completed spans.
-
-  flt_otel_event_run
-      Top-level event dispatcher.  Called from filter callbacks, iterates over
-      all scopes matching the event index and calls flt_otel_scope_run() for
-      each.
-
-
-src/scope.c
-----------------------------------------------------------------------
-
-Runtime context, span and context lifecycle management.
-
-  flt_otel_pools_info [D]
-      Logs the sizes of all registered HAProxy memory pools used by the OTel
-      filter.
-
-  flt_otel_runtime_context_init
-      Allocates and initializes the per-stream runtime context.  Generates a
-      UUID and stores it in the sess.otel.uuid HAProxy variable.
-
-  flt_otel_runtime_context_free
-      Frees the runtime context: ends all active spans, destroys all extracted
-      contexts, and releases pool memory.
-
-  flt_otel_scope_span_init
-      Finds an existing scope span by name or creates a new one.  Resolves the
-      parent reference (span or extracted context).
-
-  flt_otel_scope_span_free
-      Frees a scope span entry if its OTel span has been ended.  Refuses to free
-      an active (non-NULL) span.
-
-  flt_otel_scope_context_init
-      Finds an existing scope context by name or creates a new one by extracting
-      the span context from a text map.
-
-  flt_otel_scope_context_free
-      Frees a scope context entry and destroys the underlying OTel span context.
-
-  flt_otel_scope_data_dump [D]
-      Dumps scope data contents (baggage, attributes, events, links, status) for
-      debugging.
-
-  flt_otel_scope_data_init
-      Zero-initializes a scope data structure and its event/link lists.
-
-  flt_otel_scope_data_free
-      Frees all scope data contents: key-value arrays, event entries, link
-      entries, and status description.
-
-  flt_otel_scope_finish_mark
-      Marks spans and contexts for finishing.  Supports wildcard ("*"),
-      channel-specific ("req"/"res"), and named targets.
-
-  flt_otel_scope_finish_marked
-      Ends all spans and destroys all contexts that have been marked for
-      finishing by flt_otel_scope_finish_mark().
-
-  flt_otel_scope_free_unused
-      Removes scope spans with NULL OTel span and scope contexts with NULL OTel
-      context.  Cleans up associated HTTP headers and variables.
-
-
-src/parser.c
-----------------------------------------------------------------------
-
-Configuration file parsing for otel-instrumentation, otel-group and otel-scope
-sections.
-
-  flt_otel_parse_strdup
-      Duplicates a string with error handling; optionally stores the string
-      length.
-
-  flt_otel_parse_keyword
-      Parses a single keyword argument: checks for duplicates and missing
-      values, then stores via flt_otel_parse_strdup().
-
-  flt_otel_parse_invalid_char
-      Validates characters in a name according to the specified type
-      (identifier, domain, context prefix, variable).
-
-  flt_otel_parse_cfg_check
-      Common validation for config keywords: looks up the keyword, checks
-      argument count and character validity, verifies that the parent section ID
-      is set.
-
-  flt_otel_parse_cfg_sample_expr
-      Parses a single HAProxy sample expression within a sample definition.
-      Calls sample_parse_expr().
-
-  flt_otel_parse_cfg_sample
-      Parses a complete sample definition (key plus one or more sample
-      expressions).
-
-  flt_otel_parse_cfg_str
-      Parses one or more string arguments into a conf_str list (used for the
-      "finish" keyword).
-
-  flt_otel_parse_cfg_file
-      Parses and validates a file path argument; checks that the file exists and
-      is readable.
-
-  flt_otel_parse_check_scope
-      Checks whether the current config parsing is within the correct HAProxy
-      configuration scope (cfg_scope filtering).
-
-  flt_otel_parse_cfg_instr
-      Section parser for the otel-instrumentation block.  Handles keywords:
-      otel-instrumentation ID, log, config, groups, scopes, acl, rate-limit,
-      option, debug-level.
-
-  flt_otel_post_parse_cfg_instr
-      Post-parse callback for otel-instrumentation.  Links the instrumentation
-      to the config and checks that a config file is specified.
-
-  flt_otel_parse_cfg_group
-      Section parser for the otel-group block.  Handles keywords: otel-group ID,
-      scopes.
-
-  flt_otel_post_parse_cfg_group
-      Post-parse callback for otel-group.  Checks that at least one scope is
-      defined.
-
-  flt_otel_parse_cfg_scope_ctx
-      Parses the context storage type argument ("use-headers" or "use-vars") for
-      inject/extract keywords.
-
-  flt_otel_parse_acl
-      Builds an ACL condition by trying multiple ACL lists in order
-      (scope-local, instrumentation, proxy).
-
-  flt_otel_parse_bounds
-      Parses a space-separated string of numbers into a dynamically allocated
-      array of doubles for histogram bucket boundaries.  Sorts the values
-      internally.
-
-  flt_otel_parse_cfg_instrument
-      Parses the "instrument" keyword inside an otel-scope section.  Supports
-      both "update" form (referencing an existing instrument) and "create" form
-      (defining a new metric instrument with type, name, optional aggregation
-      type, description, unit, value, and optional histogram bounds).
-
-  flt_otel_parse_cfg_scope
-      Section parser for the otel-scope block.  Handles keywords: otel-scope ID,
-      span, link, attribute, event, baggage, status, inject, extract, finish,
-      instrument, log-record, acl, otel-event.
-
-  flt_otel_post_parse_cfg_scope
-      Post-parse callback for otel-scope.  Checks that HTTP header injection is
-      only used on events that support it.
-
-  flt_otel_parse_cfg
-      Parses the OTel filter configuration file.  Backs up current sections,
-      registers temporary otel-instrumentation/group/scope section parsers,
-      loads and parses the file, then restores the original sections.
-
-  flt_otel_parse
-      Main filter parser entry point, registered for the "otel" filter keyword.
-      Parses the filter ID and configuration file path from the HAProxy config
-      line.
-
-
-src/conf.c
-----------------------------------------------------------------------
-
-Configuration structure allocation and deallocation.  Most init/free pairs are
-generated by the FLT_OTEL_CONF_FUNC_INIT and FLT_OTEL_CONF_FUNC_FREE macros.
-
-  flt_otel_conf_hdr_init
-      Allocates and initializes a conf_hdr structure.
-
-  flt_otel_conf_hdr_free
-      Frees a conf_hdr structure and removes it from its list.
-
-  flt_otel_conf_str_init
-      Allocates and initializes a conf_str structure.
-
-  flt_otel_conf_str_free
-      Frees a conf_str structure and removes it from its list.
-
-  flt_otel_conf_link_init
-      Allocates and initializes a conf_link structure (span link).
-
-  flt_otel_conf_link_free
-      Frees a conf_link structure and removes it from its list.
-
-  flt_otel_conf_ph_init
-      Allocates and initializes a conf_ph (placeholder) structure.
-
-  flt_otel_conf_ph_free
-      Frees a conf_ph structure and removes it from its list.
-
-  flt_otel_conf_sample_expr_init
-      Allocates and initializes a conf_sample_expr structure.
-
-  flt_otel_conf_sample_expr_free
-      Frees a conf_sample_expr structure and releases the parsed sample
-      expression.
-
-  flt_otel_conf_sample_init
-      Allocates and initializes a conf_sample structure.
-
-  flt_otel_conf_sample_init_ex
-      Extended sample initialization: sets the key, extra data (event name or
-      status code), concatenated value string, and expression count.
-
-  flt_otel_conf_sample_free
-      Frees a conf_sample structure including its value, extra data, and all
-      sample expressions.
-
-  flt_otel_conf_context_init
-      Allocates and initializes a conf_context structure.
-
-  flt_otel_conf_context_free
-      Frees a conf_context structure and removes it from its list.
-
-  flt_otel_conf_span_init
-      Allocates and initializes a conf_span structure with empty lists for
-      links, attributes, events, baggages and statuses.
-
-  flt_otel_conf_span_free
-      Frees a conf_span structure and all its child lists.
-
-  flt_otel_conf_instrument_init
-      Allocates and initializes a conf_instrument structure.
-
-  flt_otel_conf_instrument_free
-      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 empty
-      attributes and samples lists.
-
-  flt_otel_conf_log_record_free
-      Frees a conf_log_record structure: event_name, span, attributes and
-      samples list.
-
-  flt_otel_conf_scope_init
-      Allocates and initializes a conf_scope structure with empty lists for
-      ACLs, contexts, spans, spans_to_finish and instruments.
-
-  flt_otel_conf_scope_free
-      Frees a conf_scope structure, ACLs, condition, and all child lists.
-
-  flt_otel_conf_group_init
-      Allocates and initializes a conf_group structure with an empty placeholder
-      scope list.
-
-  flt_otel_conf_group_free
-      Frees a conf_group structure and its placeholder scope list.
-
-  flt_otel_conf_instr_init
-      Allocates and initializes a conf_instr structure.  Sets the default rate
-      limit to 100%, initializes the proxy_log, and creates empty ACL and
-      placeholder lists.
-
-  flt_otel_conf_instr_free
-      Frees a conf_instr structure including ACLs, loggers, config path, and
-      placeholder lists.
-
-  flt_otel_conf_init
-      Allocates and initializes the top-level flt_otel_conf structure with empty
-      group and scope lists.
-
-  flt_otel_conf_free
-      Frees the top-level flt_otel_conf structure and all of its children
-      (instrumentation, groups, scopes).
-
-
-src/cli.c
-----------------------------------------------------------------------
-
-HAProxy CLI command handlers for runtime filter management.
-
-  cmn_cli_set_msg
-      Sets the CLI appctx response message and state.
-
-  flt_otel_cli_parse_debug [D]
-      CLI handler for "otel debug [level]".  Gets or sets the debug level.
-
-  flt_otel_cli_parse_disabled
-      CLI handler for "otel enable" and "otel disable".
-
-  flt_otel_cli_parse_option
-      CLI handler for "otel soft-errors" and "otel hard-errors".
-
-  flt_otel_cli_parse_logging
-      CLI handler for "otel logging [state]".  Gets or sets the logging state
-      (off/on/dontlog-normal).
-
-  flt_otel_cli_parse_rate
-      CLI handler for "otel rate [value]".  Gets or sets the rate limit
-      percentage.
-
-  flt_otel_cli_parse_status
-      CLI handler for "otel status".  Displays filter configuration and runtime
-      state for all OTel filter instances.
-
-  flt_otel_cli_init
-      Registers the OTel CLI keywords with HAProxy.
-
-
-src/otelc.c
-----------------------------------------------------------------------
-
-OpenTelemetry context propagation bridge (inject/extract) between HAProxy and
-the OTel C wrapper library.
-
-  flt_otel_text_map_writer_set_cb
-      Writer callback for text map injection.  Appends a key-value pair to the
-      text map.
-
-  flt_otel_http_headers_writer_set_cb
-      Writer callback for HTTP headers injection.  Appends a key-value pair to
-      the text map.
-
-  flt_otel_inject_text_map
-      Injects span context into a text map carrier.
-
-  flt_otel_inject_http_headers
-      Injects span context into an HTTP headers carrier.
-
-  flt_otel_text_map_reader_foreach_key_cb
-      Reader callback for text map extraction.  Iterates over all key-value
-      pairs in the text map.
-
-  flt_otel_http_headers_reader_foreach_key_cb
-      Reader callback for HTTP headers extraction.  Iterates over all key-value
-      pairs in the text map.
-
-  flt_otel_extract_text_map
-      Extracts a span context from a text map carrier via the tracer.
-
-  flt_otel_extract_http_headers
-      Extracts a span context from an HTTP headers carrier via the tracer.
-
-
-src/http.c
-----------------------------------------------------------------------
-
-HTTP header manipulation for context propagation.
-
-  flt_otel_http_headers_dump [D]
-      Dumps all HTTP headers from the channel's HTX buffer.
-
-  flt_otel_http_headers_get
-      Extracts HTTP headers matching a prefix into a text map.  Used by the
-      "extract" keyword to read span context from incoming request headers.
-
-  flt_otel_http_header_set
-      Sets or removes an HTTP header.  Combines prefix and name into the full
-      header name, removes all existing occurrences, then adds the new value
-      (if non-NULL).
-
-  flt_otel_http_headers_remove
-      Removes all HTTP headers matching a prefix.  Wrapper around
-      flt_otel_http_header_set() with NULL name and value.
-
-
-src/vars.c
-----------------------------------------------------------------------
-
-HAProxy variable integration for context propagation and storage.  Only compiled
-when USE_OTEL_VARS is defined.
-
-  flt_otel_vars_scope_dump [D]
-      Dumps all variables for a single HAProxy variable scope.
-
-  flt_otel_vars_dump [D]
-      Dumps all variables across all scopes (PROC, SESS, TXN, REQ/RES).
-
-  flt_otel_smp_init
-      Initializes a sample structure with stream ownership and optional string
-      data.
-
-  flt_otel_smp_add
-      Appends a context variable name to the binary sample data buffer used for
-      tracking registered context variables.
-
-  flt_otel_normalize_name
-      Normalizes a variable name: replaces dashes with 'D' and spaces with 'S',
-      converts to lowercase.
-
-  flt_otel_denormalize_name
-      Reverses the normalization applied by flt_otel_normalize_name().  Restores
-      dashes from 'D' and spaces from 'S'.
-
-  flt_otel_var_name
-      Constructs a full variable name from scope, prefix and name components,
-      separated by dots.
-
-  flt_otel_ctx_loop
-      Iterates over all context variable names stored in the binary sample data,
-      calling a callback for each.
-
-  flt_otel_ctx_set_cb
-      Callback for flt_otel_ctx_loop() that checks whether a context variable
-      name already exists.
-
-  flt_otel_ctx_set
-      Registers a context variable name in the binary tracking buffer if it is
-      not already present.
-
-  flt_otel_var_register
-      Registers a HAProxy variable via vars_check_arg() so it can be used at
-      runtime.
-
-  flt_otel_var_set
-      Sets a HAProxy variable value.  For context-scope variables, also
-      registers the name in the context tracking buffer.
-
-  flt_otel_vars_unset_cb
-      Callback for flt_otel_ctx_loop() that unsets each context variable.
-
-  flt_otel_vars_unset
-      Unsets all context variables for a given prefix and removes the tracking
-      variable itself.
-
-  flt_otel_vars_get_scope
-      Resolves a scope name string ("proc", "sess", "txn", "req", "res") to the
-      corresponding HAProxy variable store.
-
-  flt_otel_vars_get_cb
-      Callback for flt_otel_ctx_loop() that reads each context variable value
-      and adds it to a text map.
-
-  flt_otel_vars_get
-      Reads all context variables for a prefix into a text map.  Used by the
-      "extract" keyword with variable storage.
-
-
-src/pool.c
-----------------------------------------------------------------------
-
-Memory pool and trash buffer helpers.
-
-  flt_otel_pool_alloc
-      Allocates memory from a HAProxy pool (if available) or from the heap.
-      Optionally zero-fills the allocated block.
-
-  flt_otel_pool_strndup
-      Duplicates a string using a HAProxy pool (if available) or the heap.
-
-  flt_otel_pool_free
-      Returns memory to a HAProxy pool or frees it from the heap.
-
-  flt_otel_trash_alloc
-      Allocates a trash buffer chunk, optionally zero-filled.
-
-  flt_otel_trash_free
-      Frees a trash buffer chunk.
-
-
-src/util.c
-----------------------------------------------------------------------
-
-Utility and conversion functions.
-
-  flt_otel_args_dump [D]
-      Dumps configuration arguments array to stderr.
-
-  flt_otel_filters_dump [D]
-      Dumps all OTel filter instances across all proxies.
-
-  flt_otel_chn_label [D]
-      Returns "REQuest" or "RESponse" based on channel flags.
-
-  flt_otel_pr_mode [D]
-      Returns "HTTP" or "TCP" based on proxy mode.
-
-  flt_otel_stream_pos [D]
-      Returns "frontend" or "backend" based on stream flags.
-
-  flt_otel_type [D]
-      Returns "frontend" or "backend" based on filter flags.
-
-  flt_otel_analyzer [D]
-      Returns the analyzer name string for a given analyzer bit.
-
-  flt_otel_list_dump [D]
-      Returns a summary string for a list (empty, single, count).
-
-  flt_otel_args_count
-      Counts the number of valid (non-NULL) arguments in an args array, handling
-      gaps from blank arguments.
-
-  flt_otel_args_concat
-      Concatenates arguments starting from a given index into a single
-      space-separated string.
-
-  flt_otel_strtod
-      Parses a string to double with range validation.
-
-  flt_otel_strtoll
-      Parses a string to int64 with range validation.
-
-  flt_otel_sample_to_str
-      Converts sample data to its string representation.  Handles bool, sint,
-      IPv4, IPv6, str, and HTTP method types.
-
-  flt_otel_sample_to_value
-      Converts sample data to an otelc_value.  Preserves native types (bool,
-      int64) where possible; falls back to string.
-
-  flt_otel_sample_add_event
-      Adds a sample value as a span event attribute.  Groups attributes by event
-      name; dynamically grows the attribute array.
-
-  flt_otel_sample_set_status
-      Sets the span status code and description from sample data.
-
-  flt_otel_sample_add_kv
-      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 and dispatcher.  Calls flt_otel_sample_eval()
-      to evaluate the sample, then dispatches the result to the appropriate
-      handler (attribute, event, baggage, status).
-
-
-src/group.c
-----------------------------------------------------------------------
-
-Group action support for http-response / http-after-response / tcp-request /
-tcp-response rules.
-
-  flt_otel_group_action
-      Action callback (action_ptr) for the otel-group rule.  Finds the filter
-      instance on the current stream and runs all scopes defined in the group.
-
-  flt_otel_group_check
-      Check callback (check_ptr) for the otel-group rule.  Resolves filter ID
-      and group ID references against the proxy's filter configuration.
-
-  flt_otel_group_release
-      Release callback (release_ptr) for the otel-group rule.
-
-  flt_otel_group_parse
-      Parses the "otel-group" action keyword from HAProxy config rules.
-      Registered for tcp-request, tcp-response, http-request, http-response and
-      http-after-response action contexts.
diff --git a/addons/otel/README-implementation b/addons/otel/README-implementation
deleted file mode 100644 (file)
index 5b358c2..0000000
+++ /dev/null
@@ -1,1224 +0,0 @@
-OpenTelemetry Filter Implementation Review
-======================================================================
-
-1  Overview
-----------------------------------------------------------------------
-
-The OpenTelemetry (OTel) filter for HAProxy provides distributed tracing,
-metrics and logging capabilities.  It creates, propagates and exports spans,
-metric instruments and log records that follow the OpenTelemetry specification.
-The filter hooks into the HAProxy stream processing pipeline through the
-filter API and maps HAProxy channel analyzer events to OpenTelemetry span
-lifecycle operations, metric recordings and log-record emissions.
-
-The implementation is located entirely under addons/otel/ and consists of
-header files, C source files, a Makefile, and a set of test configurations
-with runner scripts.
-
-
-2  Directory Structure
-----------------------------------------------------------------------
-
-  addons/otel/
-  |-- Makefile           Build integration (USE_OTEL option)
-  |-- include/
-  |   |-- include.h      Master include (pulls all headers)
-  |   |-- config.h       Build-time tunables (pool sizes, limits)
-  |   |-- define.h       Utility macros (memory, strings, lists)
-  |   |-- debug.h        Debug/logging infrastructure
-  |   |-- filter.h       Filter return codes, alert macros
-  |   |-- parser.h       Configuration keyword definitions
-  |   |-- conf.h         Configuration data structures
-  |   |-- conf_funcs.h   Generated init/free function macros
-  |   |-- event.h        Event enumeration and data table
-  |   |-- scope.h        Runtime span/context structures
-  |   |-- pool.h         Memory pool helpers
-  |   |-- http.h         HTTP header manipulation
-  |   |-- otelc.h        Span context inject/extract wrappers
-  |   |-- vars.h         HAProxy variable integration
-  |   |-- util.h         String conversion, sample helpers
-  |   |-- group.h        Group action (HAProxy rule integration)
-  |   `-- cli.h          CLI command interface
-  |-- src/
-  |   |-- filter.c       Filter lifecycle and channel callbacks
-  |   |-- parser.c       Configuration file parser
-  |   |-- conf.c         Configuration structure init/free
-  |   |-- event.c        Scope/span execution engine
-  |   |-- scope.c        Runtime context and span management
-  |   |-- http.c         HTTP header get/set/remove
-  |   |-- otelc.c        C wrapper inject/extract bridge
-  |   |-- vars.c         HAProxy variable read/write
-  |   |-- pool.c         Pool alloc/free, trash buffers
-  |   |-- util.c         Argument handling, sample conversion
-  |   |-- group.c        Group action parsing and execution
-  |   `-- cli.c          CLI command handlers
-  `-- test/
-      |-- copy-yml.sh    YAML configuration transformer
-      |-- test-speed.sh  Performance benchmarking runner
-      |-- run-sa.sh      Standalone test runner
-      |-- run-fe-be.sh   Frontend-backend chain runner
-      |-- run-ctx.sh     Context propagation test runner
-      |-- run-cmp.sh     Comparison test runner
-      |-- sa/            Standalone test configs
-      |-- fe/            Frontend-only test configs
-      |-- be/            Backend-only test configs
-      |-- ctx/           Context propagation test configs
-      |-- cmp/           Comparison test configs
-      `-- empty/         Minimal/empty configuration test
-
-
-3  Build System
-----------------------------------------------------------------------
-
-The Makefile is included from the main HAProxy build when USE_OTEL is set.
-It detects the opentelemetry-c-wrapper library via pkg-config or manual
-OTEL_INC/OTEL_LIB paths.
-
-Build options:
-
-  USE_OTEL=1        Enable the filter (required).
-  OTEL_DEBUG=1      Compile with DEBUG_OTEL; links the _dbg variant of the
-                    wrapper library and enables additional debug callbacks in
-                    filter.c (stream_set_backend, http_headers, http_payload,
-                    tcp_payload, etc.).
-  OTEL_USE_VARS=1   Compile vars.c; enables USE_OTEL_VARS which allows span
-                    context propagation via HAProxy transaction variables in
-                    addition to HTTP headers.
-  OTEL_INC=<path>   Manual include path for the C wrapper.
-  OTEL_LIB=<path>   Manual library path for the C wrapper.
-  OTEL_RUNPATH=1    Embed RPATH to the wrapper library.
-
-Compiled objects (11 always, 12 with OTEL_USE_VARS):
-
-  cli.o  conf.o  event.o  filter.o  group.o  http.o  opentelemetry.o  parser.o
-  pool.o  scope.o  util.o  [vars.o]
-
-
-4  Configuration Parsing
-----------------------------------------------------------------------
-
-Configuration parsing is driven by parser.c.  The filter is declared in the
-HAProxy configuration with:
-
-  filter opentelemetry [id <name>] config <file>
-
-The flt_otel_parse() function (parser.c) handles the "filter" line, creates an
-flt_otel_conf structure, and delegates to parse_cfg() which loads the referenced
-YAML/CFG file.  That file is parsed using temporary section registrations for
-three section types:
-
-  otel-instrumentation   ->  flt_otel_parse_cfg_instr()
-  otel-group             ->  flt_otel_parse_cfg_group()
-  otel-scope             ->  flt_otel_parse_cfg_scope()
-
-After each section is fully parsed, a post-parse function validates the section
-(e.g., flt_otel_post_parse_cfg_scope() checks that context injection is only
-used on events that support it).
-
-4.1  Instrumentation Section
-
-  otel-instrumentation <name>
-      config <file>
-      log <target>
-      debug-level <value>
-      rate-limit <value>
-      option { disabled | hard-errors | dontlog-normal }
-      groups <name> ...
-      scopes <name> ...
-      acl <name> <criterion> ...
-
-The instrumentation block defines global filter parameters: the YAML exporter
-configuration file, logging, rate limiting, and references to groups and scopes.
-Exactly one instrumentation block is allowed per filter instance.
-
-4.2  Group Section
-
-  otel-group <name>
-      scopes <name> ...
-
-Groups bundle multiple scopes under a single name for use with HAProxy
-http-request/http-response rules via the "otel-group" action.  The group action
-(group.c) parses the rule, resolves the scope references at check time, and
-executes all referenced scopes when the rule fires.
-
-4.3  Scope Section
-
-  otel-scope <name>
-      otel-event <event-name> [if|unless <condition>]
-      extract <name-prefix> [use-headers|use-vars]
-      span <name> [parent <ref>] [link <ref>] [root]
-        link <span> ...
-        attribute <key> <sample> ...
-        event <name> <key> <sample> ...
-        baggage <key> <sample> ...
-        status <code> [<sample> ...]
-        inject <name-prefix> [use-headers] [use-vars]
-      finish <name> ...
-      instrument <type> <name> ... / instrument update <name> ...
-      log-record <severity> [id <int>] [event <name>] [span <ref>] [attr <key> <sample>] ... <sample> ...
-      acl <name> <criterion> ...
-
-Each scope ties to a single HAProxy analyzer event (or none, if used only
-through groups).  Scopes contain context extraction directives, span
-definitions, metric instruments, log records, and finish directives.
-
-A span may specify:
-  - A parent reference (another span or extracted context).
-  - One or more links to other spans/contexts.  Inline link syntax allows one
-    link on the span line; the standalone "link" keyword allows multiple.
-  - The "root" flag marking it as the trace root.
-  - Attributes, events, baggages and status evaluated from HAProxy sample
-    expressions at runtime.
-  - An inject directive to propagate the span context via HTTP headers and/or
-    HAProxy variables.
-
-4.4  Configuration Structure Initialization
-
-All configuration structures are allocated and freed using macro-generated
-functions from conf_funcs.h:
-
-  FLT_OTEL_CONF_FUNC_INIT(type, id_field, extra_init)
-  FLT_OTEL_CONF_FUNC_FREE(type, id_field, extra_free)
-
-These macros produce flt_otel_conf_<type>_init() and _free() functions.
-The init function:
-  - Checks the identifier length against FLT_OTEL_ID_MAXLEN (64).
-  - Checks for duplicate identifiers in the target list.
-  - Allocates the structure with OTELC_CALLOC.
-  - Copies the identifier with OTELC_STRDUP.
-  - Appends to the head list.
-  - Executes any extra initialization (e.g., LIST_INIT for sub-lists in the
-    span structure).
-
-The free function:
-  - Executes any extra cleanup (e.g., destroying sub-lists).
-  - Frees the identifier string.
-  - Removes the node from its list.
-  - Frees the structure.
-
-The full init/free chain for all structures:
-
-  flt_otel_conf          flt_otel_conf_init() / flt_otel_conf_free()
-    flt_otel_conf_instr  generated via macro
-      flt_otel_conf_ph   generated (for ph_groups, ph_scopes)
-    flt_otel_conf_group  generated
-      flt_otel_conf_ph   generated (for ph_scopes)
-    flt_otel_conf_scope  generated
-      flt_otel_conf_context    generated
-      flt_otel_conf_span       generated
-        flt_otel_conf_link       generated
-        flt_otel_conf_sample     generated + _init_ex()
-          flt_otel_conf_sample_expr  generated
-      flt_otel_conf_instrument generated
-      flt_otel_conf_log_record generated
-        flt_otel_conf_sample     generated + _init_ex()
-          flt_otel_conf_sample_expr  generated
-
-
-5  Filter Lifecycle
-----------------------------------------------------------------------
-
-The filter registers its operations in the flt_otel_ops structure (filter.c)
-and the keyword parser via INITCALL1 (parser.c).
-
-5.1  Proxy-Level Initialization
-
-  flt_otel_ops_init():
-    - Registers CLI commands via flt_otel_cli_init().
-    - Initializes the OpenTelemetry library via flt_otel_lib_init(): verifies
-      the C wrapper version, resolves the absolute path of the YAML
-      configuration file, calls otelc_init() to set up exporters, creates the
-      tracer, meter and logger objects, and registers custom memory allocation
-      and thread-id callbacks with the wrapper via otelc_ext_init().
-
-  flt_otel_ops_check():
-    - Validates that filter IDs are unique across all proxies.
-    - Resolves group->scope and instrumentation->scope/group placeholder
-      references to actual configuration structures (setting the ptr field
-      and flag_used).
-    - Warns about unused scopes, missing root spans, or multiple root spans.
-    - Validates metric instruments: resolves update-form references to their
-      matching create-form definitions, and rejects duplicate create-form names
-      across scopes.
-    - Computes the aggregated analyzer bitmask from all used scopes.
-
-  flt_otel_ops_init_per_thread():
-    - Starts the tracer, meter and logger background threads on first call.
-    - Sets the FLT_CFG_FL_HTX flag to enable HTX stream filtering.
-
-  flt_otel_ops_deinit():
-    - Destroys the tracer, meter and logger.
-    - Frees the entire configuration tree.
-    - Calls otelc_deinit() to shut down the wrapper library.
-
-5.2  Stream-Level Callbacks
-
-  flt_otel_ops_attach():
-    - Checks if the filter is globally disabled; returns IGNORE.
-    - Applies rate limiting via ha_random32(); returns IGNORE if the random
-      value exceeds the configured rate_limit.
-    - Creates the runtime context (flt_otel_runtime_context_init) with a
-      generated UUID and initialized span/context lists.
-    - Sets pre_analyzers and post_analyzers bitmasks from the instrumentation's
-      aggregated analyzer flags.  AN_REQ_WAIT_HTTP and AN_RES_WAIT_HTTP are
-      placed in post_analyzers because those analyzers can only be used in the
-      post_analyze callback.  AN_REQ_HTTP_TARPIT is excluded from pre_analyzers.
-
-  flt_otel_ops_detach():
-    - Frees the runtime context, which finishes all remaining active spans and
-      destroys all remaining contexts.
-
-  flt_otel_ops_check_timeouts():
-    - Checks whether the idle-timeout timer has expired; if so, fires the
-      on-idle-timeout event and reschedules the timer for the next interval.
-    - Sets STRM_EVT_MSG on the stream's pending_events to ensure the filter is
-      re-evaluated after a timeout.
-
-5.3  Error Handling
-
-Two helper functions manage errors:
-
-  flt_otel_return_int() / flt_otel_return_void():
-    - If the result indicates an error or an error string is set: in hard-error
-      mode, the filter is disabled for the current stream (flag_disabled = 1)
-      and the disabled counter is incremented atomically.  In soft-error mode,
-      the error is merely logged.
-    - The error string is always freed.
-    - For int returns, FLT_OTEL_RET_OK is returned regardless, so the stream
-      continues processing even after an error.
-
-
-6  Event Processing (Channel Analyzers)
-----------------------------------------------------------------------
-
-The filter maps HAProxy channel analyzer callbacks to a table of named events
-defined in event.h (FLT_OTEL_EVENT_DEFINES).
-
-6.1  Event Table
-
-Each event entry carries:
-  - an_bit:           the HAProxy analyzer bit (AN_REQ_*, AN_RES_*)
-  - an_name:          the analyzer bit name (e.g. "AN_REQ_FLT_HTTP_HDRS")
-  - smp_opt_dir:      sample fetch direction (REQ or RES)
-  - smp_val_fe/be:    valid sample fetch locations
-  - flag_http_inject: whether span context can be injected into HTTP headers
-                      at this point
-  - name:             configuration event name (e.g. "on-frontend-http-request")
-
-Events with an_bit == 0 are pseudo-events not tied to any channel
-analyzer.  Two of them fire from stream lifecycle callbacks:
-  - on-stream-start  (flt_otel_ops_stream_start, before channel processing)
-  - on-stream-stop   (flt_otel_ops_stream_stop, after channel processing)
-
-One fires periodically from the check_timeouts callback:
-  - on-idle-timeout  (flt_otel_ops_check_timeouts, when stream is idle)
-
-One fires from the stream_set_backend callback:
-  - on-backend-set   (flt_otel_ops_stream_set_backend, when backend is assigned)
-
-Four fire from HTTP lifecycle callbacks:
-  - on-http-headers-request / on-http-headers-response (flt_otel_ops_http_headers)
-  - on-http-end-request / on-http-end-response         (flt_otel_ops_http_end)
-  - on-http-reply                                      (flt_otel_ops_http_reply)
-
-The remaining pseudo-events fire from channel start/end callbacks:
-  - on-client-session-start / on-client-session-end
-  - on-server-session-start / on-server-session-end
-  - on-server-unavailable
-
-The stream lifecycle events pass NULL for the channel argument, so
-context injection/extraction via HTTP headers cannot be used.  Their
-sample fetch direction is unconstrained (0xff), allowing both request
-and response fetches.
-
-6.2  Callback Flow
-
-  stream_start(s, f):
-    - Fires on-stream-start with chn=NULL.
-    - Called when a new stream begins, before any channel processing.
-    - Initializes the idle timer from the precomputed minimum idle_timeout in
-      the instrumentation configuration.
-
-  stream_set_backend(s, f, be):
-    - Fires on-backend-set with chn=&s->req.
-    - Called when a backend is assigned (skipped if frontend == backend).
-
-  stream_stop(s, f):
-    - Fires on-stream-stop with chn=NULL.
-    - Called when a stream is destroyed, after all channel processing.
-
-  check_timeouts(s, f):
-    - Checks whether the idle-timeout timer has expired.
-    - If expired, fires on-idle-timeout and reschedules the timer.
-
-  channel_start_analyze(chn):
-    - Enables the per-channel analyzers from pre_analyzers.
-    - Fires on-client-session-start (request) or on-server-session-start
-      (response).
-    - Propagates the idle-timeout expiry to the channel's analyse_exp.
-
-  channel_pre_analyze(chn, an_bit):
-    - Looks up the event by an_bit in the event table.
-    - Calls flt_otel_event_run() for the matching event.
-
-  channel_post_analyze(chn, an_bit):
-    - Same as pre_analyze but for post-analyzers (AN_REQ_WAIT_HTTP,
-      AN_RES_WAIT_HTTP).
-
-  channel_end_analyze(chn):
-    - Fires on-client-session-end (request) or on-server-session-end (response).
-    - For the request channel: if response analyzers were configured but
-      none executed (server was unreachable), fires on-server-unavailable.
-
-  http_headers(s, f, msg):
-    - Fires on-http-headers-request or on-http-headers-response depending on
-      msg->chn direction.
-
-  http_end(s, f, msg):
-    - Fires on-http-end-request or on-http-end-response depending on
-      msg->chn direction.
-
-  http_reply(s, f, status, msg):
-    - Fires on-http-reply with chn=&s->res.
-
-6.3  Scope Execution
-
-  flt_otel_event_run() (event.c):
-    - Captures timestamps (CLOCK_MONOTONIC + CLOCK_REALTIME).
-    - Updates the runtime context's executed-analyzers bitmask.
-    - Iterates all scopes matching the event; calls flt_otel_scope_run() for
-      each used scope.
-
-  flt_otel_scope_run() (event.c):
-    1. Evaluates the scope's ACL condition; if it fails:
-       - If the scope contains a root span, disables the stream.
-       - Returns without processing.
-    2. Extracts contexts: for each configured extract directive, reads
-       the span context from HTTP headers or HAProxy variables via
-       flt_otel_scope_context_init().
-    3. Processes spans: for each configured span:
-       a. Calls flt_otel_scope_span_init() which either returns an existing
-          scope_span (by name) or creates a new one with resolved parent
-          reference.
-       b. Resolves span links against the runtime context -- first searching
-          active spans, then extracted contexts.  Unresolved links produce a
-          NOTICE-level warning and are skipped.
-       c. Evaluates attributes, events, baggages, and status from sample
-          expressions via flt_otel_sample_add().
-       d. Calls flt_otel_scope_run_span() which:
-          - Creates the OTel span via tracer->start_span_with_options()
-            (if not already started).
-          - Adds all resolved links via span->add_link().
-          - Sets baggage, attributes, events, and status.
-          - Optionally injects the span context into HTTP headers and/or
-            HAProxy variables.
-    4. Processes metric instruments via flt_otel_scope_run_instrument(), which
-       runs two passes: the first lazily creates create-form instruments using
-       HA_ATOMIC_CAS for thread-safe one-time initialization; the second records
-       measurements for update-form instruments, skipping any whose index is
-       still negative (creation pending or not yet attempted).
-    5. Emits log records via flt_otel_scope_run_log_record(), which iterates
-       the scope's log-record list, skips entries below the logger's severity
-       threshold, evaluates sample expressions into a body string, resolves
-       the optional span reference, and emits the record via the logger.
-    6. Marks spans listed in "finish" directives.
-    7. Calls flt_otel_scope_finish_marked() to end marked spans/contexts.
-    8. Calls flt_otel_scope_free_unused() to remove finished and destroyed
-       scope_span/scope_context entries from the runtime lists.
-
-
-7  Runtime Data Structures
-----------------------------------------------------------------------
-
-7.1  Runtime Context (per stream)
-
-  flt_otel_runtime_context:
-    stream         Owning stream pointer.
-    filter         Owning filter pointer.
-    uuid[40]       Generated UUID v4 for the session.
-    flag_harderr   Copied from instrumentation config.
-    flag_disabled  Set when the filter encounters a hard error or ACL disables
-                   processing.
-    logging        Logging flags.
-    analyzers      Bitmask of analyzers that have actually executed.
-    idle_timeout   Idle timeout interval in milliseconds (0 = off).
-    idle_exp       Tick at which the next idle timeout fires.
-    spans          Linked list of flt_otel_scope_span.
-    contexts       Linked list of flt_otel_scope_context.
-
-7.2  Scope Span
-
-  flt_otel_scope_span:
-    id / id_len    Span operation name (borrowed from config).
-    smp_opt_dir    Direction in which the span was created.
-    flag_finish    Set by finish directives, cleared after ending.
-    span           The OTel span object (NULL before start, NULL after
-                   end_with_options).
-    ref_span       Parent span pointer (resolved at init).
-    ref_ctx        Parent context pointer (resolved at init).
-    list           Chain in runtime_context.spans.
-
-  flt_otel_scope_span_init() performs memoization: if a span with the same name
-  already exists in rt_ctx->spans, it returns the existing entry.  This allows
-  multiple scopes to contribute attributes/events to the same logical span.
-
-7.3  Scope Context
-
-  flt_otel_scope_context:
-    id / id_len    Context name (borrowed from config).
-    smp_opt_dir    Direction in which the context was extracted.
-    flag_finish    Marks the context for destruction.
-    context        The OTel span_context object.
-    list           Chain in runtime_context.contexts.
-
-  Similarly memoized: duplicate extraction of the same context name returns the
-  existing entry.
-
-7.4  Scope Data (per span per scope run, stack-allocated)
-
-  flt_otel_scope_data:
-    baggage        Key-value array for baggage items.
-    attributes     Key-value array for span attributes.
-    events         Linked list of flt_otel_scope_data_event (each with name
-                   + key-value array).
-    links          Linked list of flt_otel_scope_data_link (each with span
-                   and/or context pointer).
-    status         Status code and description string.
-
-  Initialized at the start of each span processing block and freed at the end.
-  The link entries hold borrowed pointers to OTel objects owned by the runtime
-  context, so only the link nodes themselves are freed.
-
-7.5  Span Finishing
-
-  finish <name> / finish * / finish *req* / finish *res*
-
-  The "finish" directive marks spans and contexts for completion:
-    - "*" marks all.
-    - "*req*" / "*res*" marks those created in the request/response direction
-      respectively.
-    - Otherwise, marks by exact name.
-
-  flt_otel_scope_finish_marked() iterates all marked entries:
-    - Spans are ended via span->end_with_options() which NULLs the span pointer.
-    - Contexts are destroyed via context->destroy() which NULLs the context
-      pointer.
-
-  flt_otel_scope_free_unused() then removes entries with NULL span/context
-  pointers from the runtime lists.  For contexts, associated HTTP headers
-  and variables are also cleaned up.
-
-  On stream detach (flt_otel_runtime_context_free), any remaining active spans
-  are force-ended and all entries are freed.
-
-
-8  Span Links
-----------------------------------------------------------------------
-
-Span links associate a span with other spans or contexts without establishing
-a parent-child relationship.
-
-8.1  Configuration
-
-Two syntaxes are supported:
-
-  Inline (one link per span declaration):
-    span <name> [parent <ref>] link <linked-span> [root]
-
-  Standalone (multiple links, requires a preceding span):
-    link <span-name> [<span-name> ...]
-
-The flt_otel_conf_link structure stores each link target name.  Duplicate link
-names within the same span are rejected by the init macro's duplicate check.
-The links list is initialized in flt_otel_conf_span_init() and destroyed in
-flt_otel_conf_span_free().
-
-8.2  Runtime Resolution
-
-At scope execution time (event.c, flt_otel_scope_run), for each configured link:
-  1. The name is searched in rt_ctx->spans (active scope_span entries).
-     If found, the OTel span pointer is captured.
-  2. If not found in spans, the name is searched in rt_ctx->contexts (extracted
-     scope_context entries).  If found, the OTel span_context pointer is
-     captured.
-  3. If neither found, a NOTICE warning is logged and the link is skipped.
-  4. A flt_otel_scope_data_link node is allocated and appended to the scope
-     data's links list.
-
-In flt_otel_scope_run_span(), all resolved links are applied via
-span->add_link(span, link_span, link_context, NULL, 0).  The last two arguments
-(attributes array and count) are NULL/0, meaning links carry no additional
-attributes.
-
-
-9  Context Propagation
-----------------------------------------------------------------------
-
-9.1  Extraction
-
-  extract <name-prefix> [use-headers|use-vars]
-
-Extracts an incoming trace context.  The prefix identifies the header name
-pattern (for HTTP) or variable name pattern (for vars).
-
-  - use-headers (default): flt_otel_http_headers_get() iterates HTX headers
-    matching the prefix and builds an otelc_text_map.
-  - use-vars: flt_otel_vars_get() reads HAProxy variables matching the prefix
-    pattern.
-
-The text map is passed to flt_otel_extract_http_headers() which uses the
-C wrapper to reconstruct an otelc_span_context.
-
-9.2  Injection
-
-  inject <name-prefix> [use-headers] [use-vars]
-
-Injects the current span's context into outgoing data.  Both storage types can
-be used simultaneously.
-
-  flt_otel_inject_http_headers() serializes the span context into an
-  otelc_http_headers_writer which produces a text_map.  For each key-value pair:
-    - use-headers: flt_otel_http_header_set() adds/replaces the header with the
-      prefixed name.
-    - use-vars: flt_otel_var_register() + flt_otel_var_set() stores the value
-      in a HAProxy transaction variable with normalized name (dashes replaced
-      with 'D', spaces with 'S', uppercase lowered; dots serve as component
-      separators).
-
-
-10  HTTP Header Manipulation
-----------------------------------------------------------------------
-
-  http.c provides three operations:
-
-  flt_otel_http_headers_get(chn, prefix, prefix_len, err):
-    Iterates the HTX message headers.  Headers whose name starts with the given
-    prefix are collected into an otelc_text_map.  The prefix is stripped from
-    the names in the returned map.
-
-  flt_otel_http_header_set(chn, prefix, name, value, err):
-    Removes any existing header matching "prefix" + "name", then adds a new
-    header with the given value.  If name is NULL, all headers with the prefix
-    are removed (bulk delete).
-
-  flt_otel_http_headers_remove(chn, prefix, err):
-    Convenience wrapper; removes all headers matching the prefix.
-
-
-11  HAProxy Variable Integration
-----------------------------------------------------------------------
-
-Enabled with OTEL_USE_VARS=1.  Provides an alternative propagation mechanism
-using HAProxy transaction-scoped variables.
-
-Variable names are normalized: dashes and spaces are replaced with special
-characters to comply with HAProxy variable naming rules.  A meta-variable
-tracks the list of context variable names so they can be enumerated for
-extraction.
-
-Key functions:
-  flt_otel_var_register()   Registers a variable with HAProxy.
-  flt_otel_var_set()        Sets a variable value.
-  flt_otel_vars_get()       Reads all context variables into a text_map for
-                            extraction.
-  flt_otel_vars_unset()     Removes all context variables.
-
-
-12  Group Action Integration
-----------------------------------------------------------------------
-
-The "otel-group" HAProxy action allows triggering trace scopes from
-tcp-request, tcp-response, http-request, http-response and
-http-after-response rules:
-
-  tcp-request         otel-group <filter-id> <group-name>
-  tcp-response        otel-group <filter-id> <group-name>
-  http-request        otel-group <filter-id> <group-name>
-  http-response       otel-group <filter-id> <group-name>
-  http-after-response otel-group <filter-id> <group-name>
-
-  group.c implements:
-    flt_otel_group_parse():   Parses the action arguments.
-    flt_otel_group_check():   Resolves group and scope references.
-    flt_otel_group_action():  At runtime, finds the OTel filter in the stream,
-                              iterates all scopes in the group, and calls
-                              flt_otel_scope_run() for each.
-
-
-13  Memory Management
-----------------------------------------------------------------------
-
-  pool.c provides wrappers around HAProxy memory pools and standard
-  allocation:
-
-  flt_otel_pool_alloc()   Allocates from a pool (if non-NULL and the requested
-                          size fits) or via calloc.
-  flt_otel_pool_free()    Returns memory to the pool or frees it.
-  flt_otel_pool_strndup() Duplicates a string via pool allocation.
-  flt_otel_trash_alloc()  Acquires a trash buffer chunk.
-  flt_otel_trash_free()   Releases a trash buffer chunk.
-
-Four pool heads are registered for hot-path structures:
-  - otel_scope_span       (scope.c)
-  - otel_scope_context    (scope.c)
-  - otel_runtime_context  (scope.c)
-  - otel_span_context     (filter.c, used by the C wrapper via otelc_ext_init
-                          callback)
-
-The wrapper library's memory allocations are redirected through
-flt_otel_mem_malloc() / flt_otel_mem_free() which use the otel_span_context
-pool.  This ensures OTel objects benefit from HAProxy's pool allocator.
-
-
-14  CLI Interface
-----------------------------------------------------------------------
-
-  cli.c registers commands under "flt-otel" for runtime control:
-  - Setting the debug level.
-  - Enabling/disabling the filter on the fly.
-
-Logging can be independently controlled via the instrumentation's logging
-flags (ON, NOLOGNORM).  Log output goes to the log servers configured in the
-instrumentation block.
-
-
-15  Debug Infrastructure
-----------------------------------------------------------------------
-
-When compiled with OTEL_DEBUG=1 (DEBUG_OTEL defined), the filter enables:
-
-  - Additional flt_ops callbacks: stream_set_backend, deinit_per_thread,
-    http_headers, http_payload, http_end, http_reset, http_reply, tcp_payload.
-    In non-debug builds these are set to NULL.  (Note: stream_start and
-    stream_stop are always registered because they fire the on-stream-start
-    and on-stream-stop events.)
-
-  - The OTELC_DBG() macro produces debug output at various levels.
-
-  - flt_otel_scope_data_dump() dumps the complete scope data (baggage,
-    attributes, events, links, status) for inspection.
-
-  - Event usage counters (per-event htx_is_empty statistics) are maintained and
-    printed at deinit.
-
-  - Pool size information is printed at startup.
-
-The debug level is a bitmask that can be adjusted at runtime via the CLI.
-
-
-16  Test Infrastructure
-----------------------------------------------------------------------
-
-16.1  Test Scenarios
-
-  sa    Standalone: comprehensive test exercising all request and response
-        events, span links (both inline and standalone syntax), events with data
-        capture, baggage, and the full span hierarchy from client session start
-        to server session end.
-
-  fe    Frontend-only: tests the request-side span chain with context injection
-        into HTTP headers.
-
-  be    Backend-only: tests context extraction from HTTP headers and
-        response-side processing.  Designed to run as the backend of
-        the fe/ test.
-
-  ctx   Context propagation: deep nesting test that verifies context propagation
-        via both HTTP headers and HAProxy variables.
-
-  cmp   Comparison: simplified configuration made for comparison with other
-        tracing implementations.
-
-  empty Minimal: validates that an empty configuration (only the
-        instrumentation block, no scopes) does not crash.
-
-16.2  Test Runners
-
-All runners are POSIX shell scripts (/bin/sh).  They accept an optional HAProxy
-binary path and log to test/_logs/.
-
-  run-sa.sh     Runs a single HAProxy instance with sa/ config.
-  run-cmp.sh    Runs a single HAProxy instance with cmp/ config.
-  test-speed.sh Runs performance benchmarks for one or all configurations.
-  run-ctx.sh    Runs a single HAProxy instance with ctx/ config.
-  run-fe-be.sh  Launches two HAProxy instances (frontend on port 10080, backend
-                on port 11080) forming a trace propagation chain.  Handles
-                graceful shutdown via SIGUSR1.
-
-  copy-yml.sh   Transforms a template YAML configuration by replacing
-                placeholders with test-specific values (service names, file
-                suffixes, etc.).
-
-16.3  Exporter Configuration
-
-Each test directory contains an otel.yml file configuring three exporter types:
-  - OTLP file exporter (writes traces to local files).
-  - OTLP gRPC exporter (sends to localhost:4317).
-  - OTLP HTTP exporter (sends to localhost:4318 in JSON format).
-
-
-17  Notable Design Decisions
-----------------------------------------------------------------------
-
-  - Span memoization: flt_otel_scope_span_init() and
-    flt_otel_scope_context_init() return existing entries if one with the
-    same name already exists.  This allows multiple scopes to contribute data
-    (attributes, events) to the same logical span across different analyzer
-    events.
-
-  - Lazy span creation: the OTel span object is created on first use in
-    flt_otel_scope_run_span(), not at scope_span_init time.  This separates
-    the span identity (name, parent reference) from the actual OTel resource.
-
-  - Soft/hard error modes: in soft mode, errors are logged but the stream
-    continues with tracing effectively abandoned for that span.  In hard mode,
-    the filter disables itself for the rest of the stream.  Either way, stream
-    processing is never interrupted by a tracing failure (FLT_OTEL_RET_OK is
-    always returned).
-
-  - Rate limiting uses a uint32 representation of a percentage
-    (FLT_OTEL_FLOAT_U32), compared against ha_random32() for uniform
-    distribution without floating-point at runtime.
-
-  - Server-unavailable fallback: if the backend was never reached (no response
-    analyzers executed), the on-server-unavailable event is fired at client
-    session end to ensure all spans are properly closed.
-
-  - Custom memory allocator: the C wrapper's allocations are routed through
-    HAProxy memory pools via otelc_ext_init(), keeping OTel objects in the
-    same allocation domain as the rest of the filter.
-
-  - Thread integration: flt_otel_thread_id() returns the HAProxy tid, ensuring
-    the wrapper's thread-local operations map to HAProxy worker threads.
-
-
-18  Tracer, Span and Metrics Internals
-----------------------------------------------------------------------
-
-This chapter describes the end-to-end lifecycle of the tracer and meter
-objects, the runtime span management model, and the metric instrument
-recording pipeline.
-
-18.1  Tracer Provider Initialization
-
-The tracer provider is set up during the proxy-level flt_otel_ops_init()
-callback, which delegates to flt_otel_lib_init() (filter.c).
-The initialization sequence is as follows:
-
-  1. Version check: OTELC_IS_VALID_VERSION() verifies that the
-     OpenTelemetry C wrapper library version matches the header files.
-
-  2. Configuration path: the relative path from the "config" keyword in
-     the instrumentation section is resolved to an absolute path using
-     getcwd() + snprintf().
-
-  3. SDK initialization: otelc_init(path, err) loads the YAML
-     configuration file and sets up the SDK exporters, samplers,
-     processors and metric readers.
-
-  4. Tracer creation: otelc_tracer_create(err) allocates the tracer
-     handle and stores it in instr->tracer.
-
-  5. Meter creation: otelc_meter_create(err) allocates the meter handle
-     and stores it in instr->meter.
-
-  6. Logger creation: otelc_logger_create(err) allocates the logger
-     handle and stores it in instr->logger.
-
-  7. Extension callbacks: on success, otelc_ext_init() registers custom
-     memory allocation (flt_otel_mem_malloc / flt_otel_mem_free) and
-     thread-id (flt_otel_thread_id) callbacks so that OTel SDK objects
-     use HAProxy memory pools and thread numbering.
-
-  8. Log handler: otelc_log_set_handler() installs a callback that
-     counts SDK diagnostic messages via the flt_otel_drop_cnt counter.
-
-All three handles are stored in the flt_otel_conf_instr structure
-(conf.h):
-
-  struct flt_otel_conf_instr {
-      ...
-      struct otelc_tracer *tracer;  /* The OpenTelemetry tracer handle. */
-      struct otelc_meter  *meter;   /* The OpenTelemetry meter handle. */
-      struct otelc_logger *logger;  /* The OpenTelemetry logger handle. */
-      ...
-  };
-
-18.2  Per-Thread Tracer, Meter and Logger Startup
-
-The flt_otel_ops_init_per_thread() callback (filter.c) starts the
-tracer, meter and logger background threads on the first call:
-
-  if (!(fconf->flags & FLT_CFG_FL_HTX)) {
-      retval = OTELC_OPS(conf->instr->tracer, start);
-      if (retval != OTELC_RET_ERROR) {
-          retval = OTELC_OPS(conf->instr->meter, start);
-          ...
-      }
-      if (retval != OTELC_RET_ERROR) {
-          retval = OTELC_OPS(conf->instr->logger, start);
-          ...
-      }
-      fconf->flags |= FLT_CFG_FL_HTX;
-  }
-
-The FLT_CFG_FL_HTX flag ensures that start is called only once, even
-when multiple proxies share the same filter configuration.  If any
-start operation fails, the error string from the failing handle is
-forwarded via FLT_OTEL_ALERT.
-
-18.3  Tracer, Meter and Logger Shutdown
-
-At proxy deinit (flt_otel_ops_deinit, filter.c), the tracer, meter
-and logger are destroyed in a single call:
-
-  otelc_deinit(&((*conf)->instr->tracer), &((*conf)->instr->meter), &((*conf)->instr->logger));
-
-This flushes any pending spans, metric data and log records to the
-configured exporters, then releases the SDK resources.  The full
-configuration tree is freed immediately after via flt_otel_conf_free().
-
-18.4  Span Lifecycle
-
-Spans progress through four phases: identity allocation, OTel span
-creation, data population, and completion.
-
-18.4.1  Span Identity Allocation
-
-When a scope containing a span definition executes for the first time,
-flt_otel_scope_span_init() (scope.c) allocates a scope_span
-entry from the otel_scope_span pool and inserts it into the runtime
-context's spans list:
-
-  retptr = flt_otel_pool_alloc(pool_head_otel_scope_span, ...);
-  retptr->id          = id;       /* Borrowed from config. */
-  retptr->id_len      = id_len;
-  retptr->smp_opt_dir = dir;
-  retptr->ref_span    = ref_span; /* Resolved parent span. */
-  retptr->ref_ctx     = ref_ctx;  /* Resolved parent context. */
-  LIST_INSERT(&(rt_ctx->spans), &(retptr->list));
-
-The parent reference (ref_id) is resolved at this point by searching the
-runtime context's spans list first, then the contexts list.  If the
-parent name cannot be found in either list, an error is returned and the
-span is not created.
-
-Memoization: if a span with the same name already exists in
-rt_ctx->spans, the existing entry is returned without allocation.  This
-allows multiple scopes (across different analyzer events) to contribute
-attributes, events and other data to the same logical span.
-
-18.4.2  OTel Span Creation (Lazy)
-
-The actual OTel span object is created lazily on first use in
-flt_otel_scope_run_span() (event.c):
-
-  if (span->span == NULL) {
-      span->span = OTELC_OPS(conf->instr->tracer,
-          start_span_with_options, span->id,
-          span->ref_span, span->ref_ctx,
-          ts_steady, ts_system, OTELC_SPAN_KIND_SERVER);
-  }
-
-The arguments are:
-
-  span->id       The operation name (string identifier from config).
-  span->ref_span The parent span pointer (NULL if root or no parent).
-  span->ref_ctx  The parent span context (from extracted context).
-  ts_steady      Monotonic timestamp (CLOCK_MONOTONIC) for duration.
-  ts_system      Wall-clock timestamp (CLOCK_REALTIME) for events.
-  OTELC_SPAN_KIND_SERVER  Fixed span kind for all HAProxy spans.
-
-This separation between identity allocation and OTel creation means the
-span name, parent references and pool entry exist before the OTel
-resource is allocated.  Subsequent scope executions that reference the
-same span name find the existing entry (via memoization) and add their
-data to the already-created OTel span.
-
-18.4.3  Span Data Population
-
-After creation, flt_otel_scope_run_span() (event.c) populates
-the span with data collected during scope execution:
-
-  Links (event.c):
-    Each resolved link is added via span->add_link(span, link_span,
-    link_context, NULL, 0).  Links associate the span with other spans
-    or contexts without establishing a parent-child relationship.  The
-    last two arguments (attributes array and count) are always NULL/0.
-
-  Baggage (event.c):
-    span->set_baggage_kv_n(data->baggage.attr, data->baggage.cnt)
-    sets key-value baggage items propagated across service boundaries.
-
-  Attributes (event.c):
-    span->set_attribute_kv_n(data->attributes.attr, data->attributes.cnt)
-    sets key-value span attributes evaluated from HAProxy sample
-    expressions.
-
-  Events (event.c):
-    For each event in data->events (iterated in reverse insertion order):
-    span->add_event_kv_n(event->name, ts_system, event->attr, event->cnt)
-    adds a named event with a wall-clock timestamp and key-value
-    attributes.
-
-  Status (event.c):
-    span->set_status(data->status.code, data->status.description)
-    sets the span's status code and description string.  Only one status
-    per event is allowed.
-
-18.4.4  Span Context Injection
-
-After populating the span, if the configuration contains an "inject"
-directive (conf_span->ctx_id is non-NULL), the span context is
-serialized for downstream propagation (event.c).
-
-  flt_otel_inject_http_headers() serializes the span context into an
-  otelc_http_headers_writer, producing a text_map of key-value pairs.
-  For each pair, depending on the ctx_flags:
-
-    FLT_OTEL_CTX_USE_HEADERS:
-      flt_otel_http_header_set() writes the header into the HTX message.
-
-    FLT_OTEL_CTX_USE_VARS (requires OTEL_USE_VARS=1):
-      flt_otel_var_register() + flt_otel_var_set() store the value
-      in a HAProxy transaction variable.
-
-  Both storage types can be used simultaneously on the same span.
-
-18.4.5  Span Completion
-
-Spans are ended through the marking mechanism described in chapter 7.5.
-The actual end call in flt_otel_scope_finish_marked() (scope.c) is:
-
-  OTELC_OPSR(span->span, end_with_options,
-             ts_finish, OTELC_SPAN_STATUS_IGNORE, NULL);
-
-The arguments are the monotonic timestamp, a status hint (IGNORE means
-"do not override the status already set on the span"), and NULL for
-error string.  After end_with_options returns, the OTELC_OPSR macro
-NULLs the span pointer, making the entry eligible for removal by
-flt_otel_scope_free_unused().
-
-On stream detach, flt_otel_runtime_context_free() (scope.c)
-force-ends any remaining active spans with the current monotonic
-timestamp and frees all pool entries.
-
-18.5  Metric Instruments
-
-The filter supports the full set of OpenTelemetry metric instrument
-types through a two-form configuration model: "create" form instruments
-define the instrument, and "update" form instruments record measurements
-against it.
-
-18.5.1  Instrument Types
-
-The following instrument types are available (parser.h):
-
-    cnt_int         Counter (uint64)
-    hist_int        Histogram (uint64)
-    udcnt_int       UpDownCounter (int64)
-    gauge_int       Gauge (int64)
-
-Observable (asynchronous) instruments are not supported.  The OTel SDK invokes
-their callbacks from an external background thread that is not a HAProxy
-thread.  HAProxy sample fetches rely on internal per-thread-group state and
-return incorrect results when called from a non-HAProxy thread.
-
-Double-precision types are not supported because HAProxy sample fetches do not
-return double values.
-
-  Special:
-    update          Update-form instrument (records measurements)
-
-Each create-form instrument carries a description, unit, aggregation type,
-sample expression list, and optional histogram bucket boundaries.  Each
-update-form instrument carries a reference to its create-form counterpart
-and an attribute key-value array for per-scope dimensions.
-
-18.5.2  Instrument Configuration Structure
-
-The flt_otel_conf_instrument structure (conf.h) holds:
-
-  idx          Meter instrument index.  Initially set to
-               OTELC_METRIC_INSTRUMENT_UNSET (-1).  Transitions to
-               OTELC_METRIC_INSTRUMENT_PENDING (-2) during creation,
-               then to the positive meter index on success.
-  type         The otelc_metric_instrument_t type constant, or
-               OTELC_METRIC_INSTRUMENT_UPDATE (0xff) for update-form.
-  aggr_type    The otelc_metric_aggregation_type_t constant.
-               Initially OTELC_METRIC_AGGREGATION_UNSET (-1).
-  description  Instrument description string (create-form only).
-  unit         Instrument unit string (create-form only).
-  samples      List of sample expressions for the instrument value.
-  bounds       Histogram bucket boundaries array (create-form only).
-  bounds_num   Number of histogram bucket boundaries.
-  attributes   List of flt_otel_conf_sample entries (update-form only).
-  ref          Pointer to the create-form instrument (update-form only).
-
-18.5.3  Meter Initialization and Startup
-
-The meter handle is created alongside the tracer in flt_otel_lib_init()
-(filter.c) via otelc_meter_create(err) and started per-thread
-in flt_otel_ops_init_per_thread() (filter.c) via
-OTELC_OPS(conf->instr->meter, start).  The meter background thread
-handles periodic collection and export of metric data.
-
-18.5.4  Instrument Creation and Recording
-
-Metric instrument processing is performed by
-flt_otel_scope_run_instrument() (event.c), which runs in two
-passes during scope execution.
-
-  Pass 1 -- Create-form instruments (event.c):
-
-    Iterates all instruments in the scope.  For each create-form
-    instrument whose idx is OTELC_METRIC_INSTRUMENT_UNSET:
-
-    a. Thread-safe one-time creation: HA_ATOMIC_CAS transitions the idx
-       from UNSET to PENDING.  If the CAS fails (another thread is
-       already creating this instrument), the current thread skips it.
-
-    b. Instrument creation: meter->create_instrument() is called with
-       the instrument name, description, unit, type and callback data.
-       On success, the returned index is stored atomically; on failure,
-       the idx is reset to UNSET.  If the instrument has an explicit
-       aggregation type or histogram bucket boundaries, meter->add_view()
-       is called before instrument creation to register a view with the
-       configured aggregation strategy and optional bounds.  When bounds
-       are present without an explicit aggregation type, histogram
-       aggregation is used automatically for backward compatibility.
-
-  Pass 2 -- Update-form instruments (event.c):
-
-    Iterates all instruments again.  For each update-form instrument:
-
-    a. Reference validation: the ref pointer must be non-NULL (resolved
-       at check time to the create-form instrument).
-
-    b. Index check: if the create-form instrument's idx is still
-       negative (UNUSED or PENDING), the measurement is skipped.
-
-    c. Recording: flt_otel_scope_run_instrument_record() evaluates the
-       sample expression, converts it to an otelc_value, and calls
-       meter->update_instrument_kv_n(idx, &value, attr, attr_len).
-
-18.5.5  Sample Evaluation for Metrics
-
-The recording function flt_otel_scope_run_instrument_record()
-(event.c) supports two evaluation paths:
-
-  Standard path: evaluates sample_process() on the first expression in
-  the create-form instrument's samples list, using the stream's backend,
-  session and direction context.
-
-  Log-format path: if sample->lf_used is set, allocates a temporary
-  buffer of global.tune.bufsize, calls build_logline() to evaluate the
-  log-format expression, and presents the result as an SMP_T_STR sample.
-
-Both paths converge on flt_otel_sample_to_value(), which converts the
-HAProxy sample data to an otelc_value.  Metric instruments require
-numeric values (INT64); if the conversion produces
-OTELC_VALUE_DATA (string), a warning is logged and the measurement is
-rejected.
-
-
-18.5.6  Instrument Lifecycle Summary
-
-  Configuration time:
-    idx = OTELC_METRIC_INSTRUMENT_UNSET (-1)
-    type = instrument type constant
-
-  First scope execution (any thread):
-    idx transitions:  UNSET -> PENDING -> meter_index  (success)
-                      UNSET -> PENDING -> UNSET       (failure)
-
-  Subsequent scope executions:
-    Create-form: skipped (idx is already a valid meter index).
-    Update-form: evaluates samples and records via meter API.
-
-  Shutdown:
-    otelc_deinit() flushes and destroys tracer, meter and logger,
-    including all registered instruments and their callbacks.
-
-
-18.6  Log Records
-
-The filter supports OpenTelemetry log records via the "log-record"
-keyword inside otel-scope sections.  Each log record is emitted through
-the OTel logger at a configured severity level, with an evaluated body,
-optional span correlation and optional key-value attributes.
-
-18.6.1  Log Record Configuration Structure
-
-The flt_otel_conf_log_record structure (conf.h) holds:
-
-  severity     The otelc_log_severity_t severity level.
-  event_id     Optional numeric event identifier (int64).
-  event_name   Optional event name string.
-  span         Optional span reference name (resolved at runtime).
-  attributes   List of flt_otel_conf_sample entries for attributes.
-  samples      List of sample expressions for the body.
-
-The attributes list contains flt_otel_conf_sample entries, one per "attr"
-keyword.  Each entry's key field holds the attribute name and its sample
-expressions are evaluated at runtime, following the same two-path model
-(bare sample or log-format) as span attributes.
-
-The samples list contains exactly one flt_otel_conf_sample entry, which
-in turn holds either a list of bare sample expressions or a single
-log-format expression (when the value contains "%[").
-
-18.6.2  Log Record Emission
-
-Log record processing is performed by flt_otel_scope_run_log_record()
-(event.c), called from flt_otel_scope_run() after metric instrument
-processing and before span finishing.
-
-For each configured log record the function performs:
-
-  1. Severity check: OTELC_OPS(logger, enabled, severity) tests whether
-     the logger accepts records at this severity.  If not, the entry is
-     skipped.  The threshold is controlled by the "min_severity" option
-     in the YAML logs signal configuration.
-
-  2. Attribute evaluation: each entry in the attributes list is evaluated via
-     flt_otel_sample_add() into a temporary flt_otel_scope_data structure.
-     The evaluated key-value array is passed to logger->log_span() and freed
-     after emission.
-
-  3. Body evaluation: the single sample entry is evaluated using one of
-     two paths:
-
-     Log-format path (sample->lf_used is true):
-       A temporary buffer of global.tune.bufsize is allocated and
-       build_logline() evaluates the log-format expression into it.
-
-     Bare sample expression path:
-       Each expression in sample->exprs is evaluated via
-       sample_process() and converted to a string via
-       flt_otel_sample_to_str().  Results are concatenated into a
-       single buffer.
-
-  4. Span resolution: if conf_log->span is non-NULL, the runtime
-     context's spans list is searched for a scope_span with a matching
-     name.  If found, the OTel span pointer is captured for correlation.
-     A missing span is non-fatal -- a NOTICE warning is logged and the
-     record is emitted without span correlation.
-
-  5. Emission: logger->log_span() is called with the severity, event_id,
-     event_name, resolved span (or NULL), wall-clock timestamp, the evaluated
-     attributes and the evaluated body string.
-
-18.6.3  Logger Lifecycle Summary
-
-  Proxy init (flt_otel_lib_init):
-    otelc_logger_create() allocates the logger handle.
-
-  Per-thread init (flt_otel_ops_init_per_thread):
-    logger->start() launches the logger background thread.
-
-  Scope execution (flt_otel_scope_run):
-    flt_otel_scope_run_log_record() emits records via logger->log_span().
-
-  Shutdown (flt_otel_ops_deinit):
-    otelc_deinit() flushes pending log records and destroys the logger.
diff --git a/addons/otel/README-misc b/addons/otel/README-misc
deleted file mode 100644 (file)
index 235e5d8..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-OpenTelemetry filter -- miscellaneous notes
-==============================================================================
-
-1  Parsing sample expressions in HAProxy
-------------------------------------------------------------------------------
-
-HAProxy provides two entry points for turning a configuration string into an
-evaluable sample expression.
-
-
-1.1  sample_parse_expr()
-..............................................................................
-
-Parses a bare sample-fetch name with an optional converter chain.  The input is
-the raw expression without any surrounding syntax.
-
-  Declared in:  include/haproxy/sample.h
-  Defined in:   src/sample.c
-
-  struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, int line, char **err_msg, struct arg_list *al, char **endptr);
-
-The function reads from str[*idx] and advances *idx past the consumed tokens.
-
-Configuration example (otel-scope instrument keyword):
-
-  instrument my_counter "name" desc req.hdr(host),lower ...
-
-Here "req.hdr(host),lower" is a single configuration token that
-sample_parse_expr() receives directly.  It recognises the fetch "req.hdr(host)"
-and the converter "lower" separated by a comma.
-
-
-1.2  parse_logformat_string()
-..............................................................................
-
-Parses a log-format string that may contain literal text mixed with sample
-expressions wrapped in %[...] delimiters.
-
-  Declared in:  include/haproxy/log.h
-  Defined in:   src/log.c
-
-  int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct lf_expr *lf_expr, int options, int cap, char **err);
-
-Configuration example (HAProxy log-format directive):
-
-  log-format "host=%[req.hdr(host),lower] status=%[status]"
-
-The %[...] wrapper tells parse_logformat_string() where each embedded sample
-expression begins and ends.  The text outside the brackets ("host=", " status=")
-is emitted as-is.
-
-
-1.3  Which one to use
-..............................................................................
-
-Use sample_parse_expr() when the configuration token is a single, standalone
-sample expression (no surrounding text).  This is the case for the otel filter
-keywords such as "attribute", "event", "baggage", "status", "value", and
-similar.
-
-Use parse_logformat_string() when the value is a free-form string that may mix
-literal text with zero or more embedded expressions.
-
-
-2  Signal keywords
-------------------------------------------------------------------------------
-
-The OTel filter configuration uses one keyword per signal to create or update
-signal-specific objects.  The keyword names follow the OpenTelemetry
-specification's own terminology rather than using informal synonyms.
-
-  Signal      Keyword        Creates / updates
-  --------    -----------    ------------------------------------------
-  Tracing     span           A trace span.
-  Metrics     instrument     A metric instrument (counter, gauge, ...).
-  Logging     log-record     A log record.
-
-The tracing keyword follows the same logic.  A "trace" is the complete
-end-to-end path of a request through a distributed system, composed of one or
-more "spans".  Each span represents a single unit of work within that trace.
-The configuration operates at the span level: it creates individual spans, sets
-their parent-child relationships, and attaches attributes and events.  Using
-"trace" as the keyword would be imprecise because one does not configure a trace
-directly; one configures the spans that collectively form a trace.
-
-The metrics keyword is analogous.  In the OpenTelemetry data model the
-terminology is layered: a "metric" is the aggregated output that the SDK
-produces after processing recorded measurements, while an "instrument" is the
-concrete object through which those measurements are recorded -- a counter,
-histogram, gauge, or up-down counter.  The configuration operates at the
-instrument level: it creates an instrument of a specific type and records values
-through it.  Using "metric" as the keyword would be imprecise because one does
-not configure a metric directly; one configures an instrument that yields
-metrics.
-
-The logging keyword follows the same pattern.  A "log" is the broad signal
-category, while a "log record" is a single discrete entry within that signal.
-The configuration operates at the log-record level: it creates individual log
-records with a severity, a body, and optional attributes and span context.
-Using "log" as the keyword would be imprecise because one does not configure a
-log stream directly; one configures the individual log records that comprise it.
diff --git a/addons/otel/README.md b/addons/otel/README.md
deleted file mode 100644 (file)
index dcc8b26..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-## HAProxy OpenTelemetry Filter (OTel)
-
-The OTel filter enables HAProxy to emit telemetry data -- traces, metrics and
-logs -- to any OpenTelemetry-compatible backend via the OpenTelemetry protocol
-(OTLP).
-
-It is the successor to the OpenTracing (OT) filter, built on the OpenTelemetry
-standard which unifies distributed tracing, metrics and logging into a single
-observability framework.
-
-### Features
-
-- **Distributed tracing** -- spans with parent-child relationships, context
-  propagation via HTTP headers or HAProxy variables, links, baggage and status.
-- **Metrics** -- counter, histogram, up-down counter and gauge instruments with
-  configurable aggregation and bucket boundaries.
-- **Logging** -- log records with severity levels, optional span correlation and
-  runtime-evaluated attributes.
-- **Rate limiting** -- percentage-based sampling (0.0--100.0) for controlling
-  overhead.
-- **ACL integration** -- fine-grained conditional execution at instrumentation,
-  scope and event levels.
-- **CLI management** -- runtime enable/disable, rate adjustment, error mode
-  switching and status inspection.
-- **Context propagation** -- inject/extract span contexts between cascaded
-  HAProxy instances or external services.
-
-### Dependencies
-
-The filter requires the
-[OpenTelemetry C Wrapper](https://github.com/haproxytech/opentelemetry-c-wrapper)
-library, which wraps the OpenTelemetry C++ SDK.
-
-### Building
-
-The OTel filter is compiled together with HAProxy by adding `USE_OTEL=1` to the
-make command.
-
-#### Using pkg-config
-
-```
-PKG_CONFIG_PATH=/opt/lib/pkgconfig make -j8 USE_OTEL=1 TARGET=linux-glibc
-```
-
-#### Explicit paths
-
-```
-make -j8 USE_OTEL=1 OTEL_INC=/opt/include OTEL_LIB=/opt/lib TARGET=linux-glibc
-```
-
-#### Build options
-
-| Variable        | Description                                         |
-|-----------------|-----------------------------------------------------|
-| `USE_OTEL`      | Enable the OpenTelemetry filter                     |
-| `OTEL_DEBUG`    | Compile in debug mode                               |
-| `OTEL_INC`      | Force path to opentelemetry-c-wrapper include files |
-| `OTEL_LIB`      | Force path to opentelemetry-c-wrapper library       |
-| `OTEL_RUNPATH`  | Add opentelemetry-c-wrapper RUNPATH to executable   |
-| `OTEL_USE_VARS` | Enable context propagation via HAProxy variables    |
-
-#### Debug mode
-
-```
-PKG_CONFIG_PATH=/opt/lib/pkgconfig make -j8 USE_OTEL=1 OTEL_DEBUG=1 TARGET=linux-glibc
-```
-
-#### Variable-based context propagation
-
-```
-PKG_CONFIG_PATH=/opt/lib/pkgconfig make -j8 USE_OTEL=1 OTEL_USE_VARS=1 TARGET=linux-glibc
-```
-
-#### Verifying the build
-
-```
-./haproxy -vv | grep -i opentelemetry
-```
-
-If the filter is built in, the output contains:
-
-```
-Built with OpenTelemetry support (C++ version 1.26.0, C Wrapper version 1.0.0-842).
-       [OTEL] opentelemetry
-```
-
-#### Library path at runtime
-
-When pkg-config is not used, the executable may not find the library at startup.
-Use `LD_LIBRARY_PATH` or build with `OTEL_RUNPATH=1`:
-
-```
-LD_LIBRARY_PATH=/opt/lib ./haproxy ...
-```
-
-```
-make -j8 USE_OTEL=1 OTEL_RUNPATH=1 OTEL_INC=/opt/include OTEL_LIB=/opt/lib TARGET=linux-glibc
-```
-
-### Configuration
-
-The filter uses a two-file configuration model:
-
-1. **OTel configuration file** (`.cfg`) -- defines the telemetry model:
-   instrumentation settings, scopes and groups.
-2. **YAML configuration file** (`.yml`) -- defines the OpenTelemetry SDK
-   pipeline: exporters, samplers, processors, providers and signal routing.
-
-#### Activating the filter
-
-Add the filter to a HAProxy proxy section (frontend/listen/backend):
-
-```
-frontend my-frontend
-    ...
-    filter opentelemetry [id <id>] config <file>
-    ...
-```
-
-If no filter id is specified, `otel-filter` is used as default.
-
-#### OTel configuration file structure
-
-The OTel configuration file contains three section types:
-
-- `otel-instrumentation` -- mandatory; references the YAML file, sets rate
-  limits, error modes, logging and declares groups and scopes.
-- `otel-scope` -- defines actions (spans, attributes, metrics, logs) triggered
-  by stream events or from groups.
-- `otel-group` -- a named collection of scopes triggered from HAProxy TCP/HTTP
-  rules.
-
-#### Minimal YAML configuration
-
-```yaml
-exporters:
-  my_exporter:
-    type:     otlp_http
-    endpoint: "http://localhost:4318/v1/traces"
-
-samplers:
-  my_sampler:
-    type: always_on
-
-processors:
-  my_processor:
-    type: batch
-
-providers:
-  my_provider:
-    resources:
-      - service.name: "haproxy"
-
-signals:
-  traces:
-    scope_name: "HAProxy OTel"
-    exporters:  my_exporter
-    samplers:   my_sampler
-    processors: my_processor
-    providers:  my_provider
-```
-
-#### Supported YAML exporters
-
-| Type            | Description                           |
-|-----------------|---------------------------------------|
-| `otlp_grpc`     | OTLP over gRPC                        |
-| `otlp_http`     | OTLP over HTTP (JSON or Protobuf)     |
-| `otlp_file`     | Local files in OTLP format            |
-| `zipkin`        | Zipkin-compatible backends            |
-| `elasticsearch` | Elasticsearch                         |
-| `ostream`       | Text output to a file (for debugging) |
-| `memory`        | In-memory buffer (for testing)        |
-
-### Scope keywords
-
-| Keyword        | Description                                             |
-|----------------|---------------------------------------------------------|
-| `span`         | Create or reference a span                              |
-| `attribute`    | Set key-value span attributes                           |
-| `event`        | Add timestamped span events                             |
-| `baggage`      | Set context propagation data                            |
-| `status`       | Set span status (ok/error/ignore/unset)                 |
-| `link`         | Add span links to related spans                         |
-| `inject`       | Inject context into headers or variables                |
-| `extract`      | Extract context from headers or variables               |
-| `finish`       | Close spans (supports wildcards: `*`, `*req*`, `*res*`) |
-| `instrument`   | Create or update metric instruments                     |
-| `log-record`   | Emit a log record with severity                         |
-| `otel-event`   | Bind scope to a filter event with optional ACL          |
-| `idle-timeout` | Set periodic event interval for idle streams            |
-
-### CLI commands
-
-Available via the HAProxy CLI socket (prefix: `flt-otel`):
-
-| Command                    | Description                        |
-|----------------------------|------------------------------------|
-| `flt-otel status`          | Show filter status                 |
-| `flt-otel enable`          | Enable the filter                  |
-| `flt-otel disable`         | Disable the filter                 |
-| `flt-otel hard-errors`     | Enable hard-errors mode            |
-| `flt-otel soft-errors`     | Disable hard-errors mode           |
-| `flt-otel logging [state]` | Set logging state                  |
-| `flt-otel rate [value]`    | Set or show the rate limit         |
-| `flt-otel debug [level]`   | Set debug level (debug build only) |
-
-When invoked without arguments, `rate`, `logging` and `debug` display the
-current value.
-
-### Performance
-
-Benchmark results from the standalone (`sa`) configuration, which exercises all
-events (worst-case scenario):
-
-| Rate limit | Req/s  | Avg latency | Overhead |
-|------------|--------|-------------|----------|
-| 100.0%     | 38,202 | 213.08 us   | 21.6%    |
-| 50.0%      | 42,777 | 190.49 us   | 12.2%    |
-| 25.0%      | 45,302 | 180.46 us   | 7.0%     |
-| 10.0%      | 46,879 | 174.69 us   | 3.7%     |
-| 2.5%       | 47,993 | 170.58 us   | 1.4%     |
-| disabled   | 48,788 | 167.74 us   | ~0       |
-| off        | 48,697 | 168.00 us   | baseline |
-
-With a rate limit of 10% or less, the performance impact is negligible.
-Detailed methodology and additional results are in the `test/` directory.
-
-### Test configurations
-
-The `test/` directory contains ready-to-run example configurations:
-
-- **sa** -- standalone; the most comprehensive example, demonstrating spans,
-  attributes, events, links, baggage, status, metrics, log records, ACL
-  conditions and idle-timeout events.
-- **fe/be** -- distributed tracing across two cascaded HAProxy instances using
-  HTTP header-based context propagation.
-- **ctx** -- context propagation via HAProxy variables using the inject/extract
-  mechanism.
-- **cmp** -- minimal configuration for benchmarking comparison.
-- **empty** -- filter initialized with no active telemetry.
-
-#### Quick start with Jaeger
-
-Start a Jaeger all-in-one container:
-
-```
-docker run -d --name jaeger -p 4317:4317 -p 4318:4318 -p 16686:16686 jaegertracing/all-in-one:latest
-```
-
-Run one of the test configurations:
-
-```
-./test/run-sa.sh
-```
-
-Open the Jaeger UI at `http://localhost:16686` to view traces.
-
-### Documentation
-
-Detailed documentation is available in the following files:
-
-- [README](README) -- complete reference documentation
-- [README-configuration](README-configuration) -- configuration guide
-- [README-conf](README-conf) -- configuration details
-- [README-design](README-design) -- cross-cutting design patterns
-- [README-implementation](README-implementation) -- component architecture
-- [README-func](README-func) -- function reference
-- [README-misc](README-misc) -- miscellaneous notes
-
-### Copyright
-
-Copyright 2026 HAProxy Technologies
-
-### Author
-
-Miroslav Zagorac <mzagorac@haproxy.com>
diff --git a/addons/otel/include/cli.h b/addons/otel/include/cli.h
deleted file mode 100644 (file)
index fa5fe04..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* 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
- */
diff --git a/addons/otel/include/conf.h b/addons/otel/include/conf.h
deleted file mode 100644 (file)
index 6346c51..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/* 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
-
-/*
- * Special two-byte prefix that triggers automatic id generation in
- * FLT_OTEL_CONF_FUNC_INIT(): the text after the prefix is combined
- * with the configuration line number to form a unique identifier.
- */
-#define FLT_OTEL_CONF_HDR_SPECIAL     "\x1e\x1f"
-
-#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 %hhu }", (p),              \
-                 (p)->key, (p)->fmt_string, otelc_value_dump(&((p)->extra), ""), \
-                 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))
-
-#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 %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)->links)), 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 %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)),    \
-                        flt_otel_list_dump(&((p)->instruments)), flt_otel_list_dump(&((p)->log_records)))
-
-#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 %p %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)->meter, (p)->logger,              \
-                        (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_INSTRUMENT(h,p)                                                                                     \
-       OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%" PRId64 " %d %d '%s' '%s' %s %s %p %zu %p }", (p),              \
-                        FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->idx, (p)->type, (p)->aggr_type, OTELC_STR_ARG((p)->description), \
-                        OTELC_STR_ARG((p)->unit), flt_otel_list_dump(&((p)->samples)), flt_otel_list_dump(&((p)->attributes)), \
-                        (p)->ref, (p)->bounds_num, (p)->bounds)
-
-#define FLT_OTEL_DBG_CONF_LOG_RECORD(h,p)                                                                             \
-       OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%d %" PRId64 " '%s' '%s' %s %s }", (p),                  \
-                        FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->severity, (p)->event_id, OTELC_STR_ARG((p)->event_name), \
-                        OTELC_STR_ARG((p)->span), flt_otel_list_dump(&((p)->attributes)), flt_otel_list_dump(&((p)->samples)))
-
-#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)
- * flt_otel_conf_instrument->samples
- * flt_otel_conf_log_record->samples
- */
-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. */
-       struct lf_expr      lf_expr;    /* The log-format expression. */
-       bool                lf_used;    /* Whether lf_expr is used instead of exprs. */
-};
-
-/*
- * 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.  */
-};
-
-/* flt_otel_conf_span->links */
-struct flt_otel_conf_link {
-       FLT_OTEL_CONF_HDR(span); /* The list containing link names. */
-};
-
-/*
- * 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 links;         /* The set of linked span names. */
-       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). */
-};
-
-/*
- * Metric instrument configuration within a scope.
- *   flt_otel_conf_scope->instruments
- */
-struct flt_otel_conf_instrument {
-       FLT_OTEL_CONF_HDR(id);                          /* The name of the instrument. */
-       int64_t                            idx;         /* Meter instrument index (-1 if not yet created). */
-       otelc_metric_instrument_t          type;        /* Instrument type (or UPDATE). */
-       otelc_metric_aggregation_type_t    aggr_type;   /* Aggregation type for the view (create only). */
-       char                              *description; /* Instrument description (create only). */
-       char                              *unit;        /* Instrument unit (create only). */
-       struct list                        samples;     /* Sample expressions for the value. */
-       double                            *bounds;      /* Histogram bucket boundaries (create only). */
-       size_t                             bounds_num;  /* Number of histogram bucket boundaries. */
-       struct list                        attributes;  /* Instrument attributes (update only, flt_otel_conf_sample). */
-       struct flt_otel_conf_instrument   *ref;         /* Resolved create-form instrument (update only). */
-};
-
-/*
- * Log record configuration within a scope.
- *   flt_otel_conf_scope->log_records
- */
-struct flt_otel_conf_log_record {
-       FLT_OTEL_CONF_HDR(id);            /* Required by macro; member <id> is not used directly. */
-       otelc_log_severity_t  severity;   /* The severity level. */
-       int64_t               event_id;   /* Optional event identifier. */
-       char                 *event_name; /* Optional event name. */
-       char                 *span;       /* Optional span reference. */
-       struct list           attributes; /* Log record attributes (flt_otel_conf_sample). */
-       struct list           samples;    /* Sample expressions for the body. */
-};
-
-/* 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. */
-       struct list      instruments;     /* The list of metric instruments. */
-       struct list      log_records;     /* The list of log records. */
-};
-
-/* 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, meter, 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. */
-       struct otelc_meter  *meter;         /* The OpenTelemetry meter handle. */
-       struct otelc_logger *logger;        /* The OpenTelemetry logger 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. */
-};
-
-/* Runtime counters for filter diagnostics. */
-struct flt_otel_counters {
-#ifdef DEBUG_OTEL
-       struct {
-               bool     flag_used; /* Whether this event is used. */
-               uint64_t htx[2];    /* htx_is_empty() function result counter. */
-       } event[FLT_OTEL_EVENT_MAX];
-#endif
-
-#ifdef FLT_OTEL_USE_COUNTERS
-       uint64_t attached[4];       /* [run rate-limit disabled error] */
-       uint64_t disabled[2];       /* How many times stream processing is disabled. */
-#endif
-};
-
-/* 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 flt_otel_counters    cnt;      /* Various counters related to filter operation. */
-       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
- */
diff --git a/addons/otel/include/conf_funcs.h b/addons/otel/include/conf_funcs.h
deleted file mode 100644 (file)
index 6e11bac..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* 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;                                                                           \
-               char                           id_buffer[FLT_OTEL_ID_MAXLEN + 16];                                            \
-               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);                                                                             \
-               }                                                                                                             \
-               else if ((id[0] == FLT_OTEL_CONF_HDR_SPECIAL[0]) && (id[1] == FLT_OTEL_CONF_HDR_SPECIAL[1])) {                \
-                       (void)snprintf(id_buffer, sizeof(id_buffer), "%s:%d", id + 2, line);                                  \
-                                                                                                                             \
-                       id = id_buffer;                                                                                       \
-               }                                                                                                             \
-                                                                                                                             \
-               _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(link)
-FLT_OTEL_CONF_FUNC_DECL(context)
-FLT_OTEL_CONF_FUNC_DECL(span)
-FLT_OTEL_CONF_FUNC_DECL(scope)
-FLT_OTEL_CONF_FUNC_DECL(instrument)
-FLT_OTEL_CONF_FUNC_DECL(log_record)
-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
- */
diff --git a/addons/otel/include/config.h b/addons/otel/include/config.h
deleted file mode 100644 (file)
index 9042ae8..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_CONFIG_H_
-#define _OTEL_CONFIG_H_
-
-/* Memory pool selection flags. */
-#define USE_POOL_BUFFER
-#define USE_POOL_OTEL_SPAN_CONTEXT
-#define USE_POOL_OTEL_SCOPE_SPAN
-#define USE_POOL_OTEL_SCOPE_CONTEXT
-#define USE_POOL_OTEL_RUNTIME_CONTEXT
-#define USE_TRASH_CHUNK
-
-/* Enable per-event and per-stream diagnostic counters in debug builds. */
-#if defined(DEBUG_OTEL) && !defined(FLT_OTEL_USE_COUNTERS)
-#  define FLT_OTEL_USE_COUNTERS
-#endif
-
-#define FLT_OTEL_ID_MAXLEN        64            /* Maximum identifier length. */
-#define FLT_OTEL_DEBUG_LEVEL   0b11101111111 /* Default debug bitmask. */
-
-#define FLT_OTEL_ATTR_INIT_SIZE   8 /* Initial attribute array capacity. */
-#define FLT_OTEL_ATTR_INC_SIZE    4 /* Attribute array growth increment. */
-
-#endif /* _OTEL_CONFIG_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/debug.h b/addons/otel/include/debug.h
deleted file mode 100644 (file)
index 5a8b6cb..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_DEBUG_H_
-#define _OTEL_DEBUG_H_
-
-#ifdef DEBUG_FULL
-#  define DEBUG_OTEL
-#endif
-
-/*
- * FLT_OTEL_DBG_ARGS - include extra debug-only function parameters.
- * FLT_OTEL_DBG_BUF  - dump a buffer structure for debugging.
- *
- * When DEBUG_OTEL is not defined, these expand to nothing.
- */
-#ifdef DEBUG_OTEL
-#  define FLT_OTEL_DBG_ARGS(a, ...)   a, ##__VA_ARGS__
-#  define FLT_OTEL_DBG_BUF(l,a)       OTELC_DBG(l, "%p:{ %zu %p %zu %zu }", (a), (a)->size, (a)->area, (a)->data, (a)->head)
-#else
-#  define FLT_OTEL_DBG_ARGS(...)
-#  define FLT_OTEL_DBG_BUF(...)       while (0)
-#endif /* DEBUG_OTEL */
-
-/*
- *  ON  | NOLOGNORM |
- * -----+-----------+-------------
- *   0  |     0     |  no log
- *   0  |     1     |  no log
- *   1  |     0     |  log all
- *   1  |     1     |  log errors
- * -----+-----------+-------------
- */
-#define FLT_OTEL_LOG(l,f, ...)                                                                                                   \
-       do {                                                                                                                     \
-               if (!(conf->instr->logging & FLT_OTEL_LOGGING_ON))                                                               \
-                       OTELC_DBG(DEBUG, "NOLOG[%d]: [" FLT_OTEL_SCOPE "]: [%s] " f, (l), conf->id, ##__VA_ARGS__);              \
-               else if ((conf->instr->logging & FLT_OTEL_LOGGING_NOLOGNORM) && ((l) > LOG_ERR))                                 \
-                       OTELC_DBG(NOTICE, "NOLOG[%d]: [" FLT_OTEL_SCOPE "]: [%s] " f, (l), conf->id, ##__VA_ARGS__);             \
-               else {                                                                                                           \
-                       send_log(&(conf->instr->proxy_log), (l), "[" FLT_OTEL_SCOPE "]: [%s] " f "\n", conf->id, ##__VA_ARGS__); \
-                                                                                                                                \
-                       OTELC_DBG(INFO, "LOG[%d]: %s", (l), logline);                                                            \
-               }                                                                                                                \
-       } while (0)
-
-#endif /* _OTEL_DEBUG_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/define.h b/addons/otel/include/define.h
deleted file mode 100644 (file)
index 9e434bb..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_DEFINE_H_
-#define _OTEL_DEFINE_H_
-
-/* Safe pointer dereference with default value. */
-#define FLT_OTEL_DEREF(p,m,v)        (((p) != NULL) ? (p)->m : (v))
-
-/* 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)
-
-/* Expand to address and length pair for a string literal. */
-#define FLT_OTEL_STR_ADDRSIZE(a)     (a), FLT_OTEL_STR_SIZE(a)
-
-/* Compare a runtime string against a compile-time string literal. */
-#define FLT_OTEL_STR_CMP(S,s)        ((s##_len == FLT_OTEL_STR_SIZE(S)) && (memcmp((s), FLT_OTEL_STR_ADDRSIZE(S)) == 0))
-
-/* Tolerance for double comparison in flt_otel_qsort_compar_double(). */
-#define FLT_OTEL_DBL_EPSILON         1e-9
-
-/* 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_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/event.h b/addons/otel/include/event.h
deleted file mode 100644 (file)
index 4051956..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_EVENT_H_
-#define _OTEL_EVENT_H_
-
-/*
- * This must be defined in order for macro FLT_OTEL_EVENT_DEFINES
- * and structure flt_otel_event_data to have the correct contents.
- */
-#define AN__NONE                    0
-#define AN__STREAM_START            0     /* on-stream-start */
-#define AN__STREAM_STOP             0     /* on-stream-stop */
-#define AN__IDLE_TIMEOUT            0     /* on-idle-timeout */
-#define AN__BACKEND_SET             0     /* on-backend-set */
-#define AN_REQ_HTTP_HEADERS         0     /* on-http-headers-request */
-#define AN_RES_HTTP_HEADERS         0     /* on-http-headers-response */
-#define AN_REQ_HTTP_END             0     /* on-http-end-request */
-#define AN_RES_HTTP_END             0     /* on-http-end-response */
-#define AN_RES_HTTP_REPLY           0     /* on-http-reply */
-#define AN_REQ_CLIENT_SESS_START    0
-#define AN_REQ_SERVER_UNAVAILABLE   0
-#define AN_REQ_CLIENT_SESS_END      0
-#define AN_RES_SERVER_SESS_START    0
-#define AN_RES_SERVER_SESS_END      0
-#define SMP_VAL_FE_                 0
-#define SMP_VAL_BE_                 0
-#define SMP_OPT_DIR_                0xff
-
-/*
- * Event names are selected to be somewhat compatible with the SPOE filter,
- * from which the following names are taken:
- *   - on-client-session -> on-client-session-start
- *   - on-frontend-tcp-request
- *   - on-frontend-http-request
- *   - on-backend-tcp-request
- *   - on-backend-http-request
- *   - on-server-session -> on-server-session-start
- *   - on-tcp-response
- *   - on-http-response
- *
- * FLT_OTEL_EVENT_NONE is used as an index for 'otel-scope' sections that do not
- * have an event defined.  The 'otel-scope' sections thus defined can be used
- * within the 'otel-group' section.
- *
- * A description of the macro arguments can be found in the structure
- * flt_otel_event_data definition.
- *
- * The following table is derived from the definitions AN_REQ_* and AN_RES_*
- * found in the HAProxy include file include/haproxy/channel-t.h.
- */
-#define FLT_OTEL_EVENT_DEFINES                                                                                \
-       /* Stream lifecycle pseudo-events (an_bit = 0, not tied to a channel analyzer) */                     \
-       FLT_OTEL_EVENT_DEF(              NONE,    ,        ,        , 0, "")                                  \
-       FLT_OTEL_EVENT_DEF(      STREAM_START,    ,        ,        , 0, "on-stream-start")                   \
-       FLT_OTEL_EVENT_DEF(       STREAM_STOP,    ,        ,        , 0, "on-stream-stop")                    \
-       FLT_OTEL_EVENT_DEF( CLIENT_SESS_START, REQ, CON_ACC,        , 1, "on-client-session-start")           \
-       FLT_OTEL_EVENT_DEF(      IDLE_TIMEOUT,    ,        ,        , 0, "on-idle-timeout")                   \
-       FLT_OTEL_EVENT_DEF(       BACKEND_SET,    ,        ,        , 0, "on-backend-set")                    \
-                                                                                                             \
-       /* Request analyzers */                                                                               \
-/*     FLT_OTEL_EVENT_DEF(      FLT_START_FE, REQ,        ,        ,  , "on-filter-start") */                \
-       FLT_OTEL_EVENT_DEF(        INSPECT_FE, REQ, REQ_CNT,        , 1, "on-frontend-tcp-request")           \
-       FLT_OTEL_EVENT_DEF(         WAIT_HTTP, REQ,        ,        , 1, "on-http-wait-request")              \
-       FLT_OTEL_EVENT_DEF(         HTTP_BODY, REQ,        ,        , 1, "on-http-body-request")              \
-       FLT_OTEL_EVENT_DEF(   HTTP_PROCESS_FE, REQ, HRQ_HDR,        , 1, "on-frontend-http-request")          \
-       FLT_OTEL_EVENT_DEF(   SWITCHING_RULES, REQ,        ,        , 1, "on-switching-rules-request")        \
-/*     FLT_OTEL_EVENT_DEF(      FLT_START_BE, REQ,        ,        ,  , "") */                               \
-       FLT_OTEL_EVENT_DEF(        INSPECT_BE, REQ, REQ_CNT, REQ_CNT, 1, "on-backend-tcp-request")            \
-       FLT_OTEL_EVENT_DEF(   HTTP_PROCESS_BE, REQ, HRQ_HDR, HRQ_HDR, 1, "on-backend-http-request")           \
-/*     FLT_OTEL_EVENT_DEF(       HTTP_TARPIT, REQ,        ,        , 1, "on-http-tarpit-request") */         \
-       FLT_OTEL_EVENT_DEF(         SRV_RULES, REQ,        ,        , 1, "on-process-server-rules-request")   \
-       FLT_OTEL_EVENT_DEF(        HTTP_INNER, REQ,        ,        , 1, "on-http-process-request")           \
-       FLT_OTEL_EVENT_DEF(   PRST_RDP_COOKIE, REQ,        ,        , 1, "on-tcp-rdp-cookie-request")         \
-       FLT_OTEL_EVENT_DEF(    STICKING_RULES, REQ,        ,        , 1, "on-process-sticking-rules-request") \
-/*     FLT_OTEL_EVENT_DEF(     FLT_HTTP_HDRS, REQ,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(    HTTP_XFER_BODY, REQ,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(          WAIT_CLI, REQ,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(     FLT_XFER_DATA, REQ,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(           FLT_END, REQ,        ,        ,  , "") */                               \
-       FLT_OTEL_EVENT_DEF(      HTTP_HEADERS, REQ, HRQ_HDR, HRQ_HDR, 1, "on-http-headers-request")           \
-       FLT_OTEL_EVENT_DEF(          HTTP_END, REQ,        ,        , 1, "on-http-end-request")               \
-       FLT_OTEL_EVENT_DEF(   CLIENT_SESS_END, REQ,        ,        , 0, "on-client-session-end")             \
-       FLT_OTEL_EVENT_DEF(SERVER_UNAVAILABLE, REQ,        ,        , 0, "on-server-unavailable")             \
-                                                                                                             \
-       /* Response analyzers */                                                                              \
-       FLT_OTEL_EVENT_DEF( SERVER_SESS_START, RES,        , SRV_CON, 0, "on-server-session-start")           \
-/*     FLT_OTEL_EVENT_DEF(      FLT_START_FE, RES,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(      FLT_START_BE, RES,        ,        ,  , "") */                               \
-       FLT_OTEL_EVENT_DEF(           INSPECT, RES, RES_CNT, RES_CNT, 0, "on-tcp-response")                   \
-       FLT_OTEL_EVENT_DEF(         WAIT_HTTP, RES,        ,        , 1, "on-http-wait-response")             \
-       FLT_OTEL_EVENT_DEF(       STORE_RULES, RES,        ,        , 1, "on-process-store-rules-response")   \
-       FLT_OTEL_EVENT_DEF(   HTTP_PROCESS_BE, RES, HRS_HDR, HRS_HDR, 1, "on-http-response")                  \
-       FLT_OTEL_EVENT_DEF(      HTTP_HEADERS, RES, HRS_HDR, HRS_HDR, 1, "on-http-headers-response")          \
-       FLT_OTEL_EVENT_DEF(          HTTP_END, RES,        ,        , 0, "on-http-end-response")              \
-       FLT_OTEL_EVENT_DEF(        HTTP_REPLY, RES,        ,        , 0, "on-http-reply")                     \
-/*     FLT_OTEL_EVENT_DEF(   HTTP_PROCESS_FE, RES,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(     FLT_HTTP_HDRS, RES,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(    HTTP_XFER_BODY, RES,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(          WAIT_CLI, RES,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(     FLT_XFER_DATA, RES,        ,        ,  , "") */                               \
-/*     FLT_OTEL_EVENT_DEF(           FLT_END, RES,        ,        ,  , "") */                               \
-       FLT_OTEL_EVENT_DEF(   SERVER_SESS_END, RES,        ,        , 0, "on-server-session-end")
-
-enum FLT_OTEL_EVENT_enum {
-#define FLT_OTEL_EVENT_DEF(a,b,c,d,e,f)   FLT_OTEL_EVENT_##b##_##a,
-       FLT_OTEL_EVENT_DEFINES
-       FLT_OTEL_EVENT_MAX
-#undef FLT_OTEL_EVENT_DEF
-};
-
-/* Sample data types associated with a scope event. */
-enum FLT_OTEL_EVENT_SAMPLE_enum {
-       FLT_OTEL_EVENT_SAMPLE_ATTRIBUTE = 0,
-       FLT_OTEL_EVENT_SAMPLE_EVENT,
-       FLT_OTEL_EVENT_SAMPLE_BAGGAGE,
-       FLT_OTEL_EVENT_SAMPLE_STATUS,
-};
-
-/* Per-event metadata mapping analyzer bits to filter event names. */
-struct flt_otel_event_data {
-       uint        an_bit;           /* Used channel analyser. */
-       const char *an_name;          /* Channel analyser name. */
-       uint        smp_opt_dir;      /* Fetch direction (request/response). */
-       uint        smp_val_fe;       /* Valid FE fetch location. */
-       uint        smp_val_be;       /* Valid BE fetch location. */
-       bool        flag_http_inject; /* Span context injection allowed. */
-       const char *name;             /* Filter event name. */
-};
-
-struct flt_otel_conf_scope;
-
-
-/* Per-event metadata table indexed by FLT_OTEL_EVENT_* constants. */
-extern const struct flt_otel_event_data flt_otel_event_data[FLT_OTEL_EVENT_MAX];
-
-
-/* Execute a single scope: create spans, record instruments, evaluate samples. */
-int flt_otel_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_otel_conf_scope *conf_scope, const struct timespec *ts_steady, const struct timespec *ts_system, uint dir, char **err);
-
-/* Run all scopes matching a filter event on the given stream and channel. */
-int flt_otel_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err);
-
-#endif /* _OTEL_EVENT_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/filter.h b/addons/otel/include/filter.h
deleted file mode 100644 (file)
index 8af922b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_FILTER_H_
-#define _OTEL_FILTER_H_
-
-#define FLT_OTEL_FMT_NAME           "'" FLT_OTEL_OPT_NAME "' : "
-#define FLT_OTEL_FMT_TYPE           "'filter' : "
-#define FLT_OTEL_VAR_UUID           "sess", "otel", "uuid"
-#define FLT_OTEL_ALERT(f, ...)      ha_alert(FLT_OTEL_FMT_TYPE FLT_OTEL_FMT_NAME f "\n", ##__VA_ARGS__)
-
-#define FLT_OTEL_CONDITION_IF       "if"
-#define FLT_OTEL_CONDITION_UNLESS   "unless"
-
-/* Return codes for OTel filter operations. */
-enum FLT_OTEL_RET_enum {
-       FLT_OTEL_RET_ERROR  = -1,
-       FLT_OTEL_RET_WAIT   = 0,
-       FLT_OTEL_RET_IGNORE = 0,
-       FLT_OTEL_RET_OK     = 1,
-};
-
-/* Dump or iterate a named configuration list for debugging. */
-#define FLT_OTEL_DBG_LIST(d,m,p,t,v,f)                               \
-       do {                                                         \
-               if (LIST_ISEMPTY(&((d)->m##s))) {                    \
-                       OTELC_DBG(DEBUG, p "- no " #m "s " t);       \
-               } else {                                             \
-                       const struct flt_otel_conf_##m *v;           \
-                                                                    \
-                       OTELC_DBG(DEBUG, p "- " t " " #m "s: %s",    \
-                                 flt_otel_list_dump(&((d)->m##s))); \
-                       list_for_each_entry(v, &((d)->m##s), list)   \
-                               do { f; } while (0);                 \
-               }                                                    \
-       } while (0)
-
-
-extern const char     *otel_flt_id;
-extern uint64_t        flt_otel_drop_cnt;
-extern struct flt_ops  flt_otel_ops;
-
-
-/* Check whether the OTel filter is disabled for a stream. */
-bool flt_otel_is_disabled(const struct filter *f FLT_OTEL_DBG_ARGS(, int event));
-
-#endif /* _OTEL_FILTER_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/group.h b/addons/otel/include/group.h
deleted file mode 100644 (file)
index 3850992..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_GROUP_H_
-#define _OTEL_GROUP_H_
-
-#define FLT_OTEL_ACTION_GROUP   "otel-group"
-
-/* Argument indices for the otel-group action rule. */
-enum FLT_OTEL_ARG_enum {
-       FLT_OTEL_ARG_FILTER_ID = 0,
-       FLT_OTEL_ARG_GROUP_ID,
-
-       FLT_OTEL_ARG_FLT_CONF = 0,
-       FLT_OTEL_ARG_CONF,
-       FLT_OTEL_ARG_GROUP,
-};
-
-/*
- * A description of the macro arguments can be found in the structure
- * flt_otel_group_data definition
- */
-#define FLT_OTEL_GROUP_DEFINES                                                     \
-       FLT_OTEL_GROUP_DEF(ACT_F_TCP_REQ_CON, SMP_VAL_FE_CON_ACC, SMP_OPT_DIR_REQ) \
-       FLT_OTEL_GROUP_DEF(ACT_F_TCP_REQ_SES, SMP_VAL_FE_SES_ACC, SMP_OPT_DIR_REQ) \
-       FLT_OTEL_GROUP_DEF(ACT_F_TCP_REQ_CNT, SMP_VAL_FE_REQ_CNT, SMP_OPT_DIR_REQ) \
-       FLT_OTEL_GROUP_DEF(ACT_F_TCP_RES_CNT, SMP_VAL_BE_RES_CNT, SMP_OPT_DIR_RES) \
-       FLT_OTEL_GROUP_DEF(ACT_F_HTTP_REQ,    SMP_VAL_FE_HRQ_HDR, SMP_OPT_DIR_REQ) \
-       FLT_OTEL_GROUP_DEF(ACT_F_HTTP_RES,    SMP_VAL_BE_HRS_HDR, SMP_OPT_DIR_RES)
-
-/* Per-action-from metadata mapping action types to fetch directions. */
-struct flt_otel_group_data {
-       enum act_from act_from;    /* ACT_F_* */
-       uint          smp_val;     /* Valid FE/BE fetch location. */
-       uint          smp_opt_dir; /* Fetch direction (request/response). */
-};
-
-#endif /* _OTEL_GROUP_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/http.h b/addons/otel/include/http.h
deleted file mode 100644 (file)
index 40fd4d1..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_HTTP_H_
-#define _OTEL_HTTP_H_
-
-#ifndef DEBUG_OTEL
-#  define flt_otel_http_headers_dump(...)   while (0)
-#else
-/* Dump all HTTP headers from a channel for debugging. */
-void                   flt_otel_http_headers_dump(const struct channel *chn);
-#endif
-
-/* Extract HTTP headers matching a prefix into a text map. */
-struct otelc_text_map *flt_otel_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err);
-
-/* Set or replace an HTTP header in a channel. */
-int                    flt_otel_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err);
-
-/* Remove all HTTP headers matching a prefix from a channel. */
-int                    flt_otel_http_headers_remove(struct channel *chn, const char *prefix, char **err);
-
-#endif /* _OTEL_HTTP_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/include.h b/addons/otel/include/include.h
deleted file mode 100644 (file)
index 5c11493..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_INCLUDE_H_
-#define _OTEL_INCLUDE_H_
-
-#include <errno.h>
-#include <stdbool.h>
-#include <math.h>
-#include <values.h>
-#ifdef USE_THREAD
-#  include <pthread.h>
-#endif
-
-#include <haproxy/api.h>
-#include <haproxy/cfgparse.h>
-#include <haproxy/acl.h>
-#include <haproxy/cli.h>
-#include <haproxy/clock.h>
-#include <haproxy/filters.h>
-#include <haproxy/http_htx.h>
-#include <haproxy/http_rules.h>
-#include <haproxy/log.h>
-#include <haproxy/proxy.h>
-#include <haproxy/sample.h>
-#include <haproxy/tcp_rules.h>
-#include <haproxy/tools.h>
-#include <haproxy/vars.h>
-
-#include <opentelemetry-c-wrapper/include.h>
-
-#include "config.h"
-#include "debug.h"
-#include "define.h"
-#include "cli.h"
-#include "event.h"
-#include "conf.h"
-#include "conf_funcs.h"
-#include "filter.h"
-#include "group.h"
-#include "http.h"
-#include "otelc.h"
-#include "parser.h"
-#include "pool.h"
-#include "scope.h"
-#include "util.h"
-#include "vars.h"
-
-#endif /* _OTEL_INCLUDE_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/otelc.h b/addons/otel/include/otelc.h
deleted file mode 100644 (file)
index 0c04f04..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_OTELC_H_
-#define _OTEL_OTELC_H_
-
-/* Inject span context into a text map carrier. */
-int                        flt_otel_inject_text_map(const struct otelc_span *span, struct otelc_text_map_writer *carrier);
-
-/* Inject span context into an HTTP headers carrier. */
-int                        flt_otel_inject_http_headers(const struct otelc_span *span, struct otelc_http_headers_writer *carrier);
-
-/* Extract span context from a text map carrier. */
-struct otelc_span_context *flt_otel_extract_text_map(struct otelc_tracer *tracer, struct otelc_text_map_reader *carrier, const struct otelc_text_map *text_map);
-
-/* Extract span context from an HTTP headers carrier. */
-struct otelc_span_context *flt_otel_extract_http_headers(struct otelc_tracer *tracer, struct otelc_http_headers_reader *carrier, const struct otelc_text_map *text_map);
-
-#endif /* _OTEL_OTELC_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/parser.h b/addons/otel/include/parser.h
deleted file mode 100644 (file)
index 8412b20..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_PARSER_H_
-#define _OTEL_PARSER_H_
-
-#define FLT_OTEL_SCOPE                        "OTEL"
-
-/*
- * filter FLT_OTEL_OPT_NAME FLT_OTEL_OPT_FILTER_ID <FLT_OTEL_OPT_FILTER_ID_DEFAULT> FLT_OTEL_OPT_CONFIG <file>
- */
-#define FLT_OTEL_OPT_NAME                     "opentelemetry"
-#define FLT_OTEL_OPT_FILTER_ID                "id"
-#define FLT_OTEL_OPT_FILTER_ID_DEFAULT        "otel-filter"
-#define FLT_OTEL_OPT_CONFIG                   "config"
-
-#define FLT_OTEL_PARSE_SECTION_INSTR_ID       "otel-instrumentation"
-#define FLT_OTEL_PARSE_SECTION_GROUP_ID       "otel-group"
-#define FLT_OTEL_PARSE_SECTION_SCOPE_ID       "otel-scope"
-
-#define FLT_OTEL_PARSE_SPAN_ROOT              "root"
-#define FLT_OTEL_PARSE_SPAN_PARENT            "parent"
-#define FLT_OTEL_PARSE_SPAN_LINK              "link"
-#define FLT_OTEL_PARSE_INSTRUMENT_DESC        "desc"
-#define FLT_OTEL_PARSE_INSTRUMENT_VALUE       "value"
-#define FLT_OTEL_PARSE_INSTRUMENT_ATTR        "attr"
-#define FLT_OTEL_PARSE_INSTRUMENT_UNIT        "unit"
-#define FLT_OTEL_PARSE_INSTRUMENT_BOUNDS      "bounds"
-#define FLT_OTEL_PARSE_INSTRUMENT_AGGR        "aggr"
-#define FLT_OTEL_PARSE_LOG_RECORD_ID          "id"
-#define FLT_OTEL_PARSE_LOG_RECORD_EVENT       "event"
-#define FLT_OTEL_PARSE_LOG_RECORD_SPAN        "span"
-#define FLT_OTEL_PARSE_LOG_RECORD_ATTR        "attr"
-#define FLT_OTEL_PARSE_CTX_AUTONAME           "-"
-#define FLT_OTEL_PARSE_CTX_IGNORE_NAME        '-'
-#define FLT_OTEL_PARSE_CTX_USE_HEADERS        "use-headers"
-#define FLT_OTEL_PARSE_CTX_USE_VARS           "use-vars"
-#define FLT_OTEL_PARSE_OPTION_HARDERR         "hard-errors"
-#define FLT_OTEL_PARSE_OPTION_DISABLED        "disabled"
-#define FLT_OTEL_PARSE_OPTION_NOLOGNORM       "dontlog-normal"
-
-/*
- * A description of the macro arguments can be found in the structure
- * flt_otel_parse_data definition
- */
-#define FLT_OTEL_PARSE_INSTR_DEFINES                                                                                                                                      \
-       FLT_OTEL_PARSE_INSTR_DEF(         ID, 0, CHAR, 2, 2, "otel-instrumentation", " <name>")                                                                           \
-       FLT_OTEL_PARSE_INSTR_DEF(        ACL, 0, CHAR, 3, 0, "acl",                  " <name> <criterion> [flags] [operator] <value> ...")                                \
-       FLT_OTEL_PARSE_INSTR_DEF(        LOG, 0, CHAR, 2, 0, "log",                  " { global | <addr> [len <len>] [format <fmt>] <facility> [<level> [<minlevel>]] }") \
-       FLT_OTEL_PARSE_INSTR_DEF(     CONFIG, 0, NONE, 2, 2, "config",               " <file>")                                                                           \
-       FLT_OTEL_PARSE_INSTR_DEF(     GROUPS, 0, NONE, 2, 0, "groups",               " <name> ...")                                                                       \
-       FLT_OTEL_PARSE_INSTR_DEF(     SCOPES, 0, NONE, 2, 0, "scopes",               " <name> ...")                                                                       \
-       FLT_OTEL_PARSE_INSTR_DEF( RATE_LIMIT, 0, NONE, 2, 2, "rate-limit",           " <value>")                                                                          \
-       FLT_OTEL_PARSE_INSTR_DEF(     OPTION, 0, NONE, 2, 2, "option",               " { disabled | dontlog-normal | hard-errors }")                                      \
-       FLT_OTEL_PARSE_INSTR_DEF(DEBUG_LEVEL, 0, NONE, 2, 2, "debug-level",          " <value>")
-
-#define FLT_OTEL_PARSE_GROUP_DEFINES                                             \
-       FLT_OTEL_PARSE_GROUP_DEF(    ID, 0, CHAR, 2, 2, "otel-group", " <name>") \
-       FLT_OTEL_PARSE_GROUP_DEF(SCOPES, 0, NONE, 2, 0, "scopes",   " <name> ...")
-
-#ifdef USE_OTEL_VARS
-#  define FLT_OTEL_PARSE_SCOPE_INJECT_HELP    " <name-prefix> [use-vars] [use-headers]"
-#  define FLT_OTEL_PARSE_SCOPE_EXTRACT_HELP   " <name-prefix> [use-vars | use-headers]"
-#else
-#  define FLT_OTEL_PARSE_SCOPE_INJECT_HELP    " <name-prefix> [use-headers]"
-#  define FLT_OTEL_PARSE_SCOPE_EXTRACT_HELP   " <name-prefix> [use-headers]"
-#endif
-
-/*
- * The first argument of the FLT_OTEL_PARSE_SCOPE_STATUS_DEF() macro is defined
- * as otelc_span_status_t in <opentelemetry-c-wrapper/span.h> .
- */
-#define FLT_OTEL_PARSE_SCOPE_STATUS_DEFINES               \
-       FLT_OTEL_PARSE_SCOPE_STATUS_DEF(IGNORE, "ignore") \
-       FLT_OTEL_PARSE_SCOPE_STATUS_DEF( UNSET, "unset" ) \
-       FLT_OTEL_PARSE_SCOPE_STATUS_DEF(    OK, "ok"    ) \
-       FLT_OTEL_PARSE_SCOPE_STATUS_DEF( ERROR, "error" )
-
-/* Sentinel: instrument has not been created yet. */
-#define OTELC_METRIC_INSTRUMENT_UNSET         -1
-
-/* Sentinel: instrument creation is in progress by another thread. */
-#define OTELC_METRIC_INSTRUMENT_PENDING       -2
-
-/* Sentinel: update-form instrument (re-evaluates an existing one). */
-#define OTELC_METRIC_INSTRUMENT_UPDATE        0xff
-
-#define OTELC_METRIC_AGGREGATION_UNSET        -1
-
-/*
- * Observable (asynchronous) instruments are not supported.  The OTel SDK
- * invokes their callbacks from an external background thread that is not a
- * HAProxy thread.  HAProxy sample fetches rely on internal per-thread-group
- * state and return incorrect results when called from a non-HAProxy thread.
- *
- * Double-precision instruments are not supported because HAProxy sample fetches
- * do not return double values.
- */
-#define FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEFINES                            \
-       FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEF(UPDATE,           "update"   ) \
-       FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEF(COUNTER_UINT64,   "cnt_int"  ) \
-       FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEF(HISTOGRAM_UINT64, "hist_int" ) \
-       FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEF(UDCOUNTER_INT64,  "udcnt_int") \
-       FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEF(GAUGE_INT64,      "gauge_int")
-
-/*
- * In case the possibility of working with OpenTelemetry context via HAProxy
- * variables is not used, args_max member of the structure flt_otel_parse_data
- * should be reduced for 'inject' keyword.  However, this is not critical
- * because in this case the 'use-vars' argument cannot be entered anyway,
- * so I will not complicate it here with additional definitions.
- */
-#define FLT_OTEL_PARSE_SCOPE_DEFINES                                                                                                                                           \
-       FLT_OTEL_PARSE_SCOPE_DEF(          ID, 0, CHAR, 2, 2, "otel-scope",   " <name>")                                                                                       \
-       FLT_OTEL_PARSE_SCOPE_DEF(        SPAN, 0, NONE, 2, 7, "span",         " <name> [<reference>] [<link>] [root]")                                                         \
-       FLT_OTEL_PARSE_SCOPE_DEF(        LINK, 1, NONE, 2, 0,   "link",       " <span> ...")                                                                                   \
-       FLT_OTEL_PARSE_SCOPE_DEF(   ATTRIBUTE, 1, NONE, 3, 0,   "attribute",  " <key> <sample> ...")                                                                           \
-       FLT_OTEL_PARSE_SCOPE_DEF(       EVENT, 1, NONE, 4, 0,   "event",      " <name> <key> <sample> ...")                                                                    \
-       FLT_OTEL_PARSE_SCOPE_DEF(     BAGGAGE, 1,  VAR, 3, 0,   "baggage",    " <key> <sample> ...")                                                                           \
-       FLT_OTEL_PARSE_SCOPE_DEF(      INJECT, 1,  CTX, 2, 4,   "inject",     FLT_OTEL_PARSE_SCOPE_INJECT_HELP)                                                                \
-       FLT_OTEL_PARSE_SCOPE_DEF(     EXTRACT, 0,  CTX, 2, 3,   "extract",    FLT_OTEL_PARSE_SCOPE_EXTRACT_HELP)                                                               \
-       FLT_OTEL_PARSE_SCOPE_DEF(      STATUS, 1, NONE, 2, 0,   "status",     " <code> [<sample> ...]")                                                                        \
-       FLT_OTEL_PARSE_SCOPE_DEF(      FINISH, 0, NONE, 2, 0,   "finish",     " <name> ...")                                                                                   \
-       FLT_OTEL_PARSE_SCOPE_DEF(  INSTRUMENT, 0, NONE, 3, 0, "instrument",   " { update <name> [<attr> ...] | <type> <name> [<aggr>] [<desc>] [<unit>] <value> [<bounds>] }") \
-       FLT_OTEL_PARSE_SCOPE_DEF(  LOG_RECORD, 0, NONE, 3, 0, "log-record",   " <severity> [<id>] [<event>] [<span>] [<attr>] <sample> ...")                                   \
-       FLT_OTEL_PARSE_SCOPE_DEF(IDLE_TIMEOUT, 0, NONE, 2, 2, "idle-timeout", " <time>")                                                                                       \
-       FLT_OTEL_PARSE_SCOPE_DEF(         ACL, 0, CHAR, 3, 0, "acl",          " <name> <criterion> [flags] [operator] <value> ...")                                            \
-       FLT_OTEL_PARSE_SCOPE_DEF(    ON_EVENT, 0, NONE, 2, 0, "otel-event",   " <name> [{ if | unless } <condition>]")
-
-/* Invalid character check modes for identifier validation. */
-enum FLT_OTEL_PARSE_INVCHAR_enum {
-       FLT_OTEL_PARSE_INVALID_NONE,
-       FLT_OTEL_PARSE_INVALID_CHAR,
-       FLT_OTEL_PARSE_INVALID_DOM,
-       FLT_OTEL_PARSE_INVALID_CTX,
-       FLT_OTEL_PARSE_INVALID_VAR,
-};
-
-enum FLT_OTEL_PARSE_INSTR_enum {
-#define FLT_OTEL_PARSE_INSTR_DEF(a,b,c,d,e,f,g)   FLT_OTEL_PARSE_INSTR_##a,
-       FLT_OTEL_PARSE_INSTR_DEFINES
-#undef FLT_OTEL_PARSE_INSTR_DEF
-};
-
-enum FLT_OTEL_PARSE_GROUP_enum {
-#define FLT_OTEL_PARSE_GROUP_DEF(a,b,c,d,e,f,g)   FLT_OTEL_PARSE_GROUP_##a,
-       FLT_OTEL_PARSE_GROUP_DEFINES
-#undef FLT_OTEL_PARSE_GROUP_DEF
-};
-
-enum FLT_OTEL_PARSE_SCOPE_enum {
-#define FLT_OTEL_PARSE_SCOPE_DEF(a,b,c,d,e,f,g)   FLT_OTEL_PARSE_SCOPE_##a,
-       FLT_OTEL_PARSE_SCOPE_DEFINES
-#undef FLT_OTEL_PARSE_SCOPE_DEF
-};
-
-/* Context storage type flags for inject/extract operations. */
-enum FLT_OTEL_CTX_USE_enum {
-       FLT_OTEL_CTX_USE_VARS    = 1 << 0,
-       FLT_OTEL_CTX_USE_HEADERS = 1 << 1,
-};
-
-/* Logging state flags for the OTel filter. */
-enum FLT_OTEL_LOGGING_enum {
-       FLT_OTEL_LOGGING_OFF       = 0,
-       FLT_OTEL_LOGGING_ON        = 1 << 0,
-       FLT_OTEL_LOGGING_NOLOGNORM = 1 << 1,
-};
-
-/* Keyword metadata used by the configuration section parsers. */
-struct flt_otel_parse_data {
-       int         keyword;       /* Keyword index. */
-       bool        flag_check_id; /* Whether the group ID must be defined for the keyword. */
-       int         check_name;    /* Checking allowed characters in the name. */
-       int         args_min;      /* The minimum number of arguments required. */
-       int         args_max;      /* The maximum number of arguments allowed. */
-       const char *name;          /* Keyword name. */
-       const char *usage;         /* Usage text to be printed in case of an error. */
-};
-
-#define FLT_OTEL_PARSE_KEYWORD(n,s)           (strcmp(args[n], (s)) == 0)
-
-#define FLT_OTEL_PARSE_WARNING(f, ...) \
-       ha_warning("parsing [%s:%d] : " FLT_OTEL_FMT_TYPE FLT_OTEL_FMT_NAME "'" f "'\n", ##__VA_ARGS__);
-
-#define FLT_OTEL_PARSE_ALERT(f, ...)                                                                           \
-       do {                                                                                                   \
-               ha_alert("parsing [%s:%d] : " FLT_OTEL_FMT_TYPE FLT_OTEL_FMT_NAME "'" f "'\n", ##__VA_ARGS__); \
-                                                                                                              \
-               retval |= ERR_ABORT | ERR_ALERT;                                                               \
-       } while (0)
-
-#define FLT_OTEL_POST_PARSE_ALERT(f, ...) \
-       FLT_OTEL_PARSE_ALERT(f, flt_otel_current_config->cfg_file, ##__VA_ARGS__)
-
-#define FLT_OTEL_PARSE_ERR(e,f, ...)                            \
-       do {                                                    \
-               if (*(e) == NULL)                               \
-                       (void)memprintf((e), f, ##__VA_ARGS__); \
-                                                               \
-               retval |= ERR_ABORT | ERR_ALERT;                \
-       } while (0)
-
-#define FLT_OTEL_PARSE_IFERR_ALERT()                         \
-       do {                                                 \
-               if (err == NULL)                             \
-                       break;                               \
-                                                            \
-               FLT_OTEL_PARSE_ALERT("%s", file, line, err); \
-               FLT_OTEL_ERR_FREE(err);                      \
-       } while (0)
-
-#endif /* _OTEL_PARSER_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/pool.h b/addons/otel/include/pool.h
deleted file mode 100644 (file)
index 300cafb..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_POOL_H_
-#define _OTEL_POOL_H_
-
-#define FLT_OTEL_POOL_INIT(p,n,s,r)                                                       \
-       do {                                                                              \
-               if (((r) == FLT_OTEL_RET_OK) && ((p) == NULL)) {                          \
-                       (p) = create_pool(n, (s), MEM_F_SHARED);                          \
-                       if ((p) == NULL)                                                  \
-                               (r) = FLT_OTEL_RET_ERROR;                                 \
-                                                                                         \
-                       OTELC_DBG(DEBUG, #p " %p %u", (p), FLT_OTEL_DEREF((p), size, 0)); \
-               }                                                                         \
-       } while (0)
-
-#define FLT_OTEL_POOL_DESTROY(p)                                       \
-       do {                                                           \
-               if ((p) != NULL) {                                     \
-                       OTELC_DBG(DEBUG, #p " %p %u", (p), (p)->size); \
-                                                                      \
-                       pool_destroy(p);                               \
-                       (p) = NULL;                                    \
-               }                                                      \
-       } while (0)
-
-
-extern struct pool_head *pool_head_otel_scope_span __read_mostly;
-extern struct pool_head *pool_head_otel_scope_context __read_mostly;
-extern struct pool_head *pool_head_otel_runtime_context __read_mostly;
-extern struct pool_head *pool_head_otel_span_context __read_mostly;
-
-
-/* Allocate memory from a pool with optional zeroing. */
-void          *flt_otel_pool_alloc(struct pool_head *pool, size_t size, bool flag_clear, char **err);
-
-/* Duplicate a string into pool-allocated memory. */
-void          *flt_otel_pool_strndup(struct pool_head *pool, const char *s, size_t size, char **err);
-
-/* Release pool-allocated memory and clear the pointer. */
-void           flt_otel_pool_free(struct pool_head *pool, void **ptr);
-
-/* Initialize OTel filter memory pools. */
-int            flt_otel_pool_init(void);
-
-/* Destroy OTel filter memory pools. */
-void           flt_otel_pool_destroy(void);
-
-/* Log debug information about OTel filter memory pools. */
-#ifndef DEBUG_OTEL
-#  define flt_otel_pool_info()   while (0)
-#else
-void           flt_otel_pool_info(void);
-#endif
-
-/* Allocate a trash buffer with optional zeroing. */
-struct buffer *flt_otel_trash_alloc(bool flag_clear, char **err);
-
-/* Release a trash buffer and clear the pointer. */
-void           flt_otel_trash_free(struct buffer **ptr);
-
-#endif /* _OTEL_POOL_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/scope.h b/addons/otel/include/scope.h
deleted file mode 100644 (file)
index 669a8ad..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_SCOPE_H_
-#define _OTEL_SCOPE_H_
-
-#define FLT_OTEL_SCOPE_SPAN_FINISH_REQ       "*req*"
-#define FLT_OTEL_SCOPE_SPAN_FINISH_RES       "*res*"
-#define FLT_OTEL_SCOPE_SPAN_FINISH_ALL       "*"
-
-#define FLT_OTEL_RT_CTX(p)                   ((struct flt_otel_runtime_context *)(p))
-
-#define FLT_OTEL_DBG_SCOPE_SPAN(h,p)                                \
-       OTELC_DBG(DEBUG, h "%p:{ '%s' %zu %u %hhu %p %p %p }", (p), \
-                 FLT_OTEL_STR_HDR_ARGS(p, id), (p)->smp_opt_dir,   \
-                 (p)->flag_finish, (p)->span, (p)->ref_span, (p)->ref_ctx)
-
-#define FLT_OTEL_DBG_SCOPE_CONTEXT(h,p)                           \
-       OTELC_DBG(DEBUG, h "%p:{ '%s' %zu %u %hhu %p }", (p),     \
-                 FLT_OTEL_STR_HDR_ARGS(p, id), (p)->smp_opt_dir, \
-                 (p)->flag_finish, (p)->context)
-
-#define FLT_OTEL_DBG_SCOPE_DATA_EVENT(h,p)                    \
-       OTELC_DBG(DEBUG, h "%p:{ '%s' %p %zu %zu %s }", &(p), \
-                 (p).name, (p).attr, (p).cnt, (p).size,      \
-                 flt_otel_list_dump(&((p).list)))
-
-#define FLT_OTEL_DBG_SCOPE_DATA_STATUS(h,p) \
-       OTELC_DBG(DEBUG, h "%p:{ %d '%s' }", (p), (p)->code, OTELC_STR_ARG((p)->description))
-
-#define FLT_OTEL_DBG_SCOPE_DATA_KV_FMT       "%p:{ %p %zu %zu }"
-#define FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS(p)   &(p), (p).attr, (p).cnt, (p).size
-#define FLT_OTEL_DBG_SCOPE_DATA(h,p)                                                                                   \
-       OTELC_DBG(DEBUG, h "%p:{ " FLT_OTEL_DBG_SCOPE_DATA_KV_FMT " " FLT_OTEL_DBG_SCOPE_DATA_KV_FMT " %s %s }", (p), \
-                 FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS((p)->baggage), FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS((p)->attributes),    \
-                 flt_otel_list_dump(&((p)->events)), flt_otel_list_dump(&((p)->links)))
-
-#define FLT_OTEL_DBG_RUNTIME_CONTEXT(h,p)                                                     \
-       OTELC_DBG(DEBUG, h "%p:{ %p %p '%s' %hhu %hhu 0x%02hhx 0x%08x %u %d %s %s }", (p),    \
-                 (p)->stream, (p)->filter, (p)->uuid, (p)->flag_harderr, (p)->flag_disabled, \
-                 (p)->logging, (p)->analyzers, (p)->idle_timeout, (p)->idle_exp,             \
-                 flt_otel_list_dump(&((p)->spans)), flt_otel_list_dump(&((p)->contexts)))
-
-/* Anonymous struct containing a const string pointer and its length. */
-#define FLT_OTEL_CONST_STR_HDR(p)    \
-       struct {                     \
-               const char *p;       \
-               size_t      p##_len; \
-       }
-
-
-/* Growable key-value array for span attributes or baggage. */
-struct flt_otel_scope_data_kv {
-       struct otelc_kv *attr; /* Key-value array for storing attributes. */
-       size_t           cnt;  /* Number of currently used array elements. */
-       size_t           size; /* Total number of array elements. */
-};
-
-/* Named event with its own key-value attribute array. */
-struct flt_otel_scope_data_event {
-       char            *name; /* Event name, not used for other data types. */
-       struct otelc_kv *attr; /* Key-value array for storing attributes. */
-       size_t           cnt;  /* Number of currently used array elements. */
-       size_t           size; /* Total number of array elements. */
-       struct list      list; /* Used to chain this structure. */
-};
-
-/* Span link referencing another span or span context. */
-struct flt_otel_scope_data_link {
-       struct otelc_span         *span;    /* Linked span, or NULL. */
-       struct otelc_span_context *context; /* Linked span context, or NULL. */
-       struct list                list;    /* Used to chain this structure. */
-};
-
-/* Span status code and description. */
-struct flt_otel_scope_data_status {
-       int   code;        /* OTELC_SPAN_STATUS_* value. */
-       char *description; /* Span status description string. */
-};
-
-/* Aggregated runtime data collected during scope execution. */
-struct flt_otel_scope_data {
-       struct flt_otel_scope_data_kv     baggage;    /* Defined scope baggage. */
-       struct flt_otel_scope_data_kv     attributes; /* Defined scope attributes. */
-       struct list                       events;     /* Defined scope events. */
-       struct list                       links;      /* Defined scope links. */
-       struct flt_otel_scope_data_status status;     /* Defined scope status. */
-};
-
-/* flt_otel_runtime_context->spans */
-struct flt_otel_scope_span {
-       FLT_OTEL_CONST_STR_HDR(id);             /* The span operation name/len. */
-       uint                       smp_opt_dir; /* SMP_OPT_DIR_RE(Q|S) */
-       bool                       flag_finish; /* Whether the span is marked for completion. */
-       struct otelc_span         *span;        /* The current span. */
-       struct otelc_span         *ref_span;    /* Span to which the current span refers. */
-       struct otelc_span_context *ref_ctx;     /* Span context to which the current span refers. */
-       struct list                list;        /* Used to chain this structure. */
-};
-
-/* flt_otel_runtime_context->contexts */
-struct flt_otel_scope_context {
-       FLT_OTEL_CONST_STR_HDR(id);             /* The span context name/len. */
-       uint                       smp_opt_dir; /* SMP_OPT_DIR_RE(Q|S) */
-       bool                       flag_finish; /* Whether the span context is marked for completion. */
-       struct otelc_span_context *context;     /* The current span context. */
-       struct list                list;        /* Used to chain this structure. */
-};
-
-/* The runtime filter context attached to a stream. */
-struct flt_otel_runtime_context {
-       struct stream *stream;        /* The stream to which the filter is attached. */
-       struct filter *filter;        /* The OpenTelemetry filter. */
-       char           uuid[40];      /* Randomly generated UUID. */
-       bool           flag_harderr;  /* [0 1] */
-       bool           flag_disabled; /* [0 1] */
-       uint8_t        logging;       /* [0 1 3] */
-       uint           analyzers;     /* Executed channel analyzers. */
-       uint           idle_timeout;  /* Idle timeout interval in milliseconds (0 = off). */
-       int            idle_exp;      /* Tick at which the next idle timeout fires. */
-       struct list    spans;         /* The scope spans. */
-       struct list    contexts;      /* The scope contexts. */
-};
-
-
-#ifndef DEBUG_OTEL
-#  define flt_otel_scope_data_dump(...)   while (0)
-#else
-/* Dump scope data contents for debugging. */
-void                             flt_otel_scope_data_dump(const struct flt_otel_scope_data *data);
-#endif
-
-/* Allocate and initialize a runtime context for a stream. */
-struct flt_otel_runtime_context *flt_otel_runtime_context_init(struct stream *s, struct filter *f, char **err);
-
-/* Free the runtime context attached to a filter. */
-void                             flt_otel_runtime_context_free(struct filter *f);
-
-/* Allocate and initialize a scope span in the runtime context. */
-struct flt_otel_scope_span      *flt_otel_scope_span_init(struct flt_otel_runtime_context *rt_ctx, const char *id, size_t id_len, const char *ref_id, size_t ref_id_len, uint dir, char **err);
-
-/* Free a scope span and remove it from the runtime context. */
-void                             flt_otel_scope_span_free(struct flt_otel_scope_span **ptr);
-
-/* Allocate and initialize a scope context in the runtime context. */
-struct flt_otel_scope_context   *flt_otel_scope_context_init(struct flt_otel_runtime_context *rt_ctx, struct otelc_tracer *tracer, const char *id, size_t id_len, const struct otelc_text_map *text_map, uint dir, char **err);
-
-/* Free a scope context and remove it from the runtime context. */
-void                             flt_otel_scope_context_free(struct flt_otel_scope_context **ptr);
-
-/* Initialize scope data arrays and lists. */
-void                             flt_otel_scope_data_init(struct flt_otel_scope_data *ptr);
-
-/* Free all scope data contents. */
-void                             flt_otel_scope_data_free(struct flt_otel_scope_data *ptr);
-
-/* Mark a span for finishing by name in the runtime context. */
-int                              flt_otel_scope_finish_mark(const struct flt_otel_runtime_context *rt_ctx, const char *id, size_t id_len);
-
-/* End all spans that have been marked for finishing. */
-void                             flt_otel_scope_finish_marked(const struct flt_otel_runtime_context *rt_ctx, const struct timespec *ts_finish);
-
-/* Free scope spans and contexts no longer needed by a channel. */
-void                             flt_otel_scope_free_unused(struct flt_otel_runtime_context *rt_ctx, struct channel *chn);
-
-#endif /* _OTEL_SCOPE_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/util.h b/addons/otel/include/util.h
deleted file mode 100644 (file)
index cf05f3b..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* 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)
-
-/* 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
-#  define FLT_OTEL_ARGS_DUMP()   while (0)
-#endif
-
-
-#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);
-
-/* Return the proxy mode string for a stream. */
-const char *flt_otel_pr_mode(const struct stream *s);
-
-/* Return the stream processing position as a string. */
-const char *flt_otel_stream_pos(const struct stream *s);
-
-/* Return the filter type string for a filter instance. */
-const char *flt_otel_type(const struct filter *f);
-
-/* Return the analyzer name string for an analyzer bit. */
-const char *flt_otel_analyzer(uint an_bit);
-
-/* 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);
-
-/* Comparator for qsort: ascending order of doubles with epsilon tolerance. */
-int         flt_otel_qsort_compar_double(const void *a, const void *b);
-
-/* Parse a string to double with range validation. */
-bool        flt_otel_strtod(const char *nptr, double *value, double limit_min, double limit_max, char **err);
-
-/* Parse a string to int64_t with range validation. */
-bool        flt_otel_strtoll(const char *nptr, int64_t *value, int64_t limit_min, int64_t limit_max, char **err);
-
-/* 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);
-
-/* 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);
-
-#endif /* _OTEL_UTIL_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/include/vars.h b/addons/otel/include/vars.h
deleted file mode 100644 (file)
index d6bde50..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef _OTEL_VARS_H_
-#define _OTEL_VARS_H_
-
-#define FLT_OTEL_VARS_SCOPE       "txn"
-#define FLT_OTEL_VAR_CHAR_DASH    'D'
-#define FLT_OTEL_VAR_CHAR_SPACE   'S'
-
-#ifndef USE_OTEL_VARS_NAME
-#  define FLT_OTEL_VAR_CTX_SIZE   int8_t
-
-/* Context buffer for storing a single variable value during iteration. */
-struct flt_otel_ctx {
-       char value[BUFSIZ]; /* Variable value string. */
-       int  value_len;     /* Length of the value string. */
-};
-
-/* Callback type invoked for each context variable during iteration. */
-typedef int (*flt_otel_ctx_loop_cb)(struct sample *, size_t, const char *, const char *, const char *, FLT_OTEL_VAR_CTX_SIZE, char **, void *);
-#endif /* !USE_OTEL_VARS_NAME */
-
-
-#ifndef DEBUG_OTEL
-#  define flt_otel_vars_dump(...)   while (0)
-#else
-/* Dump all OTel-related variables for a stream. */
-void                   flt_otel_vars_dump(struct stream *s);
-#endif
-
-/* Register a HAProxy variable for OTel context storage. */
-int                    flt_otel_var_register(const char *scope, const char *prefix, const char *name, char **err);
-
-/* Set an OTel context variable on a stream. */
-int                    flt_otel_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err);
-
-/* Unset all OTel context variables matching a prefix on a stream. */
-int                    flt_otel_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err);
-
-/* Retrieve all OTel context variables matching a prefix into a text map. */
-struct otelc_text_map *flt_otel_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err);
-
-#endif /* _OTEL_VARS_H_ */
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/cli.c b/addons/otel/src/cli.c
deleted file mode 100644 (file)
index abed15a..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-/* 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 "dontlog-normal"
- *   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 and meter 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       meter:         %s\n", msg, (conf->instr->meter != NULL) ? "active" : "not initialized");
-               (void)memprintf(&msg, "%s       logger:        %s\n", msg, (conf->instr->logger != 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
- */
diff --git a/addons/otel/src/conf.c b/addons/otel/src/conf.c
deleted file mode 100644 (file)
index 9bec45c..0000000
+++ /dev/null
@@ -1,885 +0,0 @@
-/* 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_link_init - conf_link structure allocation
- *
- * SYNOPSIS
- *   struct flt_otel_conf_link *flt_otel_conf_link_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_link structure for a span link
- *   reference.  The <id> string is duplicated and stored as the linked
- *   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(link, span, )
-
-
-/***
- * NAME
- *   flt_otel_conf_link_free - conf_link structure deallocation
- *
- * SYNOPSIS
- *   void flt_otel_conf_link_free(struct flt_otel_conf_link **ptr)
- *
- * ARGUMENTS
- *   ptr - a pointer to the address of a structure
- *
- * DESCRIPTION
- *   Deallocates memory used by the flt_otel_conf_link 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(link, span,
-       FLT_OTEL_DBG_CONF_HDR("- conf_link free ", *ptr, span);
-)
-
-
-/***
- * 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));
-       lf_expr_init(&(retptr->lf_expr));
-)
-
-
-/***
- * 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 - 1) 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));
-       lf_expr_deinit(&((*ptr)->lf_expr));
-)
-
-
-/***
- * 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
- *   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->links));
-       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(link, &((*ptr)->links));
-       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_instrument_init - conf_instrument structure allocation
- *
- * SYNOPSIS
- *   struct flt_otel_conf_instrument *flt_otel_conf_instrument_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_instrument structure.  Sets the instrument
- *   type and meter index to OTELC_METRIC_INSTRUMENT_UNSET and initializes the
- *   samples and attributes lists.  The <id> string is duplicated and stored as
- *   the instrument 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(instrument, id,
-       retptr->idx       = OTELC_METRIC_INSTRUMENT_UNSET;
-       retptr->type      = OTELC_METRIC_INSTRUMENT_UNSET;
-       retptr->aggr_type = OTELC_METRIC_AGGREGATION_UNSET;
-       LIST_INIT(&(retptr->samples));
-       LIST_INIT(&(retptr->attributes));
-)
-
-
-/***
- * NAME
- *   flt_otel_conf_instrument_free - conf_instrument structure deallocation
- *
- * SYNOPSIS
- *   void flt_otel_conf_instrument_free(struct flt_otel_conf_instrument **ptr)
- *
- * ARGUMENTS
- *   ptr - a pointer to the address of a structure
- *
- * DESCRIPTION
- *   Deallocates memory used by the flt_otel_conf_instrument 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(instrument, id,
-       FLT_OTEL_DBG_CONF_INSTRUMENT("- conf_instrument free ", *ptr);
-
-       OTELC_SFREE((*ptr)->description);
-       OTELC_SFREE((*ptr)->unit);
-       FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->samples));
-       OTELC_SFREE((*ptr)->bounds);
-       FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->attributes));
-)
-
-
-/***
- * NAME
- *   flt_otel_conf_log_record_init - conf_log_record structure allocation
- *
- * SYNOPSIS
- *   struct flt_otel_conf_log_record *flt_otel_conf_log_record_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_log_record structure.  Initializes the
- *   attributes and sample expressions lists.  The <id> string is required by
- *   the macro but is not used directly; the severity level is stored
- *   separately.  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(log_record, id,
-       LIST_INIT(&(retptr->attributes));
-       LIST_INIT(&(retptr->samples));
-)
-
-
-/***
- * NAME
- *   flt_otel_conf_log_record_free - conf_log_record structure deallocation
- *
- * SYNOPSIS
- *   void flt_otel_conf_log_record_free(struct flt_otel_conf_log_record **ptr)
- *
- * ARGUMENTS
- *   ptr - a pointer to the address of a structure
- *
- * DESCRIPTION
- *   Deallocates memory used by the flt_otel_conf_log_record 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(log_record, id,
-       FLT_OTEL_DBG_CONF_LOG_RECORD("- conf_log_record free ", *ptr);
-
-       OTELC_SFREE((*ptr)->event_name);
-       OTELC_SFREE((*ptr)->span);
-       FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->attributes));
-       FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->samples));
-)
-
-
-/***
- * 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, and spans_to_finish.  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));
-       LIST_INIT(&(retptr->instruments));
-       LIST_INIT(&(retptr->log_records));
-)
-
-
-/***
- * 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));
-       FLT_OTEL_LIST_DESTROY(instrument, &((*ptr)->instruments));
-       FLT_OTEL_LIST_DESTROY(log_record, &((*ptr)->log_records));
-)
-
-
-/***
- * 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
- */
diff --git a/addons/otel/src/event.c b/addons/otel/src/event.c
deleted file mode 100644 (file)
index 8a6c05d..0000000
+++ /dev/null
@@ -1,849 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-/* Event data table built from the X-macro list. */
-#define FLT_OTEL_EVENT_DEF(a,b,c,d,e,f)   { AN_##b##_##a, OTELC_STRINGIFY_ARG(AN_##b##_##a), SMP_OPT_DIR_##b, SMP_VAL_FE_##c, SMP_VAL_BE_##d, e, f },
-const struct flt_otel_event_data flt_otel_event_data[FLT_OTEL_EVENT_MAX] = { FLT_OTEL_EVENT_DEFINES };
-#undef FLT_OTEL_EVENT_DEF
-
-
-/***
- * NAME
- *   flt_otel_scope_run_instrument_record - metric instrument value recorder
- *
- * SYNOPSIS
- *   static int flt_otel_scope_run_instrument_record(struct stream *s, uint dir, struct otelc_meter *meter, struct flt_otel_conf_instrument *instr_ref, struct flt_otel_conf_instrument *instr, char **err)
- *
- * ARGUMENTS
- *   s         - the stream providing the sample context
- *   dir       - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
- *   meter     - the OTel meter instance
- *   instr_ref - the create-form instrument providing samples and meter index
- *   instr     - the update-form instrument providing per-scope attributes
- *   err       - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Evaluates sample expressions from a create-form instrument and records
- *   the resulting value via the <meter> API.  Each expression is evaluated
- *   with sample_process(), converted to an otelc_value via
- *   flt_otel_sample_to_value(), and recorded via
- *   <meter>->update_instrument_kv_n().
- *
- * RETURN VALUE
- *   Returns FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_scope_run_instrument_record(struct stream *s, uint dir, struct otelc_meter *meter, struct flt_otel_conf_instrument *instr_ref, struct flt_otel_conf_instrument *instr, char **err)
-{
-       struct flt_otel_conf_sample      *sample;
-       struct flt_otel_conf_sample_expr *expr;
-       struct sample                     smp;
-       struct otelc_value                value;
-       struct flt_otel_scope_data_kv     instr_attr;
-       int                               retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %u, %p, %p, %p, %p:%p", s, dir, meter, instr_ref, instr, OTELC_DPTR_ARGS(err));
-
-       /* Evaluate instrument attributes from sample expressions. */
-       (void)memset(&instr_attr, 0, sizeof(instr_attr));
-
-       list_for_each_entry(sample, &(instr->attributes), list) {
-               struct otelc_value attr_value;
-
-               OTELC_DBG(DEBUG, "adding instrument attribute '%s' -> '%s'", sample->key, sample->fmt_string);
-
-               if (flt_otel_sample_eval(s, dir, sample, true, &attr_value, err) == FLT_OTEL_RET_ERROR) {
-                       retval = FLT_OTEL_RET_ERROR;
-
-                       continue;
-               }
-
-               if (flt_otel_sample_add_kv(&instr_attr, sample->key, &attr_value) == FLT_OTEL_RET_ERROR) {
-                       if (attr_value.u_type == OTELC_VALUE_DATA)
-                               OTELC_SFREE(attr_value.u.value_data);
-
-                       retval = FLT_OTEL_RET_ERROR;
-               }
-       }
-
-       /* The samples list always contains exactly one entry. */
-       sample = LIST_NEXT(&(instr_ref->samples), struct flt_otel_conf_sample *, list);
-
-       (void)memset(&smp, 0, sizeof(smp));
-
-       if (sample->lf_used) {
-               /*
-                * Log-format path: evaluate into a temporary buffer and present
-                * the result as a string sample.
-                */
-               smp.data.u.str.area = OTELC_CALLOC(1, global.tune.bufsize);
-               if (smp.data.u.str.area == NULL) {
-                       FLT_OTEL_ERR("out of memory");
-
-                       otelc_kv_destroy(&(instr_attr.attr), instr_attr.cnt);
-
-                       OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-               }
-
-               smp.data.type       = SMP_T_STR;
-               smp.data.u.str.data = build_logline(s, smp.data.u.str.area, global.tune.bufsize, &(sample->lf_expr));
-       } else {
-               /* The expressions list always contains exactly one entry. */
-               expr = LIST_NEXT(&(sample->exprs), struct flt_otel_conf_sample_expr *, list);
-
-               FLT_OTEL_DBG_CONF_SAMPLE_EXPR("sample expression ", expr);
-
-               if (sample_process(s->be, s->sess, s, dir | SMP_OPT_FINAL, expr->expr, &smp) == NULL) {
-                       OTELC_DBG(NOTICE, "WARNING: failed to fetch '%s'", expr->fmt_expr);
-
-                       retval = FLT_OTEL_RET_ERROR;
-               }
-       }
-
-       if (retval == FLT_OTEL_RET_ERROR) {
-               /* Do nothing. */
-       }
-       else if (flt_otel_sample_to_value(sample->key, &(smp.data), &value, err) == FLT_OTEL_RET_ERROR) {
-               if (value.u_type == OTELC_VALUE_DATA)
-                       OTELC_SFREE(value.u.value_data);
-
-               retval = FLT_OTEL_RET_ERROR;
-       }
-       else {
-               OTELC_DBG_VALUE(DEBUG, "value ", &value);
-
-               /*
-                * Metric instruments expect numeric values (INT64 or DOUBLE).
-                * Reject OTELC_VALUE_DATA since the meter cannot interpret
-                * arbitrary string data as a numeric measurement.
-                */
-               if (value.u_type == OTELC_VALUE_DATA) {
-                       OTELC_DBG(NOTICE, "WARNING: non-numeric value type for instrument '%s'", instr_ref->id);
-
-                       if (otelc_value_strtonum(&value, OTELC_VALUE_INT64) == OTELC_RET_ERROR) {
-                               OTELC_SFREE(value.u.value_data);
-
-                               retval = FLT_OTEL_RET_ERROR;
-                       }
-               }
-
-               if (retval != FLT_OTEL_RET_ERROR)
-                       if (OTELC_OPS(meter, update_instrument_kv_n, HA_ATOMIC_LOAD(&(instr_ref->idx)), &value, instr_attr.attr, instr_attr.cnt) == OTELC_RET_ERROR)
-                               retval = FLT_OTEL_RET_ERROR;
-       }
-
-       otelc_kv_destroy(&(instr_attr.attr), instr_attr.cnt);
-
-       if (sample->lf_used)
-               OTELC_SFREE(smp.data.u.str.area);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_run_instrument - metric instrument processor
- *
- * SYNOPSIS
- *   static int flt_otel_scope_run_instrument(struct stream *s, uint dir, struct flt_otel_conf_scope *scope, struct otelc_meter *meter, char **err)
- *
- * ARGUMENTS
- *   s     - the stream providing the sample context
- *   dir   - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
- *   scope - the scope configuration containing the instrument list
- *   meter - the OTel meter instance
- *   err   - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Processes all metric instruments configured in <scope>.  Runs in two
- *   passes: the first pass lazily creates create-form instruments via <meter>
- *   on first use, using HA_ATOMIC_CAS on the instrument index to guarantee
- *   thread-safe one-time initialization.  The second pass iterates over
- *   update-form instruments and records measurements via
- *   flt_otel_scope_run_instrument_record().  Instruments whose index is still
- *   negative (UNUSED or PENDING) are skipped, so that a concurrent creation by
- *   another thread does not cause an invalid <meter> access.
- *
- * RETURN VALUE
- *   Returns FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_scope_run_instrument(struct stream *s, uint dir, struct flt_otel_conf_scope *scope, struct otelc_meter *meter, char **err)
-{
-       struct flt_otel_conf_instrument *conf_instr;
-       int                              retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %u, %p, %p, %p:%p", s, dir, scope, meter, OTELC_DPTR_ARGS(err));
-
-       list_for_each_entry(conf_instr, &(scope->instruments), list) {
-               if (conf_instr->type == OTELC_METRIC_INSTRUMENT_UPDATE) {
-                       /* Do nothing. */
-               }
-               else if (HA_ATOMIC_LOAD(&(conf_instr->idx)) == OTELC_METRIC_INSTRUMENT_UNSET) {
-                       int64_t expected = OTELC_METRIC_INSTRUMENT_UNSET;
-                       int     rc;
-
-                       OTELC_DBG(DEBUG, "run instrument '%s' -> '%s'", scope->id, conf_instr->id);
-                       FLT_OTEL_DBG_CONF_INSTRUMENT("", conf_instr);
-
-                       /*
-                        * Create form: use this instrument directly.  Lazily
-                        * create the instrument on first use.  Use CAS to
-                        * ensure only one thread performs the creation in a
-                        * multi-threaded environment.
-                        */
-                       if (!HA_ATOMIC_CAS(&(conf_instr->idx), &expected, OTELC_METRIC_INSTRUMENT_PENDING))
-                               continue;
-
-                       /*
-                        * The view must be created before the instrument,
-                        * otherwise bucket boundaries cannot be set.
-                        */
-                       if ((conf_instr->bounds != NULL) && (conf_instr->bounds_num > 0))
-                               if (OTELC_OPS(meter, add_view, conf_instr->id, conf_instr->description, conf_instr->id, conf_instr->unit, conf_instr->type, conf_instr->aggr_type, conf_instr->bounds, conf_instr->bounds_num) == OTELC_RET_ERROR)
-                                       OTELC_DBG(NOTICE, "WARNING: failed to add view for instrument '%s'", conf_instr->id);
-
-                       rc = OTELC_OPS(meter, create_instrument, conf_instr->id, conf_instr->description, conf_instr->unit, conf_instr->type, NULL);
-                       if (rc == OTELC_RET_ERROR) {
-                               OTELC_DBG(NOTICE, "WARNING: failed to create instrument '%s'", conf_instr->id);
-
-                               HA_ATOMIC_STORE(&(conf_instr->idx), OTELC_METRIC_INSTRUMENT_UNSET);
-
-                               retval = FLT_OTEL_RET_ERROR;
-
-                               continue;
-                       } else {
-                               HA_ATOMIC_STORE(&(conf_instr->idx), rc);
-                       }
-               }
-       }
-
-       list_for_each_entry(conf_instr, &(scope->instruments), list)
-               if (conf_instr->type == OTELC_METRIC_INSTRUMENT_UPDATE) {
-                       struct flt_otel_conf_instrument *instr = conf_instr->ref;
-
-                       OTELC_DBG(DEBUG, "run instrument '%s' -> '%s'", scope->id, conf_instr->id);
-                       FLT_OTEL_DBG_CONF_INSTRUMENT("", conf_instr);
-
-                       /*
-                        * Update form: record a measurement using an existing
-                        * create-form instrument.
-                        */
-                       if (instr == NULL) {
-                               OTELC_DBG(NOTICE, "WARNING: invalid reference instrument '%s'", conf_instr->id);
-
-                               retval = FLT_OTEL_RET_ERROR;
-                       }
-                       else if (HA_ATOMIC_LOAD(&(instr->idx)) < 0) {
-                               OTELC_DBG(NOTICE, "WARNING: instrument '%s' not yet created, skipping", instr->id);
-                       }
-                       else if (flt_otel_scope_run_instrument_record(s, dir, meter, instr, conf_instr, err) == FLT_OTEL_RET_ERROR) {
-                               retval = FLT_OTEL_RET_ERROR;
-                       }
-               }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_run_log_record - log record emitter
- *
- * SYNOPSIS
- *   static int flt_otel_scope_run_log_record(struct stream *s, struct filter *f, uint dir, struct flt_otel_conf_scope *scope, struct otelc_logger *logger, const struct timespec *ts, char **err)
- *
- * ARGUMENTS
- *   s      - the stream providing the sample context
- *   f      - the filter instance
- *   dir    - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
- *   scope  - the scope configuration containing the log record list
- *   logger - the OTel logger instance
- *   ts     - the wall-clock timestamp for the log record
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Processes all log records configured in <scope>.  For each record, checks
- *   whether the logger is enabled for the configured severity, evaluates the
- *   sample expressions into a body string, resolves the optional span reference
- *   against the runtime context, and emits the log record via the logger's
- *   log_span operation.
- *
- * RETURN VALUE
- *   Returns FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_scope_run_log_record(struct stream *s, struct filter *f, uint dir, struct flt_otel_conf_scope *scope, struct otelc_logger *logger, const struct timespec *ts, char **err)
-{
-       struct flt_otel_conf_log_record *conf_log;
-       int                              retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %p, %u, %p, %p, %p, %p:%p", s, f, dir, scope, logger, ts, OTELC_DPTR_ARGS(err));
-
-       list_for_each_entry(conf_log, &(scope->log_records), list) {
-               struct flt_otel_conf_sample      *sample;
-               struct flt_otel_conf_sample_expr *expr;
-               struct sample                     smp;
-               struct otelc_span                *otel_span = NULL;
-               struct flt_otel_scope_data_kv     log_attr;
-               struct buffer                     buffer;
-               int                               rc;
-
-               OTELC_DBG(DEBUG, "run log-record '%s' -> '%s'", scope->id, conf_log->id);
-
-               /* Skip if the logger is not enabled for this severity. */
-               if (OTELC_OPS(logger, enabled, conf_log->severity) == 0)
-                       continue;
-
-               /* Evaluate log record attributes from sample expressions. */
-               (void)memset(&log_attr, 0, sizeof(log_attr));
-
-               list_for_each_entry(sample, &(conf_log->attributes), list) {
-                       struct otelc_value attr_value;
-
-                       OTELC_DBG(DEBUG, "adding log-record attribute '%s' -> '%s'", sample->key, sample->fmt_string);
-
-                       if (flt_otel_sample_eval(s, dir, sample, true, &attr_value, err) == FLT_OTEL_RET_ERROR) {
-                               retval = FLT_OTEL_RET_ERROR;
-
-                               continue;
-                       }
-
-                       if (flt_otel_sample_add_kv(&log_attr, sample->key, &attr_value) == FLT_OTEL_RET_ERROR) {
-                               if (attr_value.u_type == OTELC_VALUE_DATA)
-                                       OTELC_SFREE(attr_value.u.value_data);
-
-                               retval = FLT_OTEL_RET_ERROR;
-                       }
-               }
-
-               /* The samples list has exactly one entry. */
-               sample = LIST_NEXT(&(conf_log->samples), typeof(sample), list);
-
-               (void)memset(&buffer, 0, sizeof(buffer));
-
-               if (sample->lf_used) {
-                       /*
-                        * Log-format path: evaluate the log-format expression
-                        * into a dynamically allocated buffer.
-                        */
-                       chunk_init(&buffer, OTELC_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
-                       if (buffer.area != NULL)
-                               buffer.data = build_logline(s, buffer.area, buffer.size, &(sample->lf_expr));
-               } else {
-                       /*
-                        * Bare sample expression path: evaluate each expression
-                        * and concatenate the results.
-                        */
-                       list_for_each_entry(expr, &(sample->exprs), list) {
-                               (void)memset(&smp, 0, sizeof(smp));
-
-                               if (sample_process(s->be, s->sess, s, dir | SMP_OPT_FINAL, expr->expr, &smp) == NULL) {
-                                       OTELC_DBG(NOTICE, "WARNING: failed to fetch '%s'", expr->fmt_expr);
-
-                                       retval = FLT_OTEL_RET_ERROR;
-
-                                       break;
-                               }
-
-                               if (buffer.area == NULL) {
-                                       chunk_init(&buffer, OTELC_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
-                                       if (buffer.area == NULL)
-                                               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;
-
-                                       break;
-                               }
-
-                               buffer.data += rc;
-                       }
-               }
-
-               if (buffer.area == NULL) {
-                       FLT_OTEL_ERR("out of memory");
-
-                       retval = FLT_OTEL_RET_ERROR;
-
-                       otelc_kv_destroy(&(log_attr.attr), log_attr.cnt);
-
-                       continue;
-               }
-
-               /*
-                * If the log record references a span, resolve it against the
-                * runtime context.  A missing span is not fatal -- the log
-                * record is emitted without span correlation.
-                */
-               if (conf_log->span != NULL) {
-                       struct flt_otel_runtime_context *rt_ctx = FLT_OTEL_RT_CTX(f->ctx);
-                       struct flt_otel_scope_span      *sc_span;
-
-                       list_for_each_entry(sc_span, &(rt_ctx->spans), list)
-                               if (strcmp(sc_span->id, conf_log->span) == 0) {
-                                       otel_span = sc_span->span;
-
-                                       break;
-                               }
-
-                       if (otel_span == NULL)
-                               OTELC_DBG(NOTICE, "WARNING: cannot find span '%s' for log-record", conf_log->span);
-               }
-
-               if (OTELC_OPS(logger, log_span, conf_log->severity, conf_log->event_id, conf_log->event_name, otel_span, ts, log_attr.attr, log_attr.cnt, "%s", buffer.area) == OTELC_RET_ERROR)
-                       retval = FLT_OTEL_RET_ERROR;
-
-               otelc_kv_destroy(&(log_attr.attr), log_attr.cnt);
-               OTELC_SFREE(buffer.area);
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_run_span - single span execution
- *
- * SYNOPSIS
- *   static int flt_otel_scope_run_span(struct stream *s, struct filter *f, struct channel *chn, uint dir, struct flt_otel_scope_span *span, struct flt_otel_scope_data *data, const struct flt_otel_conf_span *conf_span, const struct timespec *ts_steady, const struct timespec *ts_system, char **err)
- *
- * ARGUMENTS
- *   s         - the stream being processed
- *   f         - the filter instance
- *   chn       - the channel used for HTTP header injection
- *   dir       - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
- *   span      - the runtime scope span to execute
- *   data      - the evaluated scope data (attributes, events, links, status)
- *   conf_span - the span configuration
- *   ts_steady - the monotonic timestamp for span creation
- *   ts_system - the wall-clock timestamp for span events
- *   err       - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Executes a single span: creates the OTel span on first call via the tracer,
- *   adds links, baggage, attributes, events and status from <data>, then
- *   injects the span context into HTTP headers or HAProxy variables if
- *   configured in <conf_span>.
- *
- * RETURN VALUE
- *   Returns FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_scope_run_span(struct stream *s, struct filter *f, struct channel *chn, uint dir, struct flt_otel_scope_span *span, struct flt_otel_scope_data *data, const struct flt_otel_conf_span *conf_span, const struct timespec *ts_steady, const struct timespec *ts_system, char **err)
-{
-       struct flt_otel_conf *conf = FLT_OTEL_CONF(f);
-       int                   retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %p, %p, %u, %p, %p, %p, %p, %p, %p:%p", s, f, chn, dir, span, data, conf_span, ts_steady, ts_system, OTELC_DPTR_ARGS(err));
-
-       if (span == NULL)
-               OTELC_RETURN_INT(retval);
-
-       /* Create the OTel span on first invocation. */
-       if (span->span == NULL) {
-               span->span = OTELC_OPS(conf->instr->tracer, start_span_with_options, span->id, span->ref_span, span->ref_ctx, ts_steady, ts_system, OTELC_SPAN_KIND_SERVER, NULL, 0);
-               if (span->span == NULL)
-                       OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-       }
-
-       /* Add all resolved span links to the current span. */
-       if (!LIST_ISEMPTY(&(data->links))) {
-               struct flt_otel_scope_data_link *link;
-
-               list_for_each_entry(link, &(data->links), list) {
-                       OTELC_DBG(DEBUG, "adding link %p %p", link->span, link->context);
-
-                       if (OTELC_OPS(span->span, add_link, link->span, link->context, NULL, 0) == -1)
-                               retval = FLT_OTEL_RET_ERROR;
-               }
-       }
-
-       /* Set baggage key-value pairs on the span. */
-       if (data->baggage.attr != NULL)
-               if (OTELC_OPS(span->span, set_baggage_kv_n, data->baggage.attr, data->baggage.cnt) == -1)
-                       retval = FLT_OTEL_RET_ERROR;
-
-       /* Set span attributes. */
-       if (data->attributes.attr != NULL)
-               if (OTELC_OPS(span->span, set_attribute_kv_n, data->attributes.attr, data->attributes.cnt) == -1)
-                       retval = FLT_OTEL_RET_ERROR;
-
-       /* Add span events in reverse order. */
-       if (!LIST_ISEMPTY(&(data->events))) {
-               struct flt_otel_scope_data_event *event;
-
-               list_for_each_entry_rev(event, &(data->events), list)
-                       if (OTELC_OPS(span->span, add_event_kv_n, event->name, ts_system, event->attr, event->cnt) == -1)
-                               retval = FLT_OTEL_RET_ERROR;
-       }
-
-       /* Set span status code and description. */
-       if (data->status.description != NULL)
-               if (OTELC_OPS(span->span, set_status, data->status.code, data->status.description) == -1)
-                       retval = FLT_OTEL_RET_ERROR;
-
-       /* Inject span context into HTTP headers and variables. */
-       if (conf_span->ctx_id != NULL) {
-               struct otelc_http_headers_writer  writer;
-               struct otelc_text_map            *text_map = NULL;
-
-               if (flt_otel_inject_http_headers(span->span, &writer) != FLT_OTEL_RET_ERROR) {
-                       int i = 0;
-
-                       if (conf_span->ctx_flags & (FLT_OTEL_CTX_USE_VARS | FLT_OTEL_CTX_USE_HEADERS)) {
-                               for (text_map = &(writer.text_map); i < text_map->count; i++) {
-#ifdef USE_OTEL_VARS
-                                       if (!(conf_span->ctx_flags & FLT_OTEL_CTX_USE_VARS))
-                                               /* Do nothing. */;
-                                       else if (flt_otel_var_register(FLT_OTEL_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], err) == FLT_OTEL_RET_ERROR)
-                                               retval = FLT_OTEL_RET_ERROR;
-                                       else if (flt_otel_var_set(s, FLT_OTEL_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], text_map->value[i], dir, err) == FLT_OTEL_RET_ERROR)
-                                               retval = FLT_OTEL_RET_ERROR;
-#endif
-
-                                       if (!(conf_span->ctx_flags & FLT_OTEL_CTX_USE_HEADERS))
-                                               /* Do nothing. */;
-                                       else if (flt_otel_http_header_set(chn, conf_span->ctx_id, text_map->key[i], text_map->value[i], err) == FLT_OTEL_RET_ERROR)
-                                               retval = FLT_OTEL_RET_ERROR;
-                               }
-                       }
-
-                       otelc_text_map_destroy(&text_map);
-               }
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_run - scope execution engine
- *
- * SYNOPSIS
- *   int flt_otel_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_otel_conf_scope *conf_scope, const struct timespec *ts_steady, const struct timespec *ts_system, uint dir, char **err)
- *
- * ARGUMENTS
- *   s          - the stream being processed
- *   f          - the filter instance
- *   chn        - the channel for context extraction and injection
- *   conf_scope - the scope configuration to execute
- *   ts_steady  - the monotonic timestamp, or NULL to use current time
- *   ts_system  - the wall-clock timestamp, or NULL to use current time
- *   dir        - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
- *   err        - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Executes a complete scope: evaluates ACL conditions, extracts contexts
- *   from HTTP headers or HAProxy variables, iterates over configured spans
- *   (resolving links, evaluating sample expressions for attributes, events,
- *   baggage and status), calls flt_otel_scope_run_span() for each, processes
- *   metric instruments, emits log records, then marks and finishes completed
- *   spans.
- *
- * RETURN VALUE
- *   Returns FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_otel_conf_scope *conf_scope, const struct timespec *ts_steady, const struct timespec *ts_system, uint dir, char **err)
-{
-       struct flt_otel_conf         *conf = FLT_OTEL_CONF(f);
-       struct flt_otel_conf_context *conf_ctx;
-       struct flt_otel_conf_span    *conf_span;
-       struct flt_otel_conf_str     *span_to_finish;
-       struct timespec               ts_now_steady, ts_now_system;
-       int                           retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %p, %p, %p, %p, %p, %u, %p:%p", s, f, chn, conf_scope, ts_steady, ts_system, dir, OTELC_DPTR_ARGS(err));
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s)", flt_otel_chn_label(chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s));
-       OTELC_DBG(DEBUG, "run scope '%s' %d", conf_scope->id, conf_scope->event);
-       FLT_OTEL_DBG_CONF_SCOPE("run scope ", conf_scope);
-
-       if (ts_steady == NULL) {
-               (void)clock_gettime(CLOCK_MONOTONIC, &ts_now_steady);
-
-               ts_steady = &ts_now_steady;
-       }
-       if (ts_system == NULL) {
-               (void)clock_gettime(CLOCK_REALTIME, &ts_now_system);
-
-               ts_system = &ts_now_system;
-       }
-
-       /* Evaluate the scope's ACL condition; skip this scope on mismatch. */
-       if (conf_scope->cond != NULL) {
-               enum acl_test_res res;
-               int               rc;
-
-               res = acl_exec_cond(conf_scope->cond, s->be, s->sess, s, dir | SMP_OPT_FINAL);
-               rc  = acl_pass(res);
-               if (conf_scope->cond->pol == ACL_COND_UNLESS)
-                       rc = !rc;
-
-               OTELC_DBG(DEBUG, "the ACL rule %s", rc ? "matches" : "does not match");
-
-               /*
-                * If the rule does not match, the current scope is skipped.
-                *
-                * If it is a root span, further processing of the session is
-                * disabled.  As soon as the first span is encountered which
-                * is marked as root, further search is interrupted.
-                */
-               if (rc == 0) {
-                       list_for_each_entry(conf_span, &(conf_scope->spans), list)
-                               if (conf_span->flag_root) {
-                                       OTELC_DBG(LOG, "session disabled");
-
-                                       FLT_OTEL_RT_CTX(f->ctx)->flag_disabled = 1;
-
-#ifdef FLT_OTEL_USE_COUNTERS
-                                       _HA_ATOMIC_ADD(conf->cnt.disabled + 0, 1);
-#endif
-
-                                       break;
-                               }
-
-                       OTELC_RETURN_INT(retval);
-               }
-       }
-
-       /* Extract and initialize OpenTelemetry propagation contexts. */
-       list_for_each_entry(conf_ctx, &(conf_scope->contexts), list) {
-               struct otelc_text_map *text_map = NULL;
-
-               OTELC_DBG(DEBUG, "run context '%s' -> '%s'", conf_scope->id, conf_ctx->id);
-               FLT_OTEL_DBG_CONF_CONTEXT("run context ", conf_ctx);
-
-               /*
-                * The OpenTelemetry context is read from the HTTP header
-                * or from HAProxy variables.
-                */
-               if (conf_ctx->flags & FLT_OTEL_CTX_USE_HEADERS)
-                       text_map = flt_otel_http_headers_get(chn, conf_ctx->id, conf_ctx->id_len, err);
-#ifdef USE_OTEL_VARS
-               else
-                       text_map = flt_otel_vars_get(s, FLT_OTEL_VARS_SCOPE, conf_ctx->id, dir, err);
-#endif
-
-               if (text_map != NULL) {
-                       if (flt_otel_scope_context_init(f->ctx, conf->instr->tracer, conf_ctx->id, conf_ctx->id_len, text_map, dir, err) == NULL)
-                               retval = FLT_OTEL_RET_ERROR;
-
-                       otelc_text_map_destroy(&text_map);
-               } else {
-                       retval = FLT_OTEL_RET_ERROR;
-               }
-       }
-
-       /* Process configured spans: resolve links and collect samples. */
-       list_for_each_entry(conf_span, &(conf_scope->spans), list) {
-               struct flt_otel_scope_data   data;
-               struct flt_otel_scope_span  *span;
-               struct flt_otel_conf_sample *sample;
-
-               OTELC_DBG(DEBUG, "run span '%s' -> '%s'", conf_scope->id, conf_span->id);
-               FLT_OTEL_DBG_CONF_SPAN("run span ", conf_span);
-
-               flt_otel_scope_data_init(&data);
-
-               span = flt_otel_scope_span_init(f->ctx, conf_span->id, conf_span->id_len, conf_span->ref_id, conf_span->ref_id_len, dir, err);
-               if (span == NULL)
-                       retval = FLT_OTEL_RET_ERROR;
-
-               /*
-                * Resolve configured span links against the runtime context.
-                * Each link name is looked up first in the active spans, then
-                * in the extracted contexts.
-                */
-               if (!LIST_ISEMPTY(&(conf_span->links))) {
-                       struct flt_otel_runtime_context *rt_ctx = FLT_OTEL_RT_CTX(f->ctx);
-                       struct flt_otel_conf_link       *conf_link;
-
-                       list_for_each_entry(conf_link, &(conf_span->links), list) {
-                               struct flt_otel_scope_data_link *data_link;
-                               struct otelc_span               *link_span = NULL;
-                               struct otelc_span_context       *link_ctx = NULL;
-                               struct flt_otel_scope_span      *sc_span;
-                               struct flt_otel_scope_context   *sc_ctx;
-
-                               /* Try to find a matching span first. */
-                               list_for_each_entry(sc_span, &(rt_ctx->spans), list)
-                                       if (FLT_OTEL_CONF_STR_CMP(sc_span->id, conf_link->span)) {
-                                               link_span = sc_span->span;
-
-                                               break;
-                                       }
-
-                               /* If no span found, try to find a matching context. */
-                               if (link_span == NULL) {
-                                       list_for_each_entry(sc_ctx, &(rt_ctx->contexts), list)
-                                               if (FLT_OTEL_CONF_STR_CMP(sc_ctx->id, conf_link->span)) {
-                                                       link_ctx = sc_ctx->context;
-
-                                                       break;
-                                               }
-                               }
-
-                               if ((link_span == NULL) && (link_ctx == NULL)) {
-                                       OTELC_DBG(NOTICE, "WARNING: cannot find linked span/context '%s'", conf_link->span);
-
-                                       continue;
-                               }
-
-                               data_link = OTELC_CALLOC(1, sizeof(*data_link));
-                               if (data_link == NULL) {
-                                       retval = FLT_OTEL_RET_ERROR;
-
-                                       break;
-                               }
-
-                               data_link->span    = link_span;
-                               data_link->context = link_ctx;
-                               LIST_APPEND(&(data.links), &(data_link->list));
-
-                               OTELC_DBG(DEBUG, "resolved link '%s' -> %p %p", conf_link->span, link_span, link_ctx);
-                       }
-               }
-
-               list_for_each_entry(sample, &(conf_span->attributes), list) {
-                       OTELC_DBG(DEBUG, "adding attribute '%s' -> '%s'", sample->key, sample->fmt_string);
-
-                       if (flt_otel_sample_add(s, dir, sample, &data, FLT_OTEL_EVENT_SAMPLE_ATTRIBUTE, err) == FLT_OTEL_RET_ERROR)
-                               retval = FLT_OTEL_RET_ERROR;
-               }
-
-               list_for_each_entry(sample, &(conf_span->events), list) {
-                       OTELC_DBG(DEBUG, "adding event '%s' -> '%s'", sample->key, sample->fmt_string);
-
-                       if (flt_otel_sample_add(s, dir, sample, &data, FLT_OTEL_EVENT_SAMPLE_EVENT, err) == FLT_OTEL_RET_ERROR)
-                               retval = FLT_OTEL_RET_ERROR;
-               }
-
-               list_for_each_entry(sample, &(conf_span->baggages), list) {
-                       OTELC_DBG(DEBUG, "adding baggage '%s' -> '%s'", sample->key, sample->fmt_string);
-
-                       if (flt_otel_sample_add(s, dir, sample, &data, FLT_OTEL_EVENT_SAMPLE_BAGGAGE, err) == FLT_OTEL_RET_ERROR)
-                               retval = FLT_OTEL_RET_ERROR;
-               }
-
-               /*
-                * Regardless of the use of the list, only one status per event
-                * is allowed.
-                */
-               list_for_each_entry(sample, &(conf_span->statuses), list) {
-                       OTELC_DBG(DEBUG, "adding status '%s' -> '%s'", sample->key, sample->fmt_string);
-
-                       if (flt_otel_sample_add(s, dir, sample, &data, FLT_OTEL_EVENT_SAMPLE_STATUS, err) == FLT_OTEL_RET_ERROR)
-                               retval = FLT_OTEL_RET_ERROR;
-               }
-
-               /* Attempt to run the span regardless of earlier errors. */
-               if (span != NULL)
-                       if (flt_otel_scope_run_span(s, f, chn, dir, span, &data, conf_span, ts_steady, ts_system, err) == FLT_OTEL_RET_ERROR)
-                               retval = FLT_OTEL_RET_ERROR;
-
-               flt_otel_scope_data_free(&data);
-       }
-
-       /* Process metric instruments. */
-       if (!LIST_ISEMPTY(&(conf_scope->instruments)))
-               if (flt_otel_scope_run_instrument(s, dir, conf_scope, conf->instr->meter, err) == FLT_OTEL_RET_ERROR)
-                       retval = FLT_OTEL_RET_ERROR;
-
-       /* Emit log records. */
-       if (!LIST_ISEMPTY(&(conf_scope->log_records)))
-               if (flt_otel_scope_run_log_record(s, f, dir, conf_scope, conf->instr->logger, ts_system, err) == FLT_OTEL_RET_ERROR)
-                       retval = FLT_OTEL_RET_ERROR;
-
-       /* Mark the configured spans for finishing and clean up. */
-       list_for_each_entry(span_to_finish, &(conf_scope->spans_to_finish), list)
-               if (flt_otel_scope_finish_mark(f->ctx, span_to_finish->str, span_to_finish->str_len) == FLT_OTEL_RET_ERROR)
-                       retval = FLT_OTEL_RET_ERROR;
-
-       flt_otel_scope_finish_marked(f->ctx, ts_steady);
-       flt_otel_scope_free_unused(f->ctx, chn);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_event_run - top-level event dispatcher
- *
- * SYNOPSIS
- *   int flt_otel_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err)
- *
- * ARGUMENTS
- *   s     - the stream being processed
- *   f     - the filter instance
- *   chn   - the channel being analyzed
- *   event - the event index (FLT_OTEL_EVENT_*)
- *   err   - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Top-level event dispatcher called from filter callbacks.  It iterates over
- *   all scopes matching the <event> index and calls flt_otel_scope_run() for
- *   each.  All spans within a single event share the same monotonic and
- *   wall-clock timestamps.
- *
- * RETURN VALUE
- *   Returns FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err)
-{
-       struct flt_otel_conf       *conf = FLT_OTEL_CONF(f);
-       struct flt_otel_conf_scope *conf_scope;
-       struct timespec             ts_steady, ts_system;
-       int                         retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %p, %p, %d, %p:%p", s, f, chn, event, OTELC_DPTR_ARGS(err));
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s)", flt_otel_chn_label(chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s));
-       OTELC_DBG(DEBUG, "run event '%s' %d %s", flt_otel_event_data[event].name, event, flt_otel_event_data[event].an_name);
-
-#ifdef DEBUG_OTEL
-       _HA_ATOMIC_ADD(conf->cnt.event[event].htx + ((chn == NULL) ? 1 : (htx_is_empty(htxbuf(&(chn->buf))) ? 1 : 0)), 1);
-#endif
-
-       FLT_OTEL_RT_CTX(f->ctx)->analyzers |= flt_otel_event_data[event].an_bit;
-
-       /* All spans should be created/completed at the same time. */
-       (void)clock_gettime(CLOCK_MONOTONIC, &ts_steady);
-       (void)clock_gettime(CLOCK_REALTIME, &ts_system);
-
-       /*
-        * It is possible that there are defined multiple scopes that use the
-        * same event.  Therefore, there must not be a 'break' here, ie an exit
-        * from the 'for' loop.
-        */
-       list_for_each_entry(conf_scope, &(conf->scopes), list) {
-               if (conf_scope->event != event)
-                       /* Do nothing. */;
-               else if (!conf_scope->flag_used)
-                       OTELC_DBG(DEBUG, "scope '%s' %d not used", conf_scope->id, conf_scope->event);
-               else if (flt_otel_scope_run(s, f, chn, conf_scope, &ts_steady, &ts_system, flt_otel_event_data[event].smp_opt_dir, err) == FLT_OTEL_RET_ERROR)
-                       retval = FLT_OTEL_RET_ERROR;
-       }
-
-#ifdef USE_OTEL_VARS
-       flt_otel_vars_dump(s);
-#endif
-       flt_otel_http_headers_dump(chn);
-
-       OTELC_DBG(DEBUG, "event = %d %s, chn = %p, s->req = %p, s->res = %p", event, flt_otel_event_data[event].an_name, chn, &(s->req), &(s->res));
-
-       OTELC_RETURN_INT(retval);
-}
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/filter.c b/addons/otel/src/filter.c
deleted file mode 100644 (file)
index b57b1cd..0000000
+++ /dev/null
@@ -1,1881 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-/*
- * OpenTelemetry filter id, used to identify OpenTelemetry filters.  The name
- * of this variable is consistent with the other filter names declared in
- * include/haproxy/filters.h .
- */
-const char *otel_flt_id = "the OpenTelemetry filter";
-
-/* Counter of OTel SDK internal diagnostic messages. */
-uint64_t flt_otel_drop_cnt = 0;
-
-#if defined(USE_THREAD) && defined(DEBUG_OTEL)
-/* Counter for assigning unique IDs to threads not registered as workers. */
-static int flt_otel_thread_id_offset = -1;
-
-/* Per-thread registration data for HAProxy worker threads. */
-static struct {
-       pthread_t id;         /* POSIX thread ID. */
-       bool      registered; /* Entry is valid. */
-} flt_otel_tid[MAX_THREADS + 1];
-#endif
-
-
-/***
- * NAME
- *   flt_otel_mem_malloc - OTel library memory allocator callback
- *
- * SYNOPSIS
- *   static void *flt_otel_mem_malloc(const char *func, int line, size_t size)
- *
- * ARGUMENTS
- *   func - caller function name (debug only)
- *   line - caller source line number (debug only)
- *   size - number of bytes to allocate
- *
- * DESCRIPTION
- *   Allocator callback for the OpenTelemetry C wrapper library.  It allocates
- *   the requested <size> bytes from the HAProxy pool_head_otel_span_context
- *   pool.  This function is registered via otelc_ext_init().
- *
- * RETURN VALUE
- *   Returns a pointer to the allocated memory, or NULL on failure.
- */
-static void *flt_otel_mem_malloc(FLT_OTEL_DBG_ARGS(const char *func, int line, ) size_t size)
-{
-       return flt_otel_pool_alloc(pool_head_otel_span_context, size, 1, NULL);
-}
-
-
-/***
- * NAME
- *   flt_otel_mem_free - OTel library memory deallocator callback
- *
- * SYNOPSIS
- *   static void flt_otel_mem_free(const char *func, int line, void *ptr)
- *
- * ARGUMENTS
- *   func - caller function name (debug only)
- *   line - caller source line number (debug only)
- *   ptr  - pointer to the memory to free
- *
- * DESCRIPTION
- *   Deallocator callback for the OpenTelemetry C wrapper library.  It returns
- *   the memory pointed to by <ptr> back to the HAProxy
- *   pool_head_otel_span_context pool.  This function is registered via
- *   otelc_ext_init().
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_mem_free(FLT_OTEL_DBG_ARGS(const char *func, int line, ) void *ptr)
-{
-       flt_otel_pool_free(pool_head_otel_span_context, &ptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_thread_id - OTel library thread ID callback
- *
- * SYNOPSIS
- *   static int flt_otel_thread_id(void)
- *
- * ARGUMENTS
- *   This function takes no arguments.
- *
- * DESCRIPTION
- *   Thread ID callback for the OpenTelemetry C wrapper library.  For registered
- *   HAProxy worker threads it returns the HAProxy thread identifier (tid).  For
- *   unregistered threads, such as those created internally by the OTel SDK, it
- *   assigns and returns a unique ID from the atomic offset counter.  This
- *   function is registered via otelc_ext_init().
- *
- * RETURN VALUE
- *   Returns the HAProxy thread ID for worker threads, a unique offset-based ID
- *   for unregistered threads, or -1 if the thread index is out of range or the
- *   offset counter has not yet been initialized.
- */
-static int flt_otel_thread_id(void)
-{
-#if defined(USE_THREAD) && defined(DEBUG_OTEL)
-       static THREAD_LOCAL int retval = -1;
-
-       if (!OTELC_IN_RANGE(tid, 0, OTELC_TABLESIZE(flt_otel_tid)))
-               return -1;
-       else if (!flt_otel_tid[tid].registered)
-               return tid;
-       else if (pthread_equal(flt_otel_tid[tid].id, pthread_self()))
-               return tid;
-
-       if ((retval == -1) && (HA_ATOMIC_LOAD(&flt_otel_thread_id_offset) != -1))
-               retval = HA_ATOMIC_FETCH_ADD(&flt_otel_thread_id_offset, 1);
-
-       return retval;
-
-#else
-
-       return tid;
-#endif /* USE_THREAD && DEBUG_OTEL */
-}
-
-
-/***
- * NAME
- *   flt_otel_log_handler_cb - counts SDK internal diagnostic messages
- *
- * SYNOPSIS
- *   static void flt_otel_log_handler_cb(otelc_log_level_t level, const char *file, int line, const char *msg, const struct otelc_kv *attr, size_t attr_len, void *ctx)
- *
- * ARGUMENTS
- *   level    - severity of the OTel SDK diagnostic message
- *   file     - source file that emitted the message
- *   line     - source line number
- *   msg      - formatted diagnostic message text
- *   attr     - array of key-value attributes associated with the message
- *   attr_len - number of entries in the attr array
- *   ctx      - opaque context pointer (unused)
- *
- * DESCRIPTION
- *   Custom OTel SDK internal log handler registered via otelc_log_set_handler().
- *   Each invocation atomically increments the flt_otel_drop_cnt counter so the
- *   HAProxy OTel filter can verify how many OTel SDK diagnostic messages were
- *   emitted.  The message content is intentionally ignored.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_log_handler_cb(otelc_log_level_t level __maybe_unused, const char *file __maybe_unused, int line __maybe_unused, const char *msg __maybe_unused, const struct otelc_kv *attr __maybe_unused, size_t attr_len __maybe_unused, void *ctx __maybe_unused)
-{
-       OTELC_FUNC("%d, \"%s\", %d, \"%s\", %p, %zu, %p", level, OTELC_STR_ARG(file), line, OTELC_STR_ARG(msg), attr, attr_len, ctx);
-
-       _HA_ATOMIC_INC(&flt_otel_drop_cnt);
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_lib_init - OTel library initialization
- *
- * SYNOPSIS
- *   static int flt_otel_lib_init(struct flt_otel_conf_instr *instr, char **err)
- *
- * ARGUMENTS
- *   instr - pointer to the instrumentation configuration
- *   err   - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Initializes the OpenTelemetry C wrapper library for the instrumentation
- *   specified by <instr>.  It verifies the library version, constructs the
- *   absolute configuration path from <instr>->config, calls otelc_init(), and
- *   creates the tracer and meter instances.  On success, it registers the
- *   memory and thread ID callbacks via otelc_ext_init().
- *
- * RETURN VALUE
- *   Returns 0 on success, or FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_lib_init(struct flt_otel_conf_instr *instr, char **err)
-{
-       char cwd[PATH_MAX], path[PATH_MAX];
-       int  rc, retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("%p, %p:%p", instr, OTELC_DPTR_ARGS(err));
-
-       if (!OTELC_IS_VALID_VERSION()) {
-               FLT_OTEL_ERR("OpenTelemetry C Wrapper version mismatch: library (%s) does not match header files (%s).  Please ensure both are the same version.", otelc_version(), OTELC_VERSION);
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       if (flt_otel_pool_init() == FLT_OTEL_RET_ERROR) {
-               FLT_OTEL_ERR("failed to initialize memory pools");
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       flt_otel_pool_info();
-
-       if (getcwd(cwd, sizeof(cwd)) == NULL) {
-               FLT_OTEL_ERR("failed to get current working directory");
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       rc = snprintf(path, sizeof(path), "%s/%s", cwd, instr->config);
-       if ((rc == -1) || (rc >= sizeof(path))) {
-               FLT_OTEL_ERR("failed to construct the OpenTelemetry configuration path");
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       if (otelc_init(path, err) == OTELC_RET_ERROR) {
-               if (*err == NULL)
-                       FLT_OTEL_ERR("%s", "failed to initialize tracing library");
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       instr->tracer = otelc_tracer_create(err);
-       if (instr->tracer == NULL) {
-               if (*err == NULL)
-                       FLT_OTEL_ERR("%s", "failed to initialize OpenTelemetry tracer");
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       instr->meter = otelc_meter_create(err);
-       if (instr->meter == NULL) {
-               if (*err == NULL)
-                       FLT_OTEL_ERR("%s", "failed to initialize OpenTelemetry meter");
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       instr->logger = otelc_logger_create(err);
-       if (instr->logger == NULL) {
-               if (*err == NULL)
-                       FLT_OTEL_ERR("%s", "failed to initialize OpenTelemetry logger");
-       } else {
-#if defined(USE_THREAD) && defined(DEBUG_OTEL)
-               flt_otel_tid[tid].id         = pthread_self();
-               flt_otel_tid[tid].registered = true;
-               HA_ATOMIC_STORE(&flt_otel_thread_id_offset, 1000);
-#endif
-               otelc_ext_init(flt_otel_mem_malloc, flt_otel_mem_free, flt_otel_thread_id);
-               otelc_log_set_handler(flt_otel_log_handler_cb, NULL, false);
-
-               retval = 0;
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_is_disabled - filter disabled check
- *
- * SYNOPSIS
- *   bool flt_otel_is_disabled(const struct filter *f, int event)
- *
- * ARGUMENTS
- *   f     - the filter instance to check
- *   event - the event identifier, or -1 (debug only)
- *
- * DESCRIPTION
- *   Checks whether the filter instance is disabled for the current stream by
- *   examining the runtime context's flag_disabled field.  When DEBUG_OTEL is
- *   enabled, it also logs the filter name, type and the <event> name.
- *
- * RETURN VALUE
- *   Returns true if the filter is disabled, false otherwise.
- */
-bool flt_otel_is_disabled(const struct filter *f FLT_OTEL_DBG_ARGS(, int event))
-{
-#ifdef DEBUG_OTEL
-       const struct flt_otel_conf *conf = FLT_OTEL_CONF(f);
-       const char                 *msg;
-#endif
-       bool                        retval;
-
-       retval = FLT_OTEL_RT_CTX(f->ctx)->flag_disabled ? 1 : 0;
-
-#ifdef DEBUG_OTEL
-       msg    = retval ? " (disabled)" : "";
-
-       if (OTELC_IN_RANGE(event, 0, FLT_OTEL_EVENT_MAX - 1))
-               OTELC_DBG(NOTICE, "filter '%s', type: %s, event: '%s' %d%s", conf->id, flt_otel_type(f), flt_otel_event_data[event].name, event, msg);
-       else
-               OTELC_DBG(NOTICE, "filter '%s', type: %s%s", conf->id, flt_otel_type(f), msg);
-#endif
-
-       return retval;
-}
-
-
-/***
- * NAME
- *   flt_otel_return_int - error handler for int-returning callbacks
- *
- * SYNOPSIS
- *   static int flt_otel_return_int(const struct filter *f, char **err, int retval)
- *
- * ARGUMENTS
- *   f      - the filter instance
- *   err    - indirect pointer to error message string
- *   retval - the return value from the caller
- *
- * DESCRIPTION
- *   Error handler for filter callbacks that return an integer value.  If
- *   <retval> indicates an error or <err> contains a message, the filter is
- *   disabled when hard-error mode is enabled; in soft-error mode, the error
- *   is silently cleared.  The error message is always freed before returning.
- *
- * RETURN VALUE
- *   Returns FLT_OTEL_RET_OK if an error was handled, or the original <retval>.
- */
-static int flt_otel_return_int(const struct filter *f, char **err, int retval)
-{
-       struct flt_otel_runtime_context *rt_ctx = f->ctx;
-
-       /* Disable the filter on hard errors; ignore on soft errors. */
-       if ((retval == FLT_OTEL_RET_ERROR) || ((err != NULL) && (*err != NULL))) {
-               if (rt_ctx->flag_harderr) {
-                       OTELC_DBG(INFO, "WARNING: filter hard-error (disabled)");
-
-                       rt_ctx->flag_disabled = 1;
-
-#ifdef FLT_OTEL_USE_COUNTERS
-                       _HA_ATOMIC_ADD(FLT_OTEL_CONF(f)->cnt.disabled + 1, 1);
-#endif
-               } else {
-                       OTELC_DBG(INFO, "WARNING: filter soft-error");
-               }
-
-               retval = FLT_OTEL_RET_OK;
-       }
-
-       FLT_OTEL_ERR_FREE(*err);
-
-       return retval;
-}
-
-
-/***
- * NAME
- *   flt_otel_return_void - error handler for void-returning callbacks
- *
- * SYNOPSIS
- *   static void flt_otel_return_void(const struct filter *f, char **err)
- *
- * ARGUMENTS
- *   f   - the filter instance
- *   err - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Error handler for filter callbacks that return void.  If <err> contains
- *   a message, the filter is disabled when hard-error mode is enabled; in
- *   soft-error mode, the error is silently cleared.  The error message is
- *   always freed before returning.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_return_void(const struct filter *f, char **err)
-{
-       struct flt_otel_runtime_context *rt_ctx = f->ctx;
-
-       /* Disable the filter on hard errors; ignore on soft errors. */
-       if ((err != NULL) && (*err != NULL)) {
-               if (rt_ctx->flag_harderr) {
-                       OTELC_DBG(INFO, "WARNING: filter hard-error (disabled)");
-
-                       rt_ctx->flag_disabled = 1;
-
-#ifdef FLT_OTEL_USE_COUNTERS
-                       _HA_ATOMIC_ADD(FLT_OTEL_CONF(f)->cnt.disabled + 1, 1);
-#endif
-               } else {
-                       OTELC_DBG(INFO, "WARNING: filter soft-error");
-               }
-       }
-
-       FLT_OTEL_ERR_FREE(*err);
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_init - filter init callback (flt_ops.init)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_init(struct proxy *p, struct flt_conf *fconf)
- *
- * ARGUMENTS
- *   p     - the proxy to which the filter is attached
- *   fconf - the filter configuration
- *
- * DESCRIPTION
- *   It initializes the filter for a proxy.  You may define this callback if you
- *   need to complete your filter configuration.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, any other value otherwise.
- */
-static int flt_otel_ops_init(struct proxy *p, struct flt_conf *fconf)
-{
-       struct flt_otel_conf *conf = FLT_OTEL_DEREF(fconf, conf, NULL);
-       char                 *err = NULL;
-       int                   retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("%p, %p", p, fconf);
-
-       if (conf == NULL)
-               OTELC_RETURN_INT(retval);
-
-       flt_otel_cli_init();
-
-       /*
-        * Initialize the OpenTelemetry library.
-        */
-       retval = flt_otel_lib_init(conf->instr, &err);
-       if (retval != FLT_OTEL_RET_ERROR)
-               /* Do nothing. */;
-       else if (err != NULL) {
-               FLT_OTEL_ALERT("%s", err);
-
-               FLT_OTEL_ERR_FREE(err);
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_deinit - filter deinit callback (flt_ops.deinit)
- *
- * SYNOPSIS
- *   static void flt_otel_ops_deinit(struct proxy *p, struct flt_conf *fconf)
- *
- * ARGUMENTS
- *   p     - the proxy to which the filter is attached
- *   fconf - the filter configuration
- *
- * DESCRIPTION
- *   It cleans up what the parsing function and the init callback have done.
- *   This callback is useful to release memory allocated for the filter
- *   configuration.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_ops_deinit(struct proxy *p, struct flt_conf *fconf)
-{
-       struct flt_otel_conf **conf = (fconf == NULL) ? NULL : (typeof(conf))&(fconf->conf);
-       struct otelc_tracer   *otel_tracer = NULL;
-       struct otelc_meter    *otel_meter = NULL;
-       struct otelc_logger   *otel_logger = NULL;
-#ifdef DEBUG_OTEL
-       char                   buffer[BUFSIZ];
-       int                    i;
-#endif
-
-       OTELC_FUNC("%p, %p", p, fconf);
-
-       if (conf == NULL)
-               OTELC_RETURN();
-
-#ifdef DEBUG_OTEL
-       otelc_statistics(buffer, sizeof(buffer));
-       OTELC_DBG(LOG, "%s", buffer);
-
-#  ifdef FLT_OTEL_USE_COUNTERS
-       OTELC_DBG(LOG, "attach counters: %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, (*conf)->cnt.attached[0], (*conf)->cnt.attached[1], (*conf)->cnt.attached[2], (*conf)->cnt.attached[3]);
-#  endif
-
-       OTELC_DBG(LOG, "--- used events ----------");
-       for (i = 0; i < OTELC_TABLESIZE((*conf)->cnt.event); i++)
-               if ((*conf)->cnt.event[i].flag_used)
-                       OTELC_DBG(LOG, "  %02d %25s: %" PRIu64 " / %" PRIu64, i, flt_otel_event_data[i].an_name, (*conf)->cnt.event[i].htx[0], (*conf)->cnt.event[i].htx[1]);
-#endif /* DEBUG_OTEL */
-
-       /*
-        * Save the OTel handles before freeing the configuration.
-        * flt_otel_conf_free() must run while the wrapper's ext callbacks
-        * still point to the HAProxy pool allocator; otelc_deinit() resets
-        * those callbacks, so it runs last.
-        */
-       if ((*conf)->instr != NULL) {
-               otel_tracer = (*conf)->instr->tracer;
-               otel_meter  = (*conf)->instr->meter;
-               otel_logger = (*conf)->instr->logger;
-       }
-
-       flt_otel_conf_free(conf);
-       OTELC_MEMINFO();
-       flt_otel_pool_destroy();
-       otelc_deinit(&otel_tracer, &otel_meter, &otel_logger);
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_check - filter check callback (flt_ops.check)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_check(struct proxy *p, struct flt_conf *fconf)
- *
- * ARGUMENTS
- *   p     - the proxy to which the filter is attached
- *   fconf - the filter configuration
- *
- * DESCRIPTION
- *   Validates the internal configuration of the OTel filter after the parsing
- *   phase, when the HAProxy configuration is fully defined.  The following
- *   checks are performed: duplicate filter IDs across all proxies, presence of
- *   an instrumentation section and its configuration file, duplicate group and
- *   scope names, empty groups, group-to-scope and instrumentation-to-group/scope
- *   cross-references, unused scopes, root span count, analyzer bits, and
- *   create-form instrument name uniqueness and update-form instrument
- *   resolution.
- *
- * RETURN VALUE
- *   Returns the number of encountered errors.
- */
-static int flt_otel_ops_check(struct proxy *p, struct flt_conf *fconf)
-{
-       struct proxy               *px;
-       struct flt_otel_conf       *conf = FLT_OTEL_DEREF(fconf, conf, NULL);
-       struct flt_otel_conf_group *conf_group;
-       struct flt_otel_conf_scope *conf_scope;
-       struct flt_otel_conf_ph    *ph_group, *ph_scope;
-       int                         retval = 0, scope_unused_cnt = 0, span_root_cnt = 0;
-
-       OTELC_FUNC("%p, %p", p, fconf);
-
-       if (conf == NULL)
-               OTELC_RETURN_INT(++retval);
-
-       /*
-        * Resolve deferred OTEL sample fetch arguments.
-        *
-        * These were kept out of the proxy's arg list during parsing to avoid
-        * the global smp_resolve_args() call, which would reject backend-only
-        * fetches on a frontend proxy.  All backends and servers are now
-        * available, so resolve under full FE+BE capabilities.
-        */
-       if (!LIST_ISEMPTY(&(conf->smp_args))) {
-               char *err = NULL;
-               uint  saved_cap = p->cap;
-
-               LIST_SPLICE(&(p->conf.args.list), &(conf->smp_args));
-               LIST_INIT(&(conf->smp_args));
-               p->cap |= PR_CAP_LISTEN;
-
-               if (smp_resolve_args(p, &err) != 0) {
-                       FLT_OTEL_ALERT("%s", err);
-                       ha_free(&err);
-
-                       retval++;
-               }
-
-               p->cap = saved_cap;
-       }
-
-       /*
-        * If only the proxy specified with the <p> parameter is checked, then
-        * no duplicate filters can be found that are not defined in the same
-        * configuration sections.
-        */
-       for (px = proxies_list; px != NULL; px = px->next) {
-               struct flt_conf *fconf_tmp;
-
-               OTELC_DBG(NOTICE, "proxy '%s'", px->id);
-
-               /*
-                * The names of all OTEL filters (filter ID) should be checked,
-                * they must be unique.
-                */
-               list_for_each_entry(fconf_tmp, &(px->filter_configs), list)
-                       if ((fconf_tmp != fconf) && (fconf_tmp->id == otel_flt_id)) {
-                               struct flt_otel_conf *conf_tmp = fconf_tmp->conf;
-
-                               OTELC_DBG(NOTICE, "  OTEL filter '%s'", conf_tmp->id);
-
-                               if (strcmp(conf_tmp->id, conf->id) == 0) {
-                                       FLT_OTEL_ALERT("''%s' : duplicated filter ID'", conf_tmp->id);
-
-                                       retval++;
-                               }
-                       }
-       }
-
-       if (FLT_OTEL_DEREF(conf->instr, id, NULL) == NULL) {
-               FLT_OTEL_ALERT("''%s' : no instrumentation found'", conf->id);
-
-               retval++;
-       }
-
-       if ((conf->instr != NULL) && (conf->instr->config == NULL)) {
-               FLT_OTEL_ALERT("''%s' : no configuration file specified'", conf->instr->id);
-
-               retval++;
-       }
-
-       /*
-        * Checking that defined 'otel-group' section names are unique.
-        */
-       list_for_each_entry(conf_group, &(conf->groups), list) {
-               struct flt_otel_conf_group *conf_group_tmp;
-
-               list_for_each_entry(conf_group_tmp, &(conf->groups), list) {
-                       if ((conf_group_tmp != conf_group) && (strcmp(conf_group_tmp->id, conf_group->id) == 0)) {
-                               FLT_OTEL_ALERT("''%s' : duplicated " FLT_OTEL_PARSE_SECTION_GROUP_ID " '%s''", conf->id, conf_group->id);
-
-                               retval++;
-
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * Checking that defined 'otel-scope' section names are unique.
-        */
-       list_for_each_entry(conf_scope, &(conf->scopes), list) {
-               struct flt_otel_conf_scope *conf_scope_tmp;
-
-               list_for_each_entry(conf_scope_tmp, &(conf->scopes), list) {
-                       if ((conf_scope_tmp != conf_scope) && (strcmp(conf_scope_tmp->id, conf_scope->id) == 0)) {
-                               FLT_OTEL_ALERT("''%s' : duplicated " FLT_OTEL_PARSE_SECTION_SCOPE_ID " '%s''", conf->id, conf_scope->id);
-
-                               retval++;
-
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * Checking that defined 'otel-group' sections are not empty.
-        */
-       list_for_each_entry(conf_group, &(conf->groups), list)
-               if (LIST_ISEMPTY(&(conf_group->ph_scopes)))
-                       FLT_OTEL_ALERT("''%s' : " FLT_OTEL_PARSE_SECTION_GROUP_ID " '%s' has no scopes'", conf->id, conf_group->id);
-
-       /*
-        * Checking that all defined 'otel-group' sections have correctly declared
-        * 'otel-scope' sections (ie whether the declared 'otel-scope' sections have
-        * corresponding definitions).
-        */
-       list_for_each_entry(conf_group, &(conf->groups), list)
-               list_for_each_entry(ph_scope, &(conf_group->ph_scopes), list) {
-                       bool flag_found = 0;
-
-                       list_for_each_entry(conf_scope, &(conf->scopes), list)
-                               if (strcmp(ph_scope->id, conf_scope->id) == 0) {
-                                       ph_scope->ptr         = conf_scope;
-                                       conf_scope->flag_used = 1;
-                                       flag_found            = 1;
-
-                                       break;
-                               }
-
-                       if (!flag_found) {
-                               FLT_OTEL_ALERT("'" FLT_OTEL_PARSE_SECTION_GROUP_ID " '%s' : references undefined " FLT_OTEL_PARSE_SECTION_SCOPE_ID " '%s''", conf_group->id, ph_scope->id);
-
-                               retval++;
-                       }
-               }
-
-       if (conf->instr != NULL) {
-               /*
-                * Checking that all declared 'groups' keywords have correctly
-                * defined 'otel-group' sections.
-                */
-               list_for_each_entry(ph_group, &(conf->instr->ph_groups), list) {
-                       bool flag_found = 0;
-
-                       list_for_each_entry(conf_group, &(conf->groups), list)
-                               if (strcmp(ph_group->id, conf_group->id) == 0) {
-                                       ph_group->ptr         = conf_group;
-                                       conf_group->flag_used = 1;
-                                       flag_found            = 1;
-
-                                       break;
-                               }
-
-                       if (!flag_found) {
-                               FLT_OTEL_ALERT("'" FLT_OTEL_PARSE_SECTION_INSTR_ID " '%s' : references undefined " FLT_OTEL_PARSE_SECTION_GROUP_ID " '%s''", conf->instr->id, ph_group->id);
-
-                               retval++;
-                       }
-               }
-
-               /*
-                * Checking that all declared 'scopes' keywords have correctly
-                * defined 'otel-scope' sections.
-                */
-               list_for_each_entry(ph_scope, &(conf->instr->ph_scopes), list) {
-                       bool flag_found = 0;
-
-                       list_for_each_entry(conf_scope, &(conf->scopes), list)
-                               if (strcmp(ph_scope->id, conf_scope->id) == 0) {
-                                       ph_scope->ptr         = conf_scope;
-                                       conf_scope->flag_used = 1;
-                                       flag_found            = 1;
-
-                                       break;
-                               }
-
-                       if (!flag_found) {
-                               FLT_OTEL_ALERT("'" FLT_OTEL_PARSE_SECTION_INSTR_ID " '%s' : references undefined " FLT_OTEL_PARSE_SECTION_SCOPE_ID " '%s''", conf->instr->id, ph_scope->id);
-
-                               retval++;
-                       }
-               }
-       }
-
-       OTELC_DBG(DEBUG, "--- filter '%s' configuration ----------", conf->id);
-       OTELC_DBG(DEBUG, "- defined spans ----------");
-
-       /*
-        * Walk every configured scope: for used ones, log the defined spans,
-        * count root spans, and set the required analyzer bits; for unused
-        * ones, record a warning so the operator is notified.
-        */
-       list_for_each_entry(conf_scope, &(conf->scopes), list) {
-               if (conf_scope->flag_used) {
-                       struct flt_otel_conf_span *conf_span;
-
-                       /*
-                        * In principle, only one span should be labeled
-                        * as a root span.
-                        */
-                       list_for_each_entry(conf_span, &(conf_scope->spans), list) {
-                               FLT_OTEL_DBG_CONF_SPAN("   ", conf_span);
-
-                               span_root_cnt += conf_span->flag_root ? 1 : 0;
-                       }
-
-#ifdef DEBUG_OTEL
-                       conf->cnt.event[conf_scope->event].flag_used = 1;
-#endif
-
-                       /* Set the flags of the analyzers used. */
-                       conf->instr->analyzers |= flt_otel_event_data[conf_scope->event].an_bit;
-
-                       /* Track the minimum idle timeout. */
-                       if (conf_scope->event == FLT_OTEL_EVENT__IDLE_TIMEOUT)
-                               if ((conf->instr->idle_timeout == 0) || (conf_scope->idle_timeout < conf->instr->idle_timeout))
-                                       conf->instr->idle_timeout = conf_scope->idle_timeout;
-               } else {
-                       FLT_OTEL_ALERT("''%s' : unused " FLT_OTEL_PARSE_SECTION_SCOPE_ID " '%s''", conf->id, conf_scope->id);
-
-                       scope_unused_cnt++;
-               }
-       }
-
-       /*
-        * Unused scopes or a number of root spans other than one do not
-        * necessarily have to be errors, but it is good to print it when
-        * starting HAProxy.
-        */
-       if (scope_unused_cnt > 0)
-               FLT_OTEL_ALERT("''%s' : %d scope(s) not in use'", conf->id, scope_unused_cnt);
-
-       if (LIST_ISEMPTY(&(conf->scopes)))
-               /* Do nothing. */;
-       else if (span_root_cnt == 0)
-               FLT_OTEL_ALERT("''%s' : no span is marked as the root span'", conf->id);
-       else if (span_root_cnt > 1)
-               FLT_OTEL_ALERT("''%s' : multiple spans are marked as the root span'", conf->id);
-
-       OTELC_DBG(DEBUG, "- defined instruments ----------");
-
-       /*
-        * Validate update-form instruments: for each one, resolve its reference
-        * to the matching create-form instrument definition.
-        *
-        * Validate create-form instruments: check that names are unique across
-        * all scopes.
-        */
-       list_for_each_entry(conf_scope, &(conf->scopes), list) {
-               struct flt_otel_conf_instrument *conf_instr, *instr;
-               struct flt_otel_conf_scope      *scope;
-
-               list_for_each_entry(conf_instr, &(conf_scope->instruments), list) {
-                       if (conf_instr->type == OTELC_METRIC_INSTRUMENT_UPDATE) {
-                               FLT_OTEL_DBG_CONF_INSTRUMENT("  update ", conf_instr);
-
-                               /*
-                                * Search all scopes for a create-form instrument
-                                * whose name matches this update-form instrument.
-                                */
-                               list_for_each_entry(scope, &(conf->scopes), list) {
-                                       list_for_each_entry(instr, &(scope->instruments), list) {
-                                               if ((instr->type != OTELC_METRIC_INSTRUMENT_UPDATE) && (strcmp(instr->id, conf_instr->id) == 0))
-                                                       conf_instr->ref = instr;
-
-                                               if (conf_instr->ref != NULL)
-                                                       break;
-                                       }
-
-                                       if (conf_instr->ref != NULL)
-                                               break;
-                               }
-
-                               if (conf_instr->ref == NULL) {
-                                       FLT_OTEL_ALERT("''%s' : update-form instrument has no matching create-form definition'", conf_instr->id);
-
-                                       retval++;
-                               }
-                       } else {
-                               bool flag_past = false, flag_dup = false;
-
-                               FLT_OTEL_DBG_CONF_INSTRUMENT("  create ", conf_instr);
-
-                               if (LIST_ISEMPTY(&(conf_instr->samples))) {
-                                       FLT_OTEL_ALERT("''%s' : create-form instrument '%s' has no value expression'", conf->id, conf_instr->id);
-
-                                       retval++;
-                               }
-
-                               if ((conf_instr->aggr_type == OTELC_METRIC_AGGREGATION_UNSET) && (conf_instr->type == OTELC_METRIC_INSTRUMENT_HISTOGRAM_UINT64))
-                                       conf_instr->aggr_type = OTELC_METRIC_AGGREGATION_HISTOGRAM;
-
-                               /*
-                                * Checking that create-form instrument names
-                                * are unique across all scopes.  Only compare
-                                * forward to avoid reporting the same pair
-                                * twice.
-                                */
-                               list_for_each_entry(scope, &(conf->scopes), list) {
-                                       list_for_each_entry(instr, &(scope->instruments), list)
-                                               if (instr == conf_instr) {
-                                                       flag_past = true;
-
-                                                       continue;
-                                               }
-                                               else if (!flag_past || (instr->type == OTELC_METRIC_INSTRUMENT_UPDATE)) {
-                                                       continue;
-                                               }
-                                               else if (strcmp(instr->id, conf_instr->id) == 0) {
-                                                       FLT_OTEL_ALERT("''%s' : duplicated create-form instrument '%s''", conf->id, conf_instr->id);
-
-                                                       retval++;
-
-                                                       flag_dup = true;
-                                                       break;
-                                               }
-
-                                       if (flag_dup)
-                                               break;
-                               }
-                       }
-               }
-       }
-
-       OTELC_DBG(DEBUG, "- defined log records ----------");
-
-       /*
-        * Validate log-record span references: for each log-record that
-        * names a span, verify that a span with that name exists in one
-        * of the configured scopes.
-        */
-       list_for_each_entry(conf_scope, &(conf->scopes), list) {
-               struct flt_otel_conf_log_record *conf_log;
-
-               list_for_each_entry(conf_log, &(conf_scope->log_records), list) {
-                       FLT_OTEL_DBG_CONF_LOG_RECORD("  ", conf_log);
-
-                       if (conf_log->span != NULL) {
-                               struct flt_otel_conf_scope *find_scope;
-                               struct flt_otel_conf_span  *find_span;
-                               bool                        flag_found = false;
-
-                               list_for_each_entry(find_scope, &(conf->scopes), list) {
-                                       list_for_each_entry(find_span, &(find_scope->spans), list)
-                                               if (strcmp(find_span->id, conf_log->span) == 0) {
-                                                       flag_found = true;
-
-                                                       break;
-                                               }
-
-                                       if (flag_found)
-                                               break;
-                               }
-
-                               if (!flag_found) {
-                                       FLT_OTEL_ALERT("'" FLT_OTEL_PARSE_SECTION_SCOPE_ID " '%s' : log-record references undefined span '%s''", conf_scope->id, conf_log->span);
-
-                                       retval++;
-                               }
-                       }
-               }
-       }
-
-       FLT_OTEL_DBG_LIST(conf, group, "", "defined", _group,
-                         FLT_OTEL_DBG_CONF_GROUP("   ", _group);
-                         FLT_OTEL_DBG_LIST(_group, ph_scope, "   ", "used", _scope, FLT_OTEL_DBG_CONF_PH("      ", _scope)));
-       FLT_OTEL_DBG_LIST(conf, scope, "", "defined", _scope, FLT_OTEL_DBG_CONF_SCOPE("   ", _scope));
-
-       if (conf->instr != NULL) {
-               OTELC_DBG(DEBUG, "   --- instrumentation '%s' configuration ----------", conf->instr->id);
-               FLT_OTEL_DBG_LIST(conf->instr, ph_group, "   ", "used", _group, FLT_OTEL_DBG_CONF_PH("      ", _group));
-               FLT_OTEL_DBG_LIST(conf->instr, ph_scope, "   ", "used", _scope, FLT_OTEL_DBG_CONF_PH("      ", _scope));
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_init_per_thread - per-thread init callback (flt_ops.init_per_thread)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_init_per_thread(struct proxy *p, struct flt_conf *fconf)
- *
- * ARGUMENTS
- *   p     - the proxy to which the filter is attached
- *   fconf - the filter configuration
- *
- * DESCRIPTION
- *   Per-thread filter initialization called after thread creation.  Starts
- *   the OTel tracer and meter threads via their start operations and enables
- *   HTX stream filtering.  Subsequent calls on the same filter are no-ops.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, any other value otherwise.
- */
-static int flt_otel_ops_init_per_thread(struct proxy *p, struct flt_conf *fconf)
-{
-       struct flt_otel_conf *conf = FLT_OTEL_DEREF(fconf, conf, NULL);
-       int                   retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("%p, %p", p, fconf);
-
-       if (conf == NULL)
-               OTELC_RETURN_INT(retval);
-
-#if defined(USE_THREAD) && defined(DEBUG_OTEL)
-       flt_otel_tid[tid].id         = pthread_self();
-       flt_otel_tid[tid].registered = true;
-#endif
-
-       /*
-        * Start the OpenTelemetry library tracer thread.  Enable HTX streams
-        * filtering.
-        */
-       if (!(fconf->flags & FLT_CFG_FL_HTX)) {
-               retval = OTELC_OPS(conf->instr->tracer, start);
-               if (retval == OTELC_RET_ERROR)
-                       FLT_OTEL_ALERT("%s", conf->instr->tracer->err);
-
-               if (retval != OTELC_RET_ERROR) {
-                       retval = OTELC_OPS(conf->instr->meter, start);
-                       if (retval == OTELC_RET_ERROR)
-                               FLT_OTEL_ALERT("%s", conf->instr->meter->err);
-               }
-
-               if (retval != OTELC_RET_ERROR) {
-                       retval = OTELC_OPS(conf->instr->logger, start);
-                       if (retval == OTELC_RET_ERROR)
-                               FLT_OTEL_ALERT("%s", conf->instr->logger->err);
-               }
-
-               if (retval != FLT_OTEL_RET_ERROR)
-                       fconf->flags |= FLT_CFG_FL_HTX;
-       } else {
-               retval = FLT_OTEL_RET_OK;
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-#ifdef DEBUG_OTEL
-
-/***
- * NAME
- *   flt_otel_ops_deinit_per_thread - per-thread deinit callback (flt_ops.deinit_per_thread)
- *
- * SYNOPSIS
- *   static void flt_otel_ops_deinit_per_thread(struct proxy *p, struct flt_conf *fconf)
- *
- * ARGUMENTS
- *   p     - the proxy to which the filter is attached
- *   fconf - the filter configuration
- *
- * DESCRIPTION
- *   It cleans up what the init_per_thread callback has done.  It is called
- *   in the context of a thread, before exiting it.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_ops_deinit_per_thread(struct proxy *p, struct flt_conf *fconf)
-{
-       OTELC_FUNC("%p, %p", p, fconf);
-
-       OTELC_RETURN();
-}
-
-#endif /* DEBUG_OTEL */
-
-
-/***
- * NAME
- *   flt_otel_ops_attach - filter attach callback (flt_ops.attach)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_attach(struct stream *s, struct filter *f)
- *
- * ARGUMENTS
- *   s - the stream to which the filter is being attached
- *   f - the filter instance
- *
- * DESCRIPTION
- *   It is called after a filter instance creation, when it is attached to a
- *   stream.  This happens when the stream is started for filters defined on
- *   the stream's frontend and when the backend is set for filters declared
- *   on the stream's backend.  It is possible to ignore the filter, if needed,
- *   by returning 0.  This could be useful to have conditional filtering.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, 0 to ignore the filter,
- *   any other value otherwise.
- */
-static int flt_otel_ops_attach(struct stream *s, struct filter *f)
-{
-       const struct flt_otel_conf *conf = FLT_OTEL_CONF(f);
-       char                       *err = NULL;
-
-       OTELC_FUNC("%p, %p", s, f);
-
-       /* Skip attachment when the filter is globally disabled. */
-       if (_HA_ATOMIC_LOAD(&(conf->instr->flag_disabled))) {
-               OTELC_DBG(NOTICE, "filter '%s', type: %s (disabled)", conf->id, flt_otel_type(f));
-
-#ifdef FLT_OTEL_USE_COUNTERS
-               _HA_ATOMIC_ADD(FLT_OTEL_CONF(f)->cnt.attached + 2, 1);
-#endif
-
-               OTELC_RETURN_INT(FLT_OTEL_RET_IGNORE);
-       }
-       else if (_HA_ATOMIC_LOAD(&(conf->instr->rate_limit)) < FLT_OTEL_FLOAT_U32(100.0)) {
-               uint32_t rnd = ha_random32();
-               uint32_t rate = _HA_ATOMIC_LOAD(&(conf->instr->rate_limit));
-
-               if (rate <= rnd) {
-                       OTELC_DBG(NOTICE, "filter '%s', type: %s (ignored: %u <= %u)", conf->id, flt_otel_type(f), rate, rnd);
-
-#ifdef FLT_OTEL_USE_COUNTERS
-                       _HA_ATOMIC_ADD(FLT_OTEL_CONF(f)->cnt.attached + 1, 1);
-#endif
-
-                       OTELC_RETURN_INT(FLT_OTEL_RET_IGNORE);
-               }
-       }
-
-       OTELC_DBG(NOTICE, "filter '%s', type: %s (run)", conf->id, flt_otel_type(f));
-
-       /* Create the per-stream runtime context. */
-       f->ctx = flt_otel_runtime_context_init(s, f, &err);
-       FLT_OTEL_ERR_FREE(err);
-       if (f->ctx == NULL) {
-               FLT_OTEL_LOG(LOG_EMERG, "failed to create context");
-
-#ifdef FLT_OTEL_USE_COUNTERS
-               _HA_ATOMIC_ADD(FLT_OTEL_CONF(f)->cnt.attached + 3, 1);
-#endif
-
-               OTELC_RETURN_INT(FLT_OTEL_RET_IGNORE);
-       }
-
-       /*
-        * AN_REQ_WAIT_HTTP and AN_RES_WAIT_HTTP analyzers can only be used
-        * in the .channel_post_analyze callback function.
-        */
-       f->pre_analyzers  |= conf->instr->analyzers & ((AN_REQ_ALL & ~AN_REQ_WAIT_HTTP & ~AN_REQ_HTTP_TARPIT) | (AN_RES_ALL & ~AN_RES_WAIT_HTTP));
-       f->post_analyzers |= conf->instr->analyzers & (AN_REQ_WAIT_HTTP | AN_RES_WAIT_HTTP);
-
-#ifdef FLT_OTEL_USE_COUNTERS
-       _HA_ATOMIC_ADD(FLT_OTEL_CONF(f)->cnt.attached + 0, 1);
-#endif
-       FLT_OTEL_LOG(LOG_INFO, "%08x %08x", f->pre_analyzers, f->post_analyzers);
-
-#ifdef USE_OTEL_VARS
-       flt_otel_vars_dump(s);
-#endif
-       flt_otel_http_headers_dump(&(s->req));
-
-       OTELC_RETURN_INT(FLT_OTEL_RET_OK);
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_stream_start - stream start callback (flt_ops.stream_start)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_stream_start(struct stream *s, struct filter *f)
- *
- * ARGUMENTS
- *   s - the stream that is being started
- *   f - the filter instance
- *
- * DESCRIPTION
- *   It is called when a stream is started.  This callback can fail by returning
- *   a negative value.  It will be considered as a critical error by HAProxy
- *   which disabled the listener for a short time.  After the stream-start
- *   event, it initializes the idle timer in the runtime context from the
- *   precomputed minimum idle_timeout in the instrumentation configuration.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, any other value otherwise.
- */
-static int flt_otel_ops_stream_start(struct stream *s, struct filter *f)
-{
-       const struct flt_otel_conf      *conf = FLT_OTEL_CONF(f);
-       struct flt_otel_runtime_context *rt_ctx;
-       char                            *err = NULL;
-       int                              retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %p", s, f);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, FLT_OTEL_EVENT__STREAM_START)))
-               OTELC_RETURN_INT(retval);
-
-       /* The result of the function is ignored. */
-       (void)flt_otel_event_run(s, f, NULL, FLT_OTEL_EVENT__STREAM_START, &err);
-
-       /*
-        * Initialize the idle timer from the precomputed minimum idle_timeout
-        * in the instrumentation configuration.
-        */
-       if (conf->instr->idle_timeout != 0) {
-               rt_ctx = FLT_OTEL_RT_CTX(f->ctx);
-
-               rt_ctx->idle_timeout = conf->instr->idle_timeout;
-               rt_ctx->idle_exp     = tick_add(now_ms, rt_ctx->idle_timeout);
-
-               s->req.analyse_exp = tick_first(s->req.analyse_exp, rt_ctx->idle_exp);
-       }
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_stream_set_backend - stream set-backend callback (flt_ops.stream_set_backend)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_stream_set_backend(struct stream *s, struct filter *f, struct proxy *be)
- *
- * ARGUMENTS
- *   s  - the stream being processed
- *   f  - the filter instance
- *   be - the backend proxy being assigned
- *
- * DESCRIPTION
- *   It is called when a backend is set for a stream.  This callback will be
- *   called for all filters attached to a stream (frontend and backend).  Note
- *   this callback is not called if the frontend and the backend are the same.
- *   It fires the on-backend-set event.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, any other value otherwise.
- */
-static int flt_otel_ops_stream_set_backend(struct stream *s, struct filter *f, struct proxy *be)
-{
-       char *err = NULL;
-       int   retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %p, %p", s, f, be);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, FLT_OTEL_EVENT__BACKEND_SET)))
-               OTELC_RETURN_INT(retval);
-
-       OTELC_DBG(DEBUG, "backend: %s", be->id);
-
-       (void)flt_otel_event_run(s, f, &(s->req), FLT_OTEL_EVENT__BACKEND_SET, &err);
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_stream_stop - stream stop callback (flt_ops.stream_stop)
- *
- * SYNOPSIS
- *   static void flt_otel_ops_stream_stop(struct stream *s, struct filter *f)
- *
- * ARGUMENTS
- *   s - the stream being stopped
- *   f - the filter instance
- *
- * DESCRIPTION
- *   It is called when a stream is stopped.  This callback always succeed.
- *   Anyway, it is too late to return an error.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_ops_stream_stop(struct stream *s, struct filter *f)
-{
-       char *err = NULL;
-
-       OTELC_FUNC("%p, %p", s, f);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, FLT_OTEL_EVENT__STREAM_STOP)))
-               OTELC_RETURN();
-
-       /* The result of the function is ignored. */
-       (void)flt_otel_event_run(s, f, NULL, FLT_OTEL_EVENT__STREAM_STOP, &err);
-
-       flt_otel_return_void(f, &err);
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_detach - filter detach callback (flt_ops.detach)
- *
- * SYNOPSIS
- *   static void flt_otel_ops_detach(struct stream *s, struct filter *f)
- *
- * ARGUMENTS
- *   s - the stream from which the filter is being detached
- *   f - the filter instance
- *
- * DESCRIPTION
- *   It is called when a filter instance is detached from a stream, before its
- *   destruction.  This happens when the stream is stopped for filters defined
- *   on the stream's frontend and when the analyze ends for filters defined on
- *   the stream's backend.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_ops_detach(struct stream *s, struct filter *f)
-{
-       OTELC_FUNC("%p, %p", s, f);
-
-       OTELC_DBG(NOTICE, "filter '%s', type: %s", FLT_OTEL_CONF(f)->id, flt_otel_type(f));
-
-       flt_otel_runtime_context_free(f);
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_check_timeouts - timeout callback (flt_ops.check_timeouts)
- *
- * SYNOPSIS
- *   static void flt_otel_ops_check_timeouts(struct stream *s, struct filter *f)
- *
- * ARGUMENTS
- *   s - the stream whose timer has expired
- *   f - the filter instance
- *
- * DESCRIPTION
- *   Timeout callback for the filter.  When the idle-timeout timer has expired,
- *   it fires the on-idle-timeout event via flt_otel_event_run() and reschedules
- *   the timer for the next interval.  It also sets the STRM_EVT_MSG pending
- *   event flag on the <s> stream so that the stream processing loop
- *   re-evaluates the message state after the timeout.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_ops_check_timeouts(struct stream *s, struct filter *f)
-{
-       struct flt_otel_runtime_context *rt_ctx;
-       char                            *err = NULL;
-
-       OTELC_FUNC("%p, %p", s, f);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, -1)))
-               OTELC_RETURN();
-
-       rt_ctx = FLT_OTEL_RT_CTX(f->ctx);
-
-       /*
-        * This callback is invoked for every timer event on the stream,
-        * not only for our idle timer.  The filter API provides no way to
-        * distinguish which timer expired, so the tick check below is the only
-        * mechanism to determine whether our idle timer is the one that fired.
-        */
-       if (tick_isset(rt_ctx->idle_exp) && tick_is_expired(rt_ctx->idle_exp, now_ms)) {
-               /* Fire the on-idle-timeout event. */
-               (void)flt_otel_event_run(s, f, &(s->req), FLT_OTEL_EVENT__IDLE_TIMEOUT, &err);
-
-               /* Reschedule the next idle timeout. */
-               rt_ctx->idle_exp = tick_add(now_ms, rt_ctx->idle_timeout);
-
-               /*
-                * Reset analyse_exp if it has expired before merging in the new
-                * idle tick.  Without this, tick_first() would keep returning
-                * the stale expired value, causing the stream task to wake in
-                * a tight loop.
-                */
-               if (tick_is_expired(s->req.analyse_exp, now_ms))
-                       s->req.analyse_exp = TICK_ETERNITY;
-
-               s->req.analyse_exp = tick_first(s->req.analyse_exp, rt_ctx->idle_exp);
-
-               /* Force the request and response analysers to be re-evaluated. */
-               s->pending_events |= STRM_EVT_MSG;
-       }
-
-       flt_otel_return_void(f, &err);
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_channel_start_analyze - channel start-analyze callback
- *
- * SYNOPSIS
- *   static int flt_otel_ops_channel_start_analyze(struct stream *s, struct filter *f, struct channel *chn)
- *
- * ARGUMENTS
- *   s   - the stream being analyzed
- *   f   - the filter instance
- *   chn - the channel on which the analyzing starts
- *
- * DESCRIPTION
- *   Channel start-analyze callback.  It registers the configured analyzers
- *   on the <chn> channel and runs the client or server session-start event
- *   depending on the channel direction.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, 0 if it needs to wait,
- *   any other value otherwise.
- */
-static int flt_otel_ops_channel_start_analyze(struct stream *s, struct filter *f, struct channel *chn)
-{
-       char *err = NULL;
-       int   retval;
-
-       OTELC_FUNC("%p, %p, %p", s, f, chn);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, (chn->flags & CF_ISRESP) ? FLT_OTEL_EVENT_RES_SERVER_SESS_START : FLT_OTEL_EVENT_REQ_CLIENT_SESS_START)))
-               OTELC_RETURN_INT(FLT_OTEL_RET_OK);
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s)", flt_otel_chn_label(chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s));
-
-       if (chn->flags & CF_ISRESP) {
-               /* The response channel. */
-               chn->analysers |= f->pre_analyzers & AN_RES_ALL;
-
-               /* The event 'on-server-session-start'. */
-               retval = flt_otel_event_run(s, f, chn, FLT_OTEL_EVENT_RES_SERVER_SESS_START, &err);
-
-               /*
-                * WAIT is currently never returned by flt_otel_event_run(),
-                * this is kept for defensive purposes only.
-                */
-               if (retval == FLT_OTEL_RET_WAIT) {
-                       channel_dont_read(chn);
-                       channel_dont_close(chn);
-               }
-       } else {
-               /* The request channel. */
-               chn->analysers |= f->pre_analyzers & AN_REQ_ALL;
-
-               /* The event 'on-client-session-start'. */
-               retval = flt_otel_event_run(s, f, chn, FLT_OTEL_EVENT_REQ_CLIENT_SESS_START, &err);
-       }
-
-       /*
-        * Data filter registration is intentionally disabled.  The http_payload
-        * and tcp_payload callbacks are debug-only stubs (registered via
-        * OTELC_DBG_IFDEF) and do not process data.
-        *
-        * register_data_filter(s, chn, f);
-        */
-
-       /*
-        * Propagate the idle-timeout expiry to the channel so the stream task
-        * keeps waking at the configured interval.
-        */
-       if (tick_isset(FLT_OTEL_RT_CTX(f->ctx)->idle_exp))
-               chn->analyse_exp = tick_first(chn->analyse_exp, FLT_OTEL_RT_CTX(f->ctx)->idle_exp);
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-
-/***
- * NAME
- *   flt_otel_get_event - look up an event index by analyzer bit
- *
- * SYNOPSIS
- *   static int flt_otel_get_event(uint an_bit)
- *
- * ARGUMENTS
- *   an_bit - analyzer bit to search for
- *
- * DESCRIPTION
- *   Searches the flt_otel_event_data table for the entry whose an_bit field
- *   matches <an_bit>.
- *
- * RETURN VALUE
- *   Returns the table index on success, FLT_OTEL_RET_ERROR if no match is
- *   found.
- */
-static int flt_otel_get_event(uint an_bit)
-{
-       int i;
-
-       for (i = 0; i < OTELC_TABLESIZE(flt_otel_event_data); i++)
-               if (flt_otel_event_data[i].an_bit == an_bit)
-                       return i;
-
-       return FLT_OTEL_RET_ERROR;
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_channel_pre_analyze - channel pre-analyze callback
- *
- * SYNOPSIS
- *   static int flt_otel_ops_channel_pre_analyze(struct stream *s, struct filter *f, struct channel *chn, uint an_bit)
- *
- * ARGUMENTS
- *   s      - the stream being analyzed
- *   f      - the filter instance
- *   chn    - the channel on which the analyzing is done
- *   an_bit - the analyzer identifier bit
- *
- * DESCRIPTION
- *   Channel pre-analyze callback.  It maps the <an_bit> analyzer bit to an
- *   event index and runs the corresponding event via flt_otel_event_run().
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, 0 if it needs to wait,
- *   any other value otherwise.
- */
-static int flt_otel_ops_channel_pre_analyze(struct stream *s, struct filter *f, struct channel *chn, uint an_bit)
-{
-       char *err = NULL;
-       int   event, retval;
-
-       OTELC_FUNC("%p, %p, %p, 0x%08x", s, f, chn, an_bit);
-
-       event = flt_otel_get_event(an_bit);
-       if (event == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_INT(FLT_OTEL_RET_OK);
-       else if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, event)))
-               OTELC_RETURN_INT(FLT_OTEL_RET_OK);
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s), analyzer: %s", flt_otel_chn_label(chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s), flt_otel_analyzer(an_bit));
-
-       retval = flt_otel_event_run(s, f, chn, event, &err);
-
-       /*
-        * WAIT is currently never returned by flt_otel_event_run(), this is
-        * kept for defensive purposes only.
-        */
-       if ((retval == FLT_OTEL_RET_WAIT) && (chn->flags & CF_ISRESP)) {
-               channel_dont_read(chn);
-               channel_dont_close(chn);
-       }
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_channel_post_analyze - channel post-analyze callback
- *
- * SYNOPSIS
- *   static int flt_otel_ops_channel_post_analyze(struct stream *s, struct filter *f, struct channel *chn, uint an_bit)
- *
- * ARGUMENTS
- *   s      - the stream being analyzed
- *   f      - the filter instance
- *   chn    - the channel on which the analyzing is done
- *   an_bit - the analyzer identifier bit
- *
- * DESCRIPTION
- *   This function, for its part, is not resumable.  It is called when a
- *   filterable analyzer finishes its processing.  So it is called once for
- *   the same analyzer.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, 0 if it needs to wait,
- *   any other value otherwise.
- */
-static int flt_otel_ops_channel_post_analyze(struct stream *s, struct filter *f, struct channel *chn, uint an_bit)
-{
-       char *err = NULL;
-       int   event, retval;
-
-       OTELC_FUNC("%p, %p, %p, 0x%08x", s, f, chn, an_bit);
-
-       event = flt_otel_get_event(an_bit);
-       if (event == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_INT(FLT_OTEL_RET_OK);
-       else if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, event)))
-               OTELC_RETURN_INT(FLT_OTEL_RET_OK);
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s), analyzer: %s", flt_otel_chn_label(chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s), flt_otel_analyzer(an_bit));
-
-       retval = flt_otel_event_run(s, f, chn, event, &err);
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_channel_end_analyze - channel end-analyze callback
- *
- * SYNOPSIS
- *   static int flt_otel_ops_channel_end_analyze(struct stream *s, struct filter *f, struct channel *chn)
- *
- * ARGUMENTS
- *   s   - the stream being analyzed
- *   f   - the filter instance
- *   chn - the channel on which the analyzing ends
- *
- * DESCRIPTION
- *   Channel end-analyze callback.  It runs the client or server session-end
- *   event depending on the <chn> channel direction.  For the request channel,
- *   it also fires the server-unavailable event if response analyzers were
- *   configured but never executed.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, 0 if it needs to wait,
- *   any other value otherwise.
- */
-static int flt_otel_ops_channel_end_analyze(struct stream *s, struct filter *f, struct channel *chn)
-{
-       char *err = NULL;
-       int   rc, retval;
-
-       OTELC_FUNC("%p, %p, %p", s, f, chn);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, (chn->flags & CF_ISRESP) ? FLT_OTEL_EVENT_RES_SERVER_SESS_END : FLT_OTEL_EVENT_REQ_CLIENT_SESS_END)))
-               OTELC_RETURN_INT(FLT_OTEL_RET_OK);
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s)", flt_otel_chn_label(chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s));
-
-       if (chn->flags & CF_ISRESP) {
-               /* The response channel, event 'on-server-session-end'. */
-               retval = flt_otel_event_run(s, f, chn, FLT_OTEL_EVENT_RES_SERVER_SESS_END, &err);
-       } else {
-               /* The request channel, event 'on-client-session-end'. */
-               retval = flt_otel_event_run(s, f, chn, FLT_OTEL_EVENT_REQ_CLIENT_SESS_END, &err);
-
-               /*
-                * In case an event using server response is defined and not
-                * executed, event 'on-server-unavailable' is called here.
-                */
-               if ((FLT_OTEL_CONF(f)->instr->analyzers & AN_RES_ALL) && !(FLT_OTEL_RT_CTX(f->ctx)->analyzers & AN_RES_ALL)) {
-                       rc = flt_otel_event_run(s, f, chn, FLT_OTEL_EVENT_REQ_SERVER_UNAVAILABLE, &err);
-                       if ((retval == FLT_OTEL_RET_OK) && (rc != FLT_OTEL_RET_OK))
-                               retval = rc;
-               }
-       }
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_http_headers - HTTP headers callback (flt_ops.http_headers)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_http_headers(struct stream *s, struct filter *f, struct http_msg *msg)
- *
- * ARGUMENTS
- *   s   - the stream being processed
- *   f   - the filter instance
- *   msg - the HTTP message whose headers are ready
- *
- * DESCRIPTION
- *   HTTP headers callback.  It fires the on-http-headers-request or
- *   on-http-headers-response event depending on the channel direction.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, 0 if it needs to wait,
- *   any other value otherwise.
- */
-static int flt_otel_ops_http_headers(struct stream *s, struct filter *f, struct http_msg *msg)
-{
-       int event = (msg->chn->flags & CF_ISRESP) ? FLT_OTEL_EVENT_RES_HTTP_HEADERS : FLT_OTEL_EVENT_REQ_HTTP_HEADERS;
-       char *err = NULL;
-       int   retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %p, %p", s, f, msg);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, event)))
-               OTELC_RETURN_INT(retval);
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s)", flt_otel_chn_label(msg->chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s));
-
-       (void)flt_otel_event_run(s, f, msg->chn, event, &err);
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-
-#ifdef DEBUG_OTEL
-
-/***
- * NAME
- *   flt_otel_ops_http_payload - HTTP payload callback (flt_ops.http_payload)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_http_payload(struct stream *s, struct filter *f, struct http_msg *msg, uint offset, uint len)
- *
- * ARGUMENTS
- *   s      - the stream being processed
- *   f      - the filter instance
- *   msg    - the HTTP message containing the payload
- *   offset - the offset in the HTX message where data starts
- *   len    - the maximum number of bytes to forward
- *
- * DESCRIPTION
- *   Debug-only HTTP payload callback.  It logs the channel direction, proxy
- *   mode, offset and data length.  No actual data processing is performed.
- *
- * RETURN VALUE
- *   Returns the number of bytes to forward, or a negative value on error.
- */
-static int flt_otel_ops_http_payload(struct stream *s, struct filter *f, struct http_msg *msg, uint offset, uint len)
-{
-       char *err = NULL;
-       int   retval = len;
-
-       OTELC_FUNC("%p, %p, %p, %u, %u", s, f, msg, offset, len);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, -1)))
-               OTELC_RETURN_INT(len);
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s), offset: %u, len: %u, forward: %d", flt_otel_chn_label(msg->chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s), offset, len, retval);
-
-       /* Debug stub -- retval is always len, wakeup is never reached. */
-       if (retval != len)
-               task_wakeup(s->task, TASK_WOKEN_MSG);
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-#endif /* DEBUG_OTEL */
-
-
-/***
- * NAME
- *   flt_otel_ops_http_end - HTTP end callback (flt_ops.http_end)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_http_end(struct stream *s, struct filter *f, struct http_msg *msg)
- *
- * ARGUMENTS
- *   s   - the stream being processed
- *   f   - the filter instance
- *   msg - the HTTP message that has ended
- *
- * DESCRIPTION
- *   HTTP end callback.  It fires the on-http-end-request or
- *   on-http-end-response event depending on the channel direction.
- *
- * RETURN VALUE
- *   Returns a negative value if an error occurs, 0 if it needs to wait,
- *   any other value otherwise.
- */
-static int flt_otel_ops_http_end(struct stream *s, struct filter *f, struct http_msg *msg)
-{
-       int event = (msg->chn->flags & CF_ISRESP) ? FLT_OTEL_EVENT_RES_HTTP_END : FLT_OTEL_EVENT_REQ_HTTP_END;
-       char *err = NULL;
-       int   retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("%p, %p, %p", s, f, msg);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, event)))
-               OTELC_RETURN_INT(retval);
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s)", flt_otel_chn_label(msg->chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s));
-
-       (void)flt_otel_event_run(s, f, msg->chn, event, &err);
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_http_reply - HTTP reply callback (flt_ops.http_reply)
- *
- * SYNOPSIS
- *   static void flt_otel_ops_http_reply(struct stream *s, struct filter *f, short status, const struct buffer *msg)
- *
- * ARGUMENTS
- *   s      - the stream being processed
- *   f      - the filter instance
- *   status - the HTTP status code of the reply
- *   msg    - the reply message buffer, or NULL
- *
- * DESCRIPTION
- *   HTTP reply callback.  It fires the on-http-reply event when HAProxy
- *   generates an internal reply (e.g. error page or deny response).
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_ops_http_reply(struct stream *s, struct filter *f, short status, const struct buffer *msg)
-{
-       char *err = NULL;
-
-       OTELC_FUNC("%p, %p, %hd, %p", s, f, status, msg);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, FLT_OTEL_EVENT_RES_HTTP_REPLY)))
-               OTELC_RETURN();
-
-       OTELC_DBG(DEBUG, "channel: -, mode: %s (%s), status: %hd", flt_otel_pr_mode(s), flt_otel_stream_pos(s), status);
-
-       (void)flt_otel_event_run(s, f, &(s->res), FLT_OTEL_EVENT_RES_HTTP_REPLY, &err);
-
-       flt_otel_return_void(f, &err);
-
-       OTELC_RETURN();
-}
-
-
-#ifdef DEBUG_OTEL
-
-/***
- * NAME
- *   flt_otel_ops_http_reset - HTTP reset callback (flt_ops.http_reset)
- *
- * SYNOPSIS
- *   static void flt_otel_ops_http_reset(struct stream *s, struct filter *f, struct http_msg *msg)
- *
- * ARGUMENTS
- *   s   - the stream being processed
- *   f   - the filter instance
- *   msg - the HTTP message being reset
- *
- * DESCRIPTION
- *   Debug-only HTTP reset callback.  It logs the channel direction and proxy
- *   mode when an HTTP message is reset (e.g. due to a redirect or retry).
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_ops_http_reset(struct stream *s, struct filter *f, struct http_msg *msg)
-{
-       char *err = NULL;
-
-       OTELC_FUNC("%p, %p, %p", s, f, msg);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, -1)))
-               OTELC_RETURN();
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s)", flt_otel_chn_label(msg->chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s));
-
-       flt_otel_return_void(f, &err);
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_ops_tcp_payload - TCP payload callback (flt_ops.tcp_payload)
- *
- * SYNOPSIS
- *   static int flt_otel_ops_tcp_payload(struct stream *s, struct filter *f, struct channel *chn, uint offset, uint len)
- *
- * ARGUMENTS
- *   s      - the stream being processed
- *   f      - the filter instance
- *   chn    - the channel containing the payload data
- *   offset - the offset in the buffer where data starts
- *   len    - the maximum number of bytes to forward
- *
- * DESCRIPTION
- *   Debug-only TCP payload callback.  It logs the channel direction, proxy
- *   mode, offset and data length.  No actual data processing is performed.
- *
- * RETURN VALUE
- *   Returns the number of bytes to forward, or a negative value on error.
- */
-static int flt_otel_ops_tcp_payload(struct stream *s, struct filter *f, struct channel *chn, uint offset, uint len)
-{
-       char *err = NULL;
-       int   retval = len;
-
-       OTELC_FUNC("%p, %p, %p, %u, %u", s, f, chn, offset, len);
-
-       if (flt_otel_is_disabled(f FLT_OTEL_DBG_ARGS(, -1)))
-               OTELC_RETURN_INT(len);
-
-       OTELC_DBG(DEBUG, "channel: %s, mode: %s (%s), offset: %u, len: %u, forward: %d", flt_otel_chn_label(chn), flt_otel_pr_mode(s), flt_otel_stream_pos(s), offset, len, retval);
-
-       /* Debug stub -- no data processing implemented yet. */
-       if (s->flags & SF_HTX) {
-       } else {
-       }
-
-       /* Debug stub -- retval is always len, wakeup is never reached. */
-       if (retval != len)
-               task_wakeup(s->task, TASK_WOKEN_MSG);
-
-       OTELC_RETURN_INT(flt_otel_return_int(f, &err, retval));
-}
-
-#endif /* DEBUG_OTEL */
-
-
-struct flt_ops flt_otel_ops = {
-       /* Callbacks to manage the filter lifecycle. */
-       .init                  = flt_otel_ops_init,
-       .deinit                = flt_otel_ops_deinit,
-       .check                 = flt_otel_ops_check,
-       .init_per_thread       = flt_otel_ops_init_per_thread,
-       .deinit_per_thread     = OTELC_DBG_IFDEF(flt_otel_ops_deinit_per_thread, NULL),
-
-       /* Stream callbacks. */
-       .attach                = flt_otel_ops_attach,
-       .stream_start          = flt_otel_ops_stream_start,
-       .stream_set_backend    = flt_otel_ops_stream_set_backend,
-       .stream_stop           = flt_otel_ops_stream_stop,
-       .detach                = flt_otel_ops_detach,
-       .check_timeouts        = flt_otel_ops_check_timeouts,
-
-       /* Channel callbacks. */
-       .channel_start_analyze = flt_otel_ops_channel_start_analyze,
-       .channel_pre_analyze   = flt_otel_ops_channel_pre_analyze,
-       .channel_post_analyze  = flt_otel_ops_channel_post_analyze,
-       .channel_end_analyze   = flt_otel_ops_channel_end_analyze,
-
-       /* HTTP callbacks. */
-       .http_headers          = flt_otel_ops_http_headers,
-       .http_payload          = OTELC_DBG_IFDEF(flt_otel_ops_http_payload, NULL),
-       .http_end              = flt_otel_ops_http_end,
-       .http_reset            = OTELC_DBG_IFDEF(flt_otel_ops_http_reset, NULL),
-       .http_reply            = flt_otel_ops_http_reply,
-
-       /* TCP callbacks. */
-       .tcp_payload           = OTELC_DBG_IFDEF(flt_otel_ops_tcp_payload, NULL)
-};
-
-
-/* Advertise OTel support in haproxy -vv output. */
-REGISTER_BUILD_OPTS("Built with OpenTelemetry support (C++ version " OTELCPP_VERSION ", C Wrapper version " OTELC_VERSION ").");
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/group.c b/addons/otel/src/group.c
deleted file mode 100644 (file)
index 44fb7d9..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-/* Group data table built from the X-macro list. */
-#define FLT_OTEL_GROUP_DEF(a,b,c)   { a, b, c },
-const struct flt_otel_group_data flt_otel_group_data[] = { FLT_OTEL_GROUP_DEFINES };
-#undef FLT_OTEL_GROUP_DEF
-
-
-/***
- * NAME
- *   flt_otel_group_action - group action execution callback
- *
- * SYNOPSIS
- *   static enum act_return flt_otel_group_action(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int opts)
- *
- * ARGUMENTS
- *   rule - action rule containing group configuration references
- *   px   - proxy instance
- *   sess - current session
- *   s    - current stream
- *   opts - action options (ACT_OPT_* flags)
- *
- * DESCRIPTION
- *   Executes the action_ptr callback for the FLT_OTEL_ACTION_GROUP action.
- *   Retrieves the filter configuration, group definition, and runtime context
- *   from the rule's argument pointers.  If the filter is disabled or not
- *   attached to the stream, processing is skipped.  Otherwise, iterates over
- *   all scopes defined in the group and runs each via flt_otel_scope_run().
- *   Scope execution errors are logged but do not prevent the remaining scopes
- *   from executing.
- *
- * RETURN VALUE
- *   Returns ACT_RET_CONT.
- */
-static enum act_return flt_otel_group_action(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int opts)
-{
-       const struct filter                   *filter;
-       const struct flt_conf                 *fconf;
-       const struct flt_otel_conf            *conf;
-       const struct flt_otel_conf_group      *conf_group;
-       const struct flt_otel_runtime_context *rt_ctx = NULL;
-       const struct flt_otel_conf_ph         *ph_scope;
-       char                                  *err = NULL;
-       int                                    i, rc;
-
-       OTELC_FUNC("%p, %p, %p, %p, %d", rule, px, sess, s, opts);
-
-       OTELC_DBG(DEBUG, "from: %d, arg.act %p:{ %p %p %p %p }", rule->from, &(rule->arg.act), rule->arg.act.p[0], rule->arg.act.p[1], rule->arg.act.p[2], rule->arg.act.p[3]);
-
-       fconf      = rule->arg.act.p[FLT_OTEL_ARG_FLT_CONF];
-       conf       = rule->arg.act.p[FLT_OTEL_ARG_CONF];
-       conf_group = ((const struct flt_otel_conf_ph *)(rule->arg.act.p[FLT_OTEL_ARG_GROUP]))->ptr;
-
-       if ((fconf == NULL) || (conf == NULL) || (conf_group == NULL)) {
-               FLT_OTEL_LOG(LOG_ERR, FLT_OTEL_ACTION_GROUP ": internal error, invalid group action");
-
-               OTELC_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
-       }
-
-       if (_HA_ATOMIC_LOAD(&(conf->instr->flag_disabled))) {
-               OTELC_DBG(INFO, "filter '%s' disabled, group action '%s' ignored", conf->id, conf_group->id);
-
-               OTELC_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
-       }
-
-       /* Find the OpenTelemetry filter instance from the current stream. */
-       list_for_each_entry(filter, &(s->strm_flt.filters), list)
-               if (filter->config == fconf) {
-                       rt_ctx = filter->ctx;
-
-                       break;
-               }
-
-       if (rt_ctx == NULL) {
-               OTELC_DBG(INFO, "cannot find filter, probably not attached to the stream");
-
-               OTELC_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
-       }
-       else if (flt_otel_is_disabled(filter FLT_OTEL_DBG_ARGS(, -1))) {
-               OTELC_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
-       }
-       else {
-               OTELC_DBG(DEBUG, "run group '%s'", conf_group->id);
-               FLT_OTEL_DBG_CONF_GROUP("run group ", conf_group);
-       }
-
-       /*
-        * Check the value of rule->from; in case it is incorrect,
-        * report an error.
-        */
-       for (i = 0; i < OTELC_TABLESIZE(flt_otel_group_data); i++)
-               if (flt_otel_group_data[i].act_from == rule->from)
-                       break;
-
-       if (i >= OTELC_TABLESIZE(flt_otel_group_data)) {
-               FLT_OTEL_LOG(LOG_ERR, FLT_OTEL_ACTION_GROUP ": internal error, invalid rule->from=%d", rule->from);
-
-               OTELC_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
-       }
-
-       /* Execute each scope defined in this group. */
-       list_for_each_entry(ph_scope, &(conf_group->ph_scopes), list) {
-               rc = flt_otel_scope_run(s, rt_ctx->filter, (flt_otel_group_data[i].smp_opt_dir == SMP_OPT_DIR_REQ) ? &(s->req) : &(s->res), ph_scope->ptr, NULL, NULL, flt_otel_group_data[i].smp_opt_dir, &err);
-               if ((rc == FLT_OTEL_RET_ERROR) && (opts & ACT_OPT_FINAL)) {
-                       FLT_OTEL_LOG(LOG_ERR, FLT_OTEL_ACTION_GROUP ": scope '%s' failed in group '%s'", ph_scope->id, conf_group->id);
-                       OTELC_SFREE_CLEAR(err);
-               }
-       }
-
-       OTELC_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
-}
-
-
-/***
- * NAME
- *   flt_otel_group_check - group action post-parse check callback
- *
- * SYNOPSIS
- *   static int flt_otel_group_check(struct act_rule *rule, struct proxy *px, char **err)
- *
- * ARGUMENTS
- *   rule - action rule to validate
- *   px   - proxy instance
- *   err  - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Validates the check_ptr callback for the FLT_OTEL_ACTION_GROUP action.
- *   Resolves the filter ID and group ID string references stored during parsing
- *   into direct pointers to the filter configuration and group configuration
- *   structures.  Searches the proxy's filter list for a matching OTel filter,
- *   then locates the named group within that filter's configuration.  On
- *   success, replaces the string ID pointers in <rule>->arg.act.p with the
- *   resolved configuration pointers.
- *
- * RETURN VALUE
- *   Returns 1 on success, or 0 on failure with <err> filled.
- */
-static int flt_otel_group_check(struct act_rule *rule, struct proxy *px, char **err)
-{
-       struct flt_conf         *fconf_tmp, *fconf = NULL;
-       struct flt_otel_conf    *conf;
-       struct flt_otel_conf_ph *ph_group;
-       const char              *filter_id;
-       const char              *group_id;
-       bool                     flag_found = 0;
-       int                      i;
-
-       OTELC_FUNC("%p, %p, %p:%p", rule, px, OTELC_DPTR_ARGS(err));
-
-       filter_id = rule->arg.act.p[FLT_OTEL_ARG_FILTER_ID];
-       group_id  = rule->arg.act.p[FLT_OTEL_ARG_GROUP_ID];
-
-       OTELC_DBG(NOTICE, "checking filter_id='%s', group_id='%s'", filter_id, group_id);
-
-       /*
-        * Check the value of rule->from; in case it is incorrect, report an
-        * error.
-        */
-       for (i = 0; i < OTELC_TABLESIZE(flt_otel_group_data); i++)
-               if (flt_otel_group_data[i].act_from == rule->from)
-                       break;
-
-       if (i >= OTELC_TABLESIZE(flt_otel_group_data)) {
-               FLT_OTEL_ERR("internal error, unexpected rule->from=%d, please report this bug!", rule->from);
-
-               OTELC_RETURN_INT(0);
-       }
-
-       /*
-        * Try to find the OpenTelemetry filter by checking all filters for the
-        * proxy <px>.
-        */
-       list_for_each_entry(fconf_tmp, &(px->filter_configs), list) {
-               conf = fconf_tmp->conf;
-
-               if (fconf_tmp->id != otel_flt_id) {
-                       /* This is not an OpenTelemetry filter. */
-                       continue;
-               }
-               else if (strcmp(conf->id, filter_id) == 0) {
-                       /* This is the good filter ID. */
-                       fconf = fconf_tmp;
-
-                       break;
-               }
-       }
-
-       if (fconf == NULL) {
-               FLT_OTEL_ERR("unable to find the OpenTelemetry filter '%s' used by the " FLT_OTEL_ACTION_GROUP " '%s'", filter_id, group_id);
-
-               OTELC_RETURN_INT(0);
-       }
-
-       /*
-        * Attempt to find if the group is defined in the OpenTelemetry filter
-        * configuration.
-        */
-       list_for_each_entry(ph_group, &(conf->instr->ph_groups), list)
-               if (strcmp(ph_group->id, group_id) == 0) {
-                       flag_found = 1;
-
-                       break;
-               }
-
-       if (!flag_found) {
-               FLT_OTEL_ERR("unable to find group '%s' in the OpenTelemetry filter '%s' configuration", group_id, filter_id);
-
-               OTELC_RETURN_INT(0);
-       }
-
-       OTELC_SFREE_CLEAR(rule->arg.act.p[FLT_OTEL_ARG_FILTER_ID]);
-       OTELC_SFREE_CLEAR(rule->arg.act.p[FLT_OTEL_ARG_GROUP_ID]);
-
-       /* Replace string IDs with resolved configuration pointers. */
-       rule->arg.act.p[FLT_OTEL_ARG_FLT_CONF] = fconf;
-       rule->arg.act.p[FLT_OTEL_ARG_CONF]     = conf;
-       rule->arg.act.p[FLT_OTEL_ARG_GROUP]    = ph_group;
-
-       OTELC_RETURN_INT(1);
-}
-
-
-/***
- * NAME
- *   flt_otel_group_release - group action release callback
- *
- * SYNOPSIS
- *   static void flt_otel_group_release(struct act_rule *rule)
- *
- * ARGUMENTS
- *   rule - action rule being released
- *
- * DESCRIPTION
- *   Provides the release_ptr callback for the FLT_OTEL_ACTION_GROUP action.
- *   This is a no-op because the group action's argument pointers reference
- *   shared configuration structures that are freed separately during filter
- *   deinitialization.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_group_release(struct act_rule *rule)
-{
-       OTELC_FUNC("%p", rule);
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_group_parse - group action keyword parser
- *
- * SYNOPSIS
- *   static enum act_parse_ret flt_otel_group_parse(const char **args, int *cur_arg, struct proxy *px, struct act_rule *rule, char **err)
- *
- * ARGUMENTS
- *   args    - configuration line arguments array
- *   cur_arg - pointer to the current argument index
- *   px      - proxy instance
- *   rule    - action rule to populate
- *   err     - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses the FLT_OTEL_ACTION_GROUP action keyword from HAProxy configuration
- *   rules.  Expects two arguments: a filter ID and a group ID, optionally
- *   followed by "if" or "unless" conditions.  The filter ID and group ID are
- *   duplicated and stored in the <rule>'s argument pointers for later
- *   resolution by flt_otel_group_check().  The <rule>'s callbacks are set to
- *   flt_otel_group_action(), flt_otel_group_check(), and
- *   flt_otel_group_release().  This parser is registered for tcp-request,
- *   tcp-response, http-request, http-response, and http-after-response action
- *   contexts.
- *
- * RETURN VALUE
- *   Returns ACT_RET_PRS_OK on success, or ACT_RET_PRS_ERR on failure.
- */
-static enum act_parse_ret flt_otel_group_parse(const char **args, int *cur_arg, struct proxy *px, struct act_rule *rule, char **err)
-{
-       OTELC_FUNC("%p, %p, %p, %p, %p:%p", args, cur_arg, px, rule, OTELC_DPTR_ARGS(err));
-
-       FLT_OTEL_ARGS_DUMP();
-
-       if (!FLT_OTEL_ARG_ISVALID(*cur_arg) || !FLT_OTEL_ARG_ISVALID(*cur_arg + 1) ||
-           (FLT_OTEL_ARG_ISVALID(*cur_arg + 2) &&
-            !FLT_OTEL_PARSE_KEYWORD(*cur_arg + 2, FLT_OTEL_CONDITION_IF) &&
-            !FLT_OTEL_PARSE_KEYWORD(*cur_arg + 2, FLT_OTEL_CONDITION_UNLESS))) {
-               FLT_OTEL_ERR("expects: <filter-id> <group-id> [{ if | unless } ...]");
-
-               OTELC_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d");
-       }
-
-       /* Copy the OpenTelemetry filter id. */
-       rule->arg.act.p[FLT_OTEL_ARG_FILTER_ID] = OTELC_STRDUP(args[*cur_arg]);
-       if (rule->arg.act.p[FLT_OTEL_ARG_FILTER_ID] == NULL) {
-               FLT_OTEL_ERR("%s : out of memory", args[*cur_arg]);
-
-               OTELC_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d");
-       }
-
-       /* Copy the OpenTelemetry group id. */
-       rule->arg.act.p[FLT_OTEL_ARG_GROUP_ID] = OTELC_STRDUP(args[*cur_arg + 1]);
-       if (rule->arg.act.p[FLT_OTEL_ARG_GROUP_ID] == NULL) {
-               FLT_OTEL_ERR("%s : out of memory", args[*cur_arg + 1]);
-
-               OTELC_SFREE_CLEAR(rule->arg.act.p[FLT_OTEL_ARG_FILTER_ID]);
-
-               OTELC_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d");
-       }
-
-       /* Wire up the rule callbacks. */
-       rule->action      = ACT_CUSTOM;
-       rule->action_ptr  = flt_otel_group_action;
-       rule->check_ptr   = flt_otel_group_check;
-       rule->release_ptr = flt_otel_group_release;
-
-       *cur_arg += 2;
-
-       OTELC_RETURN_EX(ACT_RET_PRS_OK, enum act_parse_ret, "%d");
-}
-
-
-/* TCP request content action keywords for the OTel group action. */
-static struct action_kw_list tcp_req_action_kws = { ILH, {
-               { FLT_OTEL_ACTION_GROUP, flt_otel_group_parse },
-               { /* END */ },
-       }
-};
-
-INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_action_kws);
-
-/* TCP response content action keywords for the OTel group action. */
-static struct action_kw_list tcp_res_action_kws = { ILH, {
-               { FLT_OTEL_ACTION_GROUP, flt_otel_group_parse },
-               { /* END */ },
-       }
-};
-
-INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_action_kws);
-
-/* HTTP request action keywords for the OTel group action. */
-static struct action_kw_list http_req_action_kws = { ILH, {
-               { FLT_OTEL_ACTION_GROUP, flt_otel_group_parse },
-               { /* END */ },
-       }
-};
-
-INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_action_kws);
-
-/* HTTP response action keywords for the OTel group action. */
-static struct action_kw_list http_res_action_kws = { ILH, {
-               { FLT_OTEL_ACTION_GROUP, flt_otel_group_parse },
-               { /* END */ },
-       }
-};
-
-INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_action_kws);
-
-/* HTTP after-response action keywords for the OTel group action. */
-static struct action_kw_list http_after_res_actions_kws = { ILH, {
-               { FLT_OTEL_ACTION_GROUP, flt_otel_group_parse },
-               { /* END */ },
-       }
-};
-
-INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_actions_kws);
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/http.c b/addons/otel/src/http.c
deleted file mode 100644 (file)
index 511747c..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-#ifdef DEBUG_OTEL
-
-/***
- * NAME
- *   flt_otel_http_headers_dump - debug HTTP headers dump
- *
- * SYNOPSIS
- *   void flt_otel_http_headers_dump(const struct channel *chn)
- *
- * ARGUMENTS
- *   chn - channel to dump HTTP headers from
- *
- * DESCRIPTION
- *   Dumps all HTTP headers from the channel's HTX buffer.  Iterates over HTX
- *   blocks, logging each header name-value pair at NOTICE level.  Processing
- *   stops at the end-of-headers marker.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_http_headers_dump(const struct channel *chn)
-{
-       const struct htx *htx;
-       int32_t           pos;
-
-       OTELC_FUNC("%p", chn);
-
-       if (chn == NULL)
-               OTELC_RETURN();
-
-       htx = htxbuf(&(chn->buf));
-
-       if (htx_is_empty(htx))
-               OTELC_RETURN();
-
-       /* Walk HTX blocks and log each header until end-of-headers. */
-       for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
-               struct htx_blk    *blk  = htx_get_blk(htx, pos);
-               enum htx_blk_type  type = htx_get_blk_type(blk);
-
-               if (type == HTX_BLK_HDR) {
-                       struct ist n = htx_get_blk_name(htx, blk);
-                       struct ist v = htx_get_blk_value(htx, blk);
-
-                       OTELC_DBG(NOTICE, "'%.*s: %.*s'", (int)n.len, n.ptr, (int)v.len, v.ptr);
-               }
-               else if (type == HTX_BLK_EOH)
-                       break;
-       }
-
-       OTELC_RETURN();
-}
-
-#endif /* DEBUG_OTEL */
-
-
-/***
- * NAME
- *   flt_otel_http_headers_get - HTTP header extraction to text map
- *
- * SYNOPSIS
- *   struct otelc_text_map *flt_otel_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err)
- *
- * ARGUMENTS
- *   chn    - channel containing HTTP headers
- *   prefix - header name prefix to match (or NULL for all)
- *   len    - length of the prefix string
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Extracts HTTP headers matching a <prefix> from the channel's HTX buffer
- *   into a newly allocated text map.  When <prefix> is NULL or its length is
- *   zero, all headers are extracted.  If the prefix starts with
- *   FLT_OTEL_PARSE_CTX_IGNORE_NAME, prefix matching is bypassed.  The prefix
- *   (including the separator dash) is stripped from header names before storing
- *   in the text map.  Empty header values are replaced with an empty string to
- *   avoid misinterpretation by otelc_text_map_add().  This function is used by
- *   the "extract" keyword to read span context from incoming request headers.
- *
- * RETURN VALUE
- *   Returns a pointer to the populated text map, or NULL on failure or when
- *   no matching headers are found.
- */
-struct otelc_text_map *flt_otel_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err)
-{
-       const struct htx    *htx;
-       size_t               prefix_len = (!OTELC_STR_IS_VALID(prefix) || (len == 0)) ? 0 : (len + 1);
-       int32_t              pos;
-       struct otelc_text_map *retptr = NULL;
-
-       OTELC_FUNC("%p, \"%s\", %zu, %p:%p", chn, OTELC_STR_ARG(prefix), len, OTELC_DPTR_ARGS(err));
-
-       if (chn == NULL)
-               OTELC_RETURN_PTR(retptr);
-
-       /*
-        * The keyword 'inject' allows you to define the name of the OpenTelemetry
-        * context without using a prefix.  In that case all HTTP headers are
-        * transferred because it is not possible to separate them from the
-        * OpenTelemetry context (this separation is usually done via a prefix).
-        *
-        * When using the 'extract' keyword, the context name must be specified.
-        * To allow all HTTP headers to be extracted, the first character of
-        * that name must be set to FLT_OTEL_PARSE_CTX_IGNORE_NAME.
-        */
-       if (OTELC_STR_IS_VALID(prefix) && (*prefix == FLT_OTEL_PARSE_CTX_IGNORE_NAME))
-               prefix_len = 0;
-
-       htx = htxbuf(&(chn->buf));
-
-       for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
-               struct htx_blk    *blk  = htx_get_blk(htx, pos);
-               enum htx_blk_type  type = htx_get_blk_type(blk);
-
-               if (type == HTX_BLK_HDR) {
-                       struct ist v, n = htx_get_blk_name(htx, blk);
-
-                       if ((prefix_len == 0) || ((n.len >= prefix_len) && (strncasecmp(n.ptr, prefix, len) == 0))) {
-                               if (retptr == NULL) {
-                                       retptr = OTELC_TEXT_MAP_NEW(NULL, 8);
-                                       if (retptr == NULL) {
-                                               FLT_OTEL_ERR("failed to create HTTP header data");
-
-                                               break;
-                                       }
-                               }
-
-                               v = htx_get_blk_value(htx, blk);
-
-                               /*
-                                * In case the data of the HTTP header is not
-                                * specified, v.ptr will have some non-null
-                                * value and v.len will be equal to 0.  The
-                                * otelc_text_map_add() function will not
-                                * interpret this well.  In this case v.ptr
-                                * is set to an empty string.
-                                */
-                               if (v.len == 0)
-                                       v = ist("");
-
-                               /*
-                                * Here, an HTTP header (which is actually part
-                                * of the span context) is added to the text_map.
-                                *
-                                * Before adding, the prefix is removed from the
-                                * HTTP header name.
-                                */
-                               if (OTELC_TEXT_MAP_ADD(retptr, n.ptr + prefix_len, n.len - prefix_len, v.ptr, v.len, OTELC_TEXT_MAP_AUTO) == -1) {
-                                       FLT_OTEL_ERR("failed to add HTTP header data");
-
-                                       otelc_text_map_destroy(&retptr);
-
-                                       break;
-                               }
-                       }
-               }
-               else if (type == HTX_BLK_EOH)
-                       break;
-       }
-
-       OTELC_TEXT_MAP_DUMP(retptr, "extracted HTTP headers");
-
-       if ((retptr != NULL) && (retptr->count == 0)) {
-               OTELC_DBG(NOTICE, "WARNING: no HTTP headers found");
-
-               otelc_text_map_destroy(&retptr);
-       }
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_http_header_set - HTTP header set or remove
- *
- * SYNOPSIS
- *   int flt_otel_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err)
- *
- * ARGUMENTS
- *   chn    - channel containing HTTP headers
- *   prefix - header name prefix (or NULL)
- *   name   - header name suffix (or NULL)
- *   value  - header value to set (or NULL to remove only)
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Sets or removes an HTTP header in the channel's HTX buffer.  The full
- *   header name is constructed by combining <prefix> and <name> with a dash
- *   separator; if only one is provided, it is used directly.  All existing
- *   occurrences of the header are removed first.  If <name> is NULL, all
- *   headers starting with <prefix> are removed.  If <value> is non-NULL, the
- *   header is then added with the new value.  A NULL <value> causes only the
- *   removal, with no subsequent addition.
- *
- * RETURN VALUE
- *   Returns 0 on success, or FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err)
-{
-       struct http_hdr_ctx  ctx = { .blk = NULL };
-       struct ist           ist_name;
-       struct buffer       *buffer = NULL;
-       struct htx          *htx;
-       int                  retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("%p, \"%s\", \"%s\", \"%s\", %p:%p", chn, OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), OTELC_STR_ARG(value), OTELC_DPTR_ARGS(err));
-
-       if ((chn == NULL) || (!OTELC_STR_IS_VALID(prefix) && !OTELC_STR_IS_VALID(name)))
-               OTELC_RETURN_INT(retval);
-
-       htx = htxbuf(&(chn->buf));
-
-       /*
-        * Very rare (about 1% of cases), htx is empty.
-        * In order to avoid segmentation fault, we exit this function.
-        */
-       if (htx_is_empty(htx)) {
-               FLT_OTEL_ERR("HTX is empty");
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       if (!OTELC_STR_IS_VALID(prefix)) {
-               ist_name = ist2((char *)name, strlen(name));
-       }
-       else if (!OTELC_STR_IS_VALID(name)) {
-               ist_name = ist2((char *)prefix, strlen(prefix));
-       }
-       else {
-               buffer = flt_otel_trash_alloc(0, err);
-               if (buffer == NULL)
-                       OTELC_RETURN_INT(retval);
-
-               (void)chunk_printf(buffer, "%s-%s", prefix, name);
-
-               ist_name = ist2(buffer->area, buffer->data);
-       }
-
-       /* Remove all occurrences of the header. */
-       while (http_find_header(htx, ist(""), &ctx, 1) == 1) {
-               struct ist n = htx_get_blk_name(htx, ctx.blk);
-#ifdef DEBUG_OTEL
-               struct ist v = htx_get_blk_value(htx, ctx.blk);
-#endif
-
-               /*
-                * If the <name> parameter is not set, then remove all headers
-                * that start with the contents of the <prefix> parameter.
-                */
-               if (!OTELC_STR_IS_VALID(name))
-                       n.len = ist_name.len;
-
-               if (isteqi(n, ist_name))
-                       if (http_remove_header(htx, &ctx) == 1)
-                               OTELC_DBG(DEBUG, "HTTP header '%.*s: %.*s' removed", (int)n.len, n.ptr, (int)v.len, v.ptr);
-       }
-
-       /*
-        * If the value pointer has a value of NULL, the HTTP header is not set
-        * after deletion.
-        */
-       if (value == NULL) {
-               retval = 0;
-       }
-       else if (http_add_header(htx, ist_name, ist(value), 1) == 1) {
-               retval = 0;
-
-               OTELC_DBG(DEBUG, "HTTP header '%s: %s' added", ist_name.ptr, value);
-       }
-       else {
-               FLT_OTEL_ERR("failed to set HTTP header '%s: %s'", ist_name.ptr, value);
-       }
-
-       flt_otel_trash_free(&buffer);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_http_headers_remove - HTTP headers removal by prefix
- *
- * SYNOPSIS
- *   int flt_otel_http_headers_remove(struct channel *chn, const char *prefix, char **err)
- *
- * ARGUMENTS
- *   chn    - channel containing HTTP headers
- *   prefix - header name prefix to match for removal
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Removes all HTTP headers matching the given <prefix> from the channel's HTX
- *   buffer.  This is a convenience wrapper around flt_otel_http_header_set()
- *   with NULL <name> and <value> arguments.
- *
- * RETURN VALUE
- *   Returns 0 on success, or FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_http_headers_remove(struct channel *chn, const char *prefix, char **err)
-{
-       int retval;
-
-       OTELC_FUNC("%p, \"%s\", %p:%p", chn, OTELC_STR_ARG(prefix), OTELC_DPTR_ARGS(err));
-
-       retval = flt_otel_http_header_set(chn, prefix, NULL, NULL, err);
-
-       OTELC_RETURN_INT(retval);
-}
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/otelc.c b/addons/otel/src/otelc.c
deleted file mode 100644 (file)
index 6933800..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-/***
- * NAME
- *   flt_otel_text_map_writer_set_cb - text map injection writer callback
- *
- * SYNOPSIS
- *   static int flt_otel_text_map_writer_set_cb(struct otelc_text_map_writer *writer, const char *key, const char *value)
- *
- * ARGUMENTS
- *   writer - text map writer instance
- *   key    - context key name
- *   value  - context key value
- *
- * DESCRIPTION
- *   Writer callback for text map injection.  Called by the OTel C wrapper
- *   library during span context injection to store each key-value pair in the
- *   <writer>'s text map.
- *
- * RETURN VALUE
- *   Returns the result of OTELC_TEXT_MAP_ADD().
- */
-static int flt_otel_text_map_writer_set_cb(struct otelc_text_map_writer *writer, const char *key, const char *value)
-{
-       OTELC_FUNC("%p, \"%s\", \"%s\"", writer, OTELC_STR_ARG(key), OTELC_STR_ARG(value));
-
-       OTELC_RETURN_INT(OTELC_TEXT_MAP_ADD(&(writer->text_map), key, 0, value, 0, OTELC_TEXT_MAP_AUTO));
-}
-
-
-/***
- * NAME
- *   flt_otel_http_headers_writer_set_cb - HTTP headers injection writer callback
- *
- * SYNOPSIS
- *   static int flt_otel_http_headers_writer_set_cb(struct otelc_http_headers_writer *writer, const char *key, const char *value)
- *
- * ARGUMENTS
- *   writer - HTTP headers writer instance
- *   key    - context key name
- *   value  - context key value
- *
- * DESCRIPTION
- *   Writer callback for HTTP headers injection.  Called by the OTel C wrapper
- *   library during span context injection to store each key-value pair in the
- *   <writer>'s text map.
- *
- * RETURN VALUE
- *   Returns the result of OTELC_TEXT_MAP_ADD().
- */
-static int flt_otel_http_headers_writer_set_cb(struct otelc_http_headers_writer *writer, const char *key, const char *value)
-{
-       OTELC_FUNC("%p, \"%s\", \"%s\"", writer, OTELC_STR_ARG(key), OTELC_STR_ARG(value));
-
-       OTELC_RETURN_INT(OTELC_TEXT_MAP_ADD(&(writer->text_map), key, 0, value, 0, OTELC_TEXT_MAP_AUTO));
-}
-
-
-/***
- * NAME
- *   flt_otel_inject_text_map - text map context injection
- *
- * SYNOPSIS
- *   int flt_otel_inject_text_map(const struct otelc_span *span, struct otelc_text_map_writer *carrier)
- *
- * ARGUMENTS
- *   span    - span instance to inject context from
- *   carrier - text map writer carrier
- *
- * DESCRIPTION
- *   Injects the span context into a text map carrier.  Initializes the
- *   <carrier> structure, sets the writer callback to
- *   flt_otel_text_map_writer_set_cb(), and delegates to the <span>'s
- *   inject_text_map() method.
- *
- * RETURN VALUE
- *   Returns the result of the <span>'s inject_text_map() method,
- *   or FLT_OTEL_RET_ERROR if arguments are NULL.
- */
-int flt_otel_inject_text_map(const struct otelc_span *span, struct otelc_text_map_writer *carrier)
-{
-       OTELC_FUNC("%p, %p", span, carrier);
-
-       if ((span == NULL) || (carrier == NULL))
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-       (void)memset(carrier, 0, sizeof(*carrier));
-       carrier->set = flt_otel_text_map_writer_set_cb;
-
-       OTELC_RETURN_INT(OTELC_OPS(span, inject_text_map, carrier));
-}
-
-
-/***
- * NAME
- *   flt_otel_inject_http_headers - HTTP headers context injection
- *
- * SYNOPSIS
- *   int flt_otel_inject_http_headers(const struct otelc_span *span, struct otelc_http_headers_writer *carrier)
- *
- * ARGUMENTS
- *   span    - span instance to inject context from
- *   carrier - HTTP headers writer carrier
- *
- * DESCRIPTION
- *   Injects the span context into an HTTP headers carrier.  Initializes the
- *   <carrier> structure, sets the writer callback to
- *   flt_otel_http_headers_writer_set_cb(), and delegates to the <span>'s
- *   inject_http_headers() method.
- *
- * RETURN VALUE
- *   Returns the result of the <span>'s inject_http_headers() method,
- *   or FLT_OTEL_RET_ERROR if arguments are NULL.
- */
-int flt_otel_inject_http_headers(const struct otelc_span *span, struct otelc_http_headers_writer *carrier)
-{
-       OTELC_FUNC("%p, %p", span, carrier);
-
-       if ((span == NULL) || (carrier == NULL))
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-       (void)memset(carrier, 0, sizeof(*carrier));
-       carrier->set = flt_otel_http_headers_writer_set_cb;
-
-       OTELC_RETURN_INT(OTELC_OPS(span, inject_http_headers, carrier));
-}
-
-
-/***
- * NAME
- *   flt_otel_text_map_reader_foreach_key_cb - text map extraction reader callback
- *
- * SYNOPSIS
- *   static int flt_otel_text_map_reader_foreach_key_cb(const struct otelc_text_map_reader *reader, int (*handler)(void *arg, const char *key, const char *value), void *arg)
- *
- * ARGUMENTS
- *   reader  - text map reader instance
- *   handler - callback function invoked for each key-value pair
- *   arg     - opaque argument passed to the handler
- *
- * DESCRIPTION
- *   Reader callback for text map extraction.  Iterates over all key-value
- *   pairs in the <reader>'s text map and invokes <handler> for each.  Iteration
- *   stops if the <handler> returns -1.
- *
- * RETURN VALUE
- *   Returns the last <handler> return value, or 0 if the text map is empty.
- */
-static int flt_otel_text_map_reader_foreach_key_cb(const struct otelc_text_map_reader *reader, int (*handler)(void *arg, const char *key, const char *value), void *arg)
-{
-       size_t i;
-       int    retval = 0;
-
-       OTELC_FUNC("%p, %p, %p", reader, handler, arg);
-
-       for (i = 0; (retval != -1) && (i < reader->text_map.count); i++) {
-               OTELC_DBG(OTELC, "\"%s\" -> \"%s\"", OTELC_STR_ARG(reader->text_map.key[i]), OTELC_STR_ARG(reader->text_map.value[i]));
-
-               retval = handler(arg, reader->text_map.key[i], reader->text_map.value[i]);
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_http_headers_reader_foreach_key_cb - HTTP headers extraction reader callback
- *
- * SYNOPSIS
- *   static int flt_otel_http_headers_reader_foreach_key_cb(const struct otelc_http_headers_reader *reader, int (*handler)(void *arg, const char *key, const char *value), void *arg)
- *
- * ARGUMENTS
- *   reader  - HTTP headers reader instance
- *   handler - callback function invoked for each key-value pair
- *   arg     - opaque argument passed to the handler
- *
- * DESCRIPTION
- *   Reader callback for HTTP headers extraction.  Iterates over all key-value
- *   pairs in the <reader>'s text map and invokes <handler> for each.  Iteration
- *   stops if the <handler> returns -1.
- *
- * RETURN VALUE
- *   Returns the last <handler> return value, or 0 if the text map is empty.
- */
-static int flt_otel_http_headers_reader_foreach_key_cb(const struct otelc_http_headers_reader *reader, int (*handler)(void *arg, const char *key, const char *value), void *arg)
-{
-       size_t i;
-       int    retval = 0;
-
-       OTELC_FUNC("%p, %p, %p", reader, handler, arg);
-
-       for (i = 0; (retval != -1) && (i < reader->text_map.count); i++) {
-               OTELC_DBG(OTELC, "\"%s\" -> \"%s\"", OTELC_STR_ARG(reader->text_map.key[i]), OTELC_STR_ARG(reader->text_map.value[i]));
-
-               retval = handler(arg, reader->text_map.key[i], reader->text_map.value[i]);
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_extract_text_map - text map context extraction
- *
- * SYNOPSIS
- *   struct otelc_span_context *flt_otel_extract_text_map(struct otelc_tracer *tracer, struct otelc_text_map_reader *carrier, const struct otelc_text_map *text_map)
- *
- * ARGUMENTS
- *   tracer   - OTel tracer instance
- *   carrier  - text map reader carrier
- *   text_map - text map containing the context data (or NULL)
- *
- * DESCRIPTION
- *   Extracts a span context from a text map carrier via the <tracer>.
- *   Initializes the <carrier> structure, sets the foreach_key callback to
- *   flt_otel_text_map_reader_foreach_key_cb(), and copies the <text_map> data
- *   into the <carrier>.  Delegates to the <tracer>'s extract_text_map() method.
- *
- * RETURN VALUE
- *   Returns a pointer to the extracted span context, or NULL on failure.
- */
-struct otelc_span_context *flt_otel_extract_text_map(struct otelc_tracer *tracer, struct otelc_text_map_reader *carrier, const struct otelc_text_map *text_map)
-{
-       OTELC_FUNC("%p, %p, %p", tracer, carrier, text_map);
-
-       if ((tracer == NULL) || (carrier == NULL))
-               OTELC_RETURN_PTR(NULL);
-
-       (void)memset(carrier, 0, sizeof(*carrier));
-       carrier->foreach_key = flt_otel_text_map_reader_foreach_key_cb;
-
-       if (text_map != NULL)
-               (void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map));
-
-       OTELC_RETURN_PTR(OTELC_OPS(tracer, extract_text_map, carrier));
-}
-
-
-/***
- * NAME
- *   flt_otel_extract_http_headers - HTTP headers context extraction
- *
- * SYNOPSIS
- *   struct otelc_span_context *flt_otel_extract_http_headers(struct otelc_tracer *tracer, struct otelc_http_headers_reader *carrier, const struct otelc_text_map *text_map)
- *
- * ARGUMENTS
- *   tracer   - OTel tracer instance
- *   carrier  - HTTP headers reader carrier
- *   text_map - text map containing the context data (or NULL)
- *
- * DESCRIPTION
- *   Extracts a span context from an HTTP headers carrier via the <tracer>.
- *   Initializes the <carrier> structure, sets the foreach_key callback to
- *   flt_otel_http_headers_reader_foreach_key_cb(), and copies the <text_map>
- *   data into the <carrier>.  Delegates to the <tracer>'s
- *   extract_http_headers() method.
- *
- * RETURN VALUE
- *   Returns a pointer to the extracted span context, or NULL on failure.
- */
-struct otelc_span_context *flt_otel_extract_http_headers(struct otelc_tracer *tracer, struct otelc_http_headers_reader *carrier, const struct otelc_text_map *text_map)
-{
-       OTELC_FUNC("%p, %p, %p", tracer, carrier, text_map);
-
-       if ((tracer == NULL) || (carrier == NULL))
-               OTELC_RETURN_PTR(NULL);
-
-       (void)memset(carrier, 0, sizeof(*carrier));
-       carrier->foreach_key = flt_otel_http_headers_reader_foreach_key_cb;
-
-       if (text_map != NULL)
-               (void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map));
-
-       OTELC_RETURN_PTR(OTELC_OPS(tracer, extract_http_headers, carrier));
-}
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/parser.c b/addons/otel/src/parser.c
deleted file mode 100644 (file)
index 0fb0a5a..0000000
+++ /dev/null
@@ -1,1821 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-#ifdef OTELC_DBG_MEM
-static struct otelc_dbg_mem_data dbg_mem_data[1000000];
-static struct otelc_dbg_mem      dbg_mem;
-#endif
-
-static struct flt_otel_conf       *flt_otel_current_config = NULL;
-static struct flt_otel_conf_instr *flt_otel_current_instr = NULL;
-static struct flt_otel_conf_group *flt_otel_current_group = NULL;
-static struct flt_otel_conf_scope *flt_otel_current_scope = NULL;
-static struct flt_otel_conf_span  *flt_otel_current_span = NULL;
-
-
-/***
- * NAME
- *   flt_otel_parse_strdup - string duplication with error handling
- *
- * SYNOPSIS
- *   static int flt_otel_parse_strdup(char **dst, size_t *dst_len, const char *src, char **err, const char *err_msg)
- *
- * ARGUMENTS
- *   dst     - pointer to the destination string pointer
- *   dst_len - optional pointer to store the duplicated string length
- *   src     - source string to duplicate
- *   err     - indirect pointer to error message string
- *   err_msg - context label used in error messages
- *
- * DESCRIPTION
- *   Duplicates the string <src> into <*dst> with error handling.  Optionally
- *   stores the string length in <dst_len>.  On failure, an error message is
- *   formatted using <err_msg> as context.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_strdup(char **dst, size_t *dst_len, const char *src, char **err, const char *err_msg)
-{
-       int retval = ERR_NONE;
-
-       OTELC_FUNC("%p:%p, %p, %p, %p:%p, \"%s\"", OTELC_DPTR_ARGS(dst), dst_len, src, OTELC_DPTR_ARGS(err), OTELC_STR_ARG(err_msg));
-
-       /* dst_len is not set if the string has not been copied. */
-       *dst = OTELC_STRDUP(src);
-       if (*dst == NULL)
-               FLT_OTEL_PARSE_ERR(err, "'%s' : out of memory", err_msg);
-       else if (dst_len != NULL)
-               *dst_len = strlen(*dst);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_keyword - keyword argument parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_keyword(char **ptr, char **args, int cur_arg, int pos, char **err, const char *err_msg)
- *
- * ARGUMENTS
- *   ptr     - pointer to the destination string pointer
- *   args    - configuration line arguments array
- *   cur_arg - current argument index for error reporting
- *   pos     - position of the keyword in <args>
- *   err     - indirect pointer to error message string
- *   err_msg - context label used in error messages
- *
- * DESCRIPTION
- *   Parses a single keyword argument from the configuration line.  Checks
- *   that the keyword has not already been set and that a value is present
- *   at position <pos> + 1 in <args>.  The value is duplicated via
- *   flt_otel_parse_strdup() into <*ptr>.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_keyword(char **ptr, char **args, int cur_arg, int pos, char **err, const char *err_msg)
-{
-       int retval = ERR_NONE;
-
-       OTELC_FUNC("%p:%p, %p, %d, %d, %p:%p, \"%s\"", OTELC_DPTR_ARGS(ptr), args, cur_arg, pos, OTELC_DPTR_ARGS(err), OTELC_STR_ARG(err_msg));
-
-       /* Reject duplicate keyword assignments. */
-       if (*ptr != NULL) {
-               if (cur_arg == pos)
-                       FLT_OTEL_PARSE_ERR(err, FLT_OTEL_FMT_TYPE "%s already set", err_msg);
-               else
-                       FLT_OTEL_PARSE_ERR(err, "'%s' : %s already set", args[cur_arg], err_msg);
-       }
-       else if (!FLT_OTEL_ARG_ISVALID(pos + 1)) {
-               if (cur_arg == pos)
-                       FLT_OTEL_PARSE_ERR(err, FLT_OTEL_FMT_TYPE "no %s set", err_msg);
-               else
-                       FLT_OTEL_PARSE_ERR(err, "'%s' : no %s set", args[cur_arg], err_msg);
-       }
-       else {
-               retval = flt_otel_parse_strdup(ptr, NULL, args[pos + 1], err, args[cur_arg]);
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_invalid_char - name character validation
- *
- * SYNOPSIS
- *   static const char *flt_otel_parse_invalid_char(const char *name, int type)
- *
- * ARGUMENTS
- *   name - string to validate
- *   type - validation type selector
- *
- * DESCRIPTION
- *   Validates characters in a <name> string according to the specified <type>.
- *   Uses HAProxy's invalid_char() for identifiers, invalid_domainchar() for
- *   domains, invalid_prefix_char() for context prefixes, and a custom
- *   alphanumeric check for variables.
- *
- * RETURN VALUE
- *   Returns a pointer to the first invalid character in <name>,
- *   or NULL if all characters are valid.
- */
-static const char *flt_otel_parse_invalid_char(const char *name, int type)
-{
-       const char *retptr = NULL;
-
-       OTELC_FUNC("\"%s\", %d", OTELC_STR_ARG(name), type);
-
-       if (!OTELC_STR_IS_VALID(name))
-               OTELC_RETURN_EX(retptr, const char *, "%p");
-
-       /* Dispatch to the appropriate character validation function. */
-       if (type == FLT_OTEL_PARSE_INVALID_CHAR) {
-               retptr = invalid_char(name);
-       }
-       else if (type == FLT_OTEL_PARSE_INVALID_DOM) {
-               retptr = invalid_domainchar(name);
-       }
-       else if (type == FLT_OTEL_PARSE_INVALID_CTX) {
-               retptr = invalid_prefix_char(name);
-       }
-       else if (type == FLT_OTEL_PARSE_INVALID_VAR) {
-               retptr = name;
-
-               /*
-                * Allowed characters are letters, numbers and '_', the first
-                * character in the string must not be a number.
-                */
-               if (!isdigit(*retptr))
-                       for (++retptr; (*retptr == '_') || isalnum(*retptr); retptr++);
-
-               if (*retptr == '\0')
-                       retptr = NULL;
-       }
-
-       OTELC_RETURN_EX(retptr, const char *, "%p");
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_check - configuration keyword validation
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_check(const char *file, int line, char **args, const void *id, const struct flt_otel_parse_data *parse_data, size_t parse_data_size, const struct flt_otel_parse_data **pdata, char **err)
- *
- * ARGUMENTS
- *   file            - configuration file path
- *   line            - configuration file line number
- *   args            - configuration line arguments array
- *   id              - parent section identifier
- *   parse_data      - keyword definition table
- *   parse_data_size - number of entries in <parse_data>
- *   pdata           - output pointer to the matched keyword entry
- *   err             - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Common validation for configuration keywords.  Looks up <args[0]> in the
- *   <parse_data> table, checks argument count bounds, validates the first
- *   argument's characters according to the keyword's check_name type, and
- *   verifies that the parent section ID is set when required.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_check(const char *file, int line, char **args, const void *id, const struct flt_otel_parse_data *parse_data, size_t parse_data_size, const struct flt_otel_parse_data **pdata, char **err)
-{
-       int i, argc, retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %d, %p, %p, %p, %zu, %p:%p, %p:%p", OTELC_STR_ARG(file), line, args, id, parse_data, parse_data_size, OTELC_DPTR_ARGS(pdata), OTELC_DPTR_ARGS(err));
-
-       FLT_OTEL_ARGS_DUMP();
-
-       *pdata = NULL;
-
-       /* First check here if args[0] is the correct keyword. */
-       for (i = 0; (*pdata == NULL) && (i < parse_data_size); i++)
-               if (FLT_OTEL_PARSE_KEYWORD(0, parse_data[i].name))
-                       *pdata = parse_data + i;
-
-       if (*pdata == NULL)
-               FLT_OTEL_PARSE_ERR(err, "'%s' : unknown keyword", args[0]);
-       else
-               argc = flt_otel_args_count((const char **)args);
-
-       if ((retval & ERR_CODE) || (id == NULL))
-               /* Do nothing. */;
-       else if ((id != flt_otel_current_instr) && (flt_otel_current_config->instr == NULL))
-               FLT_OTEL_PARSE_ERR(err, "instrumentation not defined");
-
-       /*
-        * Checking that fewer arguments are specified in the configuration
-        * line than is required.
-        */
-       if (!(retval & ERR_CODE))
-               if (argc < (*pdata)->args_min)
-                       FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[0], (*pdata)->name, (*pdata)->usage);
-
-       /*
-        * Checking that more arguments are specified in the configuration
-        * line than the maximum allowed.
-        */
-       if (!(retval & ERR_CODE) && ((*pdata)->args_max > 0))
-               if (argc > (*pdata)->args_max)
-                       FLT_OTEL_PARSE_ERR(err, "'%s' : too many arguments (use '%s%s')", args[0], (*pdata)->name, (*pdata)->usage);
-
-       /* Checking that the first argument has only allowed characters. */
-       if (!(retval & ERR_CODE) && ((*pdata)->check_name != FLT_OTEL_PARSE_INVALID_NONE)) {
-               const char *ic;
-
-               ic = flt_otel_parse_invalid_char(args[1], (*pdata)->check_name);
-               if (ic != NULL)
-                       FLT_OTEL_PARSE_ERR(err, "%s '%s' : invalid character '%c'", args[0], args[1], *ic);
-       }
-
-       /* Checking that the data group name is defined. */
-       if (!(retval & ERR_CODE) && (*pdata)->flag_check_id && (id == NULL))
-               FLT_OTEL_PARSE_ERR(err, "'%s' : %s ID not set (use '%s%s')", args[0], parse_data[1].name, parse_data[1].name, parse_data[1].usage);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_sample_expr - sample expression parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_sample_expr(const char *file, int line, char **args, int *idx, struct list *head, char **err)
- *
- * ARGUMENTS
- *   file - configuration file path
- *   line - configuration file line number
- *   args - configuration line arguments array
- *   idx  - pointer to the current position in <args>
- *   head - list head for parsed sample expressions
- *   err  - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses a single HAProxy sample expression at position <*idx> in <args>.
- *   Creates a conf_sample_expr structure and calls sample_parse_expr() to
- *   compile the expression.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_sample_expr(const char *file, int line, char **args, int *idx, struct list *head, char **err)
-{
-       struct flt_otel_conf_sample_expr *expr;
-       int                             retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %d, %p, %p, %p, %p:%p", OTELC_STR_ARG(file), line, args, idx, head, OTELC_DPTR_ARGS(err));
-
-       expr = flt_otel_conf_sample_expr_init(args[*idx], line, head, err);
-       if (expr != NULL) {
-               expr->expr = sample_parse_expr(args, idx, file, line, err, &(flt_otel_current_config->proxy->conf.args), NULL);
-               if (expr->expr != NULL)
-                       OTELC_DBG(DEBUG, "sample expression '%s' added", expr->fmt_expr);
-               else
-                       retval |= ERR_ABORT | ERR_ALERT;
-       } else {
-               retval |= ERR_ABORT | ERR_ALERT;
-       }
-
-       if (retval & ERR_CODE)
-               flt_otel_conf_sample_expr_free(&expr);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_sample - sample definition parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_sample(const char *file, int line, char **args, int idx, int n, const struct otelc_value *extra, struct list *head, char **err)
- *
- * ARGUMENTS
- *   file  - configuration file path
- *   line  - configuration file line number
- *   args  - configuration line arguments array
- *   idx   - args[] position where the sample value starts
- *   n     - maximum number of sample expressions to parse (0 means unlimited)
- *   extra - optional extra data (event name or status code)
- *   head  - list head for parsed sample definitions
- *   err   - indirect pointer to error message string
- *
- * DESCRIPTION
- *   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
- *   if an error is encountered.
- */
-static int flt_otel_parse_cfg_sample(const char *file, int line, char **args, int idx, int n, const struct otelc_value *extra, struct list *head, char **err)
-{
-       struct flt_otel_conf_sample *sample;
-       int                          retval = ERR_NONE;
-       int                          count = 0;
-
-       OTELC_FUNC("\"%s\", %d, %p, %d, %d, %p, %p, %p:%p", OTELC_STR_ARG(file), line, args, idx, n, extra, head, OTELC_DPTR_ARGS(err));
-
-       sample = flt_otel_conf_sample_init_ex((const char **)args, idx, n, extra, line, head, err);
-       if (sample == NULL)
-               FLT_OTEL_PARSE_ERR(err, "'%s' : out of memory", args[0]);
-
-       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;
-
-               while (!(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(idx) && ((n == 0) || (count < n))) {
-                       retval = flt_otel_parse_cfg_sample_expr(file, line, args, &idx, &(sample->exprs), err);
-                       if (!(retval & ERR_CODE))
-                               count++;
-               }
-
-               flt_otel_current_config->proxy->conf.args.file = NULL;
-               flt_otel_current_config->proxy->conf.args.line = 0;
-
-               OTELC_DBG(DEBUG, "sample '%s' -> '%s' added, (%d %d)", sample->key, sample->fmt_string, sample->num_exprs, count);
-       }
-
-       if (retval & ERR_CODE)
-               flt_otel_conf_sample_free(&sample);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_str - string list parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_str(const char *file, int line, char **args, struct list *head, char **err)
- *
- * ARGUMENTS
- *   file - configuration file path
- *   line - configuration file line number
- *   args - configuration line arguments array
- *   head - list head for parsed string entries
- *   err  - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses one or more string arguments into a conf_str list.  All arguments
- *   starting from index 1 are added to <head>.  Used for the "finish" keyword.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_str(const char *file, int line, char **args, struct list *head, char **err)
-{
-       int i, retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %d, %p, %p, %p:%p", OTELC_STR_ARG(file), line, args, head, OTELC_DPTR_ARGS(err));
-
-       for (i = 1; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++)
-               if (flt_otel_conf_str_init(args[i], line, head, err) == NULL)
-                       retval |= ERR_ABORT | ERR_ALERT;
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_file - file path argument parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_file(char **ptr, const char *file, int line, char **args, char **err, const char *err_msg)
- *
- * ARGUMENTS
- *   ptr     - pointer to the destination file path string pointer
- *   file    - configuration file path
- *   line    - configuration file line number
- *   args    - configuration line arguments array
- *   err     - indirect pointer to error message string
- *   err_msg - context label used in error messages
- *
- * DESCRIPTION
- *   Parses and validates a file path argument.  Checks that the argument is
- *   present, that no extra arguments follow, and that the file exists and is
- *   readable.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_file(char **ptr, const char *file, int line, char **args, char **err, const char *err_msg)
-{
-       int retval = ERR_NONE;
-
-       OTELC_FUNC("%p:%p, \"%s\", %d, %p, %p:%p, \"%s\"", OTELC_DPTR_ARGS(ptr), OTELC_STR_ARG(file), line, args, OTELC_DPTR_ARGS(err), err_msg);
-
-       if (!FLT_OTEL_ARG_ISVALID(1))
-               FLT_OTEL_PARSE_ERR(err, "'%s' : no %s specified", flt_otel_current_instr->id, err_msg);
-       else if (alertif_too_many_args(1, file, line, args, &retval))
-               retval |= ERR_ABORT | ERR_ALERT;
-       else if (access(args[1], R_OK) == -1)
-               FLT_OTEL_PARSE_ERR(err, "'%s' : %s", args[1], strerror(errno));
-       else
-               retval = flt_otel_parse_keyword(ptr, args, 0, 0, err, err_msg);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_check_scope - configuration scope filter
- *
- * SYNOPSIS
- *   static bool flt_otel_parse_check_scope(void)
- *
- * ARGUMENTS
- *   This function takes no arguments.
- *
- * DESCRIPTION
- *   Checks whether the current configuration parsing is within the correct
- *   HAProxy cfg_scope filter.  When cfg_scope is set and does not match the
- *   current filter ID, the configuration line is skipped.
- *
- * RETURN VALUE
- *   Returns TRUE in case the configuration is not in the currently
- *   defined scope, FALSE otherwise.
- */
-static bool flt_otel_parse_check_scope(void)
-{
-       bool retval = 0;
-
-       if ((cfg_scope != NULL) && (flt_otel_current_config->id != NULL) && (strcmp(flt_otel_current_config->id, cfg_scope) != 0)) {
-               OTELC_DBG(INFO, "cfg_scope: '%s', id: '%s'", cfg_scope, flt_otel_current_config->id);
-
-               retval = 1;
-       }
-
-       return retval;
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_instr - otel-instrumentation section parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_instr(const char *file, int line, char **args, int kw_mod)
- *
- * ARGUMENTS
- *   file   - configuration file path
- *   line   - configuration file line number
- *   args   - configuration line arguments array
- *   kw_mod - keyword modifier flags (e.g. KWM_NO)
- *
- * DESCRIPTION
- *   Section parser for the otel-instrumentation configuration block.  Handles
- *   keywords: instrumentation ID, log, config, groups, scopes, acl, rate-limit,
- *   option (disabled/hard-errors/dontlog-normal), and debug-level.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_instr(const char *file, int line, char **args, int kw_mod)
-{
-#define FLT_OTEL_PARSE_INSTR_DEF(a,b,c,d,e,f,g)   { FLT_OTEL_PARSE_INSTR_##a, b, FLT_OTEL_PARSE_INVALID_##c, d, e, f, g },
-       static const struct flt_otel_parse_data  parse_data[] = { FLT_OTEL_PARSE_INSTR_DEFINES };
-#undef FLT_OTEL_PARSE_INSTR_DEF
-       const struct flt_otel_parse_data        *pdata = NULL;
-       char                                    *err = NULL, *err_log = NULL;
-       int                                      i, retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %d, %p, 0x%08x", OTELC_STR_ARG(file), line, args, kw_mod);
-
-       if (flt_otel_parse_check_scope())
-               OTELC_RETURN_INT(retval);
-
-       /* Validate and identify the instrumentation keyword. */
-       retval = flt_otel_parse_cfg_check(file, line, args, flt_otel_current_instr, parse_data, OTELC_TABLESIZE(parse_data), &pdata, &err);
-       if (retval & ERR_CODE) {
-               FLT_OTEL_PARSE_IFERR_ALERT();
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       /* Handle keyword-specific instrumentation configuration. */
-       if (pdata->keyword == FLT_OTEL_PARSE_INSTR_ID) {
-               if (flt_otel_current_config->instr != NULL) {
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : instrumentation can be defined only once", args[1]);
-               } else {
-                       flt_otel_current_instr = flt_otel_conf_instr_init(args[1], line, NULL, &err);
-                       if (flt_otel_current_instr == NULL)
-                               retval |= ERR_ABORT | ERR_ALERT;
-               }
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_INSTR_LOG) {
-               if (parse_logger(args, &(flt_otel_current_instr->proxy_log.loggers), kw_mod == KWM_NO, file, line, &err_log) == 0) {
-                       FLT_OTEL_PARSE_ERR(&err, "'%s %s ...' : %s", args[0], args[1], err_log);
-                       OTELC_SFREE_CLEAR(err_log);
-               } else {
-                       flt_otel_current_instr->logging |= FLT_OTEL_LOGGING_ON;
-               }
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_INSTR_CONFIG) {
-               retval = flt_otel_parse_cfg_file(&(flt_otel_current_instr->config), file, line, args, &err, "configuration file");
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_INSTR_GROUPS) {
-               for (i = 1; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++)
-                       if (flt_otel_conf_ph_init(args[i], line, &(flt_otel_current_instr->ph_groups), &err) == NULL)
-                               retval |= ERR_ABORT | ERR_ALERT;
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_INSTR_SCOPES) {
-               for (i = 1; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++)
-                       if (flt_otel_conf_ph_init(args[i], line, &(flt_otel_current_instr->ph_scopes), &err) == NULL)
-                               retval |= ERR_ABORT | ERR_ALERT;
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_INSTR_ACL) {
-               if (FLT_OTEL_PARSE_KEYWORD(1, "or"))
-                       FLT_OTEL_PARSE_ERR(&err, "'%s %s ...' : invalid ACL name", args[0], args[1]);
-               else if (parse_acl((const char **)args + 1, &(flt_otel_current_instr->acls), &err, &(flt_otel_current_config->proxy->conf.args), file, line) == NULL)
-                       retval |= ERR_ABORT | ERR_ALERT;
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_INSTR_RATE_LIMIT) {
-               double value;
-
-               if (flt_otel_strtod(args[1], &value, 0.0, 100.0, &err))
-                       flt_otel_current_instr->rate_limit = FLT_OTEL_FLOAT_U32(value);
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_INSTR_OPTION) {
-               if (FLT_OTEL_PARSE_KEYWORD(1, FLT_OTEL_PARSE_OPTION_DISABLED)) {
-                       flt_otel_current_instr->flag_disabled = (kw_mod == KWM_NO) ? 0 : 1;
-               }
-               else if (FLT_OTEL_PARSE_KEYWORD(1, FLT_OTEL_PARSE_OPTION_HARDERR)) {
-                       flt_otel_current_instr->flag_harderr = (kw_mod == KWM_NO) ? 0 : 1;
-               }
-               else if (FLT_OTEL_PARSE_KEYWORD(1, FLT_OTEL_PARSE_OPTION_NOLOGNORM)) {
-                       if (kw_mod == KWM_NO)
-                               flt_otel_current_instr->logging &= ~FLT_OTEL_LOGGING_NOLOGNORM;
-                       else
-                               flt_otel_current_instr->logging |= FLT_OTEL_LOGGING_NOLOGNORM;
-               }
-               else
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : unknown option '%s'", args[0], args[1]);
-       }
-#ifdef DEBUG_OTEL
-       else if (pdata->keyword == FLT_OTEL_PARSE_INSTR_DEBUG_LEVEL) {
-               int64_t value;
-
-               if (flt_otel_strtoll(args[1], &value, 0, OTELC_DBG_LEVEL_MASK, &err))
-                       otelc_dbg_level = value;
-       }
-#else
-       else {
-               FLT_OTEL_PARSE_WARNING("'%s' : keyword ignored", file, line, args[0]);
-       }
-#endif
-
-       FLT_OTEL_PARSE_IFERR_ALERT();
-
-       if ((retval & ERR_CODE) && (flt_otel_current_instr != NULL))
-               flt_otel_conf_instr_free(&flt_otel_current_instr);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_post_parse_cfg_instr - otel-instrumentation post-parse check
- *
- * SYNOPSIS
- *   static int flt_otel_post_parse_cfg_instr(void)
- *
- * ARGUMENTS
- *   This function takes no arguments.
- *
- * DESCRIPTION
- *   Post-parse callback for the otel-instrumentation section.  Links the parsed
- *   instrumentation structure to the filter configuration and verifies that a
- *   configuration file path is specified.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_post_parse_cfg_instr(void)
-{
-       int retval = ERR_NONE;
-
-       OTELC_FUNC("");
-
-       if (flt_otel_current_instr == NULL)
-               OTELC_RETURN_INT(retval);
-
-       flt_otel_current_config->instr = flt_otel_current_instr;
-
-       if (flt_otel_current_instr->id == NULL)
-               OTELC_RETURN_INT(retval);
-
-       if (flt_otel_current_instr->config == NULL)
-               FLT_OTEL_POST_PARSE_ALERT("instrumentation '%s' has no configuration file specified", flt_otel_current_instr->cfg_line, flt_otel_current_instr->id);
-
-       flt_otel_current_instr = NULL;
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_group - otel-group section parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_group(const char *file, int line, char **args, int kw_mod)
- *
- * ARGUMENTS
- *   file   - configuration file path
- *   line   - configuration file line number
- *   args   - configuration line arguments array
- *   kw_mod - keyword modifier flags (e.g. KWM_NO)
- *
- * DESCRIPTION
- *   Section parser for the otel-group configuration block.  Handles keywords:
- *   group ID and scopes.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_group(const char *file, int line, char **args, int kw_mod)
-{
-#define FLT_OTEL_PARSE_GROUP_DEF(a,b,c,d,e,f,g)   { FLT_OTEL_PARSE_GROUP_##a, b, FLT_OTEL_PARSE_INVALID_##c, d, e, f, g },
-       static const struct flt_otel_parse_data  parse_data[] = { FLT_OTEL_PARSE_GROUP_DEFINES };
-#undef FLT_OTEL_PARSE_GROUP_DEF
-       const struct flt_otel_parse_data        *pdata = NULL;
-       char                                    *err = NULL;
-       int                                      i, retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %d, %p, 0x%08x", OTELC_STR_ARG(file), line, args, kw_mod);
-
-       if (flt_otel_parse_check_scope())
-               OTELC_RETURN_INT(retval);
-
-       /* Validate and identify the group keyword. */
-       retval = flt_otel_parse_cfg_check(file, line, args, flt_otel_current_group, parse_data, OTELC_TABLESIZE(parse_data), &pdata, &err);
-       if (retval & ERR_CODE) {
-               FLT_OTEL_PARSE_IFERR_ALERT();
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       /* Handle keyword-specific group configuration. */
-       if (pdata->keyword == FLT_OTEL_PARSE_GROUP_ID) {
-               flt_otel_current_group = flt_otel_conf_group_init(args[1], line, &(flt_otel_current_config->groups), &err);
-               if (flt_otel_current_group == NULL)
-                       retval |= ERR_ABORT | ERR_ALERT;
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_GROUP_SCOPES) {
-               for (i = 1; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++)
-                       if (flt_otel_conf_ph_init(args[i], line, &(flt_otel_current_group->ph_scopes), &err) == NULL)
-                               retval |= ERR_ABORT | ERR_ALERT;
-       }
-
-       FLT_OTEL_PARSE_IFERR_ALERT();
-
-       if ((retval & ERR_CODE) && (flt_otel_current_group != NULL))
-               flt_otel_conf_group_free(&flt_otel_current_group);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_post_parse_cfg_group - otel-group post-parse check
- *
- * SYNOPSIS
- *   static int flt_otel_post_parse_cfg_group(void)
- *
- * ARGUMENTS
- *   This function takes no arguments.
- *
- * DESCRIPTION
- *   Post-parse callback for the otel-group section.  Verifies that at least one
- *   scope is defined in the group.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_post_parse_cfg_group(void)
-{
-       int retval = ERR_NONE;
-
-       OTELC_FUNC("");
-
-       if (flt_otel_current_group == NULL)
-               OTELC_RETURN_INT(retval);
-
-       /* Check that the group has at least one scope defined. */
-       if (LIST_ISEMPTY(&(flt_otel_current_group->ph_scopes)))
-               FLT_OTEL_POST_PARSE_ALERT("group '%s' has no defined scope(s)", flt_otel_current_group->cfg_line, flt_otel_current_group->id);
-
-       flt_otel_current_group = NULL;
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_scope_ctx - context storage type parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_scope_ctx(char **args, int cur_arg, char **err)
- *
- * ARGUMENTS
- *   args    - configuration line arguments array
- *   cur_arg - index of the storage type argument in <args>
- *   err     - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses the context storage type argument for inject/extract keywords.
- *   Accepts "use-headers" or (when USE_OTEL_VARS is defined) "use-vars".
- *   Both types may be used simultaneously on the same span.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_scope_ctx(char **args, int cur_arg, char **err)
-{
-       uint8_t flags = 0;
-       int     retval = ERR_NONE;
-
-       OTELC_FUNC("%p, %d, %p:%p", args, cur_arg, OTELC_DPTR_ARGS(err));
-
-       if (FLT_OTEL_PARSE_KEYWORD(cur_arg, FLT_OTEL_PARSE_CTX_USE_HEADERS))
-               flags = FLT_OTEL_CTX_USE_HEADERS;
-#ifdef USE_OTEL_VARS
-       else if (FLT_OTEL_PARSE_KEYWORD(cur_arg, FLT_OTEL_PARSE_CTX_USE_VARS))
-               flags = FLT_OTEL_CTX_USE_VARS;
-#endif
-       else
-               FLT_OTEL_PARSE_ERR(err, "'%s' : invalid context storage type", args[0]);
-
-       if (flags == 0)
-               /* Do nothing. */;
-       else if (flt_otel_current_span->ctx_flags & flags)
-               FLT_OTEL_PARSE_ERR(err, "'%s' : %s already used", args[0], args[cur_arg]);
-       else
-               flt_otel_current_span->ctx_flags |= flags;
-
-       OTELC_DBG(NOTICE, "ctx_flags: 0x%02hhx (0x%02hhx)", flt_otel_current_span->ctx_flags, flags);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_acl - ACL condition builder
- *
- * SYNOPSIS
- *   static struct acl_cond *flt_otel_parse_acl(const char *file, int line, struct proxy *px, const char **args, char **err, struct list *head, ...)
- *
- * ARGUMENTS
- *   file - configuration file path
- *   line - configuration file line number
- *   px   - proxy instance for ACL resolution
- *   args - condition arguments (if/unless followed by ACL names)
- *   err  - indirect pointer to error message string
- *   head - first ACL list head to search
- *
- * DESCRIPTION
- *   Builds an ACL condition by trying multiple ACL lists in order.  The
- *   variadic arguments provide a sequence of ACL list heads to search; the
- *   first successful build_acl_cond() result is returned.
- *
- * RETURN VALUE
- *   Returns a pointer to the built ACL condition, or NULL if no condition could
- *   be built from any of the provided lists.
- */
-static struct acl_cond *flt_otel_parse_acl(const char *file, int line, struct proxy *px, const char **args, char **err, struct list *head, ...)
-{
-       va_list          ap;
-       int              n = 0;
-       struct acl_cond *retptr = NULL;
-
-       OTELC_FUNC("\"%s\", %d, %p, %p, %p:%p, %p, ...", OTELC_STR_ARG(file), line, px, args, OTELC_DPTR_ARGS(err), head);
-
-       /* Try each ACL list in order until a condition is built. */
-       for (va_start(ap, head); (retptr == NULL) && (head != NULL); head = va_arg(ap, typeof(head)), n++) {
-               retptr = build_acl_cond(file, line, head, px, args, (n == 0) ? err : NULL);
-               if (retptr != NULL)
-                       OTELC_DBG(NOTICE, "ACL build done, using list %p %d", head, n);
-       }
-       va_end(ap);
-
-       if ((retptr != NULL) && (err != NULL))
-               ha_free(err);
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_bounds - histogram boundary string parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_bounds(const char *str, double **bounds, size_t *bounds_num, char **err, const char *err_msg)
- *
- * ARGUMENTS
- *   str        - space-separated numeric boundary string
- *   bounds     - pointer to the destination boundary array
- *   bounds_num - pointer to store the number of boundaries
- *   err        - indirect pointer to error message string
- *   err_msg    - context label used in error messages
- *
- * DESCRIPTION
- *   Parses a space-separated string of numbers into a dynamically allocated
- *   array of doubles suitable for the meter add_view API.  The string is
- *   duplicated internally and tokenized with strtok().  Each token is
- *   converted with flt_otel_strtod().  The values are sorted internally.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_bounds(const char *str, double **bounds, size_t *bounds_num, char **err, const char *err_msg)
-{
-       char   *buffer, *token, *lasts;
-       size_t  bounds_len = 0, bounds_size = 8;
-       double  value, *ptr;
-       int     retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %p, %p, %p:%p, \"%s\"", OTELC_STR_ARG(str), bounds, bounds_num, OTELC_DPTR_ARGS(err), OTELC_STR_ARG(err_msg));
-
-       buffer  = OTELC_STRDUP(str);
-       *bounds = OTELC_CALLOC(bounds_size, sizeof(**bounds));
-       if ((buffer == NULL) || (*bounds == NULL)) {
-               OTELC_SFREE(buffer);
-               OTELC_SFREE(*bounds);
-
-               FLT_OTEL_PARSE_ERR(err, "'%s' : out of memory", err_msg);
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       /* Tokenize and parse space-separated boundary values. */
-       for (token = strtok_r(buffer, " \t", &lasts); token != NULL; token = strtok_r(NULL, " \t", &lasts)) {
-               if (!flt_otel_strtod(token, &value, 0.0, DBL_MAX, err)) {
-                       retval |= ERR_ABORT | ERR_ALERT;
-
-                       break;
-               }
-               else if (bounds_len >= bounds_size) {
-                       ptr = OTELC_REALLOC(*bounds, (bounds_size + 8) * sizeof(*ptr));
-                       if (ptr == NULL) {
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : out of memory", err_msg);
-
-                               OTELC_SFREE_CLEAR(*bounds);
-
-                               break;
-                       }
-
-                       *bounds      = ptr;
-                       bounds_size += 8;
-               }
-
-               (*bounds)[bounds_len++] = value;
-       }
-
-       /* Sort the bounds and reject duplicates. */
-       if ((*bounds != NULL) && (bounds_len > 1)) {
-               size_t i;
-
-               qsort(*bounds, bounds_len, sizeof(**bounds), flt_otel_qsort_compar_double);
-
-               for (i = 1; i < bounds_len; i++)
-                       if (flt_otel_qsort_compar_double(*bounds + i - 1, *bounds + i) == 0) {
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : duplicate boundary value '%.2f'", err_msg, (*bounds)[i]);
-
-                               OTELC_SFREE_CLEAR(*bounds);
-
-                               break;
-                       }
-       }
-
-       OTELC_SFREE(buffer);
-
-       if (*bounds == NULL) {
-               *bounds_num = 0;
-       }
-       else if (bounds_len == 0) {
-               FLT_OTEL_PARSE_ERR(err, "'%s' : empty bounds", err_msg);
-
-               OTELC_SFREE_CLEAR(*bounds);
-               *bounds_num = 0;
-       }
-       else {
-               *bounds_num = bounds_len;
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_instrument - instrument keyword parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_instrument(const char *file, int line, char **args, const struct flt_otel_parse_data *pdata, char **err)
- *
- * ARGUMENTS
- *   file  - configuration file path
- *   line  - configuration file line number
- *   args  - configuration line arguments array
- *   pdata - keyword metadata (name, usage, argument limits)
- *   err   - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses the "instrument" keyword inside an otel-scope section.  Two forms
- *   are supported: the "update" form that references an existing instrument by
- *   name and adds attributes to it, and the "create" form that defines a new
- *   metric instrument with a type, name, optional aggregation type (preceded by
- *   the 'aggr' keyword), optional description, optional unit, a single sample
- *   expression for the value, and optional histogram bucket boundaries
- *   (preceded by the 'bounds' keyword).  The 'bounds' keyword is only valid for
- *   histogram instrument types.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_instrument(const char *file, int line, char **args, const struct flt_otel_parse_data *pdata, char **err)
-{
-#define FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEF(a,b)   { OTELC_METRIC_INSTRUMENT_##a, b },
-       static const struct {
-               otelc_metric_instrument_t  type;
-               const char                *keyword;
-       } instr_type[] = { FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEFINES };
-#undef FLT_OTEL_PARSE_SCOPE_INSTRUMENT_DEF
-       struct flt_otel_conf_instrument *instr;
-       int                              i, retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %d, %p, %p, %p:%p", OTELC_STR_ARG(file), line, args, pdata, OTELC_DPTR_ARGS(err));
-
-       /* Look up the instrument type from args[1]. */
-       for (i = 0; i < OTELC_TABLESIZE(instr_type); i++)
-               if (FLT_OTEL_PARSE_KEYWORD(1, instr_type[i].keyword)) {
-                       OTELC_DBG(DEBUG, "instrument type: %d '%s'", instr_type[i].type, instr_type[i].keyword);
-
-                       break;
-               }
-
-       if (i >= OTELC_TABLESIZE(instr_type)) {
-               FLT_OTEL_PARSE_ERR(err, "'%s' : invalid instrument type", args[1]);
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       /*
-        * Only one create and one update instrument per name are allowed.
-        * Pass NULL as head for update instruments to bypass the generic
-        * duplicate check (which would reject the shared name), check for
-        * update duplicates separately, and append to the list manually.
-        */
-       if (instr_type[i].type == OTELC_METRIC_INSTRUMENT_UPDATE) {
-               list_for_each_entry(instr, &(flt_otel_current_scope->instruments), list)
-                       if ((instr->type == OTELC_METRIC_INSTRUMENT_UPDATE) && FLT_OTEL_PARSE_KEYWORD(2, instr->id)) {
-                               FLT_OTEL_ERR("'%s' : already defined", args[2]);
-
-                               OTELC_RETURN_INT(retval);
-                       }
-
-               instr = flt_otel_conf_instrument_init(args[2], line, NULL, err);
-               if (instr != NULL)
-                       LIST_APPEND(&(flt_otel_current_scope->instruments), &(instr->list));
-       } else {
-               instr = flt_otel_conf_instrument_init(args[2], line, &(flt_otel_current_scope->instruments), err);
-       }
-
-       if (instr == NULL) {
-               retval |= ERR_ABORT | ERR_ALERT;
-       }
-       else if (instr_type[i].type == OTELC_METRIC_INSTRUMENT_UPDATE) {
-               bool flag_add_attr = false;
-
-               instr->type = instr_type[i].type;
-
-               /* Update instruments only accept additional attributes. */
-               for (i = 3; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++) {
-                       if (flag_add_attr) {
-                               if (!FLT_OTEL_ARG_ISVALID(i) || !FLT_OTEL_ARG_ISVALID(i + 1))
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else {
-                                       retval = flt_otel_parse_cfg_sample(file, line, args, i + 1, 1, NULL, &(instr->attributes), err);
-                                       if (!(retval & ERR_CODE))
-                                               i++;
-                               }
-                       }
-                       else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_INSTRUMENT_ATTR)) {
-                               flag_add_attr = true;
-                       }
-                       else {
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : unknown keyword (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       }
-               }
-
-               if (flag_add_attr && LIST_ISEMPTY(&(instr->attributes)))
-                       FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-       }
-       else {
-               instr->type = instr_type[i].type;
-
-               /*
-                * Create instruments accept aggr, description, unit, value,
-                * and bounds.
-                */
-               for (i = 3; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++) {
-                       if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_INSTRUMENT_AGGR)) {
-                               if (!FLT_OTEL_ARG_ISVALID(i + 1))
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else if (instr->aggr_type != OTELC_METRIC_AGGREGATION_UNSET)
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else {
-                                       otelc_metric_aggregation_type_t type = otelc_meter_aggr_parse(args[++i]);
-
-                                       if (type == OTELC_RET_ERROR)
-                                               FLT_OTEL_PARSE_ERR(err, "'%s' : invalid aggregation type", args[i]);
-                                       else
-                                               instr->aggr_type = type;
-                               }
-                       }
-                       else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_INSTRUMENT_DESC)) {
-                               if (!FLT_OTEL_ARG_ISVALID(i + 1))
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else if (instr->description == NULL)
-                                       retval = flt_otel_parse_strdup(&(instr->description), NULL, args[++i], err, args[0]);
-                               else
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       }
-                       else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_INSTRUMENT_UNIT)) {
-                               if (!FLT_OTEL_ARG_ISVALID(i + 1))
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else if (instr->unit == NULL)
-                                       retval = flt_otel_parse_strdup(&(instr->unit), NULL, args[++i], err, args[0]);
-                               else
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       }
-                       else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_INSTRUMENT_VALUE)) {
-                               if (!FLT_OTEL_ARG_ISVALID(i + 1))
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else if (!LIST_ISEMPTY(&(instr->samples)))
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else {
-                                       retval = flt_otel_parse_cfg_sample(file, line, args, ++i, 1, NULL, &(instr->samples), err);
-
-                                       if (!(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i + 1) && !FLT_OTEL_PARSE_KEYWORD(i + 1, FLT_OTEL_PARSE_INSTRUMENT_AGGR) && !FLT_OTEL_PARSE_KEYWORD(i + 1, FLT_OTEL_PARSE_INSTRUMENT_DESC) && !FLT_OTEL_PARSE_KEYWORD(i + 1, FLT_OTEL_PARSE_INSTRUMENT_UNIT) && !FLT_OTEL_PARSE_KEYWORD(i + 1, FLT_OTEL_PARSE_INSTRUMENT_VALUE) && !FLT_OTEL_PARSE_KEYWORD(i + 1, FLT_OTEL_PARSE_INSTRUMENT_BOUNDS))
-                                               FLT_OTEL_PARSE_ERR(err, "'%s' : only one sample expression allowed per instrument", args[0]);
-                               }
-                       }
-                       else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_INSTRUMENT_BOUNDS)) {
-                               if (!FLT_OTEL_ARG_ISVALID(i + 1))
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else if (instr->type != OTELC_METRIC_INSTRUMENT_HISTOGRAM_UINT64)
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : bounds only valid for hist_int instruments", args[i]);
-                               else if (instr->bounds != NULL)
-                                       FLT_OTEL_PARSE_ERR(err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               else
-                                       retval = flt_otel_parse_bounds(args[++i], &(instr->bounds), &(instr->bounds_num), err, args[0]);
-                       }
-                       else {
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : invalid argument (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       }
-               }
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_log_record - log-record keyword parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_log_record(const char *file, int line, char **args, const struct flt_otel_parse_data *pdata, char **err)
- *
- * ARGUMENTS
- *   file  - configuration file path
- *   line  - configuration file line number
- *   args  - configuration line arguments array
- *   pdata - keyword metadata (name, usage, argument limits)
- *   err   - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses the "log-record" keyword inside an otel-scope section.  The first
- *   argument is a required severity level string.  Optional keywords "id",
- *   "event", "span", and "attr" follow in any order.  The remaining arguments
- *   at the end are parsed as fetch expressions or a log-format string.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_log_record(const char *file, int line, char **args, const struct flt_otel_parse_data *pdata, char **err)
-{
-       struct flt_otel_conf_log_record *log;
-       otelc_log_severity_t             severity;
-       int                              i, retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %d, %p, %p, %p:%p", OTELC_STR_ARG(file), line, args, pdata, OTELC_DPTR_ARGS(err));
-
-       /* Look up the severity level from args[1]. */
-       severity = otelc_logger_severity_parse(args[1]);
-       if (severity == OTELC_LOG_SEVERITY_INVALID) {
-               FLT_OTEL_PARSE_ERR(err, "'%s' : invalid log severity", args[1]);
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       log = flt_otel_conf_log_record_init(FLT_OTEL_CONF_HDR_SPECIAL "log-record", line, &(flt_otel_current_scope->log_records), err);
-       if (log == NULL) {
-               retval |= ERR_ABORT | ERR_ALERT;
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       log->severity = severity;
-
-       /* Parse optional keywords starting from args[2]. */
-       for (i = 2; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++) {
-               if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_LOG_RECORD_ID)) {
-                       if (!FLT_OTEL_ARG_ISVALID(i + 1))
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       else if (log->event_id != 0)
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       else if (!flt_otel_strtoll(args[++i], &(log->event_id), 0, LLONG_MAX, err))
-                               retval |= ERR_ABORT | ERR_ALERT;
-               }
-               else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_LOG_RECORD_EVENT)) {
-                       if (!FLT_OTEL_ARG_ISVALID(i + 1))
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       else if (log->event_name != NULL)
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       else
-                               retval = flt_otel_parse_strdup(&(log->event_name), NULL, args[++i], err, args[0]);
-               }
-               else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_LOG_RECORD_SPAN)) {
-                       if (!FLT_OTEL_ARG_ISVALID(i + 1))
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       else if (log->span != NULL)
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       else
-                               retval = flt_otel_parse_strdup(&(log->span), NULL, args[++i], err, args[0]);
-               }
-               else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_LOG_RECORD_ATTR)) {
-                       if (!FLT_OTEL_ARG_ISVALID(i + 1) || !FLT_OTEL_ARG_ISVALID(i + 2))
-                               FLT_OTEL_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                       else {
-                               retval = flt_otel_parse_cfg_sample(file, line, args, i + 2, 1, NULL, &(log->attributes), err);
-                               if (!(retval & ERR_CODE))
-                                       i += 2;
-                       }
-               }
-               else {
-                       /*
-                        * Not a recognized keyword -- the remaining arguments
-                        * are sample fetch expressions or a log-format string.
-                        */
-                       retval = flt_otel_parse_cfg_sample(file, line, args, i, 0, NULL, &(log->samples), err);
-
-                       break;
-               }
-       }
-
-       if (!(retval & ERR_CODE) && LIST_ISEMPTY(&(log->samples)))
-               FLT_OTEL_PARSE_ERR(err, "'%s' : missing body expression (use '%s%s')", args[0], pdata->name, pdata->usage);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg_scope - otel-scope section parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg_scope(const char *file, int line, char **args, int kw_mod)
- *
- * ARGUMENTS
- *   file   - configuration file path
- *   line   - configuration file line number
- *   args   - configuration line arguments array
- *   kw_mod - keyword modifier flags (e.g. KWM_NO)
- *
- * DESCRIPTION
- *   Section parser for the otel-scope configuration block.  Handles keywords:
- *   scope ID, span (with optional root/parent/link modifiers), link, attribute,
- *   event, baggage, status, inject, extract, finish, instrument, log-record,
- *   acl, and otel-event (with optional if/unless conditions).
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg_scope(const char *file, int line, char **args, int kw_mod)
-{
-#define FLT_OTEL_PARSE_SCOPE_DEF(a,b,c,d,e,f,g)   { FLT_OTEL_PARSE_SCOPE_##a, b, FLT_OTEL_PARSE_INVALID_##c, d, e, f, g },
-       static const struct flt_otel_parse_data  parse_data[] = { FLT_OTEL_PARSE_SCOPE_DEFINES };
-#undef FLT_OTEL_PARSE_SCOPE_DEF
-       const struct flt_otel_parse_data        *pdata = NULL;
-       char                                    *err = NULL;
-       int                                      i, retval = ERR_NONE;
-
-       OTELC_FUNC("\"%s\", %d, %p, 0x%08x", OTELC_STR_ARG(file), line, args, kw_mod);
-
-       if (flt_otel_parse_check_scope())
-               OTELC_RETURN_INT(retval);
-
-       /* Validate and identify the scope keyword. */
-       retval = flt_otel_parse_cfg_check(file, line, args, flt_otel_current_span, parse_data, OTELC_TABLESIZE(parse_data), &pdata, &err);
-       if (retval & ERR_CODE) {
-               FLT_OTEL_PARSE_IFERR_ALERT();
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       /* Handle keyword-specific scope configuration. */
-       if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_ID) {
-               /* Initialization of a new scope. */
-               flt_otel_current_scope = flt_otel_conf_scope_init(args[1], line, &(flt_otel_current_config->scopes), &err);
-               if (flt_otel_current_scope == NULL)
-                       retval |= ERR_ABORT | ERR_ALERT;
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_SPAN) {
-               /*
-                * Checking if this is the beginning of the definition of
-                * a new span.
-                */
-               if (flt_otel_current_span != NULL) {
-                       OTELC_DBG(DEBUG, "span '%s' (done)", flt_otel_current_span->id);
-
-                       flt_otel_current_span = NULL;
-               }
-
-               /* Initialization of a new span. */
-               flt_otel_current_span = flt_otel_conf_span_init(args[1], line, &(flt_otel_current_scope->spans), &err);
-
-               /*
-                * In case the span has a defined reference (parent), the
-                * correctness of the arguments is checked here.
-                */
-               if (flt_otel_current_span == NULL) {
-                       retval |= ERR_ABORT | ERR_ALERT;
-               }
-               else if (FLT_OTEL_ARG_ISVALID(2)) {
-                       for (i = 2; (i < pdata->args_max) && FLT_OTEL_ARG_ISVALID(i); i++) {
-                               if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_SPAN_ROOT)) {
-                                       if (flt_otel_current_span->flag_root)
-                                               FLT_OTEL_PARSE_ERR(&err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
-                                       else
-                                               flt_otel_current_span->flag_root = 1;
-                               }
-                               else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_SPAN_PARENT)) {
-                                       if (FLT_OTEL_ARG_ISVALID(i + 1))
-                                               retval |= flt_otel_parse_strdup(&(flt_otel_current_span->ref_id), &(flt_otel_current_span->ref_id_len), args[++i], &err, args[1]);
-                                       else
-                                               FLT_OTEL_PARSE_ERR(&err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               }
-                               else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_SPAN_LINK)) {
-                                       if (FLT_OTEL_ARG_ISVALID(i + 1)) {
-                                               if (flt_otel_conf_link_init(args[++i], line, &(flt_otel_current_span->links), &err) == NULL)
-                                                       retval |= ERR_ABORT | ERR_ALERT;
-                                       } else {
-                                               FLT_OTEL_PARSE_ERR(&err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
-                                       }
-                               }
-                               else {
-                                       FLT_OTEL_PARSE_ERR(&err, "'%s' : invalid argument (use '%s%s')", args[i], pdata->name, pdata->usage);
-                               }
-                       }
-               }
-               else {
-                       /*
-                        * This is not a faulty configuration, only such a case
-                        * will be logged.
-                        */
-                       OTELC_DBG(DEBUG, "new span '%s' without reference", flt_otel_current_span->id);
-               }
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_LINK) {
-               for (i = 1; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++)
-                       if (flt_otel_conf_link_init(args[i], line, &(flt_otel_current_span->links), &err) == NULL)
-                               retval |= ERR_ABORT | ERR_ALERT;
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_ATTRIBUTE) {
-               retval = flt_otel_parse_cfg_sample(file, line, args, 2, 0, NULL, &(flt_otel_current_span->attributes), &err);
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_EVENT) {
-               struct otelc_value extra = { .u_type = OTELC_VALUE_STRING, .u.value_string = args[1] };
-
-               retval = flt_otel_parse_cfg_sample(file, line, args, 3, 0, &extra, &(flt_otel_current_span->events), &err);
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_BAGGAGE) {
-               retval = flt_otel_parse_cfg_sample(file, line, args, 2, 0, NULL, &(flt_otel_current_span->baggages), &err);
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_STATUS) {
-#define FLT_OTEL_PARSE_SCOPE_STATUS_DEF(a,b)   { OTELC_SPAN_STATUS_##a, b },
-               static const struct {
-                       int         code;
-                       const char *keyword;
-               } status[] = { FLT_OTEL_PARSE_SCOPE_STATUS_DEFINES };
-#undef FLT_OTEL_PARSE_SCOPE_STATUS_DEF
-
-               for (i = 0; i < OTELC_TABLESIZE(status); i++)
-                       if (FLT_OTEL_PARSE_KEYWORD(1, status[i].keyword)) {
-                               OTELC_DBG(DEBUG, "span status: %d '%s'", status[i].code, status[i].keyword);
-
-                               break;
-                       }
-
-               /*
-                * Regardless of the use of the list, only one status per event
-                * is allowed.
-                */
-               if (i >= OTELC_TABLESIZE(status)) {
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : invalid span status", args[1]);
-               }
-               else if (LIST_ISEMPTY(&(flt_otel_current_span->statuses))) {
-                       struct otelc_value extra = { .u_type = OTELC_VALUE_INT32, .u.value_int32 = status[i].code };
-
-                       retval = flt_otel_parse_cfg_sample(file, line, args, 2, 0, &extra, &(flt_otel_current_span->statuses), &err);
-               }
-               else {
-                       FLT_OTEL_PARSE_ERR(&err, "only one status per event is allowed");
-               }
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_INJECT) {
-               /*
-                * Automatic context name generation can be specified here if
-                * the contents of the FLT_OTEL_PARSE_CTX_AUTONAME macro are
-                * used as the name.  In that case, if the context is after a
-                * particular event, it gets its name; otherwise it gets the
-                * name of the current span.
-                */
-               if (flt_otel_current_span->ctx_id != NULL)
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : only one context per span is allowed", args[1]);
-               else if (!FLT_OTEL_PARSE_KEYWORD(1, FLT_OTEL_PARSE_CTX_AUTONAME))
-                       retval = flt_otel_parse_strdup(&(flt_otel_current_span->ctx_id), &(flt_otel_current_span->ctx_id_len), args[1], &err, args[0]);
-               else if (flt_otel_current_scope->event != FLT_OTEL_EVENT__NONE)
-                       retval = flt_otel_parse_strdup(&(flt_otel_current_span->ctx_id), &(flt_otel_current_span->ctx_id_len), flt_otel_event_data[flt_otel_current_scope->event].name, &err, args[0]);
-               else {
-                       const char *ch;
-
-                       ch = invalid_prefix_char(flt_otel_current_span->id);
-                       if (ch == NULL)
-                               retval = flt_otel_parse_strdup(&(flt_otel_current_span->ctx_id), &(flt_otel_current_span->ctx_id_len), flt_otel_current_span->id, &err, args[0]);
-                       else
-                               FLT_OTEL_PARSE_ERR(&err, "'%s' : character '%c' is not permitted in the context name", flt_otel_current_span->id, *ch);
-               }
-
-               if (flt_otel_current_span->ctx_id != NULL) {
-                       /*
-                        * Here is checked the context storage type; which, if
-                        * not explicitly specified, is set to HTTP headers.
-                        *
-                        * It is possible to use both types of context storage
-                        * at the same time.
-                        */
-                       if (FLT_OTEL_ARG_ISVALID(2)) {
-                               retval |= flt_otel_parse_cfg_scope_ctx(args, 2, &err);
-                               if (!(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(3))
-                                       retval |= flt_otel_parse_cfg_scope_ctx(args, 3, &err);
-                       } else {
-                               flt_otel_current_span->ctx_flags = FLT_OTEL_CTX_USE_HEADERS;
-                       }
-               }
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_EXTRACT) {
-               struct flt_otel_conf_context *conf_ctx;
-
-               /*
-                * Here is checked the context storage type; which, if
-                * not explicitly specified, is set to HTTP headers.
-                */
-               conf_ctx = flt_otel_conf_context_init(args[1], line, &(flt_otel_current_scope->contexts), &err);
-               if (conf_ctx == NULL)
-                       retval |= ERR_ABORT | ERR_ALERT;
-               else if (!FLT_OTEL_ARG_ISVALID(2))
-                       conf_ctx->flags = FLT_OTEL_CTX_USE_HEADERS;
-               else if (FLT_OTEL_PARSE_KEYWORD(2, FLT_OTEL_PARSE_CTX_USE_HEADERS))
-                       conf_ctx->flags = FLT_OTEL_CTX_USE_HEADERS;
-#ifdef USE_OTEL_VARS
-               else if (FLT_OTEL_PARSE_KEYWORD(2, FLT_OTEL_PARSE_CTX_USE_VARS))
-                       conf_ctx->flags = FLT_OTEL_CTX_USE_VARS;
-#endif
-               else
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : invalid context storage type", args[2]);
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_FINISH) {
-               retval = flt_otel_parse_cfg_str(file, line, args, &(flt_otel_current_scope->spans_to_finish), &err);
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_INSTRUMENT) {
-               retval = flt_otel_parse_cfg_instrument(file, line, args, pdata, &err);
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_LOG_RECORD) {
-               retval = flt_otel_parse_cfg_log_record(file, line, args, pdata, &err);
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_ACL) {
-               if (FLT_OTEL_PARSE_KEYWORD(1, "or"))
-                       FLT_OTEL_PARSE_ERR(&err, "'%s %s ...' : invalid ACL name", args[0], args[1]);
-               else if (parse_acl((const char **)args + 1, &(flt_otel_current_scope->acls), &err, &(flt_otel_current_config->proxy->conf.args), file, line) == NULL)
-                       retval |= ERR_ABORT | ERR_ALERT;
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_IDLE_TIMEOUT) {
-               const char *res;
-               uint        timeout;
-
-               res = parse_time_err(args[1], &timeout, TIME_UNIT_MS);
-               if (res == PARSE_TIME_OVER)
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : timer overflow in argument '%s'", args[0], args[1]);
-               else if (res == PARSE_TIME_UNDER)
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : timer underflow in argument '%s'", args[0], args[1]);
-               else if (res != NULL)
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : unexpected character '%c' in '%s'", args[0], *res, args[1]);
-               else if (timeout == 0)
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : value must be greater than zero", args[0]);
-               else
-                       flt_otel_current_scope->idle_timeout = timeout;
-       }
-       else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_ON_EVENT) {
-               /* Scope can only have one event defined. */
-               if (flt_otel_current_scope->event != FLT_OTEL_EVENT__NONE) {
-                       FLT_OTEL_PARSE_ERR(&err, "'%s' : event already set", flt_otel_current_scope->id);
-               } else {
-                       /* Check the event name. */
-                       for (i = 0; i < OTELC_TABLESIZE(flt_otel_event_data); i++)
-                               if (FLT_OTEL_PARSE_KEYWORD(1, flt_otel_event_data[i].name)) {
-                                       flt_otel_current_scope->event = i;
-
-                                       break;
-                               }
-
-                       /*
-                        * The event can have some condition defined and this
-                        * is checked here.
-                        */
-                       if (flt_otel_current_scope->event == FLT_OTEL_EVENT__NONE) {
-                               FLT_OTEL_PARSE_ERR(&err, "'%s' : unknown event", args[1]);
-                       }
-                       else if (!FLT_OTEL_ARG_ISVALID(2)) {
-                               /* Do nothing. */
-                       }
-                       else if (FLT_OTEL_PARSE_KEYWORD(2, FLT_OTEL_CONDITION_IF) || FLT_OTEL_PARSE_KEYWORD(2, FLT_OTEL_CONDITION_UNLESS)) {
-                               /*
-                                * We will first try to build ACL condition using
-                                * local settings and then if that fails, using
-                                * global settings (from instrumentation block).
-                                * If it also fails, then try to use ACL defined
-                                * in the HAProxy configuration.
-                                */
-                               if (flt_otel_current_config->instr == NULL) {
-                                       FLT_OTEL_PARSE_ERR(&err, "'%s' : instrumentation not defined", args[1]);
-                               } else {
-                                       flt_otel_current_scope->cond = flt_otel_parse_acl(file, line, flt_otel_current_config->proxy, (const char **)args + 2, &err, &(flt_otel_current_scope->acls), &(flt_otel_current_config->instr->acls), &(flt_otel_current_config->proxy->acl), NULL);
-                                       if (flt_otel_current_scope->cond == NULL)
-                                               retval |= ERR_ABORT | ERR_ALERT;
-                               }
-                       }
-                       else {
-                               FLT_OTEL_PARSE_ERR(&err, "'%s' : expects either 'if' or 'unless' followed by a condition but found '%s'", args[1], args[2]);
-                       }
-
-                       if (!(retval & ERR_CODE))
-                               OTELC_DBG(DEBUG, "event '%s'", args[1]);
-               }
-       }
-
-       FLT_OTEL_PARSE_IFERR_ALERT();
-
-       if ((retval & ERR_CODE) && (flt_otel_current_scope != NULL)) {
-               flt_otel_conf_scope_free(&flt_otel_current_scope);
-
-               flt_otel_current_span = NULL;
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_post_parse_cfg_scope - otel-scope post-parse check
- *
- * SYNOPSIS
- *   static int flt_otel_post_parse_cfg_scope(void)
- *
- * ARGUMENTS
- *   This function takes no arguments.
- *
- * DESCRIPTION
- *   Post-parse callback for the otel-scope section.  Verifies that HTTP header
- *   injection is only used on events that support it.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_post_parse_cfg_scope(void)
-{
-       struct flt_otel_conf_span *conf_span;
-       int                      retval = ERR_NONE;
-
-       OTELC_FUNC("");
-
-       if (flt_otel_current_scope == NULL)
-               OTELC_RETURN_INT(retval);
-
-       /* If span context inject is used, check that this is possible. */
-       list_for_each_entry(conf_span, &(flt_otel_current_scope->spans), list)
-               if ((conf_span->ctx_id != NULL) && (conf_span->ctx_flags & FLT_OTEL_CTX_USE_HEADERS))
-                       if (!flt_otel_event_data[flt_otel_current_scope->event].flag_http_inject)
-                               FLT_OTEL_POST_PARSE_ALERT("inject '%s' : cannot use on this event", conf_span->cfg_line, conf_span->ctx_id);
-
-       /* Validate idle-timeout / on-idle-timeout consistency. */
-       if (flt_otel_current_scope->idle_timeout == 0) {
-               if (flt_otel_current_scope->event == FLT_OTEL_EVENT__IDLE_TIMEOUT)
-                       FLT_OTEL_POST_PARSE_ALERT("'%s' : 'idle-timeout' is required for event 'on-idle-timeout'", flt_otel_current_scope->cfg_line, flt_otel_current_scope->id);
-       }
-       else if (flt_otel_current_scope->event != FLT_OTEL_EVENT__IDLE_TIMEOUT) {
-               FLT_OTEL_POST_PARSE_ALERT("'%s' : 'idle-timeout' can only be used with event 'on-idle-timeout'", flt_otel_current_scope->cfg_line, flt_otel_current_scope->id);
-       }
-
-       if (retval & ERR_CODE)
-               flt_otel_conf_scope_free(&flt_otel_current_scope);
-
-       flt_otel_current_scope = NULL;
-       flt_otel_current_span  = NULL;
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse_cfg - OTel configuration file parser
- *
- * SYNOPSIS
- *   static int flt_otel_parse_cfg(struct flt_otel_conf *conf, const char *flt_name, char **err)
- *
- * ARGUMENTS
- *   conf     - pointer to the filter configuration structure
- *   flt_name - filter name for error reporting
- *   err      - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses the OTel filter configuration file.  Backs up the current HAProxy
- *   section parsers, registers temporary otel-instrumentation, otel-group, and
- *   otel-scope section parsers, loads and parses the file, then restores the
- *   original sections.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse_cfg(struct flt_otel_conf *conf, const char *flt_name, char **err)
-{
-       struct list    backup_sections;
-       struct cfgfile cfg_file;
-       int            retval = ERR_ABORT | ERR_ALERT;
-
-       OTELC_FUNC("%p, \"%s\", %p:%p", conf, OTELC_STR_ARG(flt_name), OTELC_DPTR_ARGS(err));
-
-       flt_otel_current_config = conf;
-
-       /* Backup sections. */
-       LIST_INIT(&backup_sections);
-       cfg_backup_sections(&backup_sections);
-
-       /* Register new OTEL sections and parse the OTEL filter configuration file. */
-       if (!cfg_register_section(FLT_OTEL_PARSE_SECTION_INSTR_ID, flt_otel_parse_cfg_instr, flt_otel_post_parse_cfg_instr))
-               /* Do nothing. */;
-       else if (!cfg_register_section(FLT_OTEL_PARSE_SECTION_GROUP_ID, flt_otel_parse_cfg_group, flt_otel_post_parse_cfg_group))
-               /* Do nothing. */;
-       else if (!cfg_register_section(FLT_OTEL_PARSE_SECTION_SCOPE_ID, flt_otel_parse_cfg_scope, flt_otel_post_parse_cfg_scope))
-               /* Do nothing. */;
-       else if (access(conf->cfg_file, R_OK) == -1)
-               FLT_OTEL_PARSE_ERR(err, "'%s' : %s", conf->cfg_file, strerror(errno));
-       else {
-               struct list saved_args = LIST_HEAD_INIT(saved_args);
-
-               /*
-                * Sample fetch arguments queued during parsing are normally
-                * resolved by smp_resolve_args() in the proxy
-                * post-configuration phase.  That call uses the proxy's own
-                * capabilities, so backend-only fetches like be_conn would
-                * fail when the filter is attached to a frontend.
-                *
-                * The OTel filter spans both request and response channels,
-                * so its sample fetches must be resolved with full FE+BE
-                * capabilities.  To achieve this the proxy's arg list is saved
-                * and replaced with a fresh one before parsing.  The OTel
-                * config parser adds only ARGC_OTEL entries to the new list.
-                * After parsing, those entries are moved to conf->smp_args and
-                * resolved later in flt_otel_check(), which runs after all
-                * configuration sections have been parsed so that backends and
-                * servers are available.
-                */
-               LIST_SPLICE(&saved_args, &(conf->proxy->conf.args.list));
-               LIST_INIT(&(conf->proxy->conf.args.list));
-
-               (void)memset(&cfg_file, 0, sizeof(cfg_file));
-               cfg_file.filename = conf->cfg_file;
-               cfg_file.size     = load_cfg_in_mem(cfg_file.filename, &(cfg_file.content));
-               if (cfg_file.size >= 0)
-                       retval = parse_cfg(&cfg_file);
-               ha_free(&(cfg_file.content));
-
-               /* Stash OTEL args for deferred resolution. */
-               LIST_SPLICE(&(conf->smp_args), &(conf->proxy->conf.args.list));
-               LIST_INIT(&(conf->proxy->conf.args.list));
-
-               /* Restore the original arg list unchanged. */
-               LIST_SPLICE(&(conf->proxy->conf.args.list), &saved_args);
-       }
-
-       /* Unregister OTEL sections and restore previous sections. */
-       cfg_unregister_sections();
-       cfg_restore_sections(&backup_sections);
-
-       flt_otel_current_config = NULL;
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_parse - main filter parser entry point
- *
- * SYNOPSIS
- *   static int flt_otel_parse(char **args, int *cur_arg, struct proxy *px, struct flt_conf *fconf, char **err, void *private)
- *
- * ARGUMENTS
- *   args    - configuration line arguments array
- *   cur_arg - pointer to the current argument index
- *   px      - proxy instance owning the filter
- *   fconf   - filter configuration structure to populate
- *   err     - indirect pointer to error message string
- *   private - unused private data pointer
- *
- * DESCRIPTION
- *   Main filter parser entry point, registered for the "otel" filter keyword.
- *   Parses the filter ID and configuration file path from the HAProxy
- *   configuration line.  If no filter ID is specified, the default ID is used.
- *
- * RETURN VALUE
- *   Returns ERR_NONE (== 0) in case of success,
- *   or a combination of ERR_* flags if an error is encountered.
- */
-static int flt_otel_parse(char **args, int *cur_arg, struct proxy *px, struct flt_conf *fconf, char **err, void *private)
-{
-       struct flt_otel_conf *conf = NULL;
-       int                   pos, retval = ERR_NONE;
-
-       OTELC_FUNC("%p, %p, %p, %p, %p:%p, %p", args, cur_arg, px, fconf, OTELC_DPTR_ARGS(err), private);
-
-       OTELC_DBG_IFDEF(otelc_dbg_level = FLT_OTEL_DEBUG_LEVEL, );
-
-#ifdef OTELC_DBG_MEM
-       /* Initialize the debug memory tracker before the first allocation. */
-       FLT_OTEL_RUN_ONCE(
-               if (otelc_dbg_mem_init(&dbg_mem, dbg_mem_data, OTELC_TABLESIZE(dbg_mem_data)) == -1) {
-                       FLT_OTEL_PARSE_ERR(err, "cannot initialize memory debugger");
-
-                       OTELC_RETURN_INT(retval);
-               }
-       );
-#endif
-
-       FLT_OTEL_ARGS_DUMP();
-
-       conf = flt_otel_conf_init(px);
-       if (conf == NULL) {
-               FLT_OTEL_PARSE_ERR(err, "'%s' : out of memory", args[*cur_arg]);
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       /* Process filter option key-value pairs. */
-       for (pos = *cur_arg + 1; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(pos); pos++) {
-               OTELC_DBG(DEBUG, "args[%d:2]: { '%s' '%s' }", pos, args[pos], args[pos + 1]);
-
-               if (FLT_OTEL_PARSE_KEYWORD(pos, FLT_OTEL_OPT_FILTER_ID)) {
-                       retval = flt_otel_parse_keyword(&(conf->id), args, *cur_arg, pos, err, "name");
-                       pos++;
-               }
-               else if (FLT_OTEL_PARSE_KEYWORD(pos, FLT_OTEL_OPT_CONFIG)) {
-                       retval = flt_otel_parse_keyword(&(conf->cfg_file), args, *cur_arg, pos, err, "configuration file");
-                       if (!(retval & ERR_CODE))
-                               retval = flt_otel_parse_cfg(conf, args[*cur_arg], err);
-                       pos++;
-               }
-               else {
-                       FLT_OTEL_PARSE_ERR(err, "'%s' : unknown keyword '%s'", args[*cur_arg], args[pos]);
-               }
-       }
-
-       /* If the OpenTelemetry filter ID is not set, use default name. */
-       if (!(retval & ERR_CODE) && (conf->id == NULL)) {
-               ha_warning("parsing : " FLT_OTEL_FMT_TYPE FLT_OTEL_FMT_NAME "'no filter id set, using default id '%s'\n", FLT_OTEL_OPT_FILTER_ID_DEFAULT);
-
-               retval = flt_otel_parse_strdup(&(conf->id), NULL, FLT_OTEL_OPT_FILTER_ID_DEFAULT, err, args[*cur_arg]);
-       }
-
-       if (!(retval & ERR_CODE) && (conf->cfg_file == NULL))
-               FLT_OTEL_PARSE_ERR(err, "'%s' : no configuration file specified", args[*cur_arg]);
-
-       if (retval & ERR_CODE) {
-               flt_otel_conf_free(&conf);
-       } else {
-               fconf->id   = otel_flt_id;
-               fconf->ops  = &flt_otel_ops;
-               fconf->conf = conf;
-
-               *cur_arg = pos;
-
-               OTELC_DBG(DEBUG, "filter set: id '%s', config '%s'", conf->id, conf->cfg_file);
-               FLT_OTEL_DBG_CONF("- conf ", (typeof(conf))fconf->conf);
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/* Declare the filter parser for FLT_OTEL_OPT_NAME keyword. */
-static struct flt_kw_list flt_kws = { FLT_OTEL_SCOPE, { }, {
-               { FLT_OTEL_OPT_NAME, flt_otel_parse, NULL },
-               { NULL, NULL, NULL },
-       }
-};
-
-INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/pool.c b/addons/otel/src/pool.c
deleted file mode 100644 (file)
index dc1b077..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-struct pool_head *pool_head_otel_scope_span __read_mostly = NULL;
-struct pool_head *pool_head_otel_scope_context __read_mostly = NULL;
-struct pool_head *pool_head_otel_runtime_context __read_mostly = NULL;
-struct pool_head *pool_head_otel_span_context __read_mostly = NULL;
-
-#ifdef USE_POOL_OTEL_SCOPE_SPAN
-REGISTER_POOL(&pool_head_otel_scope_span, "otel_scope_span", sizeof(struct flt_otel_scope_span));
-#endif
-#ifdef USE_POOL_OTEL_SCOPE_CONTEXT
-REGISTER_POOL(&pool_head_otel_scope_context, "otel_scope_context", sizeof(struct flt_otel_scope_context));
-#endif
-#ifdef USE_POOL_OTEL_RUNTIME_CONTEXT
-REGISTER_POOL(&pool_head_otel_runtime_context, "otel_runtime_context", sizeof(struct flt_otel_runtime_context));
-#endif
-#ifdef USE_POOL_OTEL_SPAN_CONTEXT
-REGISTER_POOL(&pool_head_otel_span_context, "otel_span_context", MAX(sizeof(struct otelc_span), sizeof(struct otelc_span_context)));
-#endif
-
-
-/***
- * NAME
- *   flt_otel_pool_alloc - pool-aware memory allocation
- *
- * SYNOPSIS
- *   void *flt_otel_pool_alloc(struct pool_head *pool, size_t size, bool flag_clear, char **err)
- *
- * ARGUMENTS
- *   pool       - HAProxy memory pool to allocate from (or NULL for heap)
- *   size       - number of bytes to allocate
- *   flag_clear - whether to zero-fill the allocated memory
- *   err        - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Allocates <size> bytes of memory from the HAProxy memory <pool>.  If <pool>
- *   is NULL, the allocation falls back to the heap via OTELC_MALLOC().  When
- *   <flag_clear> is set, the allocated memory is zero-filled.  On allocation
- *   failure, an error message is stored via <err>.
- *
- * RETURN VALUE
- *   Returns a pointer to the allocated memory, or NULL on failure.
- */
-void *flt_otel_pool_alloc(struct pool_head *pool, size_t size, bool flag_clear, char **err)
-{
-       void *retptr;
-
-       OTELC_FUNC("%p, %zu, %hhu, %p:%p", pool, size, flag_clear, OTELC_DPTR_ARGS(err));
-
-       if (pool != NULL) {
-               retptr = pool_alloc(pool);
-               if (retptr != NULL)
-                       OTELC_DBG(NOTICE, "POOL_ALLOC: %s:%d(%p %zu)", __func__, __LINE__, retptr, FLT_OTEL_DEREF(pool, size, size));
-       } else {
-               retptr = OTELC_MALLOC(size);
-       }
-
-       if (retptr == NULL)
-               FLT_OTEL_ERR("out of memory");
-       else if (flag_clear)
-               (void)memset(retptr, 0, size);
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_pool_strndup - pool-aware string duplication
- *
- * SYNOPSIS
- *   void *flt_otel_pool_strndup(struct pool_head *pool, const char *s, size_t size, char **err)
- *
- * ARGUMENTS
- *   pool - HAProxy memory pool to allocate from (or NULL for heap)
- *   s    - source string to duplicate
- *   size - maximum number of characters to copy
- *   err  - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Duplicates up to <size> characters from the string <s> using the HAProxy
- *   memory <pool>.  If <pool> is NULL, the duplication falls back to
- *   OTELC_STRNDUP().  When using a pool, the copy is truncated to <pool>->size-1
- *   bytes and null-terminated.
- *
- * RETURN VALUE
- *   Returns a pointer to the duplicated string, or NULL on failure.
- */
-void *flt_otel_pool_strndup(struct pool_head *pool, const char *s, size_t size, char **err)
-{
-       void *retptr;
-
-       OTELC_FUNC("%p, \"%.*s\", %zu, %p:%p", pool, (int)size, s, size, OTELC_DPTR_ARGS(err));
-
-       if (pool != NULL) {
-               retptr = pool_alloc(pool);
-               if (retptr != NULL) {
-                       (void)memcpy(retptr, s, MIN(pool->size - 1, size));
-
-                       ((uint8_t *)retptr)[MIN(pool->size - 1, size)] = '\0';
-               }
-       } else {
-               retptr = OTELC_STRNDUP(s, size);
-       }
-
-       if (retptr != NULL)
-               OTELC_DBG(NOTICE, "POOL_STRNDUP: %s:%d(%p %zu)", __func__, __LINE__, retptr, FLT_OTEL_DEREF(pool, size, size));
-       else
-               FLT_OTEL_ERR("out of memory");
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_pool_free - pool-aware memory deallocation
- *
- * SYNOPSIS
- *   void flt_otel_pool_free(struct pool_head *pool, void **ptr)
- *
- * ARGUMENTS
- *   pool - HAProxy memory pool to return memory to (or NULL for heap)
- *   ptr  - indirect pointer to the memory to free
- *
- * DESCRIPTION
- *   Returns memory referenced by <*ptr> to the HAProxy memory <pool>.  If
- *   <pool> is NULL, the memory is freed via OTELC_SFREE().  The pointer <*ptr>
- *   is set to NULL after freeing.  If <ptr> is NULL or <*ptr> is already NULL,
- *   the function returns immediately.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_pool_free(struct pool_head *pool, void **ptr)
-{
-       OTELC_FUNC("%p, %p:%p", pool, OTELC_DPTR_ARGS(ptr));
-
-       if ((ptr == NULL) || (*ptr == NULL))
-               OTELC_RETURN();
-
-       OTELC_DBG(NOTICE, "POOL_FREE: %s:%d(%p %u)", __func__, __LINE__, *ptr, FLT_OTEL_DEREF(pool, size, 0));
-
-       if (pool != NULL)
-               pool_free(pool, *ptr);
-       else
-               OTELC_SFREE(*ptr);
-
-       *ptr = NULL;
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_pool_init - OTel filter memory pool initialization
- *
- * SYNOPSIS
- *   int flt_otel_pool_init(void)
- *
- * ARGUMENTS
- *   This function takes no arguments.
- *
- * DESCRIPTION
- *   Initializes all memory pools used by the OTel filter.  Each pool is
- *   created only when the corresponding USE_POOL_OTEL_* macro is defined.
- *
- * RETURN VALUE
- *   Returns FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_pool_init(void)
-{
-       int retval = FLT_OTEL_RET_OK;
-
-       OTELC_FUNC("");
-
-#ifdef USE_POOL_OTEL_SCOPE_SPAN
-       FLT_OTEL_POOL_INIT(pool_head_otel_scope_span, "otel_scope_span", sizeof(struct flt_otel_scope_span), retval);
-#endif
-#ifdef USE_POOL_OTEL_SCOPE_CONTEXT
-       FLT_OTEL_POOL_INIT(pool_head_otel_scope_context, "otel_scope_context", sizeof(struct flt_otel_scope_context), retval);
-#endif
-#ifdef USE_POOL_OTEL_RUNTIME_CONTEXT
-       FLT_OTEL_POOL_INIT(pool_head_otel_runtime_context, "otel_runtime_context", sizeof(struct flt_otel_runtime_context), retval);
-#endif
-#ifdef USE_POOL_OTEL_SPAN_CONTEXT
-       FLT_OTEL_POOL_INIT(pool_head_otel_span_context, "otel_span_context", OTELC_MAX(sizeof(struct otelc_span), sizeof(struct otelc_span_context)), retval);
-#endif
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_pool_destroy - OTel filter memory pool destruction
- *
- * SYNOPSIS
- *   void flt_otel_pool_destroy(void)
- *
- * ARGUMENTS
- *   This function takes no arguments.
- *
- * DESCRIPTION
- *   Destroys all memory pools used by the OTel filter.  Each pool is
- *   destroyed only when the corresponding USE_POOL_OTEL_* macro is defined.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_pool_destroy(void)
-{
-       OTELC_FUNC("");
-
-#ifdef USE_POOL_OTEL_SCOPE_SPAN
-       FLT_OTEL_POOL_DESTROY(pool_head_otel_scope_span);
-#endif
-#ifdef USE_POOL_OTEL_SCOPE_CONTEXT
-       FLT_OTEL_POOL_DESTROY(pool_head_otel_scope_context);
-#endif
-#ifdef USE_POOL_OTEL_RUNTIME_CONTEXT
-       FLT_OTEL_POOL_DESTROY(pool_head_otel_runtime_context);
-#endif
-#ifdef USE_POOL_OTEL_SPAN_CONTEXT
-       FLT_OTEL_POOL_DESTROY(pool_head_otel_span_context);
-#endif
-
-       OTELC_RETURN();
-}
-
-
-#ifdef DEBUG_OTEL
-
-/***
- * NAME
- *   flt_otel_pool_info - debug pool sizes logging
- *
- * SYNOPSIS
- *   void flt_otel_pool_info(void)
- *
- * ARGUMENTS
- *   This function takes no arguments.
- *
- * DESCRIPTION
- *   Logs the sizes of all registered HAProxy memory pools used by the OTel
- *   filter (buffer, trash, scope_span, scope_context, runtime_context).
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_pool_info(void)
-{
-       OTELC_DBG(NOTICE, "--- pool info ----------");
-
-       /*
-        * In case we have some error in the configuration file,
-        * it is possible that this pool was not initialized.
-        */
-#ifdef USE_POOL_BUFFER
-       OTELC_DBG(NOTICE, "  buffer: %p %u", pool_head_buffer, FLT_OTEL_DEREF(pool_head_buffer, size, 0));
-#endif
-#ifdef USE_TRASH_CHUNK
-       OTELC_DBG(NOTICE, "  trash: %p %u", pool_head_trash, FLT_OTEL_DEREF(pool_head_trash, size, 0));
-#endif
-
-#ifdef USE_POOL_OTEL_SCOPE_SPAN
-       OTELC_DBG(NOTICE, "  otel_scope_span: %p %u", pool_head_otel_scope_span, FLT_OTEL_DEREF(pool_head_otel_scope_span, size, 0));
-#endif
-#ifdef USE_POOL_OTEL_SCOPE_CONTEXT
-       OTELC_DBG(NOTICE, "  otel_scope_context: %p %u", pool_head_otel_scope_context, FLT_OTEL_DEREF(pool_head_otel_scope_context, size, 0));
-#endif
-#ifdef USE_POOL_OTEL_RUNTIME_CONTEXT
-       OTELC_DBG(NOTICE, "  otel_runtime_context: %p %u", pool_head_otel_runtime_context, FLT_OTEL_DEREF(pool_head_otel_runtime_context, size, 0));
-#endif
-#ifdef USE_POOL_OTEL_SPAN_CONTEXT
-       OTELC_DBG(NOTICE, "  otel_span_context: %p %u", pool_head_otel_span_context, FLT_OTEL_DEREF(pool_head_otel_span_context, size, 0));
-#endif
-}
-
-#endif /* DEBUG_OTEL */
-
-
-/***
- * NAME
- *   flt_otel_trash_alloc - trash buffer allocation
- *
- * SYNOPSIS
- *   struct buffer *flt_otel_trash_alloc(bool flag_clear, char **err)
- *
- * ARGUMENTS
- *   flag_clear - whether to zero-fill the buffer area
- *   err        - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Allocates a temporary buffer chunk for use as scratch space.  When
- *   USE_TRASH_CHUNK is defined, the buffer is obtained via alloc_trash_chunk();
- *   otherwise, a buffer structure and its data area are allocated from the heap
- *   using global.tune.bufsize as the buffer size.  When <flag_clear> is set,
- *   the buffer's data area is zero-filled.
- *
- * RETURN VALUE
- *   Returns a pointer to the allocated buffer, or NULL on failure.
- */
-struct buffer *flt_otel_trash_alloc(bool flag_clear, char **err)
-{
-       struct buffer *retptr;
-
-       OTELC_FUNC("%hhu, %p:%p", flag_clear, OTELC_DPTR_ARGS(err));
-
-#ifdef USE_TRASH_CHUNK
-       retptr = alloc_trash_chunk();
-       if (retptr != NULL)
-               OTELC_DBG(NOTICE, "TRASH_ALLOC: %s:%d(%p %zu)", __func__, __LINE__, retptr, retptr->size);
-#else
-       retptr = OTELC_MALLOC(sizeof(*retptr));
-       if (retptr != NULL) {
-               chunk_init(retptr, OTELC_MALLOC(global.tune.bufsize), global.tune.bufsize);
-               if (retptr->area == NULL)
-                       OTELC_SFREE_CLEAR(retptr);
-               else
-                       *(retptr->area) = '\0';
-       }
-#endif
-
-       if (retptr == NULL)
-               FLT_OTEL_ERR("out of memory");
-       else if (flag_clear)
-               (void)memset(retptr->area, 0, retptr->size);
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_trash_free - trash buffer deallocation
- *
- * SYNOPSIS
- *   void flt_otel_trash_free(struct buffer **ptr)
- *
- * ARGUMENTS
- *   ptr - indirect pointer to the buffer to free
- *
- * DESCRIPTION
- *   Frees a trash buffer chunk previously allocated by flt_otel_trash_alloc().
- *   When USE_TRASH_CHUNK is defined, the buffer is freed via
- *   free_trash_chunk(); otherwise, both the data area and the buffer structure
- *   are freed individually.  The pointer <*ptr> is set to NULL after freeing.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_trash_free(struct buffer **ptr)
-{
-       OTELC_FUNC("%p:%p", OTELC_DPTR_ARGS(ptr));
-
-       if ((ptr == NULL) || (*ptr == NULL))
-               OTELC_RETURN();
-
-       OTELC_DBG(NOTICE, "TRASH_FREE: %s:%d(%p %zu)", __func__, __LINE__, *ptr, (*ptr)->size);
-
-#ifdef USE_TRASH_CHUNK
-       free_trash_chunk(*ptr);
-#else
-       OTELC_SFREE((*ptr)->area);
-       OTELC_SFREE(*ptr);
-#endif
-
-       *ptr = NULL;
-
-       OTELC_RETURN();
-}
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/scope.c b/addons/otel/src/scope.c
deleted file mode 100644 (file)
index eca2741..0000000
+++ /dev/null
@@ -1,745 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-/***
- * NAME
- *   flt_otel_runtime_context_init - per-stream runtime context allocation
- *
- * SYNOPSIS
- *   struct flt_otel_runtime_context *flt_otel_runtime_context_init(struct stream *s, struct filter *f, char **err)
- *
- * ARGUMENTS
- *   s   - the stream to which the context belongs
- *   f   - the filter instance
- *   err - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Allocates and initializes a per-stream runtime context from pool memory.
- *   It copies the hard-error, disabled and logging flags from the filter
- *   configuration, generates a UUID and stores it in the sess.otel.uuid
- *   HAProxy variable.
- *
- * RETURN VALUE
- *   Returns a pointer to the new runtime context, or NULL on failure.
- */
-struct flt_otel_runtime_context *flt_otel_runtime_context_init(struct stream *s, struct filter *f, char **err)
-{
-       const struct flt_otel_conf      *conf = FLT_OTEL_CONF(f);
-       struct buffer                    uuid;
-       struct flt_otel_runtime_context *retptr = NULL;
-
-       OTELC_FUNC("%p, %p, %p:%p", s, f, OTELC_DPTR_ARGS(err));
-
-       retptr = flt_otel_pool_alloc(pool_head_otel_runtime_context, sizeof(*retptr), 1, err);
-       if (retptr == NULL)
-               OTELC_RETURN_PTR(retptr);
-
-       /* Initialize runtime context fields and generate a session UUID. */
-       retptr->stream        = s;
-       retptr->filter        = f;
-       retptr->flag_harderr  = _HA_ATOMIC_LOAD(&(conf->instr->flag_harderr));
-       retptr->flag_disabled = _HA_ATOMIC_LOAD(&(conf->instr->flag_disabled));
-       retptr->logging       = _HA_ATOMIC_LOAD(&(conf->instr->logging));
-       retptr->idle_timeout  = 0;
-       retptr->idle_exp      = TICK_ETERNITY;
-       LIST_INIT(&(retptr->spans));
-       LIST_INIT(&(retptr->contexts));
-
-       uuid = b_make(retptr->uuid, sizeof(retptr->uuid), 0, 0);
-       ha_generate_uuid_v4(&uuid);
-
-#ifdef USE_OTEL_VARS
-       /*
-        * The HAProxy variable 'sess.otel.uuid' is registered here,
-        * after which its value is set to runtime context UUID.
-        */
-       if (flt_otel_var_register(FLT_OTEL_VAR_UUID, err) != -1)
-               (void)flt_otel_var_set(s, FLT_OTEL_VAR_UUID, retptr->uuid, SMP_OPT_DIR_REQ, err);
-#endif
-
-       FLT_OTEL_DBG_RUNTIME_CONTEXT("session context: ", retptr);
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_runtime_context_free - per-stream runtime context cleanup
- *
- * SYNOPSIS
- *   void flt_otel_runtime_context_free(struct filter *f)
- *
- * ARGUMENTS
- *   f - the filter instance whose runtime context is to be freed
- *
- * DESCRIPTION
- *   Frees the per-stream runtime context attached to <f>.  It ends all active
- *   spans with the current monotonic timestamp, destroys all extracted
- *   contexts, and returns the pool memory.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_runtime_context_free(struct filter *f)
-{
-       struct flt_otel_runtime_context *rt_ctx = f->ctx;
-
-       OTELC_FUNC("%p", f);
-
-       if (rt_ctx == NULL)
-               OTELC_RETURN();
-
-       FLT_OTEL_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
-
-       /* End all active spans with a common timestamp. */
-       if (!LIST_ISEMPTY(&(rt_ctx->spans))) {
-               struct timespec             ts_steady;
-               struct flt_otel_scope_span *span, *span_back;
-
-               /* All spans should be completed at the same time. */
-               (void)clock_gettime(CLOCK_MONOTONIC, &ts_steady);
-
-               list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list) {
-                       OTELC_OPSR(span->span, end_with_options, &ts_steady, OTELC_SPAN_STATUS_IGNORE, NULL);
-                       flt_otel_scope_span_free(&span);
-               }
-       }
-
-       /* Destroy all extracted span contexts. */
-       if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
-               struct flt_otel_scope_context *ctx, *ctx_back;
-
-               list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
-                       flt_otel_scope_context_free(&ctx);
-       }
-
-       flt_otel_pool_free(pool_head_otel_runtime_context, &(f->ctx));
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_span_init - scope span lookup or creation
- *
- * SYNOPSIS
- *   struct flt_otel_scope_span *flt_otel_scope_span_init(struct flt_otel_runtime_context *rt_ctx, const char *id, size_t id_len, const char *ref_id, size_t ref_id_len, uint dir, char **err)
- *
- * ARGUMENTS
- *   rt_ctx     - the runtime context owning the span list
- *   id         - the span operation name
- *   id_len     - length of the <id> string
- *   ref_id     - the parent span or context name, or NULL
- *   ref_id_len - length of the <ref_id> string
- *   dir        - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
- *   err        - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Finds an existing scope span by <id> in the runtime context or creates a
- *   new one.  If <ref_id> is set, it resolves the parent reference by searching
- *   the span list first, then the extracted context list.
- *
- * RETURN VALUE
- *   Returns the existing or new scope span, or NULL on failure.
- */
-struct flt_otel_scope_span *flt_otel_scope_span_init(struct flt_otel_runtime_context *rt_ctx, const char *id, size_t id_len, const char *ref_id, size_t ref_id_len, uint dir, char **err)
-{
-       struct otelc_span             *ref_span = NULL;
-       struct otelc_span_context     *ref_ctx = NULL;
-       struct flt_otel_scope_span    *span, *retptr = NULL;
-       struct flt_otel_scope_context *ctx;
-
-       OTELC_FUNC("%p, \"%s\", %zu, \"%s\", %zu, %u, %p:%p", rt_ctx, OTELC_STR_ARG(id), id_len, OTELC_STR_ARG(ref_id), ref_id_len, dir, OTELC_DPTR_ARGS(err));
-
-       if ((rt_ctx == NULL) || (id == NULL))
-               OTELC_RETURN_PTR(retptr);
-
-       /* Return the existing span if one matches this ID. */
-       list_for_each_entry(span, &(rt_ctx->spans), list)
-               if (FLT_OTEL_CONF_STR_CMP(span->id, id)) {
-                       OTELC_DBG(NOTICE, "found span %p", span);
-
-                       OTELC_RETURN_PTR(span);
-               }
-
-       /* Resolve the parent reference from spans or contexts. */
-       if (ref_id != NULL) {
-               list_for_each_entry(span, &(rt_ctx->spans), list)
-                       if (FLT_OTEL_CONF_STR_CMP(span->id, ref_id)) {
-                               ref_span = span->span;
-
-                               break;
-                       }
-
-               if (ref_span != NULL) {
-                       OTELC_DBG(NOTICE, "found referenced span %p", span);
-               } else {
-                       list_for_each_entry(ctx, &(rt_ctx->contexts), list)
-                               if (FLT_OTEL_CONF_STR_CMP(ctx->id, ref_id)) {
-                                       ref_ctx = ctx->context;
-
-                                       break;
-                               }
-
-                       if (ref_ctx != NULL) {
-                               OTELC_DBG(NOTICE, "found referenced context %p", ctx);
-                       } else {
-                               FLT_OTEL_ERR("cannot find referenced span/context '%s'", ref_id);
-
-                               OTELC_RETURN_PTR(retptr);
-                       }
-               }
-       }
-
-       retptr = flt_otel_pool_alloc(pool_head_otel_scope_span, sizeof(*retptr), 1, err);
-       if (retptr == NULL)
-               OTELC_RETURN_PTR(retptr);
-
-       /* Populate the new scope span and insert it into the list. */
-       retptr->id          = id;
-       retptr->id_len      = id_len;
-       retptr->smp_opt_dir = dir;
-       retptr->ref_span    = ref_span;
-       retptr->ref_ctx     = ref_ctx;
-       LIST_INSERT(&(rt_ctx->spans), &(retptr->list));
-
-       FLT_OTEL_DBG_SCOPE_SPAN("new span ", retptr);
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_span_free - scope span cleanup
- *
- * SYNOPSIS
- *   void flt_otel_scope_span_free(struct flt_otel_scope_span **ptr)
- *
- * ARGUMENTS
- *   ptr - pointer to the scope span pointer to free
- *
- * DESCRIPTION
- *   Frees a scope span entry pointed to by <ptr> and removes it from its list.
- *   If the OTel span is still active (non-NULL), the function refuses to free
- *   it and returns immediately.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_scope_span_free(struct flt_otel_scope_span **ptr)
-{
-       OTELC_FUNC("%p:%p", OTELC_DPTR_ARGS(ptr));
-
-       if ((ptr == NULL) || (*ptr == NULL))
-               OTELC_RETURN();
-
-       FLT_OTEL_DBG_SCOPE_SPAN("", *ptr);
-
-       /* If the span is still active, do nothing. */
-       if ((*ptr)->span != NULL) {
-               OTELC_DBG(NOTICE, "cannot finish active span");
-
-               OTELC_RETURN();
-       }
-
-       FLT_OTEL_LIST_DEL(&((*ptr)->list));
-       flt_otel_pool_free(pool_head_otel_scope_span, (void **)ptr);
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_context_init - scope context extraction
- *
- * SYNOPSIS
- *   struct flt_otel_scope_context *flt_otel_scope_context_init(struct flt_otel_runtime_context *rt_ctx, struct otelc_tracer *tracer, const char *id, size_t id_len, const struct otelc_text_map *text_map, uint dir, char **err)
- *
- * ARGUMENTS
- *   rt_ctx   - the runtime context owning the context list
- *   tracer   - the OTel tracer used for context extraction
- *   id       - the context name
- *   id_len   - length of the <id> string
- *   text_map - the carrier text map to extract from
- *   dir      - the sample fetch direction (SMP_OPT_DIR_REQ/RES)
- *   err      - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Finds an existing scope context by <id> in the runtime context or creates
- *   a new one by extracting the span context from the <text_map> carrier via
- *   the <tracer>.
- *
- * RETURN VALUE
- *   Returns the existing or new scope context, or NULL on failure.
- */
-struct flt_otel_scope_context *flt_otel_scope_context_init(struct flt_otel_runtime_context *rt_ctx, struct otelc_tracer *tracer, const char *id, size_t id_len, const struct otelc_text_map *text_map, uint dir, char **err)
-{
-       struct otelc_http_headers_reader  reader;
-       struct otelc_span_context        *span_ctx;
-       struct flt_otel_scope_context    *retptr = NULL;
-
-       OTELC_FUNC("%p, %p, \"%s\", %zu, %p, %u, %p:%p", rt_ctx, tracer, OTELC_STR_ARG(id), id_len, text_map, dir, OTELC_DPTR_ARGS(err));
-
-       if ((rt_ctx == NULL) || (tracer == NULL) || (id == NULL) || (text_map == NULL))
-               OTELC_RETURN_PTR(retptr);
-
-       /* Return the existing context if one matches this ID. */
-       list_for_each_entry(retptr, &(rt_ctx->contexts), list)
-               if (FLT_OTEL_CONF_STR_CMP(retptr->id, id)) {
-                       OTELC_DBG(NOTICE, "found context %p", retptr);
-
-                       OTELC_RETURN_PTR(retptr);
-               }
-
-       retptr = flt_otel_pool_alloc(pool_head_otel_scope_context, sizeof(*retptr), 1, err);
-       if (retptr == NULL)
-               OTELC_RETURN_PTR(retptr);
-
-       span_ctx = flt_otel_extract_http_headers(tracer, &reader, text_map);
-       if (span_ctx == NULL) {
-               flt_otel_scope_context_free(&retptr);
-
-               OTELC_RETURN_PTR(retptr);
-       }
-
-       /* Populate the new scope context and insert it into the list. */
-       retptr->id          = id;
-       retptr->id_len      = id_len;
-       retptr->smp_opt_dir = dir;
-       retptr->context     = span_ctx;
-       LIST_INSERT(&(rt_ctx->contexts), &(retptr->list));
-
-       FLT_OTEL_DBG_SCOPE_CONTEXT("new context ", retptr);
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_context_free - scope context cleanup
- *
- * SYNOPSIS
- *   void flt_otel_scope_context_free(struct flt_otel_scope_context **ptr)
- *
- * ARGUMENTS
- *   ptr - pointer to the scope context pointer to free
- *
- * DESCRIPTION
- *   Frees a scope context entry pointed to by <ptr>.  It destroys the
- *   underlying OTel span context, removes the entry from its list, and
- *   returns the pool memory.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_scope_context_free(struct flt_otel_scope_context **ptr)
-{
-       OTELC_FUNC("%p:%p", OTELC_DPTR_ARGS(ptr));
-
-       if ((ptr == NULL) || (*ptr == NULL))
-               OTELC_RETURN();
-
-       FLT_OTEL_DBG_SCOPE_CONTEXT("", *ptr);
-
-       if ((*ptr)->context != NULL)
-               OTELC_OPSR((*ptr)->context, destroy);
-
-       FLT_OTEL_LIST_DEL(&((*ptr)->list));
-       flt_otel_pool_free(pool_head_otel_scope_context, (void **)ptr);
-
-       OTELC_RETURN();
-}
-
-
-#ifdef DEBUG_OTEL
-
-/***
- * NAME
- *   flt_otel_scope_data_dump - debug scope data dump
- *
- * SYNOPSIS
- *   void flt_otel_scope_data_dump(const struct flt_otel_scope_data *data)
- *
- * ARGUMENTS
- *   data - the scope data structure to dump
- *
- * DESCRIPTION
- *   Dumps the contents of a scope <data> structure for debugging: baggage
- *   key-value pairs, attributes, events with their attributes, span links,
- *   and the status code/description.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_scope_data_dump(const struct flt_otel_scope_data *data)
-{
-       size_t i;
-
-       if (data == NULL)
-               return;
-
-       if (data->baggage.attr == NULL) {
-               OTELC_DBG(WORKER, "baggage %p:{ }", &(data->baggage));
-       } else {
-               OTELC_DBG(WORKER, "baggage %p:{", &(data->baggage));
-               for (i = 0; i < data->baggage.cnt; i++)
-                       OTELC_DBG_KV(WORKER, "  ", data->baggage.attr + i);
-               OTELC_DBG(WORKER, "}");
-       }
-
-       if (data->attributes.attr == NULL) {
-               OTELC_DBG(WORKER, "attributes %p:{ }", &(data->attributes));
-       } else {
-               OTELC_DBG(WORKER, "attributes %p:{", &(data->attributes));
-               for (i = 0; i < data->attributes.cnt; i++)
-                       OTELC_DBG_KV(WORKER, "  ", data->attributes.attr + i);
-               OTELC_DBG(WORKER, "}");
-       }
-
-       if (LIST_ISEMPTY(&(data->events))) {
-               OTELC_DBG(WORKER, "events %p:{ }", &(data->events));
-       } else {
-               struct flt_otel_scope_data_event *event;
-
-               OTELC_DBG(WORKER, "events %p:{", &(data->events));
-               list_for_each_entry_rev(event, &(data->events), list) {
-                       OTELC_DBG(WORKER, "  '%s' %zu/%zu", event->name, event->cnt, event->size);
-                       if (event->attr != NULL)
-                               for (i = 0; i < event->cnt; i++)
-                                       OTELC_DBG_KV(WORKER, "  ", event->attr + i);
-               }
-               OTELC_DBG(WORKER, "}");
-       }
-
-       if (LIST_ISEMPTY(&(data->links))) {
-               OTELC_DBG(WORKER, "links %p:{ }", &(data->links));
-       } else {
-               struct flt_otel_scope_data_link *link;
-
-               OTELC_DBG(WORKER, "links %p:{", &(data->links));
-               list_for_each_entry(link, &(data->links), list)
-                       OTELC_DBG(WORKER, "  %p %p", link->span, link->context);
-               OTELC_DBG(WORKER, "}");
-       }
-
-       if ((data->status.code == 0) && (data->status.description == NULL))
-               OTELC_DBG(WORKER, "status %p:{ }", &(data->status));
-       else
-               FLT_OTEL_DBG_SCOPE_DATA_STATUS("status ", &(data->status));
-}
-
-#endif /* DEBUG_OTEL */
-
-
-/***
- * NAME
- *   flt_otel_scope_data_init - scope data zero-initialization
- *
- * SYNOPSIS
- *   void flt_otel_scope_data_init(struct flt_otel_scope_data *ptr)
- *
- * ARGUMENTS
- *   ptr - the scope data structure to initialize
- *
- * DESCRIPTION
- *   Zero-initializes the scope data structure pointed to by <ptr> and sets up
- *   the event and link list heads.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_scope_data_init(struct flt_otel_scope_data *ptr)
-{
-       OTELC_FUNC("%p", ptr);
-
-       if (ptr == NULL)
-               OTELC_RETURN();
-
-       (void)memset(ptr, 0, sizeof(*ptr));
-       LIST_INIT(&(ptr->events));
-       LIST_INIT(&(ptr->links));
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_data_free - scope data cleanup
- *
- * SYNOPSIS
- *   void flt_otel_scope_data_free(struct flt_otel_scope_data *ptr)
- *
- * ARGUMENTS
- *   ptr - the scope data structure to free
- *
- * DESCRIPTION
- *   Frees all contents of the scope data structure pointed to by <ptr>: baggage
- *   and attribute key-value arrays, event entries with their attributes, link
- *   entries, and the status description string.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_scope_data_free(struct flt_otel_scope_data *ptr)
-{
-       struct flt_otel_scope_data_event *event, *event_back;
-       struct flt_otel_scope_data_link  *link, *link_back;
-
-       OTELC_FUNC("%p", ptr);
-
-       if (ptr == NULL)
-               OTELC_RETURN();
-
-       FLT_OTEL_DBG_SCOPE_DATA("", ptr);
-
-       /* Destroy all dynamic scope data contents. */
-       otelc_kv_destroy(&(ptr->baggage.attr), ptr->baggage.cnt);
-       otelc_kv_destroy(&(ptr->attributes.attr), ptr->attributes.cnt);
-       list_for_each_entry_safe(event, event_back, &(ptr->events), list) {
-               otelc_kv_destroy(&(event->attr), event->cnt);
-               OTELC_SFREE(event->name);
-               OTELC_SFREE(event);
-       }
-       /* Free all resolved link entries. */
-       list_for_each_entry_safe(link, link_back, &(ptr->links), list)
-               OTELC_SFREE(link);
-       OTELC_SFREE(ptr->status.description);
-
-       (void)memset(ptr, 0, sizeof(*ptr));
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_finish_mark - mark spans and contexts for finishing
- *
- * SYNOPSIS
- *   int flt_otel_scope_finish_mark(const struct flt_otel_runtime_context *rt_ctx, const char *id, size_t id_len)
- *
- * ARGUMENTS
- *   rt_ctx - the runtime context containing spans and contexts
- *   id     - the target name, or a wildcard ("*", "*req*", "*res*")
- *   id_len - length of the <id> string
- *
- * DESCRIPTION
- *   Marks spans and contexts for finishing.  The <id> argument supports
- *   wildcards: "*" marks all spans and contexts, "*req*" marks the request
- *   channel only, "*res*" marks the response channel only.  Otherwise, a named
- *   span or context is looked up by exact match.
- *
- * RETURN VALUE
- *   Returns the number of spans and contexts that were marked.
- */
-int flt_otel_scope_finish_mark(const struct flt_otel_runtime_context *rt_ctx, const char *id, size_t id_len)
-{
-       struct flt_otel_scope_span    *span;
-       struct flt_otel_scope_context *ctx;
-       int                            span_cnt = 0, ctx_cnt = 0, retval;
-
-       OTELC_FUNC("%p, \"%s\", %zu", rt_ctx, OTELC_STR_ARG(id), id_len);
-
-       /* Handle wildcard finish marks: all, request-only, response-only. */
-       if (FLT_OTEL_STR_CMP(FLT_OTEL_SCOPE_SPAN_FINISH_ALL, id)) {
-               list_for_each_entry(span, &(rt_ctx->spans), list) {
-                       span->flag_finish = 1;
-                       span_cnt++;
-               }
-
-               list_for_each_entry(ctx, &(rt_ctx->contexts), list) {
-                       ctx->flag_finish = 1;
-                       ctx_cnt++;
-               }
-
-               OTELC_DBG(NOTICE, "marked %d span(s), %d context(s)", span_cnt, ctx_cnt);
-       }
-       else if (FLT_OTEL_STR_CMP(FLT_OTEL_SCOPE_SPAN_FINISH_REQ, id)) {
-               list_for_each_entry(span, &(rt_ctx->spans), list)
-                       if (span->smp_opt_dir == SMP_OPT_DIR_REQ) {
-                               span->flag_finish = 1;
-                               span_cnt++;
-                       }
-
-               list_for_each_entry(ctx, &(rt_ctx->contexts), list)
-                       if (ctx->smp_opt_dir == SMP_OPT_DIR_REQ) {
-                               ctx->flag_finish = 1;
-                               ctx_cnt++;
-                       }
-
-               OTELC_DBG(NOTICE, "marked REQuest channel %d span(s), %d context(s)", span_cnt, ctx_cnt);
-       }
-       else if (FLT_OTEL_STR_CMP(FLT_OTEL_SCOPE_SPAN_FINISH_RES, id)) {
-               list_for_each_entry(span, &(rt_ctx->spans), list)
-                       if (span->smp_opt_dir == SMP_OPT_DIR_RES) {
-                               span->flag_finish = 1;
-                               span_cnt++;
-                       }
-
-               list_for_each_entry(ctx, &(rt_ctx->contexts), list)
-                       if (ctx->smp_opt_dir == SMP_OPT_DIR_RES) {
-                               ctx->flag_finish = 1;
-                               ctx_cnt++;
-                       }
-
-               OTELC_DBG(NOTICE, "marked RESponse channel %d span(s), %d context(s)", span_cnt, ctx_cnt);
-       }
-       else {
-               list_for_each_entry(span, &(rt_ctx->spans), list)
-                       if (FLT_OTEL_CONF_STR_CMP(span->id, id)) {
-                               span->flag_finish = 1;
-                               span_cnt++;
-
-                               break;
-                       }
-
-               list_for_each_entry(ctx, &(rt_ctx->contexts), list)
-                       if (FLT_OTEL_CONF_STR_CMP(ctx->id, id)) {
-                               ctx->flag_finish = 1;
-                               ctx_cnt++;
-
-                               break;
-                       }
-
-               if (span_cnt > 0)
-                       OTELC_DBG(NOTICE, "marked span '%s'", id);
-               if (ctx_cnt > 0)
-                       OTELC_DBG(NOTICE, "marked context '%s'", id);
-               if ((span_cnt + ctx_cnt) == 0)
-                       OTELC_DBG(NOTICE, "cannot find span/context '%s'", id);
-       }
-
-       retval = span_cnt + ctx_cnt;
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_finish_marked - finish marked spans and contexts
- *
- * SYNOPSIS
- *   void flt_otel_scope_finish_marked(const struct flt_otel_runtime_context *rt_ctx, const struct timespec *ts_finish)
- *
- * ARGUMENTS
- *   rt_ctx    - the runtime context containing spans and contexts
- *   ts_finish - the monotonic timestamp to use as the span end time
- *
- * DESCRIPTION
- *   Ends all spans and destroys all contexts that have been marked for
- *   finishing by flt_otel_scope_finish_mark().  Each span is ended with the
- *   <ts_finish> timestamp; each context's OTel span context is destroyed.
- *   The finish flags are cleared after processing.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_scope_finish_marked(const struct flt_otel_runtime_context *rt_ctx, const struct timespec *ts_finish)
-{
-       struct flt_otel_scope_span    *span;
-       struct flt_otel_scope_context *ctx;
-
-       OTELC_FUNC("%p, %p", rt_ctx, ts_finish);
-
-       /* End all spans that have been marked for finishing. */
-       list_for_each_entry(span, &(rt_ctx->spans), list)
-               if (span->flag_finish) {
-                       FLT_OTEL_DBG_SCOPE_SPAN("finishing span ", span);
-
-                       OTELC_OPSR(span->span, end_with_options, ts_finish, OTELC_SPAN_STATUS_IGNORE, NULL);
-
-                       span->flag_finish = 0;
-               }
-
-       /* Destroy all contexts that have been marked for finishing. */
-       list_for_each_entry(ctx, &(rt_ctx->contexts), list)
-               if (ctx->flag_finish) {
-                       FLT_OTEL_DBG_SCOPE_CONTEXT("finishing context ", ctx);
-
-                       if (ctx->context != NULL)
-                               OTELC_OPSR(ctx->context, destroy);
-
-                       ctx->flag_finish = 0;
-               }
-
-       OTELC_RETURN();
-}
-
-
-/***
- * NAME
- *   flt_otel_scope_free_unused - remove unused spans and contexts
- *
- * SYNOPSIS
- *   void flt_otel_scope_free_unused(struct flt_otel_runtime_context *rt_ctx, struct channel *chn)
- *
- * ARGUMENTS
- *   rt_ctx - the runtime context to clean up
- *   chn    - the channel for HTTP header cleanup
- *
- * DESCRIPTION
- *   Removes scope spans with a NULL OTel span and scope contexts with a NULL
- *   OTel context from the runtime context.  For each removed context, the
- *   associated HTTP headers and HAProxy variables are also cleaned up via
- *   <chn>.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_scope_free_unused(struct flt_otel_runtime_context *rt_ctx, struct channel *chn)
-{
-       OTELC_FUNC("%p, %p", rt_ctx, chn);
-
-       if (rt_ctx == NULL)
-               OTELC_RETURN();
-
-       /* Remove spans that were never successfully created. */
-       if (!LIST_ISEMPTY(&(rt_ctx->spans))) {
-               struct flt_otel_scope_span *span, *span_back;
-
-               list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list)
-                       if (span->span == NULL)
-                               flt_otel_scope_span_free(&span);
-       }
-
-       /* Remove contexts that failed extraction and clean up their traces. */
-       if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
-               struct flt_otel_scope_context *ctx, *ctx_back;
-
-               list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
-                       if (ctx->context == NULL) {
-                               /*
-                                * All headers and variables associated with
-                                * the context in question should be deleted.
-                                */
-                               (void)flt_otel_http_headers_remove(chn, ctx->id, NULL);
-#ifdef USE_OTEL_VARS
-                               (void)flt_otel_vars_unset(rt_ctx->stream, FLT_OTEL_VARS_SCOPE, ctx->id, ctx->smp_opt_dir, NULL);
-#endif
-
-                               flt_otel_scope_context_free(&ctx);
-                       }
-       }
-
-       FLT_OTEL_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
-
-       OTELC_RETURN();
-}
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/util.c b/addons/otel/src/util.c
deleted file mode 100644 (file)
index fb8ff76..0000000
+++ /dev/null
@@ -1,1087 +0,0 @@
-/* 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_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
- *
- * SYNOPSIS
- *   const char *flt_otel_chn_label(const struct channel *chn)
- *
- * ARGUMENTS
- *   chn - channel to identify
- *
- * DESCRIPTION
- *   Returns a human-readable label indicating the channel direction based on
- *   the CF_ISRESP flag.
- *
- * RETURN VALUE
- *   Returns "RESponse" for response channels, or "REQuest" for request
- *   channels.
- */
-const char *flt_otel_chn_label(const struct channel *chn)
-{
-       return (chn == NULL) ? "-" : ((chn->flags & CF_ISRESP) ? "RESponse" : "REQuest");
-}
-
-
-/***
- * NAME
- *   flt_otel_pr_mode - proxy mode label
- *
- * SYNOPSIS
- *   const char *flt_otel_pr_mode(const struct stream *s)
- *
- * ARGUMENTS
- *   s - stream to check
- *
- * DESCRIPTION
- *   Returns a human-readable label indicating the proxy mode.  Uses the
- *   backend proxy if a backend is assigned, otherwise the frontend proxy.
- *
- * RETURN VALUE
- *   Returns "HTTP" for HTTP mode proxies, or "TCP" for TCP mode proxies.
- */
-const char *flt_otel_pr_mode(const struct stream *s)
-{
-       struct proxy *px = (s->flags & SF_BE_ASSIGNED) ? s->be : strm_fe(s);
-
-       return (px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP";
-}
-
-
-/***
- * NAME
- *   flt_otel_stream_pos - stream position label
- *
- * SYNOPSIS
- *   const char *flt_otel_stream_pos(const struct stream *s)
- *
- * ARGUMENTS
- *   s - stream to check
- *
- * DESCRIPTION
- *   Returns a human-readable label indicating the stream position based on the
- *   SF_BE_ASSIGNED flag.
- *
- * RETURN VALUE
- *   Returns "backend" if a backend is assigned, or "frontend" otherwise.
- */
-const char *flt_otel_stream_pos(const struct stream *s)
-{
-       return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
-}
-
-
-/***
- * NAME
- *   flt_otel_type - filter type label
- *
- * SYNOPSIS
- *   const char *flt_otel_type(const struct filter *f)
- *
- * ARGUMENTS
- *   f - filter instance to check
- *
- * DESCRIPTION
- *   Returns a human-readable label indicating the filter type based on the
- *   FLT_FL_IS_BACKEND_FILTER flag.
- *
- * RETURN VALUE
- *   Returns "backend" for backend filters, or "frontend" for frontend filters.
- */
-const char *flt_otel_type(const struct filter *f)
-{
-       return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
-}
-
-
-/***
- * NAME
- *   flt_otel_analyzer - analyzer bit name lookup
- *
- * SYNOPSIS
- *   const char *flt_otel_analyzer(uint an_bit)
- *
- * ARGUMENTS
- *   an_bit - the analyzer identifier bit
- *
- * DESCRIPTION
- *   Looks up the human-readable analyzer name for the given <an_bit> value from
- *   the flt_otel_event_data table.  If the bit is not found, a formatted error
- *   string is returned from a thread-local buffer.
- *
- * RETURN VALUE
- *   Returns the analyzer name string, or a formatted error message if the bit
- *   is invalid.
- */
-const char *flt_otel_analyzer(uint an_bit)
-{
-       static THREAD_LOCAL char  retbuf[32];
-       const char               *retptr = NULL;
-       int                       i;
-
-       for (i = 0; i < OTELC_TABLESIZE(flt_otel_event_data); i++)
-               if (flt_otel_event_data[i].an_bit == an_bit) {
-                       retptr = flt_otel_event_data[i].an_name;
-
-                       break;
-               }
-
-       if (retptr == NULL)
-               (void)snprintf(retbuf, sizeof(retbuf), "invalid an_bit: 0x%08x", an_bit);
-
-       return (retptr == NULL) ? retbuf : retptr;
-}
-
-
-/***
- * 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);
-}
-
-
-/*
- * Comparator for qsort: ascending order of doubles.  Values within
- * FLT_OTEL_DBL_EPSILON of each other are treated as equal.
- */
-int flt_otel_qsort_compar_double(const void *p1, const void *p2)
-{
-       double a = *(const double *)p1;
-       double b = *(const double *)p2;
-
-       return (fabs(a - b) < FLT_OTEL_DBL_EPSILON) ? 0 : ((a < b) ? -1 : 1);
-}
-
-
-/***
- * NAME
- *   flt_otel_strtod - string to double conversion with range check
- *
- * SYNOPSIS
- *   bool flt_otel_strtod(const char *nptr, double *value, double limit_min, double limit_max, char **err)
- *
- * ARGUMENTS
- *   nptr      - string to parse
- *   value     - pointer to store the parsed double result
- *   limit_min - minimum allowed value
- *   limit_max - maximum allowed value
- *   err       - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses the string <nptr> as a double-precision floating-point number.
- *   Validates that the entire string is consumed and that the result falls
- *   within the range [<limit_min>, <limit_max>].  On parse error or range
- *   violation, an error message is stored via <err>.
- *
- * RETURN VALUE
- *   Returns true on success, false on failure.
- */
-bool flt_otel_strtod(const char *nptr, double *value, double limit_min, double limit_max, char **err)
-{
-       char *endptr = NULL;
-       bool  retval = false;
-
-       if (value == NULL)
-               return retval;
-
-       errno = 0;
-
-       *value = strtod(nptr, &endptr);
-       if ((errno != 0) || OTELC_STR_IS_VALID(endptr))
-               FLT_OTEL_ERR("'%s' : invalid value", nptr);
-       else if (!OTELC_IN_RANGE(*value, limit_min, limit_max))
-               FLT_OTEL_ERR("'%s' : value out of range [%.2f, %.2f]", nptr, limit_min, limit_max);
-       else
-               retval = true;
-
-       return retval;
-}
-
-
-/***
- * NAME
- *   flt_otel_strtoll - string to int64_t conversion with range check
- *
- * SYNOPSIS
- *   bool flt_otel_strtoll(const char *nptr, int64_t *value, int64_t limit_min, int64_t limit_max, char **err)
- *
- * ARGUMENTS
- *   nptr      - string to parse
- *   value     - pointer to store the parsed int64_t result
- *   limit_min - minimum allowed value
- *   limit_max - maximum allowed value
- *   err       - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Parses the string <nptr> as a 64-bit integer using base auto-detection.
- *   Validates that the entire string is consumed and that the result falls
- *   within the range [<limit_min>, <limit_max>].  On parse error or range
- *   violation, an error message is stored via <err>.
- *
- * RETURN VALUE
- *   Returns true on success, false on failure.
- */
-bool flt_otel_strtoll(const char *nptr, int64_t *value, int64_t limit_min, int64_t limit_max, char **err)
-{
-       char *endptr = NULL;
-       bool  retval = false;
-
-       if (value == NULL)
-               return retval;
-
-       errno = 0;
-
-       *value = strtoll(nptr, &endptr, 0);
-       if ((errno != 0) || OTELC_STR_IS_VALID(endptr))
-               FLT_OTEL_ERR("'%s' : invalid value", nptr);
-       else if (!OTELC_IN_RANGE(*value, limit_min, limit_max))
-               FLT_OTEL_ERR("'%s' : value out of range [%" PRId64 ", %" PRId64 "]", nptr, limit_min, limit_max);
-       else
-               retval = true;
-
-       return retval;
-}
-
-
-/***
- * 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);
-}
-
-
-/***
- * NAME
- *   flt_otel_sample_to_value - sample data to OTel value conversion
- *
- * SYNOPSIS
- *   int flt_otel_sample_to_value(const char *key, const struct sample_data *data, struct otelc_value *value, char **err)
- *
- * ARGUMENTS
- *   key   - sample key name (for debug output)
- *   data  - sample data to convert
- *   value - output OTel value structure
- *   err   - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Converts sample data to an otelc_value structure.  Boolean samples are
- *   stored as OTELC_VALUE_BOOL, integer samples as OTELC_VALUE_INT64.  All
- *   other types are converted to a string via flt_otel_sample_to_str() and
- *   stored as OTELC_VALUE_DATA with heap-allocated storage.
- *
- * RETURN VALUE
- *   Returns the size of the converted value, or FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_sample_to_value(const char *key, const struct sample_data *data, struct otelc_value *value, char **err)
-{
-       int retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("\"%s\", %p, %p, %p:%p", OTELC_STR_ARG(key), data, value, OTELC_DPTR_ARGS(err));
-
-       if ((data == NULL) || (value == NULL))
-               OTELC_RETURN_INT(retval);
-
-       /* Convert the sample value to an otelc_value based on its type. */
-       if (data->type == SMP_T_BOOL) {
-               value->u_type       = OTELC_VALUE_BOOL;
-               value->u.value_bool = data->u.sint ? 1 : 0;
-
-               retval = sizeof(value->u.value_bool);
-       }
-       else if (data->type == SMP_T_SINT) {
-               value->u_type        = OTELC_VALUE_INT64;
-               value->u.value_int64 = data->u.sint;
-
-               retval = sizeof(value->u.value_int64);
-       }
-       else {
-               value->u_type       = OTELC_VALUE_DATA;
-               value->u.value_data = OTELC_MALLOC(global.tune.bufsize);
-
-               if (value->u.value_data == NULL)
-                       FLT_OTEL_ERR("out of memory");
-               else
-                       retval = flt_otel_sample_to_str(data, value->u.value_data, global.tune.bufsize, err);
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_sample_add_event - span event attribute addition
- *
- * SYNOPSIS
- *   static int flt_otel_sample_add_event(struct list *events, struct flt_otel_conf_sample *sample, const struct otelc_value *value)
- *
- * ARGUMENTS
- *   events - list of span events (flt_otel_scope_data_event)
- *   sample - configured sample with event name and key
- *   value  - OTel value to add as an attribute
- *
- * DESCRIPTION
- *   Adds a sample value as a span event attribute.  Searches the existing
- *   events list for an event with a matching name; if not found, creates a new
- *   event entry with an initial attribute array of FLT_OTEL_ATTR_INIT_SIZE
- *   elements.  If the attribute array is full, it is grown by
- *   FLT_OTEL_ATTR_INC_SIZE elements.  The key-value pair is appended to the
- *   event's attribute array.
- *
- * RETURN VALUE
- *   Returns the attribute count for the event, or FLT_OTEL_RET_ERROR on
- *   failure.
- */
-static int flt_otel_sample_add_event(struct list *events, struct flt_otel_conf_sample *sample, const struct otelc_value *value)
-{
-       struct flt_otel_scope_data_event *ptr, *event = NULL;
-       struct otelc_kv                  *attr = NULL;
-       bool                              flag_list_insert = 0;
-
-       OTELC_FUNC("%p, %p, %p", events, sample, value);
-
-       if ((events == NULL) || (sample == NULL) || (value == NULL))
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-       /*
-        * First try to find an event with the same name in the list of events,
-        * if it succeeds, new data is added to the event found.
-        */
-       if (!LIST_ISEMPTY(events))
-               list_for_each_entry(ptr, events, list)
-                       if (strcmp(ptr->name, OTELC_VALUE_STR(&(sample->extra))) == 0) {
-                               event = ptr;
-
-                               break;
-                       }
-
-       /*
-        * If an event with the required name is not found, a new event is added
-        * to the list.  Initially, the number of attributes for the new event
-        * is set to FLT_OTEL_ATTR_INIT_SIZE.
-        */
-       if (event == NULL) {
-               event = OTELC_CALLOC(1, sizeof(*event));
-               if (event == NULL)
-                       OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-               event->name = OTELC_STRDUP(OTELC_VALUE_STR(&(sample->extra)));
-               event->attr = OTELC_CALLOC(FLT_OTEL_ATTR_INIT_SIZE, sizeof(*(event->attr)));
-               event->cnt  = 0;
-               event->size = FLT_OTEL_ATTR_INIT_SIZE;
-               if ((event->name == NULL) || (event->attr == NULL)) {
-                       OTELC_SFREE(event->name);
-                       OTELC_SFREE(event->attr);
-                       OTELC_SFREE(event);
-
-                       OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-               }
-
-               flag_list_insert = 1;
-
-               OTELC_DBG(DEBUG, "scope event data initialized");
-       }
-
-       /*
-        * In case event attributes are added to an already existing event in
-        * the list, it is checked whether the number of attributes should be
-        * increased.  If necessary, it will be increased by the amount
-        * FLT_OTEL_ATTR_INC_SIZE.
-        */
-       if (event->cnt == event->size) {
-               typeof(event->attr) ptr = OTELC_REALLOC(event->attr, sizeof(*ptr) * (event->size + FLT_OTEL_ATTR_INC_SIZE));
-               if (ptr == NULL)
-                       OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-               event->attr  = ptr;
-               event->size += FLT_OTEL_ATTR_INC_SIZE;
-
-               OTELC_DBG(DEBUG, "scope event data reallocated");
-       }
-
-       attr                 = event->attr + event->cnt++;
-       attr->key            = sample->key;
-       attr->key_is_dynamic = false;
-       (void)memcpy(&(attr->value), value, sizeof(attr->value));
-
-       if (flag_list_insert) {
-               if (LIST_ISEMPTY(events))
-                       LIST_INIT(events);
-
-               LIST_INSERT(events, &(event->list));
-       }
-
-       OTELC_RETURN_INT(event->cnt);
-}
-
-
-/***
- * NAME
- *   flt_otel_sample_set_status - span status setter
- *
- * SYNOPSIS
- *   static int flt_otel_sample_set_status(struct flt_otel_scope_data_status *status, struct flt_otel_conf_sample *sample, const struct otelc_value *value, char **err)
- *
- * ARGUMENTS
- *   status - span status structure to populate
- *   sample - configured sample with status code in extra data
- *   value  - OTel value for the status description
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Sets the span status code and description from sample data.  The status
- *   code is taken from the sample's extra field (an int32 value) and the
- *   description from <value>, which must be a string type.  Multiple status
- *   settings for the same span are rejected with an error.
- *
- * RETURN VALUE
- *   Returns 1 on success, or FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_sample_set_status(struct flt_otel_scope_data_status *status, struct flt_otel_conf_sample *sample, const struct otelc_value *value, char **err)
-{
-       OTELC_FUNC("%p, %p, %p, %p:%p", status, sample, value, OTELC_DPTR_ARGS(err));
-
-       if ((status == NULL) || (sample == NULL) || (value == NULL))
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-       /*
-        * This scenario should never occur, but the check is still enforced -
-        * multiple status settings are not allowed within the filter
-        * configuration for each span event.
-        */
-       if (status->description != NULL) {
-               FLT_OTEL_ERR("'%s' : span status already set", sample->key);
-
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-       }
-       else if ((value->u_type != OTELC_VALUE_STRING) && (value->u_type != OTELC_VALUE_DATA)) {
-               FLT_OTEL_ERR("'%s' : status description must be a string value", sample->key);
-
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-       }
-
-       status->code        = sample->extra.u.value_int32;
-       status->description = OTELC_STRDUP(OTELC_VALUE_STR(value));
-       if (status->description == NULL) {
-               FLT_OTEL_ERR("out of memory");
-
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-       }
-
-       OTELC_RETURN_INT(1);
-}
-
-
-/***
- * NAME
- *   flt_otel_sample_add_kv - key-value attribute addition
- *
- * SYNOPSIS
- *   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)
- *   key   - attribute or baggage key name
- *   value - OTel value to add
- *
- * DESCRIPTION
- *   Adds a sample value as a key-value attribute or baggage entry.  If the
- *   key-value array is not yet allocated, it is created with
- *   FLT_OTEL_ATTR_INIT_SIZE elements via otelc_kv_new().  When the array is
- *   full, it is grown by FLT_OTEL_ATTR_INC_SIZE elements.  The key-value pair
- *   is appended to the array.
- *
- * RETURN VALUE
- *   Returns the current element count, or FLT_OTEL_RET_ERROR on failure.
- */
-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;
-
-       OTELC_FUNC("%p, \"%s\", %p", kv, OTELC_STR_ARG(key), value);
-
-       if ((kv == NULL) || (key == NULL) || (value == NULL))
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-       if (kv->attr == NULL) {
-               kv->attr = otelc_kv_new(FLT_OTEL_ATTR_INIT_SIZE);
-               if (kv->attr == NULL)
-                       OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-               kv->cnt  = 0;
-               kv->size = FLT_OTEL_ATTR_INIT_SIZE;
-
-               OTELC_DBG(DEBUG, "scope kv data initialized");
-       }
-
-       if (kv->cnt == kv->size) {
-               typeof(kv->attr) ptr = OTELC_REALLOC(kv->attr, sizeof(*ptr) * (kv->size + FLT_OTEL_ATTR_INC_SIZE));
-               if (ptr == NULL)
-                       OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-               kv->attr  = ptr;
-               kv->size += FLT_OTEL_ATTR_INC_SIZE;
-
-               OTELC_DBG(DEBUG, "scope kv data reallocated");
-       }
-
-       attr                 = kv->attr + kv->cnt++;
-       attr->key            = (typeof(attr->key))key;
-       attr->key_is_dynamic = false;
-       (void)memcpy(&(attr->value), value, sizeof(attr->value));
-
-       OTELC_RETURN_INT(kv->cnt);
-}
-
-
-/***
- * NAME
- *   flt_otel_sample_eval - sample expression evaluation
- *
- * SYNOPSIS
- *   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
- *   flag_native - preserve native types for single-expression samples
- *   value       - evaluated result (caller-owned)
- *   err         - indirect pointer to error message string
- *
- * DESCRIPTION
- *   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 FLT_OTEL_RET_OK on success, FLT_OTEL_RET_ERROR on failure.
- */
-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 buffer                           buffer;
-       int                                     idx = 0, rc, retval = FLT_OTEL_RET_OK;
-
-       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(&buffer, 0, sizeof(buffer));
-
-       /* Evaluate the sample: log-format path or expression list path. */
-       if (sample->lf_used) {
-               /*
-                * Log-format path: evaluate the log-format expression into a
-                * dynamically allocated buffer.
-                */
-               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 {
-                       buffer.data = build_logline(s, buffer.area, buffer.size, &(sample->lf_expr));
-
-                       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);
-
-                       (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 = "";
-                       }
-
-                       /*
-                        * 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) && 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) {
-                                       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;
-
-                                               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;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       /* 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. */
-       }
-       else if (type == FLT_OTEL_EVENT_SAMPLE_ATTRIBUTE) {
-               retval = flt_otel_sample_add_kv(&(data->attributes), sample->key, &value);
-               if (retval == FLT_OTEL_RET_ERROR)
-                       FLT_OTEL_ERR("out of memory");
-       }
-       else if (type == FLT_OTEL_EVENT_SAMPLE_EVENT) {
-               retval = flt_otel_sample_add_event(&(data->events), sample, &value);
-               if (retval == FLT_OTEL_RET_ERROR)
-                       FLT_OTEL_ERR("out of memory");
-       }
-       else if (type == FLT_OTEL_EVENT_SAMPLE_BAGGAGE) {
-               retval = flt_otel_sample_add_kv(&(data->baggage), sample->key, &value);
-               if (retval == FLT_OTEL_RET_ERROR)
-                       FLT_OTEL_ERR("out of memory");
-       }
-       else if (type == FLT_OTEL_EVENT_SAMPLE_STATUS) {
-               retval = flt_otel_sample_set_status(&(data->status), sample, &value, err);
-       }
-       else {
-               FLT_OTEL_ERR("invalid event sample type: %d", type);
-
-               retval = FLT_OTEL_RET_ERROR;
-       }
-
-       /*
-        * Free dynamically allocated value data that was not transferred to
-        * a key-value array.  For ATTRIBUTE, EVENT, and BAGGAGE, the value
-        * pointer is shallow-copied into the kv array on success and will be
-        * freed by otelc_kv_destroy().  For STATUS, the handler creates its
-        * own copy, so the original must be freed.  On any error, no handler
-        * consumed the value.
-        */
-       if ((retval != FLT_OTEL_RET_ERROR) && (type != FLT_OTEL_EVENT_SAMPLE_STATUS))
-               /* Do nothing. */;
-       else if (value.u_type == OTELC_VALUE_DATA)
-               OTELC_SFREE(value.u.value_data);
-
-       flt_otel_scope_data_dump(data);
-
-       OTELC_RETURN_INT(retval);
-}
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/src/vars.c b/addons/otel/src/vars.c
deleted file mode 100644 (file)
index dcb6e7c..0000000
+++ /dev/null
@@ -1,1175 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "../include/include.h"
-
-
-#ifdef DEBUG_OTEL
-
-/***
- * NAME
- *   flt_otel_vars_scope_dump - debug variable scope dump
- *
- * SYNOPSIS
- *   static void flt_otel_vars_scope_dump(struct vars *vars, const char *scope)
- *
- * ARGUMENTS
- *   vars  - HAProxy variable store to dump
- *   scope - scope label for log output
- *
- * DESCRIPTION
- *   Dumps the contents of all variables defined for a particular <scope>.
- *   Acquires a read lock on the variable store, iterates over all name root
- *   trees, and logs each variable's name hash and string value.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static void flt_otel_vars_scope_dump(struct vars *vars, const char *scope)
-{
-       int i;
-
-       if (vars == NULL)
-               return;
-
-       /* Lock the variable store for safe iteration. */
-       vars_rdlock(vars);
-       for (i = 0; i < VAR_NAME_ROOTS; i++) {
-               struct ceb_node *node = cebu64_imm_first(&(vars->name_root[i]));
-
-               for ( ; node != NULL; node = cebu64_imm_next(&(vars->name_root[i]), node)) {
-                       struct var *var = container_of(node, struct var, name_node);
-
-                       OTELC_DBG(NOTICE, "'%s.%016" PRIx64 "' -> '%.*s'", scope, var->name_hash, (int)b_data(&(var->data.u.str)), b_orig(&(var->data.u.str)));
-               }
-       }
-       vars_rdunlock(vars);
-}
-
-
-/***
- * NAME
- *   flt_otel_vars_dump - debug all variables dump
- *
- * SYNOPSIS
- *   void flt_otel_vars_dump(struct stream *s)
- *
- * ARGUMENTS
- *   s - stream whose variables to dump
- *
- * DESCRIPTION
- *   Dumps all variables across all scopes (PROC, SESS, TXN, REQ/RES) by calling
- *   flt_otel_vars_scope_dump() for each scope's variable store.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-void flt_otel_vars_dump(struct stream *s)
-{
-       OTELC_FUNC("%p", s);
-
-       /*
-        * It would be nice if we could use the get_vars() function from HAProxy
-        * source here to get the value of the 'vars' pointer, but it is defined
-        * as 'static inline', so unfortunately none of this is possible.
-        */
-       flt_otel_vars_scope_dump(&(proc_vars), "PROC");
-       flt_otel_vars_scope_dump(&(s->sess->vars), "SESS");
-       flt_otel_vars_scope_dump(&(s->vars_txn), "TXN");
-       flt_otel_vars_scope_dump(&(s->vars_reqres), "REQ/RES");
-
-       OTELC_RETURN();
-}
-
-#endif /* DEBUG_OTEL */
-
-
-/***
- * NAME
- *   flt_otel_normalize_name - variable name normalization
- *
- * SYNOPSIS
- *   static int flt_otel_normalize_name(char *var_name, size_t size, int *len, const char *name, bool flag_cpy, char **err)
- *
- * ARGUMENTS
- *   var_name - output buffer for the normalized name
- *   size     - output buffer size
- *   len      - pointer to the current position in the output buffer
- *   name     - source name to normalize
- *   flag_cpy - whether to copy name without normalization
- *   err      - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Normalizes a variable name component into the output buffer.  Adds a
- *   dot separator between components when needed.  When <flag_cpy> is set,
- *   the name is copied verbatim; otherwise, dashes are replaced with
- *   FLT_OTEL_VAR_CHAR_DASH, spaces with FLT_OTEL_VAR_CHAR_SPACE, and uppercase
- *   letters are converted to lowercase.
- *
- * RETURN VALUE
- *   Returns the number of characters written, or FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_normalize_name(char *var_name, size_t size, int *len, const char *name, bool flag_cpy, char **err)
-{
-       int retval = 0;
-
-       OTELC_FUNC("%p, %zu, %p, \"%s\", %hhu, %p:%p", var_name, size, len, OTELC_STR_ARG(name), flag_cpy, OTELC_DPTR_ARGS(err));
-
-       if (!OTELC_STR_IS_VALID(name))
-               OTELC_RETURN_INT(retval);
-
-       /*
-        * In case the name of the variable consists of several elements,
-        * the character '.' is added between them.
-        */
-       if ((*len == 0) || (var_name[*len - 1] == '.'))
-               /* Do nothing. */;
-       else if (*len < (size - 1))
-               var_name[(*len)++] = '.';
-       else {
-               FLT_OTEL_ERR("failed to normalize variable name, buffer too small");
-
-               retval = FLT_OTEL_RET_ERROR;
-       }
-
-       if (retval == FLT_OTEL_RET_ERROR) {
-               /* Do nothing. */
-       }
-       else if (flag_cpy) {
-               /* Copy variable name without modification. */
-               retval = strlen(name);
-               if ((*len + retval + 1) > size) {
-                       FLT_OTEL_ERR("failed to normalize variable name, buffer too small");
-
-                       retval = FLT_OTEL_RET_ERROR;
-               } else {
-                       (void)memcpy(var_name + *len, name, retval + 1);
-
-                       *len += retval;
-               }
-       } else {
-               /*
-                * HAProxy does not allow the use of variable names containing
-                * '-' or ' '.  This of course applies to HTTP header names as
-                * well.  Also, here the capital letters are converted to
-                * lowercase.
-                */
-               while (retval != FLT_OTEL_RET_ERROR)
-                       if (*len >= (size - 1)) {
-                               FLT_OTEL_ERR("failed to normalize variable name, buffer too small");
-
-                               retval = FLT_OTEL_RET_ERROR;
-                       } else {
-                               uint8_t ch = name[retval];
-
-                               if (ch == '\0')
-                                       break;
-                               else if (ch == '-')
-                                       ch = FLT_OTEL_VAR_CHAR_DASH;
-                               else if (ch == ' ')
-                                       ch = FLT_OTEL_VAR_CHAR_SPACE;
-                               else if (isupper(ch))
-                                       ch = ist_lc[ch];
-
-                               var_name[(*len)++] = ch;
-                               retval++;
-                       }
-
-               var_name[*len] = '\0';
-       }
-
-       OTELC_DBG(DEBUG, "var_name: \"%s\" %d/%d", OTELC_STR_ARG(var_name), retval, *len);
-
-       if (retval == FLT_OTEL_RET_ERROR)
-               *len = retval;
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_denormalize_name - reverse variable name normalization
- *
- * SYNOPSIS
- *   static int flt_otel_denormalize_name(const char *var_name, char *name, size_t size, char **err)
- *
- * ARGUMENTS
- *   var_name - normalized variable name
- *   name     - output buffer for the denormalized name
- *   size     - output buffer size
- *   err      - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Reverses the normalization applied by flt_otel_normalize_name().  Restores
- *   dashes from FLT_OTEL_VAR_CHAR_DASH and spaces from FLT_OTEL_VAR_CHAR_SPACE.
- *
- * RETURN VALUE
- *   Returns the length of the denormalized name, or FLT_OTEL_RET_ERROR if the
- *   output buffer is too small.
- */
-static int flt_otel_denormalize_name(const char *var_name, char *name, size_t size, char **err)
-{
-       int len;
-
-       /* Reverse character substitutions applied during normalization. */
-       for (len = 0; var_name[len] != '\0'; len++) {
-               if (len >= (size - 1)) {
-                       FLT_OTEL_ERR("failed to reverse variable name, buffer too small");
-
-                       return FLT_OTEL_RET_ERROR;
-               }
-
-               if (var_name[len] == FLT_OTEL_VAR_CHAR_DASH)
-                       name[len] = '-';
-               else if (var_name[len] == FLT_OTEL_VAR_CHAR_SPACE)
-                       name[len] = ' ';
-               else
-                       name[len] = var_name[len];
-       }
-       name[len] = '\0';
-
-       return len;
-}
-
-
-/***
- * NAME
- *   flt_otel_var_name - full variable name construction
- *
- * SYNOPSIS
- *   static int flt_otel_var_name(const char *scope, const char *prefix, const char *name, bool flag_cpy, char *var_name, size_t size, char **err)
- *
- * ARGUMENTS
- *   scope    - variable scope component
- *   prefix   - variable prefix component
- *   name     - variable name component
- *   flag_cpy - whether to copy name without normalization
- *   var_name - output buffer for the constructed name
- *   size     - output buffer size
- *   err      - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Constructs a full variable name from <scope>, <prefix>, and <name>
- *   components, separated by dots.  Each component is normalized via
- *   flt_otel_normalize_name().  NULL components are skipped.
- *
- * RETURN VALUE
- *   Returns the total name length, or FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_var_name(const char *scope, const char *prefix, const char *name, bool flag_cpy, char *var_name, size_t size, char **err)
-{
-       int retval = 0;
-
-       OTELC_FUNC("\"%s\", \"%s\", \"%s\", %hhu, %p, %zu, %p:%p", OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), flag_cpy, var_name, size, OTELC_DPTR_ARGS(err));
-
-       if (flt_otel_normalize_name(var_name, size, &retval, scope, 0, err) >= 0)
-               if (flt_otel_normalize_name(var_name, size, &retval, prefix, 0, err) >= 0)
-                       (void)flt_otel_normalize_name(var_name, size, &retval, name, flag_cpy, err);
-
-       if (retval == FLT_OTEL_RET_ERROR)
-               FLT_OTEL_ERR("failed to construct variable name '%s.%s.%s'", scope, prefix, name);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_smp_init - sample structure initialization
- *
- * SYNOPSIS
- *   static inline void flt_otel_smp_init(struct stream *s, struct sample *smp, uint opt, int type, const char *data)
- *
- * ARGUMENTS
- *   s    - current stream
- *   smp  - sample structure to initialize
- *   opt  - sample option flags
- *   type - sample data type
- *   data - string data to store (or NULL)
- *
- * DESCRIPTION
- *   Initializes the <smp> structure and sets stream ownership via
- *   smp_set_owner().  If the <data> argument is non-NULL, the sample_data
- *   member is also initialized with the given <type> and string content.
- *
- * RETURN VALUE
- *   This function does not return a value.
- */
-static inline void flt_otel_smp_init(struct stream *s, struct sample *smp, uint opt, int type, const char *data)
-{
-       (void)memset(smp, 0, sizeof(*smp));
-       (void)smp_set_owner(smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
-
-       if (data != NULL) {
-               smp->data.type = type;
-
-               chunk_initstr(&(smp->data.u.str), data);
-       }
-}
-
-
-#ifndef USE_OTEL_VARS_NAME
-
-/***
- * NAME
- *   flt_otel_smp_add - context variable name registration
- *
- * SYNOPSIS
- *   static int flt_otel_smp_add(struct sample_data *data, const char *name, size_t len, char **err)
- *
- * ARGUMENTS
- *   data - binary sample data buffer
- *   name - context variable name to append
- *   len  - length of the variable name
- *   err  - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Appends a context variable name to the binary sample data buffer used for
- *   tracking registered context variables.  If the buffer is not yet allocated,
- *   it is initialized with global.tune.bufsize bytes.  The name is stored as a
- *   length-prefixed entry (FLT_OTEL_VAR_CTX_SIZE byte followed by the name
- *   data).  Validates that the name length fits in the size field and that the
- *   buffer has sufficient room.
- *
- * RETURN VALUE
- *   Returns the buffer offset before appending, or FLT_OTEL_RET_ERROR on
- *   failure.
- */
-static int flt_otel_smp_add(struct sample_data *data, const char *name, size_t len, char **err)
-{
-       bool flag_alloc = 0;
-       int  retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("%p, \"%.*s\", %zu, %p:%p", data, (int)len, name, len, OTELC_DPTR_ARGS(err));
-
-       FLT_OTEL_DBG_BUF(INFO, &(data->u.str));
-
-       /* Lazily allocate the sample buffer on first use. */
-       if (b_orig(&(data->u.str)) == NULL) {
-               data->type = SMP_T_BIN;
-               chunk_init(&(data->u.str), OTELC_MALLOC(global.tune.bufsize), global.tune.bufsize);
-
-               flag_alloc = (b_orig(&(data->u.str)) != NULL);
-       }
-
-       /* Verify the buffer allocation succeeded. */
-       if (b_orig(&(data->u.str)) == NULL) {
-               FLT_OTEL_ERR("failed to add ctx '%.*s', not enough memory", (int)len, name);
-       }
-       else if (len > ((UINT64_C(1) << ((sizeof(FLT_OTEL_VAR_CTX_SIZE) << 3) - 1)) - 1)) {
-               FLT_OTEL_ERR("failed to add ctx '%.*s', name too long", (int)len, name);
-       }
-       else if ((len + sizeof(FLT_OTEL_VAR_CTX_SIZE)) > b_room(&(data->u.str))) {
-               FLT_OTEL_ERR("failed to add ctx '%.*s', too many names", (int)len, name);
-       }
-       else {
-               retval = b_data(&(data->u.str));
-
-               b_putchr(&(data->u.str), len);
-               (void)__b_putblk(&(data->u.str), name, len);
-
-               FLT_OTEL_DBG_BUF(INFO, &(data->u.str));
-       }
-
-       if ((retval == FLT_OTEL_RET_ERROR) && flag_alloc)
-               OTELC_SFREE(b_orig(&(data->u.str)));
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_ctx_loop - context variable name iterator
- *
- * SYNOPSIS
- *   static int flt_otel_ctx_loop(struct sample *smp, const char *scope, const char *prefix, char **err, flt_otel_ctx_loop_cb func, void *ptr)
- *
- * ARGUMENTS
- *   smp    - sample used to retrieve the context tracking variable
- *   scope  - variable scope
- *   prefix - variable prefix
- *   err    - indirect pointer to error message string
- *   func   - callback function invoked for each context variable
- *   ptr    - opaque data passed to the callback
- *
- * DESCRIPTION
- *   Iterates over all context variable names stored in the binary tracking
- *   buffer.  Retrieves the tracking variable by constructing its name from
- *   <scope> and <prefix>.  Each stored entry (length-prefixed name) is
- *   extracted and passed to the <func> callback.  Iteration stops if the
- *   callback returns a positive value (match found) or FLT_OTEL_RET_ERROR.
- *
- * RETURN VALUE
- *   Returns the match position (positive), 0 if no match,
- *   or FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_ctx_loop(struct sample *smp, const char *scope, const char *prefix, char **err, flt_otel_ctx_loop_cb func, void *ptr)
-{
-       FLT_OTEL_VAR_CTX_SIZE var_ctx_size;
-       char                  var_name[BUFSIZ], var_ctx[BUFSIZ];
-       int                   i, var_name_len, var_ctx_len, rc, n = 1, retval = 0;
-
-       OTELC_FUNC("%p, \"%s\", \"%s\", %p:%p, %p, %p", smp, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), OTELC_DPTR_ARGS(err), func, ptr);
-
-       /*
-        * The variable in which we will save the name of the OpenTelemetry
-        * context variable.
-        */
-       var_name_len = flt_otel_var_name(scope, prefix, NULL, 0, var_name, sizeof(var_name), err);
-       if (var_name_len == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-       /*
-        * Here we will try to find all the previously recorded variables from
-        * the currently set OpenTelemetry context.  If we find the required
-        * variable and it is marked as deleted, we will mark it as active.
-        * If we do not find it, then it is added to the end of the previously
-        * saved names.
-        */
-       if (vars_get_by_name(var_name, var_name_len, smp, NULL) == 0) {
-               OTELC_DBG(NOTICE, "ctx '%s' no variable found", var_name);
-       }
-       else if (smp->data.type != SMP_T_BIN) {
-               FLT_OTEL_ERR("ctx '%s' invalid data type %d", var_name, smp->data.type);
-
-               retval = FLT_OTEL_RET_ERROR;
-       }
-       else {
-               FLT_OTEL_DBG_BUF(INFO, &(smp->data.u.str));
-
-               for (i = 0; i < b_data(&(smp->data.u.str)); i += sizeof(var_ctx_size) + var_ctx_len, n++) {
-                       var_ctx_size = *((typeof(var_ctx_size) *)(b_orig(&(smp->data.u.str)) + i));
-                       var_ctx_len  = abs(var_ctx_size);
-
-                       if ((i + sizeof(var_ctx_size) + var_ctx_len) > b_data(&(smp->data.u.str))) {
-                               FLT_OTEL_ERR("ctx '%s' invalid data size", var_name);
-
-                               retval = FLT_OTEL_RET_ERROR;
-
-                               break;
-                       }
-
-                       (void)memcpy(var_ctx, b_orig(&(smp->data.u.str)) + i + sizeof(var_ctx_size), var_ctx_len);
-                       var_ctx[var_ctx_len] = '\0';
-
-                       rc = func(smp, i, scope, prefix, var_ctx, var_ctx_size, err, ptr);
-                       if (rc == FLT_OTEL_RET_ERROR) {
-                               retval = FLT_OTEL_RET_ERROR;
-
-                               break;
-                       }
-                       else if (rc > 0) {
-                               retval = n;
-
-                               break;
-                       }
-               }
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_ctx_set_cb - context variable existence check callback
- *
- * SYNOPSIS
- *   static int flt_otel_ctx_set_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OTEL_VAR_CTX_SIZE name_len, char **err, void *ptr)
- *
- * ARGUMENTS
- *   smp      - current sample (unused)
- *   idx      - buffer offset (unused)
- *   scope    - variable scope (unused)
- *   prefix   - variable prefix (unused)
- *   name     - context variable name to check
- *   name_len - length of the name
- *   err      - unused
- *   ptr      - pointer to flt_otel_ctx structure with the search target
- *
- * DESCRIPTION
- *   Callback for flt_otel_ctx_loop() that checks whether a context variable
- *   <name> matches the search target stored in the flt_otel_ctx structure.
- *
- * RETURN VALUE
- *   Returns 1 if the <name> matches, or 0 otherwise.
- */
-static int flt_otel_ctx_set_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OTEL_VAR_CTX_SIZE name_len, char **err, void *ptr)
-{
-       struct flt_otel_ctx *ctx = ptr;
-       int                  retval = 0;
-
-       OTELC_FUNC("%p, %zu, \"%s\", \"%s\", \"%s\", %hhd, %p:%p, %p", smp, idx, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), name_len, OTELC_DPTR_ARGS(err), ptr);
-
-       if ((name_len == ctx->value_len) && (strncmp(name, ctx->value, name_len) == 0)) {
-               OTELC_DBG(NOTICE, "ctx '%s' found", name);
-
-               retval = 1;
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_ctx_set - context variable tracking registration
- *
- * SYNOPSIS
- *   static int flt_otel_ctx_set(struct stream *s, const char *scope, const char *prefix, const char *name, uint opt, char **err)
- *
- * ARGUMENTS
- *   s      - current stream
- *   scope  - variable scope
- *   prefix - variable prefix
- *   name   - context variable name to register
- *   opt    - sample option flags
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Registers a context variable name in the binary tracking buffer if it is
- *   not already present.  Constructs the tracking variable name from <scope>
- *   and <prefix>, then uses flt_otel_ctx_loop() with flt_otel_ctx_set_cb() to
- *   check for duplicates.  If not found, the normalized name is appended to the
- *   tracking buffer via flt_otel_smp_add() and the updated buffer is stored
- *   back into the HAProxy variable.
- *
- * RETURN VALUE
- *   Returns the buffer data size on success, a positive value if already
- *   registered, or FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_ctx_set(struct stream *s, const char *scope, const char *prefix, const char *name, uint opt, char **err)
-{
-       struct flt_otel_ctx ctx;
-       struct sample       smp_ctx;
-       char                var_name[BUFSIZ];
-       bool                flag_alloc = 0;
-       int                 rc, var_name_len, retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("%p, \"%s\", \"%s\", \"%s\", %u, %p:%p", s, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), opt, OTELC_DPTR_ARGS(err));
-
-       /*
-        * The variable in which we will save the name of the OpenTelemetry
-        * context variable.
-        */
-       var_name_len = flt_otel_var_name(scope, prefix, NULL, 0, var_name, sizeof(var_name), err);
-       if (var_name_len == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_INT(retval);
-
-       /* Normalized name of the OpenTelemetry context variable. */
-       ctx.value_len = flt_otel_var_name(name, NULL, NULL, 0, ctx.value, sizeof(ctx.value), err);
-       if (ctx.value_len == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_INT(retval);
-
-       flt_otel_smp_init(s, &smp_ctx, opt, 0, NULL);
-
-       /* Loop through existing context variables and apply set operations. */
-       retval = flt_otel_ctx_loop(&smp_ctx, scope, prefix, err, flt_otel_ctx_set_cb, &ctx);
-       if (retval == 0) {
-               rc = flt_otel_smp_add(&(smp_ctx.data), ctx.value, ctx.value_len, err);
-               if (rc == FLT_OTEL_RET_ERROR)
-                       retval = FLT_OTEL_RET_ERROR;
-
-               flag_alloc = (rc == 0);
-       }
-
-       /* Persist the context data as a HAProxy variable. */
-       if (retval == FLT_OTEL_RET_ERROR) {
-               /* Do nothing. */
-       }
-       else if (retval > 0) {
-               OTELC_DBG(NOTICE, "ctx '%s' data found", ctx.value);
-       }
-       else if (vars_set_by_name_ifexist(var_name, var_name_len, &smp_ctx) == 0) {
-               FLT_OTEL_ERR("failed to set ctx '%s'", var_name);
-
-               retval = FLT_OTEL_RET_ERROR;
-       }
-       else {
-               OTELC_DBG(NOTICE, "ctx '%s' -> '%.*s' set", var_name, (int)b_data(&(smp_ctx.data.u.str)), b_orig(&(smp_ctx.data.u.str)));
-
-               retval = b_data(&(smp_ctx.data.u.str));
-       }
-
-       if (flag_alloc)
-               OTELC_SFREE(b_orig(&(smp_ctx.data.u.str)));
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_vars_unset_cb - context variable unset callback
- *
- * SYNOPSIS
- *   static int flt_otel_vars_unset_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OTEL_VAR_CTX_SIZE name_len, char **err, void *ptr)
- *
- * ARGUMENTS
- *   smp      - current sample with stream context
- *   idx      - buffer offset (unused)
- *   scope    - variable scope
- *   prefix   - variable prefix
- *   name     - context variable name to unset
- *   name_len - length of the name (unused)
- *   err      - indirect pointer to error message string
- *   ptr      - unused
- *
- * DESCRIPTION
- *   Callback for flt_otel_ctx_loop() that unsets a single context variable.
- *   Constructs the full variable name from <scope>, <prefix>, and <name>, then
- *   calls vars_unset_by_name_ifexist() to remove it.
- *
- * RETURN VALUE
- *   Returns 0 on success, or FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_vars_unset_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OTEL_VAR_CTX_SIZE name_len, char **err, void *ptr)
-{
-       struct sample smp_ctx;
-       char          var_ctx[BUFSIZ];
-       int           var_ctx_len, retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("%p, %zu, \"%s\", \"%s\", \"%s\", %hhd, %p:%p, %p", smp, idx, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), name_len, OTELC_DPTR_ARGS(err), ptr);
-
-       var_ctx_len = flt_otel_var_name(scope, prefix, name, 1, var_ctx, sizeof(var_ctx), err);
-       if (var_ctx_len == FLT_OTEL_RET_ERROR) {
-               FLT_OTEL_ERR("ctx '%s' invalid", name);
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       flt_otel_smp_init(smp->strm, &smp_ctx, smp->opt, 0, NULL);
-
-       if (vars_unset_by_name_ifexist(var_ctx, var_ctx_len, &smp_ctx) == 0) {
-               FLT_OTEL_ERR("ctx '%s' no variable found", var_ctx);
-       } else {
-               OTELC_DBG(NOTICE, "ctx '%s' unset", var_ctx);
-
-               retval = 0;
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_vars_unset - context variables bulk unset
- *
- * SYNOPSIS
- *   int flt_otel_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
- *
- * ARGUMENTS
- *   s      - current stream
- *   scope  - variable scope
- *   prefix - variable prefix
- *   opt    - sample option flags
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Unsets all context variables for a given <prefix> by iterating the tracking
- *   buffer via flt_otel_ctx_loop() with flt_otel_vars_unset_cb().  After all
- *   individual context variables are removed, the tracking variable itself
- *   (which stores the list of names) is also unset.
- *
- * RETURN VALUE
- *   Returns 1 on success, 0 if no tracking variable exists,
- *   or FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
-{
-       struct sample smp_ctx;
-       char          var_name[BUFSIZ];
-       int           var_name_len, retval;
-
-       OTELC_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), opt, OTELC_DPTR_ARGS(err));
-
-       flt_otel_smp_init(s, &smp_ctx, opt, 0, NULL);
-
-       retval = flt_otel_ctx_loop(&smp_ctx, scope, prefix, err, flt_otel_vars_unset_cb, NULL);
-       if (retval != FLT_OTEL_RET_ERROR) {
-               /*
-                * After all ctx variables have been unset, the variable used
-                * to store their names should also be unset.
-                */
-               var_name_len = flt_otel_var_name(scope, prefix, NULL, 0, var_name, sizeof(var_name), err);
-               if (var_name_len == FLT_OTEL_RET_ERROR)
-                       OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-               flt_otel_smp_init(s, &smp_ctx, opt, 0, NULL);
-
-               if (vars_unset_by_name_ifexist(var_name, var_name_len, &smp_ctx) == 0) {
-                       OTELC_DBG(NOTICE, "variable '%s' not found", var_name);
-               } else {
-                       OTELC_DBG(NOTICE, "variable '%s' unset", var_name);
-
-                       retval = 1;
-               }
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_vars_get_cb - context variable value reader callback
- *
- * SYNOPSIS
- *   static int flt_otel_vars_get_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OTEL_VAR_CTX_SIZE name_len, char **err, void *ptr)
- *
- * ARGUMENTS
- *   smp      - current sample with stream context
- *   idx      - buffer offset (unused)
- *   scope    - variable scope
- *   prefix   - variable prefix
- *   name     - normalized context variable name
- *   name_len - length of the name (unused)
- *   err      - indirect pointer to error message string
- *   ptr      - pointer to the output text map pointer
- *
- * DESCRIPTION
- *   Callback for flt_otel_ctx_loop() that reads a single context variable value
- *   and adds it to a text map.  Constructs the full variable name, reads its
- *   value via vars_get_by_name(), reverses the <name> normalization (restoring
- *   dashes and spaces), and stores the key-value pair in the text map.  The
- *   text map is lazily allocated on first use.
- *
- * RETURN VALUE
- *   Returns 0 on success, or FLT_OTEL_RET_ERROR on failure.
- */
-static int flt_otel_vars_get_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OTEL_VAR_CTX_SIZE name_len, char **err, void *ptr)
-{
-       struct otelc_text_map **map = ptr;
-       struct sample           smp_ctx;
-       char                    var_ctx[BUFSIZ], otel_var_name[BUFSIZ];
-       int                     var_ctx_len, retval = FLT_OTEL_RET_ERROR;
-
-       OTELC_FUNC("%p, %zu, \"%s\", \"%s\", \"%s\", %hhd, %p:%p, %p", smp, idx, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), name_len, OTELC_DPTR_ARGS(err), ptr);
-
-       /* Build the HAProxy variable name for this context key. */
-       var_ctx_len = flt_otel_var_name(scope, prefix, name, 1, var_ctx, sizeof(var_ctx), err);
-       if (var_ctx_len == FLT_OTEL_RET_ERROR) {
-               FLT_OTEL_ERR("ctx '%s' invalid", name);
-
-               OTELC_RETURN_INT(retval);
-       }
-
-       flt_otel_smp_init(smp->strm, &smp_ctx, smp->opt, 0, NULL);
-
-       /* Retrieve the context variable and build a text map entry. */
-       if (vars_get_by_name(var_ctx, var_ctx_len, &smp_ctx, NULL) != 0) {
-               OTELC_DBG(NOTICE, "'%s' -> '%.*s'", var_ctx, (int)b_data(&(smp_ctx.data.u.str)), b_orig(&(smp_ctx.data.u.str)));
-
-               if (*map == NULL) {
-                       *map = OTELC_TEXT_MAP_NEW(NULL, 8);
-                       if (*map == NULL) {
-                               FLT_OTEL_ERR("failed to create map data");
-
-                               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-                       }
-               }
-
-               /*
-                * Eh, because the use of some characters is not allowed in the
-                * variable name, the conversion of the replaced characters to
-                * the original is performed here.
-                */
-               retval = flt_otel_denormalize_name(name, otel_var_name, OTELC_TABLESIZE_1(otel_var_name), err);
-               if (retval >= 0)
-                       retval = OTELC_TEXT_MAP_ADD(*map, otel_var_name, retval, b_orig(&(smp_ctx.data.u.str)), b_data(&(smp_ctx.data.u.str)), OTELC_TEXT_MAP_AUTO);
-               if (retval == FLT_OTEL_RET_ERROR) {
-                       FLT_OTEL_ERR("failed to add map data");
-
-                       otelc_text_map_destroy(map);
-               } else {
-                       retval = 0;
-               }
-       } else {
-               OTELC_DBG(NOTICE, "ctx '%s' no variable found", var_ctx);
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_vars_get - context variables to text map extraction
- *
- * SYNOPSIS
- *   struct otelc_text_map *flt_otel_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
- *
- * ARGUMENTS
- *   s      - current stream
- *   scope  - variable scope
- *   prefix - variable prefix
- *   opt    - sample option flags
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Reads all context variables for a given <prefix> into a text map.  Iterates
- *   the tracking buffer via flt_otel_ctx_loop() with flt_otel_vars_get_cb().
- *   If the resulting text map is empty, it is destroyed and NULL is returned.
- *   This function is used by the "extract" keyword with variable storage.
- *
- * RETURN VALUE
- *   Returns a pointer to the populated text map, or NULL if no variables are
- *   found.
- */
-struct otelc_text_map *flt_otel_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
-{
-       struct sample          smp_ctx;
-       struct otelc_text_map *retptr = NULL;
-
-       OTELC_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), opt, OTELC_DPTR_ARGS(err));
-
-       flt_otel_smp_init(s, &smp_ctx, opt, 0, NULL);
-
-       (void)flt_otel_ctx_loop(&smp_ctx, scope, prefix, err, flt_otel_vars_get_cb, &retptr);
-
-       OTELC_TEXT_MAP_DUMP(retptr, "extracted variables");
-
-       if ((retptr != NULL) && (retptr->count == 0)) {
-               OTELC_DBG(NOTICE, "WARNING: no variables found");
-
-               otelc_text_map_destroy(&retptr);
-       }
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-#else
-
-/***
- * NAME
- *   flt_otel_vars_get_scope - resolve scope string to variable store
- *
- * SYNOPSIS
- *   static struct vars *flt_otel_vars_get_scope(struct stream *s, const char *scope)
- *
- * ARGUMENTS
- *   s     - current stream
- *   scope - variable scope string ("proc", "sess", "txn", "req", "res")
- *
- * DESCRIPTION
- *   Resolves a scope name string to the corresponding HAProxy variable
- *   store for the given <stream>.
- *
- * RETURN VALUE
- *   Returns a pointer to the variable store, or NULL if the <scope>
- *   is unknown.
- */
-static struct vars *flt_otel_vars_get_scope(struct stream *s, const char *scope)
-{
-       if (strcmp(scope, "txn") == 0)
-               return &(s->vars_txn);
-       else if (strcmp(scope, "req") == 0)
-               return &(s->vars_reqres);
-       else if (strcmp(scope, "res") == 0)
-               return &(s->vars_reqres);
-       else if (strcmp(scope, "sess") == 0)
-               return &(s->sess->vars);
-       else if (strcmp(scope, "proc") == 0)
-               return &proc_vars;
-
-       return NULL;
-}
-
-
-/***
- * NAME
- *   flt_otel_vars_unset - context variables bulk unset via prefix scan
- *
- * SYNOPSIS
- *   int flt_otel_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
- *
- * ARGUMENTS
- *   s      - current stream
- *   scope  - variable scope
- *   prefix - variable prefix
- *   opt    - sample option flags
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Unsets all context variables whose name starts with the normalized
- *   <prefix> followed by a dot.  Walks the CEB tree of the variable
- *   store for the given <scope> and removes each matching variable.
- *
- * RETURN VALUE
- *   Returns the number of variables removed, 0 if none found,
- *   or FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
-{
-       struct vars    *vars;
-       char            norm_prefix[BUFSIZ];
-       unsigned int    size = 0;
-       int             prefix_len, retval = 0, i;
-
-       OTELC_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), opt, OTELC_DPTR_ARGS(err));
-
-       prefix_len = flt_otel_var_name(prefix, NULL, NULL, 0, norm_prefix, sizeof(norm_prefix), err);
-       if (prefix_len == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
-
-       vars = flt_otel_vars_get_scope(s, scope);
-       if (vars == NULL)
-               OTELC_RETURN_INT(0);
-
-       /* Lock and iterate all variables, clearing those matching the prefix. */
-       vars_wrlock(vars);
-       for (i = 0; i < VAR_NAME_ROOTS; i++) {
-               struct ceb_node *node = cebu64_imm_first(&(vars->name_root[i]));
-
-               while (node != NULL) {
-                       struct var      *var = container_of(node, struct var, name_node);
-                       struct ceb_node *next = cebu64_imm_next(&(vars->name_root[i]), node);
-
-                       if ((var->name != NULL) &&
-                           (strncmp(var->name, norm_prefix, prefix_len) == 0) &&
-                           (var->name[prefix_len] == '.')) {
-                               OTELC_DBG(NOTICE, "prefix unset '%s'", var->name);
-
-                               size += var_clear(vars, var, 1);
-                               retval++;
-                       }
-
-                       node = next;
-               }
-       }
-       vars_wrunlock(vars);
-
-       if (size > 0)
-               var_accounting_diff(vars, s->sess, s, -(int)size);
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_vars_get - context variables to text map via prefix scan
- *
- * SYNOPSIS
- *   struct otelc_text_map *flt_otel_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
- *
- * ARGUMENTS
- *   s      - current stream
- *   scope  - variable scope
- *   prefix - variable prefix
- *   opt    - sample option flags
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Reads all context variables whose name starts with the normalized
- *   <prefix> followed by a dot.  Walks the CEB tree of the variable
- *   store for the given <scope>, denormalizes each matching variable
- *   name, and adds the key-value pair to the returned text map.
- *
- * RETURN VALUE
- *   Returns a pointer to the populated text map, or NULL if no
- *   variables are found.
- */
-struct otelc_text_map *flt_otel_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
-{
-       struct vars           *vars;
-       struct otelc_text_map *retptr = NULL;
-       char                   norm_prefix[BUFSIZ], otel_name[BUFSIZ];
-       int                    prefix_len, i;
-
-       OTELC_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), opt, OTELC_DPTR_ARGS(err));
-
-       prefix_len = flt_otel_var_name(prefix, NULL, NULL, 0, norm_prefix, sizeof(norm_prefix), err);
-       if (prefix_len == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_PTR(NULL);
-
-       vars = flt_otel_vars_get_scope(s, scope);
-       if (vars == NULL)
-               OTELC_RETURN_PTR(NULL);
-
-       /* Read-lock and collect all variables matching the prefix into a text map. */
-       vars_rdlock(vars);
-       for (i = 0; i < VAR_NAME_ROOTS; i++) {
-               struct ceb_node *node = cebu64_imm_first(&(vars->name_root[i]));
-
-               for ( ; node != NULL; node = cebu64_imm_next(&(vars->name_root[i]), node)) {
-                       struct var *var = container_of(node, struct var, name_node);
-                       const char *key;
-                       int         otel_name_len;
-
-                       if ((var->name == NULL) ||
-                           (strncmp(var->name, norm_prefix, prefix_len) != 0) ||
-                           (var->name[prefix_len] != '.'))
-                               continue;
-
-                       /* Skip the "prefix." part to get the key name. */
-                       key = var->name + prefix_len + 1;
-
-                       otel_name_len = flt_otel_denormalize_name(key, otel_name, sizeof(otel_name), err);
-                       if (otel_name_len == FLT_OTEL_RET_ERROR) {
-                               FLT_OTEL_ERR("failed to reverse variable name, buffer too small");
-
-                               break;
-                       }
-
-                       if ((var->data.type != SMP_T_STR) && (var->data.type != SMP_T_BIN)) {
-                               OTELC_DBG(NOTICE, "skipping '%s', unsupported type %d", var->name, var->data.type);
-
-                               continue;
-                       }
-
-                       OTELC_DBG(NOTICE, "'%s' -> '%.*s'", var->name, (int)b_data(&(var->data.u.str)), b_orig(&(var->data.u.str)));
-
-                       if (retptr == NULL) {
-                               retptr = OTELC_TEXT_MAP_NEW(NULL, 8);
-                               if (retptr == NULL) {
-                                       FLT_OTEL_ERR("failed to create map data");
-
-                                       break;
-                               }
-                       }
-
-                       if (OTELC_TEXT_MAP_ADD(retptr, otel_name, otel_name_len, b_orig(&(var->data.u.str)), b_data(&(var->data.u.str)), OTELC_TEXT_MAP_AUTO) == -1) {
-                               FLT_OTEL_ERR("failed to add map data");
-
-                               otelc_text_map_destroy(&retptr);
-
-                               break;
-                       }
-               }
-       }
-       vars_rdunlock(vars);
-
-       OTELC_TEXT_MAP_DUMP(retptr, "extracted variables");
-
-       if ((retptr != NULL) && (retptr->count == 0)) {
-               OTELC_DBG(NOTICE, "WARNING: no variables found");
-
-               otelc_text_map_destroy(&retptr);
-       }
-
-       OTELC_RETURN_PTR(retptr);
-}
-
-#endif /* USE_OTEL_VARS_NAME */
-
-
-/***
- * NAME
- *   flt_otel_var_register - HAProxy variable registration
- *
- * SYNOPSIS
- *   int flt_otel_var_register(const char *scope, const char *prefix, const char *name, char **err)
- *
- * ARGUMENTS
- *   scope  - variable scope
- *   prefix - variable prefix
- *   name   - variable name
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Registers a HAProxy variable by constructing its full name from <scope>,
- *   <prefix>, and <name>, then calling vars_check_arg() to make it available
- *   at runtime.
- *
- * RETURN VALUE
- *   Returns the variable name length on success, or FLT_OTEL_RET_ERROR on
- *   failure.
- */
-int flt_otel_var_register(const char *scope, const char *prefix, const char *name, char **err)
-{
-       struct arg arg;
-       char       var_name[BUFSIZ];
-       int        retval = FLT_OTEL_RET_ERROR, var_name_len;
-
-       OTELC_FUNC("\"%s\", \"%s\", \"%s\", %p:%p", OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), OTELC_DPTR_ARGS(err));
-
-       var_name_len = flt_otel_var_name(scope, prefix, name, 0, var_name, sizeof(var_name), err);
-       if (var_name_len == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_INT(retval);
-
-       /* Set <size> to 0 to not release var_name memory in vars_check_arg(). */
-       (void)memset(&arg, 0, sizeof(arg));
-       arg.type          = ARGT_STR;
-       arg.data.str.area = var_name;
-       arg.data.str.data = var_name_len;
-
-       if (vars_check_arg(&arg, err) == 0) {
-               FLT_OTEL_ERR_APPEND("failed to register variable '%s': %s", var_name, *err);
-       } else {
-               OTELC_DBG(NOTICE, "variable '%s' registered", var_name);
-
-               retval = var_name_len;
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-
-/***
- * NAME
- *   flt_otel_var_set - HAProxy variable value setter
- *
- * SYNOPSIS
- *   int flt_otel_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err)
- *
- * ARGUMENTS
- *   s      - current stream
- *   scope  - variable scope
- *   prefix - variable prefix
- *   name   - variable name
- *   value  - string value to set
- *   opt    - sample option flags
- *   err    - indirect pointer to error message string
- *
- * DESCRIPTION
- *   Sets a HAProxy variable to the given string <value>.  The full variable
- *   name is constructed from <scope>, <prefix>, and <name>.  If the variable's
- *   scope matches FLT_OTEL_VARS_SCOPE, the name is also registered in the
- *   context tracking buffer via flt_otel_ctx_set().
- *
- * RETURN VALUE
- *   Returns the variable name length on success, the context tracking result
- *   for context-scope variables, or FLT_OTEL_RET_ERROR on failure.
- */
-int flt_otel_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err)
-{
-       struct sample smp;
-       char          var_name[BUFSIZ];
-       int           retval = FLT_OTEL_RET_ERROR, var_name_len;
-
-       OTELC_FUNC("%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, %p:%p", s, OTELC_STR_ARG(scope), OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), OTELC_STR_ARG(value), opt, OTELC_DPTR_ARGS(err));
-
-       var_name_len = flt_otel_var_name(scope, prefix, name, 0, var_name, sizeof(var_name), err);
-       if (var_name_len == FLT_OTEL_RET_ERROR)
-               OTELC_RETURN_INT(retval);
-
-       flt_otel_smp_init(s, &smp, opt, SMP_T_STR, value);
-
-       /* Set the variable if it already exists. */
-       if (vars_set_by_name_ifexist(var_name, var_name_len, &smp) == 0) {
-               FLT_OTEL_ERR("failed to set variable '%s'", var_name);
-       } else {
-               OTELC_DBG(NOTICE, "variable '%s' set", var_name);
-
-               retval = var_name_len;
-
-#ifndef USE_OTEL_VARS_NAME
-               if (strcmp(scope, FLT_OTEL_VARS_SCOPE) == 0)
-                       retval = flt_otel_ctx_set(s, scope, prefix, name, opt, err);
-#endif
-       }
-
-       OTELC_RETURN_INT(retval);
-}
-
-/*
- * Local variables:
- *  c-indent-level: 8
- *  c-basic-offset: 8
- * End:
- *
- * vi: noexpandtab shiftwidth=8 tabstop=8
- */
diff --git a/addons/otel/test/README-cmp b/addons/otel/test/README-cmp
deleted file mode 100644 (file)
index ab1b6d7..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-Comparison test configuration (cmp/)
-====================================
-
-The 'cmp' test is a simplified standalone configuration made for comparison with
-other tracing implementations.  It uses a reduced set of events and a compact
-span hierarchy without context propagation, groups or metrics.  This
-configuration is closer to a typical production deployment.
-
-All response-side scopes (http_response, http_response-error, server_session_end
-and client_session_end) share the on-http-response event, which means they fire
-in a single batch at response time.
-
-
-Files
------
-
-  cmp/otel.cfg    OTel filter configuration (scopes)
-  cmp/haproxy.cfg HAProxy frontend/backend configuration
-  cmp/otel.yml    Exporter, processor, reader and provider definitions
-  run-cmp.sh      Convenience script to launch HAProxy with this config
-
-
-Events
-------
-
-  T = Trace (span)
-
-  This configuration produces traces only -- no metrics or log-records.
-
-  Request analyzer events:
-
-    Event                      Scope                    T
-    --------------------------------------------------------
-    on-client-session-start    client_session_start     x
-    on-frontend-tcp-request    frontend_tcp_request     x
-    on-frontend-http-request   frontend_http_request    x
-    on-backend-tcp-request     backend_tcp_request      x
-    on-backend-http-request    backend_http_request     x
-    on-server-unavailable      server_unavailable       x
-
-  Response analyzer events:
-
-    Event                      Scope                    T
-    --------------------------------------------------------
-    on-server-session-start    server_session_start     x
-    on-tcp-response            tcp_response             x
-    on-http-response           http_response            x
-    on-http-response           http_response-error      x  (conditional)
-    on-http-response           server_session_end       -  (finish only)
-    on-http-response           client_session_end       -  (finish only)
-
-  The http_response-error scope fires conditionally when the ACL
-  acl-http-status-ok (status 100:399) does not match, setting an error status
-  on the "HTTP response" span.
-
-  The server_session_end and client_session_end scopes are bound to the
-  on-http-response event and only perform finish operations.
-
-
-Span hierarchy
---------------
-
-    "HAProxy session" (root)
-     +-- "Client session"
-          +-- "Frontend TCP request"
-               +-- "Frontend HTTP request"
-                    +-- "Backend TCP request"
-                         +-- "Backend HTTP request"
-
-    "HAProxy session" (root)
-     +-- "Server session"
-          +-- "TCP response"
-               +-- "HTTP response"
-
-
-Running the test
-----------------
-
-From the test/ directory:
-
-  % ./run-cmp.sh [/path/to/haproxy] [pidfile]
-
-If no arguments are given, the script looks for the haproxy binary three
-directories up from the current working directory.  The backend origin server
-must be running on 127.0.0.1:8000.
diff --git a/addons/otel/test/README-ctx b/addons/otel/test/README-ctx
deleted file mode 100644 (file)
index 512706e..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-Context propagation test configuration (ctx/)
-=============================================
-
-The 'ctx' test is a standalone configuration that uses inject/extract context
-propagation on every scope.  Spans are opened using extracted span contexts
-stored in HAProxy variables as parent references instead of direct span names.
-This adds the overhead of context serialization, variable storage and
-deserialization on every scope execution.
-
-The event coverage matches the 'sa' configuration.  The key difference is the
-propagation mechanism: each scope injects its context into a numbered variable
-(otel_ctx_1 through otel_ctx_17) and the next scope extracts from that variable
-to establish the parent relationship.
-
-The client_session_start event is split into two scopes (client_session_start_1
-and client_session_start_2) to demonstrate inject/extract between scopes
-handling the same event.
-
-
-Files
------
-
-  ctx/otel.cfg    OTel filter configuration (scopes, groups, contexts)
-  ctx/haproxy.cfg HAProxy frontend/backend configuration
-  ctx/otel.yml    Exporter, processor, reader and provider definitions
-  run-ctx.sh      Convenience script to launch HAProxy with this config
-
-
-Events
-------
-
-  T = Trace (span)
-
-  This configuration produces traces only -- no metrics or log-records.
-
-  Stream lifecycle events:
-
-    Event                    Scope                        T
-    ----------------------------------------------------------
-    on-client-session-start  client_session_start_1       x
-    on-client-session-start  client_session_start_2       x
-
-  Request analyzer events:
-
-    Event                              Scope                          T
-    --------------------------------------------------------------------
-    on-frontend-tcp-request            frontend_tcp_request           x
-    on-http-wait-request               http_wait_request              x
-    on-http-body-request               http_body_request              x
-    on-frontend-http-request           frontend_http_request          x
-    on-switching-rules-request         switching_rules_request        x
-    on-backend-tcp-request             backend_tcp_request            x
-    on-backend-http-request            backend_http_request           x
-    on-process-server-rules-request    process_server_rules_request   x
-    on-http-process-request            http_process_request           x
-    on-tcp-rdp-cookie-request          tcp_rdp_cookie_request         x
-    on-process-sticking-rules-request  process_sticking_rules_request x
-    on-client-session-end              client_session_end             -
-    on-server-unavailable              server_unavailable             -
-
-  Response analyzer events:
-
-    Event                              Scope                          T
-    --------------------------------------------------------------------
-    on-server-session-start            server_session_start           x
-    on-tcp-response                    tcp_response                   x
-    on-http-wait-response              http_wait_response             x
-    on-process-store-rules-response    process_store_rules_response   x
-    on-http-response                   http_response                  x
-    on-http-response                   http_response-error            x  (conditional)
-    on-server-session-end              server_session_end             -
-
-  The http_response_group (http_response_1, http_response_2) and
-  http_after_response_group (http_after_response) are invoked via http-response
-  and http-after-response directives in haproxy.cfg.
-
-
-Context propagation chain
--------------------------
-
-  Each scope injects its span context into a HAProxy variable and the next scope
-  extracts it.  The variable names and their flow:
-
-    otel_ctx_1   "HAProxy session"              -> client_session_start_2
-    otel_ctx_2   "Client session"               -> frontend_tcp_request
-    otel_ctx_3   "Frontend TCP request"         -> http_wait_request
-    otel_ctx_4   "HTTP wait request"            -> http_body_request
-    otel_ctx_5   "HTTP body request"            -> frontend_http_request
-    otel_ctx_6   "Frontend HTTP request"        -> switching_rules_request
-    otel_ctx_7   "Switching rules request"      -> backend_tcp_request
-    otel_ctx_8   "Backend TCP request"          -> backend_http_request
-    otel_ctx_9   "Backend HTTP request"         -> process_server_rules_request
-    otel_ctx_10  "Process server rules request" -> http_process_request
-    otel_ctx_11  "HTTP process request"         -> tcp_rdp_cookie_request
-    otel_ctx_12  "TCP RDP cookie request"       -> process_sticking_rules_request
-    otel_ctx_13  "Process sticking rules req."  -> server_session_start
-    otel_ctx_14  "Server session"               -> tcp_response
-    otel_ctx_15  "TCP response"                 -> http_wait_response
-    otel_ctx_16  "HTTP wait response"           -> process_store_rules_response
-    otel_ctx_17  "Process store rules response" -> http_response
-
-  All contexts use both use-headers and use-vars injection modes, except
-  otel_ctx_14 and otel_ctx_15 which use use-vars only.
-
-
-Span hierarchy
---------------
-
-  The span hierarchy is identical to the 'sa' configuration, but parent
-  relationships are established through extracted contexts rather than direct
-  span name references.
-
-  Request path:
-
-    "HAProxy session" (root)                                   [otel_ctx_1]
-     +-- "Client session"                                      [otel_ctx_2]
-          +-- "Frontend TCP request"                           [otel_ctx_3]
-               +-- "HTTP wait request"                         [otel_ctx_4]
-                    +-- "HTTP body request"                    [otel_ctx_5]
-                         +-- "Frontend HTTP request"           [otel_ctx_6]
-                              +-- "Switching rules request"    [otel_ctx_7]
-                                   +-- "Backend TCP request"   [otel_ctx_8]
-                                        +-- (continues to process_sticking_rules_request)
-
-  Response path:
-
-    "HAProxy session"                                          [otel_ctx_1]
-     +-- "Server session"                                      [otel_ctx_14]
-          +-- "TCP response"                                   [otel_ctx_15]
-               +-- "HTTP wait response"                        [otel_ctx_16]
-                    +-- "Process store rules response"         [otel_ctx_17]
-                         +-- "HTTP response"
-
-  Auxiliary spans:
-
-    "HAProxy session"
-     +-- "HAProxy response"       (http_after_response_group, on error)
-
-
-Running the test
-----------------
-
-From the test/ directory:
-
-  % ./run-ctx.sh [/path/to/haproxy] [pidfile]
-
-If no arguments are given, the script looks for the haproxy binary three
-directories up from the current working directory.  The backend origin server
-must be running on 127.0.0.1:8000.
diff --git a/addons/otel/test/README-empty b/addons/otel/test/README-empty
deleted file mode 100644 (file)
index 5f19651..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-Empty test configuration (empty/)
-=================================
-
-The 'empty' test is a minimal configuration that loads the OTel filter without
-defining any scopes, events or groups.  The instrumentation block contains only
-the config directive pointing to the YAML pipeline definition.
-
-This configuration verifies that the filter initializes and shuts down cleanly
-when no telemetry is configured.  It exercises the full YAML parsing path
-(exporters, processors, readers, samplers, providers and signals) without
-producing any trace, metric or log-record data.
-
-
-Files
------
-
-  empty/otel.cfg    OTel filter configuration (instrumentation only)
-  empty/haproxy.cfg HAProxy frontend/backend configuration
-  empty/otel.yml    Exporter, processor, reader and provider definitions
-
-
-Events
-------
-
-  No events are registered.  The filter is loaded and attached to the frontend
-  but performs no per-stream processing.
-
-
-YAML pipeline
--------------
-
-  Despite the empty filter configuration, the otel.yml file defines a complete
-  pipeline with all three signal types to verify that the YAML parser handles
-  the full configuration without errors:
-
-    Signal     Exporter                   Processor / Reader
-    -----------------------------------------------------------
-    traces     exporter_traces_otlp_http  processor_traces_batch
-    metrics    exporter_metrics_otlp_http reader_metrics
-    logs       exporter_logs_otlp_http    processor_logs_batch
-
-  Additional exporter definitions (otlp_file, otlp_grpc, ostream, memory,
-  zipkin, elasticsearch) are present in the YAML but are not wired into the
-  active signal pipelines.
-
-
-Running the test
-----------------
-
-There is no dedicated run script for the empty configuration.  To run it
-manually from the test/ directory:
-
-  % /path/to/haproxy -f haproxy-common.cfg -f empty/haproxy.cfg
diff --git a/addons/otel/test/README-fe-be b/addons/otel/test/README-fe-be
deleted file mode 100644 (file)
index 647a21c..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-Frontend / backend test configuration (fe/ + be/)
-=================================================
-
-The 'fe-be' test uses two cascaded HAProxy instances to demonstrate
-inter-process trace context propagation via HTTP headers.  The frontend instance
-(fe/) creates the root trace and injects span context into the HTTP request
-headers.  The backend instance (be/) extracts that context and continues the
-trace as a child of the frontend's span.
-
-The two instances run as separate processes: the frontend listens on port 10080
-and proxies to the backend on port 11080, which in turn proxies to the origin
-server on port 8000.
-
-
-Files
------
-
-  fe/otel.cfg    OTel filter configuration for the frontend instance
-  fe/haproxy.cfg HAProxy configuration for the frontend instance
-  be/otel.cfg    OTel filter configuration for the backend instance
-  be/haproxy.cfg HAProxy configuration for the backend instance
-  run-fe-be.sh   Convenience script to launch both instances
-
-
-Events
-------
-
-  T = Trace (span)
-
-  Both instances produce traces only -- no metrics or log-records.
-
-  Frontend (fe/) events:
-
-    Event                      Scope                    T
-    --------------------------------------------------------
-    on-client-session-start    client_session_start     x
-    on-frontend-tcp-request    frontend_tcp_request     x
-    on-frontend-http-request   frontend_http_request    x
-    on-backend-tcp-request     backend_tcp_request      x
-    on-backend-http-request    backend_http_request     x
-    on-client-session-end      client_session_end       -
-    on-server-session-start    server_session_start     x
-    on-tcp-response            tcp_response             x
-    on-http-response           http_response            x
-    on-server-session-end      server_session_end       -
-
-  Backend (be/) events:
-
-    Event                      Scope                    T
-    --------------------------------------------------------
-    on-frontend-http-request   frontend_http_request    x
-    on-backend-tcp-request     backend_tcp_request      x
-    on-backend-http-request    backend_http_request     x
-    on-client-session-end      client_session_end       -
-    on-server-session-start    server_session_start     x
-    on-tcp-response            tcp_response             x
-    on-http-response           http_response            x
-    on-server-session-end      server_session_end       -
-
-  The backend starts its trace at on-frontend-http-request where it extracts
-  the span context injected by the frontend.  Earlier request events
-  (on-client-session-start, on-frontend-tcp-request) are not needed because
-  the context is not yet available in the HTTP headers at that point.
-
-
-Context propagation
--------------------
-
-  The frontend injects context into HTTP headers in the backend_http_request
-  scope:
-
-    span "HAProxy session"
-        inject "otel-ctx" use-headers
-
-  The backend extracts that context in its frontend_http_request scope:
-
-    extract "otel-ctx" use-headers
-    span "HAProxy session" parent "otel-ctx" root
-
-
-Span hierarchy
---------------
-
-  Frontend (fe/):
-
-    "HAProxy session" (root)
-     +-- "Client session"
-          +-- "Frontend TCP request"
-               +-- "Frontend HTTP request"
-                    +-- "Backend TCP request"
-                         +-- "Backend HTTP request"
-
-    "HAProxy session" (root)
-     +-- "Server session"
-          +-- "TCP response"
-               +-- "HTTP response"
-
-  Backend (be/):
-
-    "HAProxy session" (root, parent: frontend's "HAProxy session")
-     +-- "Client session"
-          +-- "Frontend HTTP request"
-               +-- "Backend TCP request"
-                    +-- "Backend HTTP request"
-
-    "HAProxy session" (root)
-     +-- "Server session"
-          +-- "TCP response"
-               +-- "HTTP response"
-
-
-Running the test
-----------------
-
-From the test/ directory:
-
-  % ./run-fe-be.sh [/path/to/haproxy] [pidfile]
-
-If no arguments are given, the script looks for the haproxy binary three
-directories up from the current working directory.  The backend origin server
-must be running on 127.0.0.1:8000.
-
-The script launches both HAProxy instances in the background and waits.
-Press CTRL-C to stop both instances.
diff --git a/addons/otel/test/README-full b/addons/otel/test/README-full
deleted file mode 100644 (file)
index a93d932..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-Full event coverage test configuration (full/)
-==============================================
-
-The 'full' test is a standalone single-instance configuration that exercises
-every supported OTel filter event with all three signal types: traces (spans),
-metrics (instruments) and logs (log-records).
-
-It extends the 'sa' (standalone) configuration by adding the events that 'sa'
-does not cover and by attaching log-records to every scope.
-
-
-Files
------
-
-  full/otel.cfg    OTel filter configuration (scopes, groups, instruments)
-  full/haproxy.cfg HAProxy frontend/backend configuration
-  full/otel.yml    Exporter, processor, reader and provider definitions
-  run-full.sh      Convenience script to launch HAProxy with this config
-
-
-Events
-------
-
-The table below lists every event defined in include/event.h together with the
-scope that handles it and the signals produced by that scope.
-
-  T = Trace (span)    M = Metric (instrument)    L = Log (log-record)
-
-  Stream lifecycle events:
-
-    Event                    Scope                       T  M  L
-    ---------------------------------------------------------------
-    on-stream-start          on_stream_start             x  x  x
-    on-stream-stop           on_stream_stop              -  -  x
-    on-idle-timeout          on_idle_timeout              x  x  x
-    on-backend-set           on_backend_set               x  x  x
-
-  Request analyzer events:
-
-    Event                              Scope                          T  M  L
-    --------------------------------------------------------------------------
-    on-client-session-start            client_session_start           x  x  x
-    on-frontend-tcp-request            frontend_tcp_request           x  x  x
-    on-http-wait-request               http_wait_request              x  -  x
-    on-http-body-request               http_body_request              x  -  x
-    on-frontend-http-request           frontend_http_request          x  x  x
-    on-switching-rules-request         switching_rules_request        x  -  x
-    on-backend-tcp-request             backend_tcp_request            x  x  x
-    on-backend-http-request            backend_http_request           x  -  x
-    on-process-server-rules-request    process_server_rules_request   x  -  x
-    on-http-process-request            http_process_request           x  -  x
-    on-tcp-rdp-cookie-request          tcp_rdp_cookie_request         x  -  x
-    on-process-sticking-rules-request  process_sticking_rules_request x  -  x
-    on-http-headers-request            http_headers_request           x  x  x
-    on-http-end-request                http_end_request               x  x  x
-    on-client-session-end              client_session_end             -  x  x
-    on-server-unavailable              server_unavailable             -  -  x
-
-  Response analyzer events:
-
-    Event                              Scope                          T  M  L
-    --------------------------------------------------------------------------
-    on-server-session-start            server_session_start           x  x  x
-    on-tcp-response                    tcp_response                   x  x  x
-    on-http-wait-response              http_wait_response             x  -  x
-    on-process-store-rules-response    process_store_rules_response   x  -  x
-    on-http-response                   http_response                  x  x  x
-    on-http-headers-response           http_headers_response          x  x  x
-    on-http-end-response               http_end_response              x  x  x
-    on-http-reply                      http_reply                     x  x  x
-    on-server-session-end              server_session_end             -  x  x
-
-  Additionally, the http_response-error scope fires conditionally on the
-  on-http-response event when the response status is outside the 100-399 range,
-  setting an error status on the "HTTP response" span.
-
-  The http_response_group (http_response_1, http_response_2) and
-  http_after_response_group (http_after_response) are invoked via http-response
-  and http-after-response directives in haproxy.cfg.
-
-
-Instruments
------------
-
-Every instrument definition has at least one corresponding update.
-
-  Instrument name                Type       Defined in              Updated in
-  -------------------------------------------------------------------------------
-  haproxy.sessions.active        udcnt_int  on_stream_start         client_session_end
-  haproxy.fe.connections         gauge_int  on_stream_start         http_response
-  idle.count                     cnt_int    on_idle_timeout         on_idle_timeout
-  haproxy.backend.set            cnt_int    on_backend_set          on_backend_set
-  haproxy.client.session.start   cnt_int    client_session_start    client_session_end
-  haproxy.tcp.request.fe         cnt_int    frontend_tcp_request    frontend_http_request
-  haproxy.http.requests          cnt_int    frontend_http_request   http_response
-  haproxy.http.latency           hist_int   frontend_http_request   frontend_http_request,
-                                                                    http_response
-  haproxy.tcp.request.be         cnt_int    backend_tcp_request     backend_http_request
-  haproxy.http.headers.request   cnt_int    http_headers_request    http_end_request
-  haproxy.http.end.request       cnt_int    http_end_request        client_session_end
-  haproxy.server.session.start   cnt_int    server_session_start    server_session_end
-  haproxy.tcp.response           cnt_int    tcp_response            http_wait_response
-  haproxy.http.headers.response  cnt_int    http_headers_response   http_end_response
-  haproxy.http.end.response      cnt_int    http_end_response       http_reply
-  haproxy.http.reply             cnt_int    http_reply              server_session_end
-
-
-Span hierarchy
---------------
-
-  Request path:
-
-    "HAProxy session" (root)
-     +-- "Client session"
-          +-- "Frontend TCP request"
-               +-- "HTTP wait request"
-                    +-- "HTTP body request"
-                         +-- "Frontend HTTP request"  [link: "HAProxy session"]
-                              +-- "Switching rules request"
-                                   +-- "Backend TCP request"
-                                        +-- "Backend HTTP request"
-                                             +-- "Process server rules request"
-                                                  +-- "HTTP process request"
-                                                       +-- "TCP RDP cookie request"
-                                                            +-- "Process sticking rules request"
-                                                                 +-- "HTTP headers request"
-                                                                      +-- "HTTP end request"
-
-  Response path:
-
-    "HAProxy session" (root)
-     +-- "Server session"  [link: "HAProxy session", "Client session"]
-          +-- "TCP response"
-               +-- "HTTP wait response"
-                    +-- "Process store rules response"
-                         +-- "HTTP response"
-                              +-- "HTTP headers response"
-                                   +-- "HTTP end response"
-                                        +-- "HTTP reply"
-
-  Auxiliary spans:
-
-    "HAProxy session"
-     +-- "Backend set"
-     +-- "heartbeat"              (on-idle-timeout, periodic)
-     +-- "HAProxy response"       (http_after_response_group, on error)
-
-
-Running the test
-----------------
-
-From the test/ directory:
-
-  % ./run-full.sh [/path/to/haproxy] [pidfile]
-
-If no arguments are given, the script looks for the haproxy binary three
-directories up from the current working directory.  The backend origin server
-must be running on 127.0.0.1:8000.
diff --git a/addons/otel/test/README-sa b/addons/otel/test/README-sa
deleted file mode 100644 (file)
index f5a1c12..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-Standalone test configuration (sa/)
-=====================================
-
-The 'sa' test is a standalone single-instance configuration that
-exercises most HAProxy filter events with spans, attributes, events,
-links, baggage, status, metrics, logs and groups.  It represents the
-most comprehensive single-instance configuration and is used as the
-worst-case scenario in speed tests.
-
-Six events are not covered by this configuration: on-backend-set,
-on-http-headers-request, on-http-end-request, on-http-headers-response,
-on-http-end-response and on-http-reply.  The 'full' configuration
-extends 'sa' with those events.
-
-
-Files
-------
-
-  sa/otel.cfg    OTel filter configuration (scopes, groups, instruments)
-  sa/haproxy.cfg HAProxy frontend/backend configuration
-  sa/otel.yml    Exporter, processor, reader and provider definitions
-  run-sa.sh      Convenience script to launch HAProxy with this config
-
-
-Events
--------
-
-  T = Trace (span)    M = Metric (instrument)    L = Log (log-record)
-
-  Stream lifecycle events:
-
-    Event                    Scope                       T  M  L
-    ---------------------------------------------------------------
-    on-stream-start          on_stream_start             x  x  x
-    on-stream-stop           on_stream_stop              -  -  -
-    on-idle-timeout          on_idle_timeout              x  x  x
-
-  Request analyzer events:
-
-    Event                              Scope                          T  M  L
-    --------------------------------------------------------------------------
-    on-client-session-start            client_session_start           x  -  -
-    on-frontend-tcp-request            frontend_tcp_request           x  -  -
-    on-http-wait-request               http_wait_request              x  -  -
-    on-http-body-request               http_body_request              x  -  -
-    on-frontend-http-request           frontend_http_request          x  x  x
-    on-switching-rules-request         switching_rules_request        x  -  -
-    on-backend-tcp-request             backend_tcp_request            x  -  -
-    on-backend-http-request            backend_http_request           x  -  -
-    on-process-server-rules-request    process_server_rules_request   x  -  -
-    on-http-process-request            http_process_request           x  -  -
-    on-tcp-rdp-cookie-request          tcp_rdp_cookie_request         x  -  -
-    on-process-sticking-rules-request  process_sticking_rules_request x  -  -
-    on-client-session-end              client_session_end             -  x  -
-    on-server-unavailable              server_unavailable             -  -  -
-
-  Response analyzer events:
-
-    Event                              Scope                          T  M  L
-    --------------------------------------------------------------------------
-    on-server-session-start            server_session_start           x  -  -
-    on-tcp-response                    tcp_response                   x  -  -
-    on-http-wait-response              http_wait_response             x  -  -
-    on-process-store-rules-response    process_store_rules_response   x  -  -
-    on-http-response                   http_response                  x  x  -
-    on-server-session-end              server_session_end             -  -  -
-
-  Additionally, the http_response-error scope fires conditionally on the
-  on-http-response event when the response status is outside the 100-399
-  range, setting an error status on the "HTTP response" span.
-
-  The http_response_group (http_response_1, http_response_2) and
-  http_after_response_group (http_after_response) are invoked via
-  http-response and http-after-response directives in haproxy.cfg.
-
-
-Instruments
-------------
-
-  Instrument name            Type       Defined in              Updated in
-  --------------------------------------------------------------------------
-  haproxy.sessions.active    udcnt_int  on_stream_start         client_session_end
-  haproxy.fe.connections     gauge_int  on_stream_start         http_response
-  idle.count                 cnt_int    on_idle_timeout         on_idle_timeout
-  haproxy.http.requests      cnt_int    frontend_http_request   http_response
-  haproxy.http.latency       hist_int   frontend_http_request   frontend_http_request,
-                                                                http_response
-
-
-Span hierarchy
----------------
-
-  Request path:
-
-    "HAProxy session" (root)
-     +-- "Client session"
-          +-- "Frontend TCP request"
-               +-- "HTTP wait request"
-                    +-- "HTTP body request"
-                         +-- "Frontend HTTP request"  [link: "HAProxy session"]
-                              +-- "Switching rules request"
-                                   +-- "Backend TCP request"
-                                        +-- "Backend HTTP request"
-                                             +-- "Process server rules request"
-                                                  +-- "HTTP process request"
-                                                       +-- "TCP RDP cookie request"
-                                                            +-- "Process sticking rules request"
-
-  Response path:
-
-    "HAProxy session" (root)
-     +-- "Server session"  [link: "HAProxy session", "Client session"]
-          +-- "TCP response"
-               +-- "HTTP wait response"
-                    +-- "Process store rules response"
-                         +-- "HTTP response"
-
-  Auxiliary spans:
-
-    "HAProxy session"
-     +-- "heartbeat"              (on-idle-timeout, periodic)
-     +-- "HAProxy response"       (http_after_response_group, on error)
-
-
-Running the test
------------------
-
-From the test/ directory:
-
-  % ./run-sa.sh [/path/to/haproxy] [pidfile]
-
-If no arguments are given, the script looks for the haproxy binary three
-directories up from the current working directory.  The backend origin
-server must be running on 127.0.0.1:8000.
diff --git a/addons/otel/test/README-speed-cmp b/addons/otel/test/README-speed-cmp
deleted file mode 100644 (file)
index 8cf0d31..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
---- rate-limit 100.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   182.58us  129.11us  16.19ms   98.11%
-    Req/Sec     5.63k   240.83     6.29k    69.74%
-  Latency Distribution
-     50%  169.00us
-     75%  183.00us
-     90%  209.00us
-     99%  367.00us
-  13438310 requests in 5.00m, 3.24GB read
-Requests/sec:  44779.51
-Transfer/sec:     11.06MB
-----------------------------------------------------------------------
-
---- rate-limit 75.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   180.10us  122.51us  14.57ms   98.00%
-    Req/Sec     5.70k   253.08     6.28k    70.41%
-  Latency Distribution
-     50%  169.00us
-     75%  184.00us
-     90%  206.00us
-     99%  362.00us
-  13613023 requests in 5.00m, 3.28GB read
-Requests/sec:  45361.63
-Transfer/sec:     11.20MB
-----------------------------------------------------------------------
-
---- rate-limit 50.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   176.59us  125.34us  15.58ms   98.02%
-    Req/Sec     5.81k   230.84     6.42k    72.14%
-  Latency Distribution
-     50%  166.00us
-     75%  182.00us
-     90%  202.00us
-     99%  361.00us
-  13888448 requests in 5.00m, 3.35GB read
-Requests/sec:  46279.45
-Transfer/sec:     11.43MB
-----------------------------------------------------------------------
-
---- rate-limit 25.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   173.57us  118.35us  13.12ms   97.91%
-    Req/Sec     5.91k   257.69     6.46k    66.83%
-  Latency Distribution
-     50%  162.00us
-     75%  178.00us
-     90%  199.00us
-     99%  362.00us
-  14122906 requests in 5.00m, 3.41GB read
-Requests/sec:  47060.71
-Transfer/sec:     11.62MB
-----------------------------------------------------------------------
-
---- rate-limit 10.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   170.85us  112.24us  10.72ms   97.84%
-    Req/Sec     6.00k   269.81     8.10k    69.46%
-  Latency Distribution
-     50%  159.00us
-     75%  172.00us
-     90%  194.00us
-     99%  361.00us
-  14342642 requests in 5.00m, 3.46GB read
-Requests/sec:  47792.96
-Transfer/sec:     11.80MB
-----------------------------------------------------------------------
-
---- rate-limit 2.5 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   169.11us  127.52us  16.90ms   98.06%
-    Req/Sec     6.08k   261.57     6.55k    67.30%
-  Latency Distribution
-     50%  158.00us
-     75%  168.00us
-     90%  186.00us
-     99%  367.00us
-  14527714 requests in 5.00m, 3.50GB read
-Requests/sec:  48409.62
-Transfer/sec:     11.96MB
-----------------------------------------------------------------------
-
---- rate-limit 0.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   168.09us  108.96us   9.07ms   97.81%
-    Req/Sec     6.10k   284.22     6.55k    70.65%
-  Latency Distribution
-     50%  157.00us
-     75%  167.00us
-     90%  184.00us
-     99%  362.00us
-  14580762 requests in 5.00m, 3.52GB read
-Requests/sec:  48586.42
-Transfer/sec:     12.00MB
-----------------------------------------------------------------------
-
---- rate-limit disabled --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   168.57us  118.05us  13.51ms   97.94%
-    Req/Sec     6.09k   251.47     6.99k    67.33%
-  Latency Distribution
-     50%  158.00us
-     75%  167.00us
-     90%  184.00us
-     99%  363.00us
-  14557824 requests in 5.00m, 3.51GB read
-Requests/sec:  48509.96
-Transfer/sec:     11.98MB
-----------------------------------------------------------------------
-
---- rate-limit off --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   168.64us  120.15us  14.49ms   98.01%
-    Req/Sec     6.09k   267.94     6.57k    66.19%
-  Latency Distribution
-     50%  158.00us
-     75%  167.00us
-     90%  184.00us
-     99%  361.00us
-  14551312 requests in 5.00m, 3.51GB read
-Requests/sec:  48488.23
-Transfer/sec:     11.98MB
-----------------------------------------------------------------------
-
diff --git a/addons/otel/test/README-speed-ctx b/addons/otel/test/README-speed-ctx
deleted file mode 100644 (file)
index 17a1642..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
---- rate-limit 100.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   270.35us  136.92us  16.02ms   97.98%
-    Req/Sec     3.77k   217.57     5.33k    67.74%
-  Latency Distribution
-     50%  264.00us
-     75%  287.00us
-     90%  309.00us
-     99%  494.00us
-  9012538 requests in 5.00m, 2.17GB read
-Requests/sec:  30031.85
-Transfer/sec:      7.42MB
-----------------------------------------------------------------------
-
---- rate-limit 75.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   242.56us  131.47us   9.82ms   94.77%
-    Req/Sec     4.21k   218.42     5.61k    68.12%
-  Latency Distribution
-     50%  246.00us
-     75%  279.00us
-     90%  308.00us
-     99%  464.00us
-  10050409 requests in 5.00m, 2.42GB read
-Requests/sec:  33490.26
-Transfer/sec:      8.27MB
-----------------------------------------------------------------------
-
---- rate-limit 50.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   215.92us  130.82us   9.93ms   96.81%
-    Req/Sec     4.73k   243.84     7.13k    67.13%
-  Latency Distribution
-     50%  208.00us
-     75%  264.00us
-     90%  300.00us
-     99%  439.00us
-  11307386 requests in 5.00m, 2.73GB read
-Requests/sec:  37678.82
-Transfer/sec:      9.31MB
-----------------------------------------------------------------------
-
---- rate-limit 25.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   192.36us  132.47us  13.75ms   96.79%
-    Req/Sec     5.33k   260.46     6.17k    66.30%
-  Latency Distribution
-     50%  166.00us
-     75%  227.00us
-     90%  280.00us
-     99%  407.00us
-  12734770 requests in 5.00m, 3.07GB read
-Requests/sec:  42448.91
-Transfer/sec:     10.48MB
-----------------------------------------------------------------------
-
---- rate-limit 10.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   180.08us  127.35us  13.34ms   97.06%
-    Req/Sec     5.71k   272.98     6.40k    67.94%
-  Latency Distribution
-     50%  161.00us
-     75%  183.00us
-     90%  250.00us
-     99%  386.00us
-  13641901 requests in 5.00m, 3.29GB read
-Requests/sec:  45457.92
-Transfer/sec:     11.23MB
-----------------------------------------------------------------------
-
---- rate-limit 2.5 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   171.64us  107.08us   5.69ms   96.57%
-    Req/Sec     5.97k   289.99     6.55k    68.53%
-  Latency Distribution
-     50%  159.00us
-     75%  171.00us
-     90%  195.00us
-     99%  372.00us
-  14268464 requests in 5.00m, 3.44GB read
-Requests/sec:  47545.77
-Transfer/sec:     11.74MB
-----------------------------------------------------------------------
-
---- rate-limit 0.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   168.86us  104.53us   5.75ms   97.73%
-    Req/Sec     6.07k   282.19     6.59k    67.47%
-  Latency Distribution
-     50%  158.00us
-     75%  168.00us
-     90%  186.00us
-     99%  361.00us
-  14498699 requests in 5.00m, 3.50GB read
-Requests/sec:  48312.96
-Transfer/sec:     11.93MB
-----------------------------------------------------------------------
-
---- rate-limit disabled --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   168.36us  129.52us  17.68ms   98.13%
-    Req/Sec     6.11k   263.70     6.83k    70.42%
-  Latency Distribution
-     50%  157.00us
-     75%  167.00us
-     90%  183.00us
-     99%  363.00us
-  14590953 requests in 5.00m, 3.52GB read
-Requests/sec:  48620.36
-Transfer/sec:     12.01MB
-----------------------------------------------------------------------
-
---- rate-limit off --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   168.73us  120.51us  15.03ms   98.02%
-    Req/Sec     6.09k   270.88     6.55k    68.99%
-  Latency Distribution
-     50%  158.00us
-     75%  167.00us
-     90%  185.00us
-     99%  360.00us
-  14538507 requests in 5.00m, 3.51GB read
-Requests/sec:  48445.53
-Transfer/sec:     11.97MB
-----------------------------------------------------------------------
-
diff --git a/addons/otel/test/README-speed-fe-be b/addons/otel/test/README-speed-fe-be
deleted file mode 100644 (file)
index 4d93b0f..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
---- rate-limit 100.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   238.75us  129.45us  15.59ms   98.45%
-    Req/Sec     4.27k    75.22     5.28k    77.45%
-  Latency Distribution
-     50%  228.00us
-     75%  243.00us
-     90%  262.00us
-     99%  410.00us
-  10206938 requests in 5.00m, 2.46GB read
-Requests/sec:  34011.80
-Transfer/sec:      8.40MB
-----------------------------------------------------------------------
-
---- rate-limit 75.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   230.08us  201.50us  32.12ms   99.25%
-    Req/Sec     4.46k    83.43     5.36k    75.61%
-  Latency Distribution
-     50%  222.00us
-     75%  241.00us
-     90%  261.00us
-     99%  401.00us
-  10641998 requests in 5.00m, 2.57GB read
-Requests/sec:  35461.59
-Transfer/sec:      8.76MB
-----------------------------------------------------------------------
-
---- rate-limit 50.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   222.33us  242.52us  35.13ms   99.43%
-    Req/Sec     4.62k    99.86     5.78k    79.00%
-  Latency Distribution
-     50%  211.00us
-     75%  237.00us
-     90%  259.00us
-     99%  400.00us
-  11046951 requests in 5.00m, 2.66GB read
-Requests/sec:  36810.91
-Transfer/sec:      9.09MB
-----------------------------------------------------------------------
-
---- rate-limit 25.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   210.95us  117.20us  10.57ms   97.85%
-    Req/Sec     4.84k   101.85     6.04k    68.10%
-  Latency Distribution
-     50%  198.00us
-     75%  222.00us
-     90%  252.00us
-     99%  394.00us
-  11551741 requests in 5.00m, 2.79GB read
-Requests/sec:  38493.03
-Transfer/sec:      9.51MB
-----------------------------------------------------------------------
-
---- rate-limit 10.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   206.15us  209.34us  31.73ms   99.27%
-    Req/Sec     4.99k   112.62     5.36k    71.21%
-  Latency Distribution
-     50%  193.00us
-     75%  210.00us
-     90%  237.00us
-     99%  387.00us
-  11924489 requests in 5.00m, 2.88GB read
-Requests/sec:  39735.09
-Transfer/sec:      9.81MB
-----------------------------------------------------------------------
-
---- rate-limit 2.5 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   202.35us  180.56us  27.28ms   99.10%
-    Req/Sec     5.08k   145.06     8.27k    71.24%
-  Latency Distribution
-     50%  191.00us
-     75%  205.00us
-     90%  223.00us
-     99%  374.00us
-  12131047 requests in 5.00m, 2.93GB read
-Requests/sec:  40423.43
-Transfer/sec:      9.98MB
-----------------------------------------------------------------------
-
---- rate-limit 0.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   200.88us  223.19us  32.70ms   99.44%
-    Req/Sec     5.13k   151.03     6.55k    69.46%
-  Latency Distribution
-     50%  190.00us
-     75%  203.00us
-     90%  218.00us
-     99%  367.00us
-  12256706 requests in 5.00m, 2.96GB read
-Requests/sec:  40842.16
-Transfer/sec:     10.09MB
-----------------------------------------------------------------------
-
---- rate-limit disabled --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   194.91us  222.55us  33.80ms   99.47%
-    Req/Sec     5.29k   167.52     5.95k    68.32%
-  Latency Distribution
-     50%  184.00us
-     75%  197.00us
-     90%  214.00us
-     99%  353.00us
-  12633928 requests in 5.00m, 3.05GB read
-Requests/sec:  42112.54
-Transfer/sec:     10.40MB
-----------------------------------------------------------------------
-
---- rate-limit off --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   194.37us  166.76us  28.75ms   99.09%
-    Req/Sec     5.28k   160.02     5.86k    68.02%
-  Latency Distribution
-     50%  184.00us
-     75%  197.00us
-     90%  214.00us
-     99%  355.00us
-  12622896 requests in 5.00m, 3.04GB read
-Requests/sec:  42062.31
-Transfer/sec:     10.39MB
-----------------------------------------------------------------------
-
diff --git a/addons/otel/test/README-speed-sa b/addons/otel/test/README-speed-sa
deleted file mode 100644 (file)
index 1d9fe54..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
---- rate-limit 100.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   213.08us  136.99us  17.58ms   98.10%
-    Req/Sec     4.80k   251.04     5.97k    68.01%
-  Latency Distribution
-     50%  203.00us
-     75%  223.00us
-     90%  245.00us
-     99%  405.00us
-  11464278 requests in 5.00m, 2.77GB read
-Requests/sec:  38201.61
-Transfer/sec:      9.44MB
-----------------------------------------------------------------------
-
---- rate-limit 75.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   202.18us  121.42us  12.04ms   97.72%
-    Req/Sec     5.05k   248.48     5.85k    65.69%
-  Latency Distribution
-     50%  194.00us
-     75%  219.00us
-     90%  245.00us
-     99%  393.00us
-  12071015 requests in 5.00m, 2.91GB read
-Requests/sec:  40223.31
-Transfer/sec:      9.94MB
-----------------------------------------------------------------------
-
---- rate-limit 50.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   190.49us  117.32us   7.33ms   97.62%
-    Req/Sec     5.37k   265.60     6.98k    65.98%
-  Latency Distribution
-     50%  181.00us
-     75%  208.00us
-     90%  237.00us
-     99%  383.00us
-  12837427 requests in 5.00m, 3.10GB read
-Requests/sec:  42777.17
-Transfer/sec:     10.57MB
-----------------------------------------------------------------------
-
---- rate-limit 25.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   180.46us  123.40us  13.20ms   97.80%
-    Req/Sec     5.69k   242.93     7.75k    68.66%
-  Latency Distribution
-     50%  165.00us
-     75%  194.00us
-     90%  223.00us
-     99%  375.00us
-  13595213 requests in 5.00m, 3.28GB read
-Requests/sec:  45302.34
-Transfer/sec:     11.19MB
-----------------------------------------------------------------------
-
---- rate-limit 10.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   174.69us  129.17us  16.50ms   97.93%
-    Req/Sec     5.89k   260.40     7.03k    69.57%
-  Latency Distribution
-     50%  160.00us
-     75%  178.00us
-     90%  210.00us
-     99%  374.00us
-  14068388 requests in 5.00m, 3.39GB read
-Requests/sec:  46879.07
-Transfer/sec:     11.58MB
-----------------------------------------------------------------------
-
---- rate-limit 2.5 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   170.58us  116.89us  11.49ms   97.74%
-    Req/Sec     6.03k   249.35     6.54k    67.44%
-  Latency Distribution
-     50%  158.00us
-     75%  170.00us
-     90%  192.00us
-     99%  375.00us
-  14402604 requests in 5.00m, 3.47GB read
-Requests/sec:  47992.71
-Transfer/sec:     11.85MB
-----------------------------------------------------------------------
-
---- rate-limit 0.0 --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   167.96us  114.36us  10.99ms   97.81%
-    Req/Sec     6.12k   266.16     6.57k    70.70%
-  Latency Distribution
-     50%  157.00us
-     75%  166.00us
-     90%  183.00us
-     99%  370.00us
-  14622790 requests in 5.00m, 3.53GB read
-Requests/sec:  48726.40
-Transfer/sec:     12.04MB
-----------------------------------------------------------------------
-
---- rate-limit disabled --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   167.74us  114.11us  11.10ms   97.82%
-    Req/Sec     6.13k   251.71     6.57k    69.59%
-  Latency Distribution
-     50%  157.00us
-     75%  166.00us
-     90%  182.00us
-     99%  368.00us
-  14641307 requests in 5.00m, 3.53GB read
-Requests/sec:  48788.18
-Transfer/sec:     12.05MB
-----------------------------------------------------------------------
-
---- rate-limit off --------------------------------------------------
-Running 5m test @ http://localhost:10080/index.html
-  8 threads and 8 connections
-  Thread Stats   Avg      Stdev     Max   +/- Stdev
-    Latency   168.00us  112.83us  11.07ms   97.79%
-    Req/Sec     6.12k   264.12     7.23k    68.95%
-  Latency Distribution
-     50%  157.00us
-     75%  166.00us
-     90%  183.00us
-     99%  369.00us
-  14613970 requests in 5.00m, 3.53GB read
-Requests/sec:  48697.01
-Transfer/sec:     12.03MB
-----------------------------------------------------------------------
-
diff --git a/addons/otel/test/README-test-speed b/addons/otel/test/README-test-speed
deleted file mode 100644 (file)
index 427fad6..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-                   -----------------------------------------
-                     HAProxy OTEL filter speed test guide
-                                Version 1.0
-                          ( Last update: 2026-04-09 )
-                   -----------------------------------------
-                         Author : Miroslav Zagorac
-                   Contact : mzagorac at haproxy dot com
-
-
-SUMMARY
---------
-
-  1.    Overview
-  2.    Prerequisites
-  3.    Running the test
-  4.    Test parameters
-  5.    Rate-limit levels
-  6.    Test configurations
-  7.    Results
-  7.1.    Standalone (sa)
-  7.2.    Comparison (cmp)
-  7.3.    Context propagation (ctx)
-  7.4.    Frontend / backend (fe-be)
-  8.    Summary
-
-
-1. Overview
-------------
-
-The test-speed.sh script measures the performance impact of the OTEL filter on
-HAProxy at various rate-limit settings.  For each test configuration, the script
-iterates through a series of rate-limit values -- from full tracing (100%) down
-to the filter being completely removed -- measuring throughput and latency at
-each level.
-
-The script uses template files (haproxy.cfg.in and otel.cfg.in) from each test
-directory to generate the actual configuration files.  A sed substitution
-adjusts the rate-limit value (or disables/removes the filter) before each run.
-
-
-2. Prerequisites
------------------
-
-The following tools must be installed and available in PATH:
-
-  - thttpd : a lightweight HTTP server used as the backend origin server.
-             It serves a small static HTML file (index.html) on port 8000.
-
-  - wrk    : an HTTP benchmarking tool that generates the test load.
-             See https://github.com/wg/wrk
-
-
-3. Running the test
---------------------
-
-The test is executed from the test directory.  It can be run for all
-configurations at once or for a single configuration.
-
-To run all configurations:
-
-  % ./test-speed.sh all
-
-This produces result files in the _logs directory:
-
-  _logs/README-speed-fe-be
-  _logs/README-speed-sa
-  _logs/README-speed-cmp
-  _logs/README-speed-ctx
-
-To run a single configuration:
-
-  % ./test-speed.sh <cfg> [<dir>]
-
-Where <cfg> corresponds to a run-<cfg>.sh script and <dir> is the configuration
-directory (defaults to <cfg>).  For example:
-
-  % ./test-speed.sh sa
-  % ./test-speed.sh fe-be fe
-  % ./test-speed.sh cmp
-  % ./test-speed.sh ctx
-
-
-4. Test parameters
--------------------
-
-The wrk benchmarking tool is invoked with the following parameters:
-
-  -t8        8 threads
-  -c8        8 concurrent connections
-  -d300      5-minute test duration (300 seconds)
-  --latency  latency distribution reporting
-
-Each rate-limit level is tested sequentially.  Between runs, HAProxy is stopped
-via SIGUSR1 and restarted with the next rate-limit configuration.  A 10-second
-pause separates consecutive runs.
-
-The backend origin server (thttpd) serves a small static HTML page (index.html,
-approximately 50 bytes) on port 8000.  HAProxy listens on port 10080 and proxies
-requests to the origin.
-
-
-5. Rate-limit levels
----------------------
-
-The script tests nine rate-limit levels in the following order:
-
-  100.0    - the filter processes every stream (worst case)
-   75.0    - the filter processes 75% of streams
-   50.0    - the filter processes 50% of streams
-   25.0    - the filter processes 25% of streams
-   10.0    - the filter processes 10% of streams
-    2.5    - the filter processes 2.5% of streams
-    0.0    - the filter is loaded and attached to every stream but never
-             processes any telemetry (the rate-limit check always fails);
-             this measures the per-stream attach and detach overhead
-
-  disabled - the filter is loaded but disabled via 'option disabled'; it is not
-             attached to streams at all; this measures the cost of loading and
-             initializing the filter library without any per-stream work
-
-  off      - the 'filter opentelemetry' and 'otel-group' directives are
-             commented out of haproxy.cfg; the filter is not loaded and has zero
-             presence in the processing path; this is the absolute baseline
-
-In the result tables, the 'overhead' column is the throughput loss relative to
-the 'off' baseline, expressed as a percentage:
-
-  overhead = (req/s_off - req/s_test) / req/s_off * 100
-
-
-6. Test configurations
------------------------
-
-Four OTEL filter configurations are tested.  They differ in complexity and in
-the features they exercise:
-
-  sa     - Standalone.  Uses all possible HAProxy filter events with spans,
-           attributes, events, links, baggage, status, metrics and groups.
-           This is the most comprehensive single-instance configuration and
-           represents the worst-case scenario.
-
-  cmp    - Comparison.  A simplified configuration made for comparison with
-           other tracing implementations.  It uses a reduced span hierarchy
-           without context propagation, groups or metrics.  This is closer to
-           a typical production deployment.
-
-  ctx    - Context propagation.  Similar to 'sa' in scope coverage, but spans
-           are opened using extracted span contexts (inject/extract via HAProxy
-           variables) as parent references instead of direct span names.  This
-           adds the overhead of context serialization, variable storage and
-           deserialization on every scope execution.
-
-  fe-be  - Frontend / backend.  Two cascaded HAProxy instances: the frontend
-           (fe) creates the root trace and injects span context into HTTP
-           headers; the backend (be) extracts the context and continues the
-           trace.  This configuration measures the combined overhead of two
-           OTEL filter instances plus the inter-process context propagation
-           cost.
-
-           Note: the rate-limit is varied only on the frontend.  The backend
-           always runs with its default configuration (filter enabled,
-           hard-errors on).  The backend configuration is only modified for
-           the 'disabled' and 'off' levels.
-
-
-7. Results
------------
-
-The tables below summarize the benchmarking results.  The 'req/s' column shows
-the sustained request rate reported by wrk, 'avg latency' is the average
-response time, and 'overhead' is the throughput loss relative to the 'off'
-baseline.
-
-
-7.1. Standalone (sa)
----------------------
-
-  ---------------------------------------------------------------
-   rate-limit     req/s     avg latency     overhead
-  ---------------------------------------------------------------
-      100.0%     38,202       213.08 us       21.6%
-       75.0%     40,223       202.18 us       17.4%
-       50.0%     42,777       190.49 us       12.2%
-       25.0%     45,302       180.46 us        7.0%
-       10.0%     46,879       174.69 us        3.7%
-        2.5%     47,993       170.58 us        1.4%
-        0.0%     48,726       167.96 us          ~0
-     disabled    48,788       167.74 us          ~0
-     off         48,697       168.00 us      baseline
-  ---------------------------------------------------------------
-
-With all possible events active, the sa configuration at 100% rate-limit shows
-a 22% throughput reduction.  At 10% rate-limit the overhead drops to 3.7%, and
-at 2.5% it is barely measurable at 1.4%.  The 'disabled' and '0.0' levels show
-no measurable overhead above the baseline.
-
-
-7.2. Comparison (cmp)
-----------------------
-
-  ---------------------------------------------------------------
-   rate-limit     req/s     avg latency     overhead
-  ---------------------------------------------------------------
-      100.0%     44,780       182.58 us        7.6%
-       75.0%     45,362       180.10 us        6.4%
-       50.0%     46,279       176.59 us        4.6%
-       25.0%     47,061       173.57 us        2.9%
-       10.0%     47,793       170.85 us        1.4%
-        2.5%     48,410       169.11 us        0.2%
-        0.0%     48,586       168.09 us          ~0
-     disabled    48,510       168.57 us          ~0
-     off         48,488       168.64 us      baseline
-  ---------------------------------------------------------------
-
-The simplified cmp configuration shows significantly lower overhead than sa at
-every rate-limit level.  At 100% rate-limit the overhead is 7.6%, at 10% it is
-1.4%, and below 2.5% it becomes indistinguishable from the baseline.
-
-
-7.3. Context propagation (ctx)
--------------------------------
-
-  ---------------------------------------------------------------
-   rate-limit     req/s     avg latency     overhead
-  ---------------------------------------------------------------
-      100.0%     30,032       270.35 us       38.0%
-       75.0%     33,490       242.56 us       30.9%
-       50.0%     37,679       215.92 us       22.2%
-       25.0%     42,449       192.36 us       12.4%
-       10.0%     45,458       180.08 us        6.2%
-        2.5%     47,546       171.64 us        1.9%
-        0.0%     48,313       168.86 us        0.3%
-     disabled    48,620       168.36 us          ~0
-     off         48,446       168.73 us      baseline
-  ---------------------------------------------------------------
-
-The ctx configuration is the most expensive due to the inject/extract cycle on
-every scope execution.  At 100% rate-limit the overhead reaches 38%.  However,
-the cost scales linearly with the rate-limit: at 10% the overhead is 6.2%, and
-at 2.5% it drops to 1.9%.  The filter attachment overhead (0.0% vs off) is
-negligible at 0.3%.
-
-
-7.4. Frontend / backend (fe-be)
---------------------------------
-
-  ---------------------------------------------------------------
-   rate-limit     req/s     avg latency     overhead
-  ---------------------------------------------------------------
-      100.0%     34,012       238.75 us       19.1%
-       75.0%     35,462       230.08 us       15.7%
-       50.0%     36,811       222.33 us       12.5%
-       25.0%     38,493       210.95 us        8.5%
-       10.0%     39,735       206.15 us        5.5%
-        2.5%     40,423       202.35 us        3.9%
-        0.0%     40,842       200.88 us        2.9%
-     disabled    42,113       194.91 us          ~0
-     off         42,062       194.37 us      baseline
-  ---------------------------------------------------------------
-
-The fe-be configuration involves two HAProxy instances in series, so the
-absolute baseline (off) is already lower at 42,062 req/s due to the extra
-network hop.  The rate-limit is varied only on the frontend; the backend
-always has the filter loaded with hard-errors enabled.
-
-This explains the 2.9% overhead at rate-limit 0.0: even though the frontend
-never traces, the backend filter still attaches to every stream, attempts to
-extract context from the HTTP headers, fails (because the frontend did not
-inject any context), and the hard-errors option stops further processing.
-This per-stream attach/extract/error cycle accounts for the residual cost.
-
-When both instances have the filter disabled (disabled level), the overhead
-is within measurement noise, consistent with the single-instance
-configurations.
-
-
-8. Summary
------------
-
-The table below shows the overhead for each configuration at selected rate-limit
-levels:
-
-  ---------------------------------------------------
-   rate-limit    sa      cmp      ctx     fe-be
-  ---------------------------------------------------
-      100.0%   21.6%    7.6%    38.0%    19.1%
-       25.0%    7.0%    2.9%    12.4%     8.5%
-       10.0%    3.7%    1.4%     6.2%     5.5%
-        2.5%    1.4%    0.2%     1.9%     3.9%
-  ---------------------------------------------------
-
-Key observations:
-
-  - The overhead scales approximately linearly with the rate-limit value.
-    Reducing the rate-limit from 100% to 10% eliminates the vast majority
-    of the cost in all configurations.
-
-  - The cmp configuration, which uses a reduced span hierarchy typical of
-    production deployments, adds only 1.4% overhead at a 10% rate-limit.
-
-  - The sa configuration, which exercises all possible events, stays at about
-    7% overhead at a 25% rate-limit and below 4% at 10%.
-
-  - The ctx configuration is the most expensive due to the inject/extract
-    context propagation on every scope.  It is designed as a stress test for
-    the propagation mechanism rather than a practical production template.
-
-  - The fe-be configuration carries a higher fixed cost because two HAProxy
-    instances are involved and the backend filter processes context extraction
-    regardless of the frontend rate-limit setting.
-
-  - Loading the filter but disabling it via 'option disabled' adds no measurable
-    overhead in any configuration.
-
-  - The filter attachment cost without any telemetry processing (rate-limit 0.0)
-    is 0.3% or less for single-instance configurations (sa, cmp, ctx).
-
-  - In typical production use with a rate-limit of 10% or less, the performance
-    impact of the OTEL filter should be negligible for single-instance deployments.
diff --git a/addons/otel/test/be/haproxy.cfg b/addons/otel/test/be/haproxy.cfg
deleted file mode 100644 (file)
index 3860f9f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-global
-    stats socket /tmp/haproxy-be.sock mode 666 level admin
-
-listen stats
-    mode http
-    bind *:8002
-    stats uri /
-    stats admin if TRUE
-    stats refresh 10s
-
-frontend otel-test-be-frontend
-    bind *:11080
-    default_backend servers-backend
-
-    # OTel filter
-    filter opentelemetry id otel-test-be config be/otel.cfg
-
-backend servers-backend
-    server server-1 127.0.0.1:8000
diff --git a/addons/otel/test/be/otel.cfg b/addons/otel/test/be/otel.cfg
deleted file mode 100644 (file)
index 1f26f46..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-[otel-test-be]
-    otel-instrumentation otel-test-instrumentation
-        config be/otel.yml
-#       log localhost:514 local7 debug
-        option dontlog-normal
-        option hard-errors
-        no option disabled
-
-        scopes frontend_http_request
-        scopes backend_tcp_request
-        scopes backend_http_request
-        scopes client_session_end
-
-        scopes server_session_start
-        scopes tcp_response
-        scopes http_response
-        scopes server_session_end
-
-    otel-scope frontend_http_request
-        extract "otel-ctx" use-headers
-        span "HAProxy session" parent "otel-ctx" root
-            baggage "haproxy_id" var(sess.otel.uuid)
-        span "Client session" parent "HAProxy session"
-        span "Frontend HTTP request" parent "Client session"
-            attribute "http.method" method
-            attribute "http.url" url
-            attribute "http.version" str("HTTP/") req.ver
-        otel-event on-frontend-http-request
-
-    otel-scope backend_tcp_request
-        span "Backend TCP request" parent "Frontend HTTP request"
-        finish "Frontend HTTP request"
-        otel-event on-backend-tcp-request
-
-    otel-scope backend_http_request
-        span "Backend HTTP request" parent "Backend TCP request"
-        finish "Backend TCP request"
-        otel-event on-backend-http-request
-
-    otel-scope client_session_end
-        finish "Client session"
-        otel-event on-client-session-end
-
-    otel-scope server_session_start
-        span "Server session" parent "HAProxy session"
-        finish "Backend HTTP request"
-        otel-event on-server-session-start
-
-    otel-scope tcp_response
-        span "TCP response" parent "Server session"
-        otel-event on-tcp-response
-
-    otel-scope http_response
-        span "HTTP response" parent "TCP response"
-            attribute "http.status_code" status
-        finish "TCP response"
-        otel-event on-http-response
-
-    otel-scope server_session_end
-        finish *
-        otel-event on-server-session-end
diff --git a/addons/otel/test/be/otel.yml b/addons/otel/test/be/otel.yml
deleted file mode 100644 (file)
index 374b871..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-exporters:
-  exporter_traces_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file trace"
-    file_pattern:   "__be_traces_log-%F-%N"
-    alias_pattern:  "__traces_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_traces_otlp_grpc:
-    type:                             otlp_grpc
-    thread_name:                      "OTLP/gRPC trace"
-    endpoint:                         "http://localhost:4317/v1/traces"
-    use_ssl_credentials:              false
-#   ssl_credentials_cacert_path:      ""
-#   ssl_credentials_cacert_as_string: ""
-#   ssl_client_key_path:              ""
-#   ssl_client_key_string:            ""
-#   ssl_client_cert_path:             ""
-#   ssl_client_cert_string:           ""
-#   timeout:                          10
-#   user_agent:                       ""
-#   max_threads:                      0
-#   compression:                      ""
-#   max_concurrent_requests:          0
-
-  exporter_traces_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP trace"
-    endpoint:                    "http://localhost:4318/v1/traces"
-    content_type:                json
-    json_bytes_mapping:          hexid
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP traces test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP traces test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-#   ssl_ca_cert_path:            ""
-#   ssl_ca_cert_string:          ""
-#   ssl_client_key_path:         ""
-#   ssl_client_key_string:       ""
-#   ssl_client_cert_path:        ""
-#   ssl_client_cert_string:      ""
-#   ssl_min_tls:                 ""
-#   ssl_max_tls:                 ""
-#   ssl_cipher:                  ""
-#   ssl_cipher_suite:            ""
-#   compression:                 ""
-
-  exporter_traces_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_traces_ostream:
-    type:     ostream
-    filename: __be_traces
-
-  exporter_traces_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_traces_zipkin:
-    type:           zipkin
-    endpoint:       "http://localhost:9411/api/v2/spans"
-    format:         json
-    service_name:   "zipkin-service"
-#   ipv4:           ""
-#   ipv6:           ""
-
-  exporter_metrics_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file metr"
-    file_pattern:   "__be_metrics_log-%F-%N"
-    alias_pattern:  "__metrics_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_metrics_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC metr"
-    endpoint:            "http://localhost:4317/v1/metrics"
-    use_ssl_credentials: false
-
-  exporter_metrics_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP metr"
-    endpoint:                    "http://localhost:4318/v1/metrics"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP metrics test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP metrics test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_metrics_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_metrics_ostream:
-    type:     ostream
-    filename: __be_metrics
-
-  exporter_metrics_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_logs_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file logs"
-    file_pattern:   "__be_logs_log-%F-%N"
-    alias_pattern:  "__logs_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_logs_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC logs"
-    endpoint:            "http://localhost:4317/v1/logs"
-    use_ssl_credentials: false
-
-  exporter_logs_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP logs"
-    endpoint:                    "http://localhost:4318/v1/logs"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP logs test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP logs test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_logs_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_logs_ostream:
-    type:     ostream
-    filename: __be_logs
-
-  exporter_logs_elasticsearch:
-    type:             elasticsearch
-    host:             localhost
-    port:             9200
-    index:            logs
-    response_timeout: 30
-    debug:            false
-    http_headers:
-      - X-OTel-Header-1: "Elasticsearch logs test header #1"
-      - X-OTel-Header-2: "Elasticsearch logs test header #2"
-
-readers:
-  reader_metrics:
-    thread_name:     "reader metr"
-    export_interval: 10000
-    export_timeout:  5000
-
-samplers:
-  sampler_traces:
-#   type:  always_on
-#   type:  always_off
-#   type:  trace_id_ratio_based
-#   ratio: 1.0
-    type:     parent_based
-    delegate: always_on
-
-processors:
-  processor_traces_batch:
-    type:                  batch
-    thread_name:           "proc/batch trac"
-    # Note: when the queue is half full, a preemptive notification is sent
-    # to start the export call.
-    max_queue_size:        2048
-    # Time interval (in ms) between two consecutive exports
-    schedule_delay:        5000
-    # Export 'max_export_batch_size' after every `schedule_delay' milliseconds.
-    max_export_batch_size: 512
-
-  processor_traces_single:
-    type:                  single
-
-  processor_logs_batch:
-    type:                  batch
-    thread_name:           "proc/batch logs"
-    max_queue_size:        2048
-    schedule_delay:        5000
-    max_export_batch_size: 512
-
-  processor_logs_single:
-    type:                  single
-
-providers:
-  provider_traces:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-be"
-      - service.name:        "be"
-      - service.namespace:   "HAProxy traces test"
-
-  provider_metrics:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-be"
-      - service.name:        "be"
-      - service.namespace:   "HAProxy metrics test"
-
-  provider_logs:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-be"
-      - service.name:        "be"
-      - service.namespace:   "HAProxy logs test"
-
-signals:
-  traces:
-    scope_name: "HAProxy OTEL - traces"
-    exporters:  exporter_traces_otlp_http
-    samplers:   sampler_traces
-    processors: processor_traces_batch
-    providers:  provider_traces
-
-  metrics:
-    scope_name: "HAProxy OTEL - metrics"
-    exporters:  exporter_metrics_otlp_http
-    readers:    reader_metrics
-    providers:  provider_metrics
-
-  logs:
-    scope_name: "HAProxy OTEL - logs"
-    exporters:  exporter_logs_otlp_http
-    processors: processor_logs_batch
-    providers:  provider_logs
diff --git a/addons/otel/test/cmp/haproxy.cfg b/addons/otel/test/cmp/haproxy.cfg
deleted file mode 100644 (file)
index c2b1b0c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-global
-    stats socket /tmp/haproxy.sock mode 666 level admin
-
-listen stats
-    mode http
-    bind *:8001
-    stats uri /
-    stats admin if TRUE
-    stats refresh 10s
-
-frontend otel-test-cmp-frontend
-    bind *:10080
-    default_backend servers-backend
-
-    # ACL used to distinguish successful from error responses
-    acl acl-http-status-ok status 100:399
-
-    # OTel filter
-    filter opentelemetry id otel-test-cmp config cmp/otel.cfg
-
-backend servers-backend
-    server server-1 127.0.0.1:8000
diff --git a/addons/otel/test/cmp/otel.cfg b/addons/otel/test/cmp/otel.cfg
deleted file mode 100644 (file)
index 582ff68..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-[otel-test-cmp]
-    otel-instrumentation otel-test-instrumentation
-        config cmp/otel.yml
-#       log localhost:514 local7 debug
-        option dontlog-normal
-        option hard-errors
-        no option disabled
-        rate-limit 100.0
-
-        scopes client_session_start
-        scopes frontend_tcp_request
-        scopes frontend_http_request
-        scopes backend_tcp_request
-        scopes backend_http_request
-        scopes server_unavailable
-
-        scopes server_session_start
-        scopes tcp_response
-        scopes http_response http_response-error server_session_end client_session_end
-
-    otel-scope client_session_start
-        span "HAProxy session" root
-            baggage "haproxy_id" var(sess.otel.uuid)
-        span "Client session" parent "HAProxy session"
-        otel-event on-client-session-start
-
-    otel-scope frontend_tcp_request
-        span "Frontend TCP request" parent "Client session"
-        otel-event on-frontend-tcp-request
-
-    otel-scope frontend_http_request
-        span "Frontend HTTP request" parent "Frontend TCP request"
-            attribute "http.method" method
-            attribute "http.url" url
-            attribute "http.version" str("HTTP/") req.ver
-        finish "Frontend TCP request"
-        otel-event on-frontend-http-request
-
-    otel-scope backend_tcp_request
-        span "Backend TCP request" parent "Frontend HTTP request"
-        finish "Frontend HTTP request"
-        otel-event on-backend-tcp-request
-
-    otel-scope backend_http_request
-        span "Backend HTTP request" parent "Backend TCP request"
-        finish "Backend TCP request"
-        otel-event on-backend-http-request
-
-    otel-scope server_unavailable
-        span "HAProxy session"
-            status "error" str("503 Service Unavailable")
-        finish *
-        otel-event on-server-unavailable
-
-    otel-scope server_session_start
-        span "Server session" parent "HAProxy session"
-        finish "Backend HTTP request"
-        otel-event on-server-session-start
-
-    otel-scope tcp_response
-        span "TCP response" parent "Server session"
-        otel-event on-tcp-response
-
-    otel-scope http_response
-        span "HTTP response" parent "TCP response"
-            attribute "http.status_code" status
-        finish "TCP response"
-        otel-event on-http-response
-
-    otel-scope http_response-error
-        span "HTTP response"
-            status "error" str("!acl-http-status-ok")
-        otel-event on-http-response if !acl-http-status-ok
-
-    otel-scope server_session_end
-        finish "HTTP response" "Server session"
-        otel-event on-http-response
-
-    otel-scope client_session_end
-        finish "*"
-        otel-event on-http-response
diff --git a/addons/otel/test/cmp/otel.yml b/addons/otel/test/cmp/otel.yml
deleted file mode 100644 (file)
index 2cd1ea6..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-exporters:
-  exporter_traces_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file trace"
-    file_pattern:   "__cmp_traces_log-%F-%N"
-    alias_pattern:  "__traces_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_traces_otlp_grpc:
-    type:                             otlp_grpc
-    thread_name:                      "OTLP/gRPC trace"
-    endpoint:                         "http://localhost:4317/v1/traces"
-    use_ssl_credentials:              false
-#   ssl_credentials_cacert_path:      ""
-#   ssl_credentials_cacert_as_string: ""
-#   ssl_client_key_path:              ""
-#   ssl_client_key_string:            ""
-#   ssl_client_cert_path:             ""
-#   ssl_client_cert_string:           ""
-#   timeout:                          10
-#   user_agent:                       ""
-#   max_threads:                      0
-#   compression:                      ""
-#   max_concurrent_requests:          0
-
-  exporter_traces_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP trace"
-    endpoint:                    "http://localhost:4318/v1/traces"
-    content_type:                json
-    json_bytes_mapping:          hexid
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP traces test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP traces test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-#   ssl_ca_cert_path:            ""
-#   ssl_ca_cert_string:          ""
-#   ssl_client_key_path:         ""
-#   ssl_client_key_string:       ""
-#   ssl_client_cert_path:        ""
-#   ssl_client_cert_string:      ""
-#   ssl_min_tls:                 ""
-#   ssl_max_tls:                 ""
-#   ssl_cipher:                  ""
-#   ssl_cipher_suite:            ""
-#   compression:                 ""
-
-  exporter_traces_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_traces_ostream:
-    type:     ostream
-    filename: __cmp_traces
-
-  exporter_traces_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_traces_zipkin:
-    type:           zipkin
-    endpoint:       "http://localhost:9411/api/v2/spans"
-    format:         json
-    service_name:   "zipkin-service"
-#   ipv4:           ""
-#   ipv6:           ""
-
-  exporter_metrics_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file metr"
-    file_pattern:   "__cmp_metrics_log-%F-%N"
-    alias_pattern:  "__metrics_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_metrics_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC metr"
-    endpoint:            "http://localhost:4317/v1/metrics"
-    use_ssl_credentials: false
-
-  exporter_metrics_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP metr"
-    endpoint:                    "http://localhost:4318/v1/metrics"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP metrics test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP metrics test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_metrics_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_metrics_ostream:
-    type:     ostream
-    filename: __cmp_metrics
-
-  exporter_metrics_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_logs_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file logs"
-    file_pattern:   "__cmp_logs_log-%F-%N"
-    alias_pattern:  "__logs_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_logs_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC logs"
-    endpoint:            "http://localhost:4317/v1/logs"
-    use_ssl_credentials: false
-
-  exporter_logs_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP logs"
-    endpoint:                    "http://localhost:4318/v1/logs"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP logs test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP logs test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_logs_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_logs_ostream:
-    type:     ostream
-    filename: __cmp_logs
-
-  exporter_logs_elasticsearch:
-    type:             elasticsearch
-    host:             localhost
-    port:             9200
-    index:            logs
-    response_timeout: 30
-    debug:            false
-    http_headers:
-      - X-OTel-Header-1: "Elasticsearch logs test header #1"
-      - X-OTel-Header-2: "Elasticsearch logs test header #2"
-
-readers:
-  reader_metrics:
-    thread_name:     "reader metr"
-    export_interval: 10000
-    export_timeout:  5000
-
-samplers:
-  sampler_traces:
-#   type:  always_on
-#   type:  always_off
-#   type:  trace_id_ratio_based
-#   ratio: 1.0
-    type:     parent_based
-    delegate: always_on
-
-processors:
-  processor_traces_batch:
-    type:                  batch
-    thread_name:           "proc/batch trac"
-    # Note: when the queue is half full, a preemptive notification is sent
-    # to start the export call.
-    max_queue_size:        2048
-    # Time interval (in ms) between two consecutive exports
-    schedule_delay:        5000
-    # Export 'max_export_batch_size' after every `schedule_delay' milliseconds.
-    max_export_batch_size: 512
-
-  processor_traces_single:
-    type:                  single
-
-  processor_logs_batch:
-    type:                  batch
-    thread_name:           "proc/batch logs"
-    max_queue_size:        2048
-    schedule_delay:        5000
-    max_export_batch_size: 512
-
-  processor_logs_single:
-    type:                  single
-
-providers:
-  provider_traces:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-cmp"
-      - service.name:        "cmp"
-      - service.namespace:   "HAProxy traces test"
-
-  provider_metrics:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-cmp"
-      - service.name:        "cmp"
-      - service.namespace:   "HAProxy metrics test"
-
-  provider_logs:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-cmp"
-      - service.name:        "cmp"
-      - service.namespace:   "HAProxy logs test"
-
-signals:
-  traces:
-    scope_name: "HAProxy OTEL - traces"
-    exporters:  exporter_traces_otlp_http
-    samplers:   sampler_traces
-    processors: processor_traces_batch
-    providers:  provider_traces
-
-  metrics:
-    scope_name: "HAProxy OTEL - metrics"
-    exporters:  exporter_metrics_otlp_http
-    readers:    reader_metrics
-    providers:  provider_metrics
-
-  logs:
-    scope_name: "HAProxy OTEL - logs"
-    exporters:  exporter_logs_otlp_http
-    processors: processor_logs_batch
-    providers:  provider_logs
diff --git a/addons/otel/test/copy-yml.sh b/addons/otel/test/copy-yml.sh
deleted file mode 100755 (executable)
index 1a4115e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh -u
-#
-# Copyright 2026 HAProxy Technologies, Miroslav Zagorac <mzagorac@haproxy.com>
-#
-SH_FILE="${1:-}"
- SH_EXT="${2:-}"
-
-
-if test ${#} -ne 2; then
-       echo
-       echo "usage: $(basename "${0}") input-file test-name"
-       echo
-       exit 64
-fi
-
-sed '
-       s/^\( *\)\(filename:\)\( *\)_\(_[a-z]*\)/\1\2\3__'"${SH_EXT}"'\4/g
-       s/^\( *\)\(file_pattern:\)\( *\)"_\(_[a-z]*_[^"]*\)"/\1\2\3"__'"${SH_EXT}"'\4"/g
-       s/^\( *\)\(- service.instance.id:\)\( *\).*/\1\2\3"id-'"${SH_EXT}"'"/g
-       s/^\( *\)\(- service.name:\)\( *\).*/\1\2\3"'"${SH_EXT}"'"/g
-       s/^\( *\)\(- service.namespace:\)\( *\)\("otelc\)/\1\2\3"HAProxy/g
-       s/^\( *\)\(scope_name:\)\( *\)"OTEL C wrapper /\1\2 "HAProxy OTEL /g
-       s/^\( *\)\(exporters:\)\( *\)\(exporter_[a-z]*_\).*/\1\2\3\4otlp_http/g
-' "${SH_FILE}"
diff --git a/addons/otel/test/ctx/haproxy.cfg b/addons/otel/test/ctx/haproxy.cfg
deleted file mode 100644 (file)
index 5d817c7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-global
-    stats socket /tmp/haproxy.sock mode 666 level admin
-
-listen stats
-    mode http
-    bind *:8001
-    stats uri /
-    stats admin if TRUE
-    stats refresh 10s
-
-frontend otel-test-ctx-frontend
-    bind *:10080
-    default_backend servers-backend
-
-    # ACL used to distinguish successful from error responses
-    acl acl-http-status-ok status 100:399
-
-    # OTel filter
-    filter opentelemetry id otel-test-ctx config ctx/otel.cfg
-
-    # run response scopes for successful responses
-    http-response otel-group otel-test-ctx http_response_group if acl-http-status-ok
-
-    # run after-response scopes for error responses
-    http-after-response otel-group otel-test-ctx http_after_response_group if !acl-http-status-ok
-
-backend servers-backend
-    server server-1 127.0.0.1:8000
diff --git a/addons/otel/test/ctx/otel.cfg b/addons/otel/test/ctx/otel.cfg
deleted file mode 100644 (file)
index fba37b1..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-[otel-test-ctx]
-    otel-instrumentation otel-test-instrumentation
-        debug-level 0x77f
-        log localhost:514 local7 debug
-        config ctx/otel.yml
-        option dontlog-normal
-        option hard-errors
-        no option disabled
-        rate-limit 100.0
-
-        groups http_response_group
-        groups http_after_response_group
-
-        scopes client_session_start_1
-        scopes client_session_start_2
-        scopes frontend_tcp_request
-        scopes http_wait_request
-        scopes http_body_request
-        scopes frontend_http_request
-        scopes switching_rules_request
-        scopes backend_tcp_request
-        scopes backend_http_request
-        scopes process_server_rules_request
-        scopes http_process_request
-        scopes tcp_rdp_cookie_request
-        scopes process_sticking_rules_request
-        scopes client_session_end
-        scopes server_unavailable
-
-        scopes server_session_start
-        scopes tcp_response
-        scopes http_wait_response
-        scopes process_store_rules_response
-        scopes http_response http_response-error
-        scopes server_session_end
-
-    otel-group http_response_group
-        scopes http_response_1
-        scopes http_response_2
-
-    otel-scope http_response_1
-        span "HTTP response"
-            event "event_1" "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes")
-
-    otel-scope http_response_2
-        span "HTTP response"
-            event "event_2" "hdr.date" res.hdr("date") str(" / ") res.hdr("last-modified")
-
-    otel-group http_after_response_group
-        scopes http_after_response
-
-    otel-scope http_after_response
-        span "HAProxy response" parent "HAProxy session"
-            status "error" str("http.status_code") status
-
-    otel-scope client_session_start_1
-        span "HAProxy session" root
-            inject "otel_ctx_1" use-headers use-vars
-            baggage "haproxy_id" var(sess.otel.uuid)
-        otel-event on-client-session-start
-
-    otel-scope client_session_start_2
-        extract "otel_ctx_1" use-vars
-        span "Client session" parent "otel_ctx_1"
-            inject "otel_ctx_2" use-headers use-vars
-        otel-event on-client-session-start
-
-    otel-scope frontend_tcp_request
-        extract "otel_ctx_2" use-vars
-        span "Frontend TCP request" parent "otel_ctx_2"
-            inject "otel_ctx_3" use-headers use-vars
-        otel-event on-frontend-tcp-request
-
-    otel-scope http_wait_request
-        extract "otel_ctx_3" use-vars
-        span "HTTP wait request" parent "otel_ctx_3"
-            inject "otel_ctx_4" use-headers use-vars
-        finish "Frontend TCP request" "otel_ctx_3"
-        otel-event on-http-wait-request
-
-    otel-scope http_body_request
-        extract "otel_ctx_4" use-vars
-        span "HTTP body request" parent "otel_ctx_4"
-            inject "otel_ctx_5" use-headers use-vars
-        finish "HTTP wait request" "otel_ctx_4"
-        otel-event on-http-body-request
-
-    otel-scope frontend_http_request
-        extract "otel_ctx_5" use-vars
-        span "Frontend HTTP request" parent "otel_ctx_5"
-            attribute "http.method" method
-            attribute "http.url" url
-            attribute "http.version" str("HTTP/") req.ver
-            inject "otel_ctx_6" use-headers use-vars
-        finish "HTTP body request" "otel_ctx_5"
-        otel-event on-frontend-http-request
-
-    otel-scope switching_rules_request
-        extract "otel_ctx_6" use-vars
-        span "Switching rules request" parent "otel_ctx_6"
-            inject "otel_ctx_7" use-headers use-vars
-        finish "Frontend HTTP request" "otel_ctx_6"
-        otel-event on-switching-rules-request
-
-    otel-scope backend_tcp_request
-        extract "otel_ctx_7" use-vars
-        span "Backend TCP request" parent "otel_ctx_7"
-            inject "otel_ctx_8" use-headers use-vars
-        finish "Switching rules request" "otel_ctx_7"
-        otel-event on-backend-tcp-request
-
-    otel-scope backend_http_request
-        extract "otel_ctx_8" use-vars
-        span "Backend HTTP request" parent "otel_ctx_8"
-            inject "otel_ctx_9" use-headers use-vars
-        finish "Backend TCP request" "otel_ctx_8"
-        otel-event on-backend-http-request
-
-    otel-scope process_server_rules_request
-        extract "otel_ctx_9" use-vars
-        span "Process server rules request" parent "otel_ctx_9"
-            inject "otel_ctx_10" use-headers use-vars
-        finish "Backend HTTP request" "otel_ctx_9"
-        otel-event on-process-server-rules-request
-
-    otel-scope http_process_request
-        extract "otel_ctx_10" use-vars
-        span "HTTP process request" parent "otel_ctx_10"
-            inject "otel_ctx_11" use-headers use-vars
-        finish "Process server rules request" "otel_ctx_10"
-        otel-event on-http-process-request
-
-    otel-scope tcp_rdp_cookie_request
-        extract "otel_ctx_11" use-vars
-        span "TCP RDP cookie request" parent "otel_ctx_11"
-            inject "otel_ctx_12" use-headers use-vars
-        finish "HTTP process request" "otel_ctx_11"
-        otel-event on-tcp-rdp-cookie-request
-
-    otel-scope process_sticking_rules_request
-        extract "otel_ctx_12" use-vars
-        span "Process sticking rules request" parent "otel_ctx_12"
-            inject "otel_ctx_13" use-headers use-vars
-        finish "TCP RDP cookie request" "otel_ctx_12"
-        otel-event on-process-sticking-rules-request
-
-    otel-scope client_session_end
-        finish "Client session" "otel_ctx_2"
-        otel-event on-client-session-end
-
-    otel-scope server_unavailable
-        finish *
-        otel-event on-server-unavailable
-
-    otel-scope server_session_start
-        span "Server session" parent "otel_ctx_1"
-            inject "otel_ctx_14" use-vars
-        extract "otel_ctx_13" use-vars
-        finish "Process sticking rules request" "otel_ctx_13"
-        otel-event on-server-session-start
-
-    otel-scope tcp_response
-        extract "otel_ctx_14" use-vars
-        span "TCP response" parent "otel_ctx_14"
-            inject "otel_ctx_15" use-vars
-        otel-event on-tcp-response
-
-    otel-scope http_wait_response
-        extract "otel_ctx_15" use-vars
-        span "HTTP wait response" parent "otel_ctx_15"
-            inject "otel_ctx_16" use-headers use-vars
-        finish "TCP response" "otel_ctx_15"
-        otel-event on-http-wait-response
-
-    otel-scope process_store_rules_response
-        extract "otel_ctx_16" use-vars
-        span "Process store rules response" parent "otel_ctx_16"
-            inject "otel_ctx_17" use-headers use-vars
-        finish "HTTP wait response" "otel_ctx_16"
-        otel-event on-process-store-rules-response
-
-    otel-scope http_response
-        extract "otel_ctx_17" use-vars
-        span "HTTP response" parent "otel_ctx_17"
-            attribute "http.status_code" status
-        finish "Process store rules response" "otel_ctx_17"
-        otel-event on-http-response
-
-    otel-scope http_response-error
-        span "HTTP response"
-            status "error" str("!acl-http-status-ok")
-        otel-event on-http-response if !acl-http-status-ok
-
-    otel-scope server_session_end
-        finish *
-        otel-event on-server-session-end
diff --git a/addons/otel/test/ctx/otel.yml b/addons/otel/test/ctx/otel.yml
deleted file mode 100644 (file)
index 56b96f3..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-exporters:
-  exporter_traces_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file trace"
-    file_pattern:   "__ctx_traces_log-%F-%N"
-    alias_pattern:  "__traces_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_traces_otlp_grpc:
-    type:                             otlp_grpc
-    thread_name:                      "OTLP/gRPC trace"
-    endpoint:                         "http://localhost:4317/v1/traces"
-    use_ssl_credentials:              false
-#   ssl_credentials_cacert_path:      ""
-#   ssl_credentials_cacert_as_string: ""
-#   ssl_client_key_path:              ""
-#   ssl_client_key_string:            ""
-#   ssl_client_cert_path:             ""
-#   ssl_client_cert_string:           ""
-#   timeout:                          10
-#   user_agent:                       ""
-#   max_threads:                      0
-#   compression:                      ""
-#   max_concurrent_requests:          0
-
-  exporter_traces_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP trace"
-    endpoint:                    "http://localhost:4318/v1/traces"
-    content_type:                json
-    json_bytes_mapping:          hexid
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP traces test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP traces test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-#   ssl_ca_cert_path:            ""
-#   ssl_ca_cert_string:          ""
-#   ssl_client_key_path:         ""
-#   ssl_client_key_string:       ""
-#   ssl_client_cert_path:        ""
-#   ssl_client_cert_string:      ""
-#   ssl_min_tls:                 ""
-#   ssl_max_tls:                 ""
-#   ssl_cipher:                  ""
-#   ssl_cipher_suite:            ""
-#   compression:                 ""
-
-  exporter_traces_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_traces_ostream:
-    type:     ostream
-    filename: __ctx_traces
-
-  exporter_traces_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_traces_zipkin:
-    type:           zipkin
-    endpoint:       "http://localhost:9411/api/v2/spans"
-    format:         json
-    service_name:   "zipkin-service"
-#   ipv4:           ""
-#   ipv6:           ""
-
-  exporter_metrics_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file metr"
-    file_pattern:   "__ctx_metrics_log-%F-%N"
-    alias_pattern:  "__metrics_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_metrics_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC metr"
-    endpoint:            "http://localhost:4317/v1/metrics"
-    use_ssl_credentials: false
-
-  exporter_metrics_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP metr"
-    endpoint:                    "http://localhost:4318/v1/metrics"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP metrics test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP metrics test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_metrics_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_metrics_ostream:
-    type:     ostream
-    filename: __ctx_metrics
-
-  exporter_metrics_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_logs_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file logs"
-    file_pattern:   "__ctx_logs_log-%F-%N"
-    alias_pattern:  "__logs_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_logs_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC logs"
-    endpoint:            "http://localhost:4317/v1/logs"
-    use_ssl_credentials: false
-
-  exporter_logs_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP logs"
-    endpoint:                    "http://localhost:4318/v1/logs"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP logs test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP logs test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_logs_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_logs_ostream:
-    type:     ostream
-    filename: __ctx_logs
-
-  exporter_logs_elasticsearch:
-    type:             elasticsearch
-    host:             localhost
-    port:             9200
-    index:            logs
-    response_timeout: 30
-    debug:            false
-    http_headers:
-      - X-OTel-Header-1: "Elasticsearch logs test header #1"
-      - X-OTel-Header-2: "Elasticsearch logs test header #2"
-
-readers:
-  reader_metrics:
-    thread_name:     "reader metr"
-    export_interval: 10000
-    export_timeout:  5000
-
-samplers:
-  sampler_traces:
-#   type:  always_on
-#   type:  always_off
-#   type:  trace_id_ratio_based
-#   ratio: 1.0
-    type:     parent_based
-    delegate: always_on
-
-processors:
-  processor_traces_batch:
-    type:                  batch
-    thread_name:           "proc/batch trac"
-    # Note: when the queue is half full, a preemptive notification is sent
-    # to start the export call.
-    max_queue_size:        2048
-    # Time interval (in ms) between two consecutive exports
-    schedule_delay:        5000
-    # Export 'max_export_batch_size' after every `schedule_delay' milliseconds.
-    max_export_batch_size: 512
-
-  processor_traces_single:
-    type:                  single
-
-  processor_logs_batch:
-    type:                  batch
-    thread_name:           "proc/batch logs"
-    max_queue_size:        2048
-    schedule_delay:        5000
-    max_export_batch_size: 512
-
-  processor_logs_single:
-    type:                  single
-
-providers:
-  provider_traces:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-ctx"
-      - service.name:        "ctx"
-      - service.namespace:   "HAProxy traces test"
-
-  provider_metrics:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-ctx"
-      - service.name:        "ctx"
-      - service.namespace:   "HAProxy metrics test"
-
-  provider_logs:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-ctx"
-      - service.name:        "ctx"
-      - service.namespace:   "HAProxy logs test"
-
-signals:
-  traces:
-    scope_name: "HAProxy OTEL - traces"
-    exporters:  exporter_traces_otlp_http
-    samplers:   sampler_traces
-    processors: processor_traces_batch
-    providers:  provider_traces
-
-  metrics:
-    scope_name: "HAProxy OTEL - metrics"
-    exporters:  exporter_metrics_otlp_http
-    readers:    reader_metrics
-    providers:  provider_metrics
-
-  logs:
-    scope_name: "HAProxy OTEL - logs"
-    exporters:  exporter_logs_otlp_http
-    processors: processor_logs_batch
-    providers:  provider_logs
diff --git a/addons/otel/test/empty/haproxy.cfg b/addons/otel/test/empty/haproxy.cfg
deleted file mode 100644 (file)
index a714136..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-global
-    stats socket /tmp/haproxy.sock mode 666 level admin
-
-listen stats
-    mode http
-    bind *:8001
-    stats uri /
-    stats admin if TRUE
-    stats refresh 10s
-
-frontend otel-test-empty
-    bind *:10080
-    default_backend servers-backend
-
-    # OTel filter
-    filter opentelemetry id otel-test-empty config empty/otel.cfg
-
-backend servers-backend
-    server server-1 127.0.0.1:8000
diff --git a/addons/otel/test/empty/otel.cfg b/addons/otel/test/empty/otel.cfg
deleted file mode 100644 (file)
index 3508936..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-otel-instrumentation otel-test-instrumentation
-    config empty/otel.yml
diff --git a/addons/otel/test/empty/otel.yml b/addons/otel/test/empty/otel.yml
deleted file mode 100644 (file)
index 1c8281f..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-exporters:
-  exporter_traces_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file trace"
-    file_pattern:   "__empty_traces_log-%F-%N"
-    alias_pattern:  "__traces_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_traces_otlp_grpc:
-    type:                             otlp_grpc
-    thread_name:                      "OTLP/gRPC trace"
-    endpoint:                         "http://localhost:4317/v1/traces"
-    use_ssl_credentials:              false
-#   ssl_credentials_cacert_path:      ""
-#   ssl_credentials_cacert_as_string: ""
-#   ssl_client_key_path:              ""
-#   ssl_client_key_string:            ""
-#   ssl_client_cert_path:             ""
-#   ssl_client_cert_string:           ""
-#   timeout:                          10
-#   user_agent:                       ""
-#   max_threads:                      0
-#   compression:                      ""
-#   max_concurrent_requests:          0
-
-  exporter_traces_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP trace"
-    endpoint:                    "http://localhost:4318/v1/traces"
-    content_type:                json
-    json_bytes_mapping:          hexid
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP traces test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP traces test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-#   ssl_ca_cert_path:            ""
-#   ssl_ca_cert_string:          ""
-#   ssl_client_key_path:         ""
-#   ssl_client_key_string:       ""
-#   ssl_client_cert_path:        ""
-#   ssl_client_cert_string:      ""
-#   ssl_min_tls:                 ""
-#   ssl_max_tls:                 ""
-#   ssl_cipher:                  ""
-#   ssl_cipher_suite:            ""
-#   compression:                 ""
-
-  exporter_traces_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_traces_ostream:
-    type:     ostream
-    filename: __empty_traces
-
-  exporter_traces_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_traces_zipkin:
-    type:           zipkin
-    endpoint:       "http://localhost:9411/api/v2/spans"
-    format:         json
-    service_name:   "zipkin-service"
-#   ipv4:           ""
-#   ipv6:           ""
-
-  exporter_metrics_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file metr"
-    file_pattern:   "__empty_metrics_log-%F-%N"
-    alias_pattern:  "__metrics_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_metrics_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC metr"
-    endpoint:            "http://localhost:4317/v1/metrics"
-    use_ssl_credentials: false
-
-  exporter_metrics_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP metr"
-    endpoint:                    "http://localhost:4318/v1/metrics"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP metrics test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP metrics test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_metrics_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_metrics_ostream:
-    type:     ostream
-    filename: __empty_metrics
-
-  exporter_metrics_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_logs_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file logs"
-    file_pattern:   "__empty_logs_log-%F-%N"
-    alias_pattern:  "__logs_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_logs_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC logs"
-    endpoint:            "http://localhost:4317/v1/logs"
-    use_ssl_credentials: false
-
-  exporter_logs_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP logs"
-    endpoint:                    "http://localhost:4318/v1/logs"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP logs test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP logs test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_logs_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_logs_ostream:
-    type:     ostream
-    filename: __empty_logs
-
-  exporter_logs_elasticsearch:
-    type:             elasticsearch
-    host:             localhost
-    port:             9200
-    index:            logs
-    response_timeout: 30
-    debug:            false
-    http_headers:
-      - X-OTel-Header-1: "Elasticsearch logs test header #1"
-      - X-OTel-Header-2: "Elasticsearch logs test header #2"
-
-readers:
-  reader_metrics:
-    thread_name:     "reader metr"
-    export_interval: 10000
-    export_timeout:  5000
-
-samplers:
-  sampler_traces:
-#   type:  always_on
-#   type:  always_off
-#   type:  trace_id_ratio_based
-#   ratio: 1.0
-    type:     parent_based
-    delegate: always_on
-
-processors:
-  processor_traces_batch:
-    type:                  batch
-    thread_name:           "proc/batch trac"
-    # Note: when the queue is half full, a preemptive notification is sent
-    # to start the export call.
-    max_queue_size:        2048
-    # Time interval (in ms) between two consecutive exports
-    schedule_delay:        5000
-    # Export 'max_export_batch_size' after every `schedule_delay' milliseconds.
-    max_export_batch_size: 512
-
-  processor_traces_single:
-    type:                  single
-
-  processor_logs_batch:
-    type:                  batch
-    thread_name:           "proc/batch logs"
-    max_queue_size:        2048
-    schedule_delay:        5000
-    max_export_batch_size: 512
-
-  processor_logs_single:
-    type:                  single
-
-providers:
-  provider_traces:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-empty"
-      - service.name:        "empty"
-      - service.namespace:   "HAProxy traces test"
-
-  provider_metrics:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-empty"
-      - service.name:        "empty"
-      - service.namespace:   "HAProxy metrics test"
-
-  provider_logs:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-empty"
-      - service.name:        "empty"
-      - service.namespace:   "HAProxy logs test"
-
-signals:
-  traces:
-    scope_name: "HAProxy OTEL - traces"
-    exporters:  exporter_traces_otlp_http
-    samplers:   sampler_traces
-    processors: processor_traces_batch
-    providers:  provider_traces
-
-  metrics:
-    scope_name: "HAProxy OTEL - metrics"
-    exporters:  exporter_metrics_otlp_http
-    readers:    reader_metrics
-    providers:  provider_metrics
-
-  logs:
-    scope_name: "HAProxy OTEL - logs"
-    exporters:  exporter_logs_otlp_http
-    processors: processor_logs_batch
-    providers:  provider_logs
diff --git a/addons/otel/test/fe/haproxy.cfg b/addons/otel/test/fe/haproxy.cfg
deleted file mode 100644 (file)
index 1d25db1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-global
-    stats socket /tmp/haproxy-fe.sock mode 666 level admin
-
-listen stats
-    mode http
-    bind *:8001
-    stats uri /
-    stats admin if TRUE
-    stats refresh 10s
-
-frontend otel-test-fe-frontend
-    bind *:10080
-    default_backend servers-backend
-
-    # OTel filter
-    filter opentelemetry id otel-test-fe config fe/otel.cfg
-
-backend servers-backend
-    server server-1 127.0.0.1:11080
diff --git a/addons/otel/test/fe/otel.cfg b/addons/otel/test/fe/otel.cfg
deleted file mode 100644 (file)
index 7eb1a56..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-[otel-test-fe]
-    otel-instrumentation otel-test-instrumentation
-        config fe/otel.yml
-#       log localhost:514 local7 debug
-        option dontlog-normal
-        option hard-errors
-        no option disabled
-        rate-limit 100.0
-
-        scopes client_session_start
-        scopes frontend_tcp_request
-        scopes frontend_http_request
-        scopes backend_tcp_request
-        scopes backend_http_request
-        scopes client_session_end
-
-        scopes server_session_start
-        scopes tcp_response
-        scopes http_response
-        scopes server_session_end
-
-    otel-scope client_session_start
-        span "HAProxy session" root
-            baggage "haproxy_id" var(sess.otel.uuid)
-        span "Client session" parent "HAProxy session"
-        otel-event on-client-session-start
-
-    otel-scope frontend_tcp_request
-        span "Frontend TCP request" parent "Client session"
-        otel-event on-frontend-tcp-request
-
-    otel-scope frontend_http_request
-        span "Frontend HTTP request" parent "Frontend TCP request"
-            attribute "http.method" method
-            attribute "http.url" url
-            attribute "http.version" str("HTTP/") req.ver
-        finish "Frontend TCP request"
-        otel-event on-frontend-http-request
-
-    otel-scope backend_tcp_request
-        span "Backend TCP request" parent "Frontend HTTP request"
-        finish "Frontend HTTP request"
-        otel-event on-backend-tcp-request
-
-    otel-scope backend_http_request
-        span "Backend HTTP request" parent "Backend TCP request"
-        finish "Backend TCP request"
-        span "HAProxy session"
-            inject "otel-ctx" use-headers
-        otel-event on-backend-http-request
-
-    otel-scope client_session_end
-        finish "Client session"
-        otel-event on-client-session-end
-
-    otel-scope server_session_start
-        span "Server session" parent "HAProxy session"
-        finish "Backend HTTP request"
-        otel-event on-server-session-start
-
-    otel-scope tcp_response
-        span "TCP response" parent "Server session"
-        otel-event on-tcp-response
-
-    otel-scope http_response
-        span "HTTP response" parent "TCP response"
-            attribute "http.status_code" status
-        finish "TCP response"
-        otel-event on-http-response
-
-    otel-scope server_session_end
-        finish *
-        otel-event on-server-session-end
diff --git a/addons/otel/test/fe/otel.yml b/addons/otel/test/fe/otel.yml
deleted file mode 100644 (file)
index 89e25f7..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-exporters:
-  exporter_traces_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file trace"
-    file_pattern:   "__fe_traces_log-%F-%N"
-    alias_pattern:  "__traces_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_traces_otlp_grpc:
-    type:                             otlp_grpc
-    thread_name:                      "OTLP/gRPC trace"
-    endpoint:                         "http://localhost:4317/v1/traces"
-    use_ssl_credentials:              false
-#   ssl_credentials_cacert_path:      ""
-#   ssl_credentials_cacert_as_string: ""
-#   ssl_client_key_path:              ""
-#   ssl_client_key_string:            ""
-#   ssl_client_cert_path:             ""
-#   ssl_client_cert_string:           ""
-#   timeout:                          10
-#   user_agent:                       ""
-#   max_threads:                      0
-#   compression:                      ""
-#   max_concurrent_requests:          0
-
-  exporter_traces_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP trace"
-    endpoint:                    "http://localhost:4318/v1/traces"
-    content_type:                json
-    json_bytes_mapping:          hexid
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP traces test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP traces test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-#   ssl_ca_cert_path:            ""
-#   ssl_ca_cert_string:          ""
-#   ssl_client_key_path:         ""
-#   ssl_client_key_string:       ""
-#   ssl_client_cert_path:        ""
-#   ssl_client_cert_string:      ""
-#   ssl_min_tls:                 ""
-#   ssl_max_tls:                 ""
-#   ssl_cipher:                  ""
-#   ssl_cipher_suite:            ""
-#   compression:                 ""
-
-  exporter_traces_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_traces_ostream:
-    type:     ostream
-    filename: __fe_traces
-
-  exporter_traces_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_traces_zipkin:
-    type:           zipkin
-    endpoint:       "http://localhost:9411/api/v2/spans"
-    format:         json
-    service_name:   "zipkin-service"
-#   ipv4:           ""
-#   ipv6:           ""
-
-  exporter_metrics_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file metr"
-    file_pattern:   "__fe_metrics_log-%F-%N"
-    alias_pattern:  "__metrics_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_metrics_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC metr"
-    endpoint:            "http://localhost:4317/v1/metrics"
-    use_ssl_credentials: false
-
-  exporter_metrics_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP metr"
-    endpoint:                    "http://localhost:4318/v1/metrics"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP metrics test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP metrics test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_metrics_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_metrics_ostream:
-    type:     ostream
-    filename: __fe_metrics
-
-  exporter_metrics_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_logs_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file logs"
-    file_pattern:   "__fe_logs_log-%F-%N"
-    alias_pattern:  "__logs_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_logs_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC logs"
-    endpoint:            "http://localhost:4317/v1/logs"
-    use_ssl_credentials: false
-
-  exporter_logs_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP logs"
-    endpoint:                    "http://localhost:4318/v1/logs"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP logs test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP logs test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_logs_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_logs_ostream:
-    type:     ostream
-    filename: __fe_logs
-
-  exporter_logs_elasticsearch:
-    type:             elasticsearch
-    host:             localhost
-    port:             9200
-    index:            logs
-    response_timeout: 30
-    debug:            false
-    http_headers:
-      - X-OTel-Header-1: "Elasticsearch logs test header #1"
-      - X-OTel-Header-2: "Elasticsearch logs test header #2"
-
-readers:
-  reader_metrics:
-    thread_name:     "reader metr"
-    export_interval: 10000
-    export_timeout:  5000
-
-samplers:
-  sampler_traces:
-#   type:  always_on
-#   type:  always_off
-#   type:  trace_id_ratio_based
-#   ratio: 1.0
-    type:     parent_based
-    delegate: always_on
-
-processors:
-  processor_traces_batch:
-    type:                  batch
-    thread_name:           "proc/batch trac"
-    # Note: when the queue is half full, a preemptive notification is sent
-    # to start the export call.
-    max_queue_size:        2048
-    # Time interval (in ms) between two consecutive exports
-    schedule_delay:        5000
-    # Export 'max_export_batch_size' after every `schedule_delay' milliseconds.
-    max_export_batch_size: 512
-
-  processor_traces_single:
-    type:                  single
-
-  processor_logs_batch:
-    type:                  batch
-    thread_name:           "proc/batch logs"
-    max_queue_size:        2048
-    schedule_delay:        5000
-    max_export_batch_size: 512
-
-  processor_logs_single:
-    type:                  single
-
-providers:
-  provider_traces:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-fe"
-      - service.name:        "fe"
-      - service.namespace:   "HAProxy traces test"
-
-  provider_metrics:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-fe"
-      - service.name:        "fe"
-      - service.namespace:   "HAProxy metrics test"
-
-  provider_logs:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-fe"
-      - service.name:        "fe"
-      - service.namespace:   "HAProxy logs test"
-
-signals:
-  traces:
-    scope_name: "HAProxy OTEL - traces"
-    exporters:  exporter_traces_otlp_http
-    samplers:   sampler_traces
-    processors: processor_traces_batch
-    providers:  provider_traces
-
-  metrics:
-    scope_name: "HAProxy OTEL - metrics"
-    exporters:  exporter_metrics_otlp_http
-    readers:    reader_metrics
-    providers:  provider_metrics
-
-  logs:
-    scope_name: "HAProxy OTEL - logs"
-    exporters:  exporter_logs_otlp_http
-    processors: processor_logs_batch
-    providers:  provider_logs
diff --git a/addons/otel/test/full/haproxy.cfg b/addons/otel/test/full/haproxy.cfg
deleted file mode 100644 (file)
index 0decae7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-global
-    stats socket /tmp/haproxy.sock mode 666 level admin
-
-listen stats
-    mode http
-    bind *:8001
-    stats uri /
-    stats admin if TRUE
-    stats refresh 10s
-
-frontend otel-test-full-frontend
-    bind *:10080
-    default_backend servers-backend
-
-    # ACL used to distinguish successful from error responses
-    acl acl-http-status-ok status 100:399
-
-    # OTel filter
-    filter opentelemetry id otel-test-full config full/otel.cfg
-
-    # run response scopes for successful responses
-    http-response otel-group otel-test-full http_response_group if acl-http-status-ok
-
-    # run after-response scopes for error responses
-    http-after-response otel-group otel-test-full http_after_response_group if !acl-http-status-ok
-
-backend servers-backend
-    server server-1 127.0.0.1:8000
diff --git a/addons/otel/test/full/otel.cfg b/addons/otel/test/full/otel.cfg
deleted file mode 100644 (file)
index 921c507..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-[otel-test-full]
-    otel-instrumentation otel-test-instrumentation
-        debug-level 0x77f
-        log localhost:514 local7 debug
-        config full/otel.yml
-        option dontlog-normal
-        option hard-errors
-        no option disabled
-        rate-limit 100.0
-
-        groups http_response_group
-        groups http_after_response_group
-
-        scopes on_stream_start
-        scopes on_stream_stop
-        scopes on_idle_timeout
-        scopes on_backend_set
-
-        scopes client_session_start
-        scopes frontend_tcp_request
-        scopes http_wait_request
-        scopes http_body_request
-        scopes frontend_http_request
-        scopes switching_rules_request
-        scopes backend_tcp_request
-        scopes backend_http_request
-        scopes process_server_rules_request
-        scopes http_process_request
-        scopes tcp_rdp_cookie_request
-        scopes process_sticking_rules_request
-        scopes http_headers_request
-        scopes http_end_request
-        scopes client_session_end
-        scopes server_unavailable
-
-        scopes server_session_start
-        scopes tcp_response
-        scopes http_wait_response
-        scopes process_store_rules_response
-        scopes http_response http_response-error
-        scopes http_headers_response
-        scopes http_end_response
-        scopes http_reply
-        scopes server_session_end
-
-    otel-group http_response_group
-        scopes http_response_1
-        scopes http_response_2
-
-    otel-scope http_response_1
-        span "HTTP response"
-            event "event_content" "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes")
-
-    otel-scope http_response_2
-        span "HTTP response"
-            event "event_date" "hdr.date" res.hdr("date") str(" / ") res.hdr("last-modified")
-
-    otel-group http_after_response_group
-        scopes http_after_response
-
-    otel-scope http_after_response
-        span "HAProxy response" parent "HAProxy session"
-            status "error" str("http.status_code: ") status
-
-    otel-scope on_stream_start
-        instrument udcnt_int "haproxy.sessions.active" desc "Active sessions"      value int(1)  unit "{session}"
-        instrument gauge_int "haproxy.fe.connections"  desc "Frontend connections" value fe_conn unit "{connection}"
-        span "HAProxy session" root
-            baggage "haproxy_id" var(sess.otel.uuid)
-            event "event_ip" "src" src str(":") src_port
-            event "event_be" "be"  be_id str(" ") be_name
-            event "event_ip" "dst" dst str(":") dst_port
-            event "event_fe" "fe"  fe_id str(" ") fe_name
-        log-record trace id 1000 event "session-start" span "HAProxy session" attr "attr_1_key" src attr "attr_2_key" src_port src str(":") src_port
-        acl acl-test-src-ip src 127.0.0.1
-        otel-event on-stream-start if acl-test-src-ip
-
-    otel-scope on_stream_stop
-        finish *
-        log-record info event "session-stop" str("stream stopped")
-        otel-event on-stream-stop
-
-    otel-scope on_idle_timeout
-        idle-timeout 1s
-        span "heartbeat" parent "HAProxy session"
-            attribute "idle.elapsed" str("idle-check")
-        instrument cnt_int "idle.count" value int(1)
-        instrument update "idle.count"
-        log-record info str("heartbeat")
-        otel-event on-idle-timeout
-
-    otel-scope on_backend_set
-        span "Backend set" parent "HAProxy session"
-            attribute "backend.name" be_name
-            attribute "backend.id" be_id
-        instrument cnt_int "haproxy.backend.set" desc "Backend assignments" value int(1) unit "{assignment}"
-        instrument update "haproxy.backend.set"
-        log-record info id 1010 event "backend-set" span "Backend set" be_name
-        otel-event on-backend-set
-
-    otel-scope client_session_start
-        span "Client session" parent "HAProxy session"
-        instrument cnt_int "haproxy.client.session.start" desc "Client session starts" value int(1) unit "{session}"
-        log-record info id 1001 event "client-session-start" span "Client session" src str(":") src_port
-        otel-event on-client-session-start
-
-    otel-scope frontend_tcp_request
-        span "Frontend TCP request" parent "Client session"
-        instrument cnt_int "haproxy.tcp.request.fe" desc "Frontend TCP requests" value int(1) unit "{request}"
-        log-record info event "frontend-tcp-request" span "Frontend TCP request" src str(":") src_port
-        otel-event on-frontend-tcp-request
-
-    otel-scope http_wait_request
-        span "HTTP wait request" parent "Frontend TCP request"
-        finish "Frontend TCP request"
-        log-record info event "http-wait-request" span "HTTP wait request" str("waiting")
-        otel-event on-http-wait-request
-
-    otel-scope http_body_request
-        span "HTTP body request" parent "HTTP wait request"
-        finish "HTTP wait request"
-        log-record info event "http-body-request" span "HTTP body request" str("body")
-        otel-event on-http-body-request
-
-    otel-scope frontend_http_request
-        instrument cnt_int  "haproxy.http.requests" desc "HTTP request count"   value int(1)     unit "{request}"
-        instrument hist_int "haproxy.http.latency"  desc "HTTP request latency" value lat_ns_tot unit "ns" aggr "histogram" bounds "1000 1000000 1000000000"
-        instrument update "haproxy.http.latency" attr "phase" str("request")
-        instrument update "haproxy.tcp.request.fe"
-        span "Frontend HTTP request" parent "HTTP body request" link "HAProxy session"
-            attribute "http.method" method
-            attribute "http.url" url
-            attribute "http.version" str("HTTP/") req.ver
-        finish "HTTP body request"
-        log-record info id 1002 event "http-request" span "Frontend HTTP request" attr "http.method" method method url
-        otel-event on-frontend-http-request
-
-    otel-scope switching_rules_request
-        span "Switching rules request" parent "Frontend HTTP request"
-        finish "Frontend HTTP request"
-        log-record info event "switching-rules" span "Switching rules request" be_name
-        otel-event on-switching-rules-request
-
-    otel-scope backend_tcp_request
-        span "Backend TCP request" parent "Switching rules request"
-        finish "Switching rules request"
-        instrument cnt_int "haproxy.tcp.request.be" desc "Backend TCP requests" value int(1) unit "{request}"
-        log-record info event "backend-tcp-request" span "Backend TCP request" be_name
-        otel-event on-backend-tcp-request
-
-    otel-scope backend_http_request
-        instrument update "haproxy.tcp.request.be"
-        span "Backend HTTP request" parent "Backend TCP request"
-        finish "Backend TCP request"
-        log-record info event "backend-http-request" span "Backend HTTP request" be_name
-        otel-event on-backend-http-request
-
-    otel-scope process_server_rules_request
-        span "Process server rules request" parent "Backend HTTP request"
-        finish "Backend HTTP request"
-        log-record info event "server-rules" span "Process server rules request" str("processing")
-        otel-event on-process-server-rules-request
-
-    otel-scope http_process_request
-        span "HTTP process request" parent "Process server rules request"
-        finish "Process server rules request"
-        log-record info event "http-process" span "HTTP process request" str("processing")
-        otel-event on-http-process-request
-
-    otel-scope tcp_rdp_cookie_request
-        span "TCP RDP cookie request" parent "HTTP process request"
-        finish "HTTP process request"
-        log-record info event "tcp-rdp-cookie" span "TCP RDP cookie request" str("cookie")
-        otel-event on-tcp-rdp-cookie-request
-
-    otel-scope process_sticking_rules_request
-        span "Process sticking rules request" parent "TCP RDP cookie request"
-        finish "TCP RDP cookie request"
-        log-record info event "sticking-rules" span "Process sticking rules request" str("sticking")
-        otel-event on-process-sticking-rules-request
-
-    otel-scope http_headers_request
-        span "HTTP headers request" parent "Process sticking rules request"
-        finish "Process sticking rules request"
-        instrument cnt_int "haproxy.http.headers.request" desc "Request headers processed" value int(1) unit "{header}"
-        log-record info event "http-headers-request" span "HTTP headers request" method url
-        otel-event on-http-headers-request
-
-    otel-scope http_end_request
-        span "HTTP end request" parent "HTTP headers request"
-        finish "HTTP headers request"
-        instrument cnt_int "haproxy.http.end.request" desc "Request end events" value int(1) unit "{request}"
-        instrument update "haproxy.http.headers.request"
-        log-record info event "http-end-request" span "HTTP end request" str("end")
-        otel-event on-http-end-request
-
-    otel-scope client_session_end
-        instrument update "haproxy.sessions.active"
-        instrument update "haproxy.client.session.start"
-        instrument update "haproxy.http.end.request"
-        finish "*req*"
-        log-record info event "client-session-end" str("session ended")
-        otel-event on-client-session-end
-
-    otel-scope server_unavailable
-        finish "*req*" "*res*"
-        log-record warn event "server-unavailable" str("503 Service Unavailable")
-        otel-event on-server-unavailable
-
-    otel-scope server_session_start
-        span "Server session" parent "HAProxy session"
-        link "HAProxy session" "Client session"
-        finish "HTTP end request"
-        instrument cnt_int "haproxy.server.session.start" desc "Server session starts" value int(1) unit "{session}"
-        log-record info event "server-session-start" span "Server session" str("server session")
-        otel-event on-server-session-start
-
-    otel-scope tcp_response
-        span "TCP response" parent "Server session"
-        instrument cnt_int "haproxy.tcp.response" desc "TCP responses" value int(1) unit "{response}"
-        log-record info event "tcp-response" span "TCP response" str("tcp response")
-        otel-event on-tcp-response
-
-    otel-scope http_wait_response
-        instrument update "haproxy.tcp.response"
-        span "HTTP wait response" parent "TCP response"
-        finish "TCP response"
-        log-record info event "http-wait-response" span "HTTP wait response" str("waiting")
-        otel-event on-http-wait-response
-
-    otel-scope process_store_rules_response
-        span "Process store rules response" parent "HTTP wait response"
-        finish "HTTP wait response"
-        log-record info event "store-rules" span "Process store rules response" str("store rules")
-        otel-event on-process-store-rules-response
-
-    otel-scope http_response
-        instrument update "haproxy.http.requests" attr "phase" str("response")
-        instrument update "haproxy.http.latency"  attr "phase" str("response")
-        instrument update "haproxy.fe.connections"
-        span "HTTP response" parent "Process store rules response"
-            attribute "http.status_code" status
-        finish "Process store rules response"
-        log-record info id 1003 event "http-response" span "HTTP response" status
-        otel-event on-http-response
-
-    otel-scope http_response-error
-        span "HTTP response"
-            status "error" str("http.status_code: ") status
-        otel-event on-http-response if !acl-http-status-ok
-
-    otel-scope http_headers_response
-        span "HTTP headers response" parent "HTTP response"
-        finish "HTTP response"
-        instrument cnt_int "haproxy.http.headers.response" desc "Response headers processed" value int(1) unit "{header}"
-        log-record info event "http-headers-response" span "HTTP headers response" status
-        otel-event on-http-headers-response
-
-    otel-scope http_end_response
-        span "HTTP end response" parent "HTTP headers response"
-        finish "HTTP headers response"
-        instrument cnt_int "haproxy.http.end.response" desc "Response end events" value int(1) unit "{response}"
-        instrument update "haproxy.http.headers.response"
-        log-record info event "http-end-response" span "HTTP end response" str("end")
-        otel-event on-http-end-response
-
-    otel-scope http_reply
-        span "HTTP reply" parent "HTTP end response"
-        finish "HTTP end response"
-        instrument cnt_int "haproxy.http.reply" desc "HTTP replies" value int(1) unit "{reply}"
-        instrument update "haproxy.http.end.response"
-        log-record info event "http-reply" span "HTTP reply" status
-        otel-event on-http-reply
-
-    otel-scope server_session_end
-        instrument update "haproxy.server.session.start"
-        instrument update "haproxy.http.reply"
-        finish "*res*"
-        log-record info event "server-session-end" str("server session ended")
-        otel-event on-server-session-end
diff --git a/addons/otel/test/full/otel.yml b/addons/otel/test/full/otel.yml
deleted file mode 100644 (file)
index 03811bf..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-exporters:
-  exporter_traces_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file trace"
-    file_pattern:   "__full_traces_log-%F-%N"
-    alias_pattern:  "__traces_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_traces_otlp_grpc:
-    type:                             otlp_grpc
-    thread_name:                      "OTLP/gRPC trace"
-    endpoint:                         "http://localhost:4317/v1/traces"
-    use_ssl_credentials:              false
-#   ssl_credentials_cacert_path:      ""
-#   ssl_credentials_cacert_as_string: ""
-#   ssl_client_key_path:              ""
-#   ssl_client_key_string:            ""
-#   ssl_client_cert_path:             ""
-#   ssl_client_cert_string:           ""
-#   timeout:                          10
-#   user_agent:                       ""
-#   max_threads:                      0
-#   compression:                      ""
-#   max_concurrent_requests:          0
-
-  exporter_traces_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP trace"
-    endpoint:                    "http://localhost:4318/v1/traces"
-    content_type:                json
-    json_bytes_mapping:          hexid
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP traces test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP traces test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-#   ssl_ca_cert_path:            ""
-#   ssl_ca_cert_string:          ""
-#   ssl_client_key_path:         ""
-#   ssl_client_key_string:       ""
-#   ssl_client_cert_path:        ""
-#   ssl_client_cert_string:      ""
-#   ssl_min_tls:                 ""
-#   ssl_max_tls:                 ""
-#   ssl_cipher:                  ""
-#   ssl_cipher_suite:            ""
-#   compression:                 ""
-
-  exporter_traces_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_traces_ostream:
-    type:     ostream
-    filename: __full_traces
-
-  exporter_traces_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_traces_zipkin:
-    type:           zipkin
-    endpoint:       "http://localhost:9411/api/v2/spans"
-    format:         json
-    service_name:   "zipkin-service"
-#   ipv4:           ""
-#   ipv6:           ""
-
-  exporter_metrics_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file metr"
-    file_pattern:   "__full_metrics_log-%F-%N"
-    alias_pattern:  "__metrics_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_metrics_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC metr"
-    endpoint:            "http://localhost:4317/v1/metrics"
-    use_ssl_credentials: false
-
-  exporter_metrics_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP metr"
-    endpoint:                    "http://localhost:4318/v1/metrics"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP metrics test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP metrics test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_metrics_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_metrics_ostream:
-    type:     ostream
-    filename: __full_metrics
-
-  exporter_metrics_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_logs_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file logs"
-    file_pattern:   "__full_logs_log-%F-%N"
-    alias_pattern:  "__logs_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_logs_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC logs"
-    endpoint:            "http://localhost:4317/v1/logs"
-    use_ssl_credentials: false
-
-  exporter_logs_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP logs"
-    endpoint:                    "http://localhost:4318/v1/logs"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP logs test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP logs test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_logs_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_logs_ostream:
-    type:     ostream
-    filename: __full_logs
-
-  exporter_logs_elasticsearch:
-    type:             elasticsearch
-    host:             localhost
-    port:             9200
-    index:            logs
-    response_timeout: 30
-    debug:            false
-    http_headers:
-      - X-OTel-Header-1: "Elasticsearch logs test header #1"
-      - X-OTel-Header-2: "Elasticsearch logs test header #2"
-
-readers:
-  reader_metrics:
-    thread_name:     "reader metr"
-    export_interval: 10000
-    export_timeout:  5000
-
-samplers:
-  sampler_traces:
-#   type:  always_on
-#   type:  always_off
-#   type:  trace_id_ratio_based
-#   ratio: 1.0
-    type:     parent_based
-    delegate: always_on
-
-processors:
-  processor_traces_batch:
-    type:                  batch
-    thread_name:           "proc/batch trac"
-    # Note: when the queue is half full, a preemptive notification is sent
-    # to start the export call.
-    max_queue_size:        2048
-    # Time interval (in ms) between two consecutive exports
-    schedule_delay:        5000
-    # Export 'max_export_batch_size' after every `schedule_delay' milliseconds.
-    max_export_batch_size: 512
-
-  processor_traces_single:
-    type:                  single
-
-  processor_logs_batch:
-    type:                  batch
-    thread_name:           "proc/batch logs"
-    max_queue_size:        2048
-    schedule_delay:        5000
-    max_export_batch_size: 512
-
-  processor_logs_single:
-    type:                  single
-
-providers:
-  provider_traces:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-full"
-      - service.name:        "full"
-      - service.namespace:   "HAProxy traces test"
-
-  provider_metrics:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-full"
-      - service.name:        "full"
-      - service.namespace:   "HAProxy metrics test"
-
-  provider_logs:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-full"
-      - service.name:        "full"
-      - service.namespace:   "HAProxy logs test"
-
-signals:
-  traces:
-    scope_name: "HAProxy OTEL - traces"
-    exporters:  exporter_traces_otlp_http
-    samplers:   sampler_traces
-    processors: processor_traces_batch
-    providers:  provider_traces
-
-  metrics:
-    scope_name: "HAProxy OTEL - metrics"
-    exporters:  exporter_metrics_otlp_http
-    readers:    reader_metrics
-    providers:  provider_metrics
-
-  logs:
-    scope_name: "HAProxy OTEL - logs"
-    exporters:  exporter_logs_otlp_http
-    processors: processor_logs_batch
-    providers:  provider_logs
diff --git a/addons/otel/test/haproxy-common.cfg b/addons/otel/test/haproxy-common.cfg
deleted file mode 100644 (file)
index 124a025..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-global
-#   nbthread 1
-    maxconn 5000
-    hard-stop-after 10s
-#   log localhost:514 local7 debug
-#   debug
-
-defaults
-#   log     global
-#   option  httplog
-#   option  dontlognull
-#   option  httpclose
-    mode    http
-    retries 3
-    maxconn 4000
-    timeout connect 5000
-    timeout client  50000
-    timeout server  50000
diff --git a/addons/otel/test/index.html b/addons/otel/test/index.html
deleted file mode 100644 (file)
index 09ed6fa..0000000
+++ /dev/null
@@ -1 +0,0 @@
-<html><body><p>Did I err?</p></body></html>
diff --git a/addons/otel/test/run-cmp.sh b/addons/otel/test/run-cmp.sh
deleted file mode 120000 (symlink)
index 0bf0176..0000000
+++ /dev/null
@@ -1 +0,0 @@
-run-test-config.sh
\ No newline at end of file
diff --git a/addons/otel/test/run-ctx.sh b/addons/otel/test/run-ctx.sh
deleted file mode 120000 (symlink)
index 0bf0176..0000000
+++ /dev/null
@@ -1 +0,0 @@
-run-test-config.sh
\ No newline at end of file
diff --git a/addons/otel/test/run-empty.sh b/addons/otel/test/run-empty.sh
deleted file mode 120000 (symlink)
index 0bf0176..0000000
+++ /dev/null
@@ -1 +0,0 @@
-run-test-config.sh
\ No newline at end of file
diff --git a/addons/otel/test/run-fe-be.sh b/addons/otel/test/run-fe-be.sh
deleted file mode 100755 (executable)
index 6146951..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh -u
-#
-# Copyright 2026 HAProxy Technologies, Miroslav Zagorac <mzagorac@haproxy.com>
-#
-SH_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}"
-SH_ARG_PIDFILE="${2:-haproxy.pid}"
-       SH_TIME="$(date +%s)"
-    SH_LOG_DIR="_logs"
-     SH_LOG_FE="${SH_LOG_DIR}/_log-$(basename "${0}" fe-be.sh)fe-${SH_TIME}"
-     SH_LOG_BE="${SH_LOG_DIR}/_log-$(basename "${0}" fe-be.sh)be-${SH_TIME}"
-
-
-__exit ()
-{
-       test -z "${2}" && {
-               echo
-               echo "Script killed!"
-
-               echo "Waiting for jobs to complete..."
-               pkill --signal SIGUSR1 haproxy
-               wait
-       }
-
-       test -n "${1}" && {
-               echo
-               echo "${1}"
-               echo
-       }
-
-       exit ${2:-100}
-}
-
-
-trap __exit INT TERM
-
-test -x "${SH_ARG_HAPROXY}" || __exit "${SH_ARG_HAPROXY}: executable does not exist" 1
-mkdir -p "${SH_LOG_DIR}"    || __exit "${SH_ARG_HAPROXY}: cannot create log directory" 2
-
-echo "\n------------------------------------------------------------------------"
-set -- -f haproxy-common.cfg -f be/haproxy.cfg -p "${SH_ARG_PIDFILE}"
-echo "--- executing: ${SH_ARG_HAPROXY} ${@}" >${SH_LOG_BE}
-"${SH_ARG_HAPROXY}" "${@}" >>"${SH_LOG_BE}" 2>&1 &
-
-set -- -f haproxy-common.cfg -f fe/haproxy.cfg -p "${SH_ARG_PIDFILE}"
-echo "--- executing: ${SH_ARG_HAPROXY} ${@}" >${SH_LOG_FE}
-"${SH_ARG_HAPROXY}" "${@}" >>"${SH_LOG_FE}" 2>&1 &
-echo "------------------------------------------------------------------------\n"
-
-echo "Press CTRL-C to quit..."
-wait
diff --git a/addons/otel/test/run-full.sh b/addons/otel/test/run-full.sh
deleted file mode 120000 (symlink)
index 0bf0176..0000000
+++ /dev/null
@@ -1 +0,0 @@
-run-test-config.sh
\ No newline at end of file
diff --git a/addons/otel/test/run-sa.sh b/addons/otel/test/run-sa.sh
deleted file mode 120000 (symlink)
index 0bf0176..0000000
+++ /dev/null
@@ -1 +0,0 @@
-run-test-config.sh
\ No newline at end of file
diff --git a/addons/otel/test/run-test-config.sh b/addons/otel/test/run-test-config.sh
deleted file mode 100755 (executable)
index 9c46608..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh -u
-#
-# Copyright 2026 HAProxy Technologies, Miroslav Zagorac <mzagorac@haproxy.com>
-#
-SH_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}"
-SH_ARG_PIDFILE="${2:-haproxy.pid}"
-       SH_NAME="$(basename "${0}" .sh)"
-    SH_CONFDIR="${SH_NAME#run-}"
-    SH_LOG_DIR="_logs"
-        SH_LOG="${SH_LOG_DIR}/_log-${SH_NAME}-$(date +%s)"
-
-
-test -x "${SH_ARG_HAPROXY}" || exit 1
-mkdir -p "${SH_LOG_DIR}"    || exit 2
-
-set -- -f haproxy-common.cfg -f "${SH_CONFDIR}/haproxy.cfg" -p "${SH_ARG_PIDFILE}"
-echo "executing: ${SH_ARG_HAPROXY} ${@}" >${SH_LOG}
-"${SH_ARG_HAPROXY}" "${@}" >>"${SH_LOG}" 2>&1
diff --git a/addons/otel/test/sa/haproxy.cfg b/addons/otel/test/sa/haproxy.cfg
deleted file mode 100644 (file)
index 8b62b7b..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-global
-    stats socket /tmp/haproxy.sock mode 666 level admin
-
-listen stats
-    mode http
-    bind *:8001
-    stats uri /
-    stats admin if TRUE
-    stats refresh 10s
-
-frontend otel-test-sa-frontend
-    bind *:10080
-    default_backend servers-backend
-
-    # ACL used to distinguish successful from error responses
-    acl acl-http-status-ok status 100:399
-
-    # OTel filter
-    filter opentelemetry id otel-test-sa config sa/otel.cfg
-
-    # run response scopes for successful responses
-    http-response otel-group otel-test-sa http_response_group if acl-http-status-ok
-
-    # run after-response scopes for error responses
-    http-after-response otel-group otel-test-sa http_after_response_group if !acl-http-status-ok
-
-backend servers-backend
-    server server-1 127.0.0.1:8000
diff --git a/addons/otel/test/sa/otel.cfg b/addons/otel/test/sa/otel.cfg
deleted file mode 100644 (file)
index 5b213a0..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-[otel-test-sa]
-    otel-instrumentation otel-test-instrumentation
-        debug-level 0x77f
-        log localhost:514 local7 debug
-        config sa/otel.yml
-        option dontlog-normal
-        option hard-errors
-        no option disabled
-        rate-limit 100.0
-
-        groups http_response_group
-        groups http_after_response_group
-
-        scopes on_stream_start
-        scopes on_stream_stop
-        scopes on_idle_timeout
-
-        scopes client_session_start
-        scopes frontend_tcp_request
-        scopes http_wait_request
-        scopes http_body_request
-        scopes frontend_http_request
-        scopes switching_rules_request
-        scopes backend_tcp_request
-        scopes backend_http_request
-        scopes process_server_rules_request
-        scopes http_process_request
-        scopes tcp_rdp_cookie_request
-        scopes process_sticking_rules_request
-        scopes client_session_end
-        scopes server_unavailable
-
-        scopes server_session_start
-        scopes tcp_response
-        scopes http_wait_response
-        scopes process_store_rules_response
-        scopes http_response http_response-error
-        scopes server_session_end
-
-    otel-group http_response_group
-        scopes http_response_1
-        scopes http_response_2
-
-    otel-scope http_response_1
-        span "HTTP response"
-            event "event_content" "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes")
-
-    otel-scope http_response_2
-        span "HTTP response"
-            event "event_date" "hdr.date" res.hdr("date") str(" / ") res.hdr("last-modified")
-
-    otel-group http_after_response_group
-        scopes http_after_response
-
-    otel-scope http_after_response
-        span "HAProxy response" parent "HAProxy session"
-            status "error" str("http.status_code: ") status
-
-    otel-scope on_stream_start
-        instrument udcnt_int "haproxy.sessions.active" desc "Active sessions"      value int(1)  unit "{session}"
-        instrument gauge_int "haproxy.fe.connections"  desc "Frontend connections" value fe_conn unit "{connection}"
-        span "HAProxy session" root
-            baggage "haproxy_id" var(sess.otel.uuid)
-            event "event_ip" "src" src str(":") src_port
-            event "event_be" "be"  be_id str(" ") be_name
-            event "event_ip" "dst" dst str(":") dst_port
-            event "event_fe" "fe"  fe_id str(" ") fe_name
-        log-record trace id 1000 event "session-start" span "Client session" attr "attr_1_key" src attr "attr_2_key" src_port src str(":") src_port
-        acl acl-test-src-ip src 127.0.0.1
-        otel-event on-stream-start if acl-test-src-ip
-
-    otel-scope on_stream_stop
-        finish *
-        otel-event on-stream-stop
-
-    otel-scope on_idle_timeout
-        idle-timeout 1s
-        span "heartbeat" parent "HAProxy session"
-            attribute "idle.elapsed" str("idle-check")
-        instrument cnt_int "idle.count" value int(1)
-        instrument update "idle.count"
-        log-record info str("heartbeat")
-        otel-event on-idle-timeout
-
-    otel-scope client_session_start
-        span "Client session" parent "HAProxy session"
-        otel-event on-client-session-start
-
-    otel-scope frontend_tcp_request
-        span "Frontend TCP request" parent "Client session"
-        otel-event on-frontend-tcp-request
-
-    otel-scope http_wait_request
-        span "HTTP wait request" parent "Frontend TCP request"
-        finish "Frontend TCP request"
-        otel-event on-http-wait-request
-
-    otel-scope http_body_request
-        span "HTTP body request" parent "HTTP wait request"
-        finish "HTTP wait request"
-        otel-event on-http-body-request
-
-    otel-scope frontend_http_request
-        instrument cnt_int  "haproxy.http.requests" desc "HTTP request count"   value int(1)     unit "{request}"
-        instrument hist_int "haproxy.http.latency"  desc "HTTP request latency" value lat_ns_tot unit "ns"
-        instrument update "haproxy.http.latency" attr "phase" str("request")
-        span "Frontend HTTP request" parent "HTTP body request" link "HAProxy session"
-            attribute "http.method" method
-            attribute "http.url" url
-            attribute "http.version" str("HTTP/") req.ver
-        finish "HTTP body request"
-        log-record info id 1001 event "http-request" span "Frontend HTTP request" attr "http.method" method method url
-        otel-event on-frontend-http-request
-
-    otel-scope switching_rules_request
-        span "Switching rules request" parent "Frontend HTTP request"
-        finish "Frontend HTTP request"
-        otel-event on-switching-rules-request
-
-    otel-scope backend_tcp_request
-        span "Backend TCP request" parent "Switching rules request"
-        finish "Switching rules request"
-        otel-event on-backend-tcp-request
-
-    otel-scope backend_http_request
-        span "Backend HTTP request" parent "Backend TCP request"
-        finish "Backend TCP request"
-        otel-event on-backend-http-request
-
-    otel-scope process_server_rules_request
-        span "Process server rules request" parent "Backend HTTP request"
-        finish "Backend HTTP request"
-        otel-event on-process-server-rules-request
-
-    otel-scope http_process_request
-        span "HTTP process request" parent "Process server rules request"
-        finish "Process server rules request"
-        otel-event on-http-process-request
-
-    otel-scope tcp_rdp_cookie_request
-        span "TCP RDP cookie request" parent "HTTP process request"
-        finish "HTTP process request"
-        otel-event on-tcp-rdp-cookie-request
-
-    otel-scope process_sticking_rules_request
-        span "Process sticking rules request" parent "TCP RDP cookie request"
-        finish "TCP RDP cookie request"
-        otel-event on-process-sticking-rules-request
-
-    otel-scope client_session_end
-        instrument update "haproxy.sessions.active"
-        finish "*req*"
-        otel-event on-client-session-end
-
-    otel-scope server_unavailable
-        finish "*req*" "*res*"
-        otel-event on-server-unavailable
-
-    otel-scope server_session_start
-        span "Server session" parent "HAProxy session"
-        link "HAProxy session" "Client session"
-        finish "Process sticking rules request"
-        otel-event on-server-session-start
-
-    otel-scope tcp_response
-        span "TCP response" parent "Server session"
-        otel-event on-tcp-response
-
-    otel-scope http_wait_response
-        span "HTTP wait response" parent "TCP response"
-        finish "TCP response"
-        otel-event on-http-wait-response
-
-    otel-scope process_store_rules_response
-        span "Process store rules response" parent "HTTP wait response"
-        finish "HTTP wait response"
-        otel-event on-process-store-rules-response
-
-    otel-scope http_response
-        instrument update "haproxy.http.requests" attr "phase" str("response")
-        instrument update "haproxy.http.latency"  attr "phase" str("response")
-        instrument update "haproxy.fe.connections"
-        span "HTTP response" parent "Process store rules response"
-            attribute "http.status_code" status
-        finish "Process store rules response"
-        otel-event on-http-response
-
-    otel-scope http_response-error
-        span "HTTP response"
-            status "error" str("http.status_code: ") status
-        otel-event on-http-response if !acl-http-status-ok
-
-    otel-scope server_session_end
-        finish "*res*"
-        otel-event on-server-session-end
diff --git a/addons/otel/test/sa/otel.yml b/addons/otel/test/sa/otel.yml
deleted file mode 100644 (file)
index b868f46..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-exporters:
-  exporter_traces_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file trace"
-    file_pattern:   "__sa_traces_log-%F-%N"
-    alias_pattern:  "__traces_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_traces_otlp_grpc:
-    type:                             otlp_grpc
-    thread_name:                      "OTLP/gRPC trace"
-    endpoint:                         "http://localhost:4317/v1/traces"
-    use_ssl_credentials:              false
-#   ssl_credentials_cacert_path:      ""
-#   ssl_credentials_cacert_as_string: ""
-#   ssl_client_key_path:              ""
-#   ssl_client_key_string:            ""
-#   ssl_client_cert_path:             ""
-#   ssl_client_cert_string:           ""
-#   timeout:                          10
-#   user_agent:                       ""
-#   max_threads:                      0
-#   compression:                      ""
-#   max_concurrent_requests:          0
-
-  exporter_traces_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP trace"
-#   background_thread_wait_for:  10000
-    endpoint:                    "http://localhost:4318/v1/traces"
-    content_type:                json
-    json_bytes_mapping:          hexid
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP traces test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP traces test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-#   ssl_ca_cert_path:            ""
-#   ssl_ca_cert_string:          ""
-#   ssl_client_key_path:         ""
-#   ssl_client_key_string:       ""
-#   ssl_client_cert_path:        ""
-#   ssl_client_cert_string:      ""
-#   ssl_min_tls:                 ""
-#   ssl_max_tls:                 ""
-#   ssl_cipher:                  ""
-#   ssl_cipher_suite:            ""
-#   compression:                 ""
-
-  exporter_traces_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_traces_ostream:
-    type:     ostream
-    filename: __sa_traces
-
-  exporter_traces_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_traces_zipkin:
-    type:           zipkin
-    endpoint:       "http://localhost:9411/api/v2/spans"
-    format:         json
-    service_name:   "zipkin-service"
-#   ipv4:           ""
-#   ipv6:           ""
-
-  exporter_metrics_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file metr"
-    file_pattern:   "__sa_metrics_log-%F-%N"
-    alias_pattern:  "__metrics_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_metrics_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC metr"
-    endpoint:            "http://localhost:4317/v1/metrics"
-    use_ssl_credentials: false
-
-  exporter_metrics_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP metr"
-#   background_thread_wait_for:  15000
-    endpoint:                    "http://localhost:4318/v1/metrics"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP metrics test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP metrics test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_metrics_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_metrics_ostream:
-    type:     ostream
-    filename: __sa_metrics
-
-  exporter_metrics_memory:
-    type:        memory
-    buffer_size: 256
-
-  exporter_logs_otlp_file:
-    type:           otlp_file
-    thread_name:    "OTLP/file logs"
-    file_pattern:   "__sa_logs_log-%F-%N"
-    alias_pattern:  "__logs_log-latest"
-    flush_interval: 30000000
-    flush_count:    256
-    file_size:      134217728
-    rotate_size:    5
-
-  exporter_logs_otlp_grpc:
-    type:                otlp_grpc
-    thread_name:         "OTLP/gRPC logs"
-    endpoint:            "http://localhost:4317/v1/logs"
-    use_ssl_credentials: false
-
-  exporter_logs_otlp_http:
-    type:                        otlp_http
-    thread_name:                 "OTLP/HTTP logs"
-#   background_thread_wait_for:  20000
-    endpoint:                    "http://localhost:4318/v1/logs"
-    content_type:                json
-    debug:                       false
-    timeout:                     10
-    http_headers:
-      - X-OTel-Header-1:         "OTLP HTTP logs test header #1"
-      - X-OTel-Header-2:         "OTLP HTTP logs test header #2"
-    max_concurrent_requests:     64
-    max_requests_per_connection: 8
-    ssl_insecure_skip_verify:    true
-
-  exporter_logs_dev_null:
-    type:     ostream
-    filename: /dev/null
-
-  exporter_logs_ostream:
-    type:     ostream
-    filename: __sa_logs
-
-  exporter_logs_elasticsearch:
-    type:             elasticsearch
-    host:             localhost
-    port:             9200
-    index:            logs
-    response_timeout: 30
-    debug:            false
-    http_headers:
-      - X-OTel-Header-1: "Elasticsearch logs test header #1"
-      - X-OTel-Header-2: "Elasticsearch logs test header #2"
-
-readers:
-  reader_metrics:
-    thread_name:     "reader metr"
-    export_interval: 10000
-    export_timeout:  5000
-
-samplers:
-  sampler_traces:
-#   type:  always_on
-#   type:  always_off
-#   type:  trace_id_ratio_based
-#   ratio: 1.0
-    type:     parent_based
-    delegate: always_on
-
-processors:
-  processor_traces_batch:
-    type:                  batch
-    thread_name:           "proc/batch trac"
-    # Note: when the queue is half full, a preemptive notification is sent
-    # to start the export call.
-    max_queue_size:        2048
-    # Time interval (in ms) between two consecutive exports
-    schedule_delay:        5000
-    # Export 'max_export_batch_size' after every `schedule_delay' milliseconds.
-    max_export_batch_size: 512
-
-  processor_traces_single:
-    type:                  single
-
-  processor_logs_batch:
-    type:                  batch
-    thread_name:           "proc/batch logs"
-    max_queue_size:        2048
-    schedule_delay:        5000
-    max_export_batch_size: 512
-
-  processor_logs_single:
-    type:                  single
-
-providers:
-  provider_traces:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-sa"
-      - service.name:        "sa"
-      - service.namespace:   "HAProxy traces test"
-
-  provider_metrics:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-sa"
-      - service.name:        "sa"
-      - service.namespace:   "HAProxy metrics test"
-
-  provider_logs:
-    resources:
-      - service.version:     "1.0.0"
-      - service.instance.id: "id-sa"
-      - service.name:        "sa"
-      - service.namespace:   "HAProxy logs test"
-
-signals:
-  traces:
-    scope_name: "HAProxy OTEL - traces"
-    exporters:  exporter_traces_otlp_http
-    samplers:   sampler_traces
-    processors: processor_traces_batch
-    providers:  provider_traces
-
-  metrics:
-    scope_name: "HAProxy OTEL - metrics"
-    exporters:  exporter_metrics_otlp_http
-    readers:    reader_metrics
-    providers:  provider_metrics
-
-  logs:
-    scope_name: "HAProxy OTEL - logs"
-    exporters:  exporter_logs_otlp_http
-    processors: processor_logs_batch
-    providers:  provider_logs
diff --git a/addons/otel/test/test-speed.sh b/addons/otel/test/test-speed.sh
deleted file mode 100755 (executable)
index 7f96984..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/bin/sh -u
-#
-                __=    # echo
-        SH_ARG_CFG=
-        SH_ARG_DIR=
-       SH_ARG_RATE="100.0 75.0 50.0 25.0 10.0 2.5 0.0 disabled off"
-   SH_ARG_DURATION="300"
-          SH_NAME="$(basename "${0}")"
-        SH_LOG_DIR="_logs"
-SH_HAPROXY_PIDFILE="${SH_LOG_DIR}/haproxy.pid"
-  SH_HTTPD_PIDFILE="${SH_LOG_DIR}/thttpd.pid"
-      SH_USAGE_MSG="usage: ${SH_NAME} [-d duration] [-h] [-r rate-limits] cfg [dir]"
-
-
-sh_exit ()
-{
-       sh_backup_clean "${SH_ARG_DIR}"
-
-       test -z "${2:-}" && {
-               echo
-               echo "Script killed!"
-       }
-
-       test -n "${1:-}" && {
-               echo
-               echo "${1}"
-               echo
-       }
-
-       ${__} sh_httpd_stop
-       rmdir -p "${SH_LOG_DIR}" 2>/dev/null
-       exit ${2:-64}
-}
-
-sh_backup_make()
-{
-       _arg_dir="${1}"
-       _var_file=
-
-       for _var_file in haproxy.cfg otel.cfg otel.yml; do
-               test -e "${_arg_dir}/${_var_file}.orig" || cp -af "${_arg_dir}/${_var_file}" "${_arg_dir}/${_var_file}.orig"
-       done
-
-       test "${_arg_dir}" = "fe" && sh_backup_make "be"
-}
-
-sh_backup_clean()
-{
-       _arg_dir="${1}"
-       _var_file=
-
-       for _var_file in haproxy.cfg otel.cfg otel.yml; do
-               test -e "${_arg_dir}/${_var_file}.orig" && mv "${_arg_dir}/${_var_file}.orig" "${_arg_dir}/${_var_file}"
-       done
-
-       test "${_arg_dir}" = "fe" && sh_backup_clean "be"
-}
-
-sh_httpd_run ()
-{
-
-       test -e "${SH_HTTPD_PIDFILE}" && return
-
-       thttpd -p 8000 -d . -nos -nov -l /dev/null -i "${SH_HTTPD_PIDFILE}"
-}
-
-sh_httpd_stop ()
-{
-       test -e "${SH_HTTPD_PIDFILE}" || return
-
-       kill -TERM "$(cat ${SH_HTTPD_PIDFILE})"
-       rm "${SH_HTTPD_PIDFILE}"
-}
-
-sh_haproxy_run ()
-{
-       _arg_cfg="${1}"
-       _arg_dir="${2}"
-       _arg_ratio="${3}"
-       _var_sed_haproxy=
-       _var_sed_otel=
-       _var_sed_yml="s/\(exporters: *exporter_[a-z]*_\).*/\1dev_null/g"
-
-       if test "${_arg_ratio}" = "disabled"; then
-               _var_sed_otel="s/no \(option disabled\)/\1/"
-       elif test "${_arg_ratio}" = "off"; then
-               _var_sed_haproxy="s/^\(.* filter opentelemetry .*\)/#\1/g; s/^\(.* otel-group .*\)/#\1/g"
-       else
-               _var_sed_otel="s/\(rate-limit\) 100.0/\1 ${_arg_ratio}/"
-       fi
-
-       sed "${_var_sed_haproxy}" "${_arg_dir}/haproxy.cfg.orig" > "${_arg_dir}/haproxy.cfg"
-       sed "${_var_sed_otel}"    "${_arg_dir}/otel.cfg.orig"    > "${_arg_dir}/otel.cfg"
-       sed "${_var_sed_yml}"     "${_arg_dir}/otel.yml.orig"    > "${_arg_dir}/otel.yml"
-
-       if test "${_arg_dir}" = "fe"; then
-               sed "${_var_sed_yml}" "be/otel.yml.orig" > "be/otel.yml"
-
-               if test "${_arg_ratio}" = "disabled" -o "${_arg_ratio}" = "off"; then
-                       sed "${_var_sed_haproxy}" "be/haproxy.cfg.orig" > "be/haproxy.cfg"
-                       sed "${_var_sed_otel}"    "be/otel.cfg.orig"    > "be/otel.cfg"
-               fi
-       fi
-
-       ./run-${_arg_cfg}.sh "" "${SH_HAPROXY_PIDFILE}" &
-       sleep 5
-}
-
-sh_haproxy_stop ()
-{
-       # HAProxy does not create a pidfile if it is not running in daemon mode,
-       # this is not used but is left regardless.
-       #
-       if test -e "${SH_HAPROXY_PIDFILE}"; then
-               kill -TERM "$(cat ${SH_HAPROXY_PIDFILE})"
-               rm "${SH_HAPROXY_PIDFILE}"
-       fi
-
-       pkill --signal SIGUSR1 haproxy
-       wait
-}
-
-sh_wrk_run ()
-{
-       _arg_ratio="${1}"
-
-       echo "--- rate-limit ${_arg_ratio} --------------------------------------------------"
-       wrk -c8 -d${SH_ARG_DURATION} -t8 --latency http://localhost:10080/index.html
-       echo "----------------------------------------------------------------------"
-       echo
-
-       sleep 10
-}
-
-
-while getopts d:hr: _var_getopt; do
-       case "${_var_getopt}" in
-         d)    SH_ARG_DURATION="${OPTARG}" ;;
-         h)    sh_exit "${SH_USAGE_MSG}" 0 ;;
-         r)    SH_ARG_RATE="${OPTARG}" ;;
-         \?)   sh_exit "${SH_USAGE_MSG}" 64
-       esac
-done
-
-shift $(expr ${OPTIND} - 1)
-SH_ARG_CFG="${1:-}"
-SH_ARG_DIR="${2:-${SH_ARG_CFG}}"
-
-
-command -v thttpd >/dev/null 2>&1 || sh_exit "thttpd: command not found" 5
-command -v wrk >/dev/null 2>&1    || sh_exit "wrk: command not found" 6
-
-test -z "${SH_ARG_CFG}" -o -z "${SH_ARG_DIR}" && sh_exit "${SH_USAGE_MSG}" 64
-mkdir -p "${SH_LOG_DIR}" || sh_exit "${SH_LOG_DIR}: Cannot create log directory" 1
-
-if test "${SH_ARG_CFG}" = "all"; then
-       _var_args="-r ${SH_ARG_RATE}"
-       "${0}" "${_var_args}" sa sa
-       "${0}" "${_var_args}" cmp cmp
-       "${0}" "${_var_args}" ctx ctx
-       "${0}" "${_var_args}" fe-be fe
-       exit 0
-elif test "${SH_ARG_CFG}" = "fe-be"; then
-       SH_ARG_DIR="fe"
-fi
-
-test -f "run-${SH_ARG_CFG}.sh" || sh_exit "run-${SH_ARG_CFG}.sh: No such test script" 2
-test -d "${SH_ARG_DIR}"        || sh_exit "${SH_ARG_DIR}: No such directory" 3
-
-trap sh_exit INT TERM
-
-echo "Running speed test ${SH_ARG_CFG}, start at $(date +"%F %T")"
-exec 1>"${SH_LOG_DIR}/README-speed-${SH_ARG_CFG}"
-
-${__} sh_backup_make "${SH_ARG_DIR}"
-${__} sh_httpd_run
-for _var_rate in ${SH_ARG_RATE}; do
-       ${__} sh_haproxy_run "${SH_ARG_CFG}" "${SH_ARG_DIR}" "${_var_rate}"
-       ${__} sh_wrk_run "${_var_rate}"
-       ${__} sh_haproxy_stop
-done
-sh_exit "" 0