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
------------------------------------------------------------------------------

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                      (log.proxy.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_exception        (exceptions list)
      |       +-- flt_otel_conf_sample       (message and attributes lists)
      |           +-- 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_sample               (set_vars list)
      |   +-- flt_otel_conf_sample_expr      (exprs list)
      +-- flt_otel_conf_set_var_ctx          (set_var_ctxs list)
      +-- flt_otel_conf_unset_var            (unset_vars list)
      |   +-- flt_otel_conf_str              (vars 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_ops_check), these names are resolved to pointers to the actual
flt_otel_conf_group or flt_otel_conf_scope structures via the ptr field.
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.
  flag_data_req          Request channel needs a data filter for http_end.
  flag_data_res          Response channel needs a data filter for http_end.
  flag_started           Atomic claim so the OTel SDK is started once.
  log                    Runtime-log emission state (struct flt_otel_log).
  n_harderr              Hard-error episodes (filter disabled), for the CLI.
  n_softerr              Soft-error occurrences (error swallowed), for the CLI.
  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).

The embedded flt_otel_log structure carries the runtime-log emission state:
the logging mode ('type', 0, 1 or 3), the log server list ('proxy', a HAProxy
proxy structure whose loggers list holds the configured targets), the sliding
emission-rate window ('rate'), the per-episode latch bits ('latch') and the
count of suppressed log lines ('suppressed').

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.
  flag_stop              Whether the scope stops tracing for the connection.
  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.
  stop_cond              ACL condition gating the stop (NULL if unconditional).
  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.
  set_vars               The list of set-var directives (conf_sample).
  set_var_ctxs           The list of set-var-ctx directives.
  unset_vars             The list of unset-var directives (conf_unset_var).

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.
  kind                       The span kind (default SERVER).
  links                      The set of linked span or context 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.
  exceptions                 Recorded exceptions (flt_otel_conf_exception).

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_exception

  FLT_OTEL_CONF_HDR(id)  Required by macro; member <id> is not used directly.
  type                   The exception type string ('exception.type').
  message                Optional message value (single conf_sample list).
  attributes             Additional event attributes (conf_sample list).
  cond                   Optional if/unless condition gating the record.

This structure backs the span 'exception' keyword: at runtime its type, the
evaluated message and the attributes are emitted via the record_exception()
operation as a span event named 'exception'.

4.7  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).
  cond                   Optional if/unless condition gating recording.

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.8  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.
  time                   Optional timestamp expression (single conf_sample).
  attributes             Log record attributes (flt_otel_conf_sample list).
  samples                Sample expressions for the body.
  cond                   Optional if/unless condition gating the record.

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.

The optional timestamp expression, set via the 'time' keyword, is stored as a
single-entry list of flt_otel_conf_sample with the unit selector (s, ms, us
or ns) packed into the sample's 'extra' data field as an OTELC_VALUE_INT32.
At runtime the sample is evaluated, normalised to int64, scaled by the chosen
unit, and packed into a struct timespec that becomes the event timestamp, while
the wall-clock value is passed as the observed timestamp.

4.9  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.10  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.
  time                    Optional per-event timestamp (single sample).
  cond                    Optional if/unless condition gating this item.

The extra field carries type-specific data: the event name strings (of type
OTELC_VALUE_DATA) for span events, status code integers (OTELC_VALUE_INT32)
for span statuses.

When the sample value argument begins with 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.  An explicit '%[ ... ]'
wrapper around the entire argument marks the inner string as a log-format string
that may itself contain HAProxy aliases such as %ci, %t or %ft; the outer '%['
and trailing ']' are stripped before parse_logformat_string() is called.  At
runtime, if the lf_used flag is true, the log-format expression is evaluated
via build_logline() instead of the sample expression list.

4.11  flt_otel_conf_sample_expr

  FLT_OTEL_CONF_HDR(fmt_expr)  The original expression format string.
  expr                         The sample expression (struct sample_expr).

4.12  flt_otel_conf_set_var_ctx

  FLT_OTEL_CONF_HDR(name)  The HAProxy variable name.
  ref                      The referenced span or context name.
  field                    FLT_OTEL_VAR_FIELD_* identifier.
  field_key                The baggage or tracestate key, or NULL.
  cond                     Optional if/unless condition gating the assignment.

This structure backs the set-var-ctx directive: it captures a field of a
referenced span or extracted context into a HAProxy variable at runtime.

4.13  flt_otel_conf_unset_var

  FLT_OTEL_CONF_HDR(id)  Required by macro; member <id> is not used directly.
  vars                   The variable names to remove (flt_otel_conf_str list).
  cond                   Optional if/unless condition gating the removal.

This structure backs the unset-var directive: it groups one or more variable
names with an optional condition, so the whole removal is gated as a unit.

4.14  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 and the unset-var name lists.
  flt_otel_conf_link  Span or context link (HDR field named "ref") with an
                      optional attributes sample list for key:value data.
  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, exceptions.
    Sets kind to OTELC_SPAN_KIND_SERVER.

  conf_exception:
    LIST_INIT for message, attributes.

  conf_scope:
    LIST_INIT for acls, contexts, spans, spans_to_finish, instruments,
    log_records, set_vars, set_var_ctxs, unset_vars.

  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 time, attributes, samples.

  conf_unset_var:
    LIST_INIT for vars.

  conf_instr:
    Sets rate_limit to FLT_OTEL_FLOAT_U32(100.0) (100%).  Calls init_new_proxy
    for log.proxy.  LIST_INIT for acls, ph_groups, ph_scopes.

Types with no custom body (hdr, str, link, ph, sample_expr, context,
set_var_ctx) 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, instrument samples, and set-var values.

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.  Destroys the time list (per-event timestamp sample) and
    frees the optional ACL condition.

  conf_sample_expr:
    Releases the HAProxy sample expression via release_sample_expr.

  conf_span:
    Frees ref_id and ctx_id strings.
    Destroys the links, attributes, events, baggages, statuses, and exceptions
    lists.

  conf_exception:
    Frees the type string.  Destroys the message and attributes lists and frees
    the optional ACL condition.

  conf_instrument:
    Frees description, unit, and bounds.  Destroys the samples list and the
    attributes list (the update-form attributes, stored as conf_sample
    entries).  Frees the optional ACL condition.

  conf_log_record:
    Frees event_name and span strings.  Destroys the time, attributes and
    samples lists.  Frees the optional ACL condition.

  conf_set_var_ctx:
    Frees the ref and field_key strings and the optional ACL condition.

  conf_unset_var:
    Destroys the vars list and frees the optional ACL condition.

  conf_scope:
    Prunes and frees each ACL entry.  Frees the ACL condition via free_acl_cond.
    Destroys contexts, spans, spans_to_finish, instruments, log_records,
    set_vars, set_var_ctxs, and unset_vars 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 log.proxy.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        ref        macro   attributes
  conf_ph          id         macro   (none)
  conf_sample_expr fmt_expr   macro   (none)
  conf_sample      key        macro   exprs, lf_expr, time, cond
  conf_sample (ex) key        manual  extra, fmt_string, exprs
  conf_context     id         macro   (none)
  conf_span        id         macro   sub-lists
  conf_exception   id         macro   message, attributes
  conf_instrument  id         macro   idx, type, samples
  conf_log_record  id         macro   time, attributes, samples
  conf_set_var_ctx name       macro   (none)
  conf_unset_var   id         macro   vars
  conf_scope       id         macro   sub-lists
  conf_group       id         macro   ph_scopes
  conf_instr       id         macro   rate_limit, log.proxy, acls, ph_groups, ph_scopes
