haproxy/addons/otel/include/define.h

99 lines
4.5 KiB
C
Raw Permalink Normal View History

MEDIUM: otel: added OpenTelemetry filter skeleton The OpenTelemetry (OTel) filter enables distributed tracing of requests across service boundaries, export of metrics such as request rates, latencies and error counts, and structured logging tied to trace context, giving operators a unified view of HAProxy traffic through any OpenTelemetry-compatible backend. The OTel filter is implemented using the standard HAProxy stream filter API. Stream filters attach to proxies and intercept traffic at each stage of processing: they receive callbacks on stream creation and destruction, channel analyzer events, HTTP header and payload processing, and TCP data forwarding. This allows the filter to collect telemetry data at every stage of the request/response lifecycle without modifying the core proxy logic. This commit added the minimum set of files required for the filter to compile: the addon Makefile with pkg-config-based detection of the opentelemetry-c-wrapper library, header files with configuration constants, utility macros and type definitions, and the source files containing stub filter operation callbacks registered through flt_otel_ops and the "opentelemetry" keyword parser entry point. The filter uses the opentelemetry-c-wrapper library from HAProxy Technologies, which provides a C interface to the OpenTelemetry C++ SDK. This wrapper allows HAProxy, a C codebase, to leverage the full OpenTelemetry observability pipeline without direct C++ dependencies in the HAProxy source tree. https://github.com/haproxytech/opentelemetry-c-wrapper https://github.com/open-telemetry/opentelemetry-cpp Build options: USE_OTEL - enable the OpenTelemetry filter OTEL_DEBUG - compile the filter in debug mode OTEL_INC - force the include path to the C wrapper OTEL_LIB - force the library path to the C wrapper OTEL_RUNPATH - add the C wrapper RUNPATH to the executable Example build with OTel and debug enabled: make -j8 USE_OTEL=1 OTEL_DEBUG=1 TARGET=linux-glibc
2026-04-13 01:48:51 -04:00
/* 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))
MEDIUM: otel: added configuration and utility layer Added the configuration structures that model the OTel filter's instrumentation hierarchy and the utility functions that support the configuration parser. The configuration is organized as a tree rooted at flt_otel_conf, which holds the proxy reference, filter identity, and lists of groups and scopes. Below it, flt_otel_conf_instr carries the instrumentation settings: tracer handle, rate limiting, hard-error mode, logging state, channel analyzers, and placeholder references to groups and scopes. Groups (flt_otel_conf_group) aggregate scopes by name. Scopes (flt_otel_conf_scope) bind an event to its ACL condition, span context declarations, span definitions and a list of spans scheduled for finishing. Spans (flt_otel_conf_span) carry attributes, events, baggages and status entries, each represented as flt_otel_conf_sample structures that pair a key with concatenated sample-expression arguments. All configuration types share a common header macro (FLT_OTEL_CONF_HDR) that embeds an identifier string, its length, a configuration line number, and a list link. Their init and free functions are generated by the FLT_OTEL_CONF_FUNC_INIT and FLT_OTEL_CONF_FUNC_FREE macros in conf_funcs.h, with per-type custom initialization and cleanup bodies. The utility layer in util.c provides argument counting and concatenation for the configuration parser, sample data to string conversion covering boolean, integer, IPv4, IPv6, string and HTTP method types, and debug helpers for dumping argument arrays and linked list state.
2026-04-12 01:30:57 -04:00
/* 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'); })
MEDIUM: otel: added CLI commands for runtime filter management Added HAProxy CLI commands that allow runtime inspection and modification of OTel filter settings without requiring a configuration reload. The new cli.c module registers CLI keywords under the "otel" prefix and implements the following commands: flt_otel_cli_parse_status() displays a comprehensive status report of all OTel filter instances including filter ID, proxy, disabled state, hard-error mode, logging state, rate limit, analyzer bits, and SDK diagnostic message count; flt_otel_cli_parse_disabled() enables or disables filtering across all instances; flt_otel_cli_parse_option() toggles the hard-error mode that controls whether errors disable the filter for a stream or are silently ignored; flt_otel_cli_parse_logging() manages the logging state with support for off, on, and dontlog-normal modes; flt_otel_cli_parse_rate() adjusts the sampling rate limit as a floating-point percentage; and flt_otel_cli_parse_debug() sets the debug verbosity level in debug builds. All modifications are applied atomically across every OTel filter instance in every proxy. The CLI initialization is called from flt_otel_ops_init() during filter startup via flt_otel_cli_init(), which registers the keyword table through cli_register_kw(). Supporting changes include the FLT_OTEL_U32_FLOAT macro for converting the internal uint32_t rate representation to a human-readable percentage, the FLT_OTEL_PROXIES_LIST_START/END iteration macros for traversing all OTel filter instances across the proxy list, and flt_otel_filters_dump() for debug logging of filter instances.
2026-04-12 05:31:30 -04:00
/* Convert a uint32_t rate value to a floating-point percentage. */
#define FLT_OTEL_U32_FLOAT(a) ((a) * 100.0 / UINT32_MAX)
MEDIUM: otel: added configuration and utility layer Added the configuration structures that model the OTel filter's instrumentation hierarchy and the utility functions that support the configuration parser. The configuration is organized as a tree rooted at flt_otel_conf, which holds the proxy reference, filter identity, and lists of groups and scopes. Below it, flt_otel_conf_instr carries the instrumentation settings: tracer handle, rate limiting, hard-error mode, logging state, channel analyzers, and placeholder references to groups and scopes. Groups (flt_otel_conf_group) aggregate scopes by name. Scopes (flt_otel_conf_scope) bind an event to its ACL condition, span context declarations, span definitions and a list of spans scheduled for finishing. Spans (flt_otel_conf_span) carry attributes, events, baggages and status entries, each represented as flt_otel_conf_sample structures that pair a key with concatenated sample-expression arguments. All configuration types share a common header macro (FLT_OTEL_CONF_HDR) that embeds an identifier string, its length, a configuration line number, and a list link. Their init and free functions are generated by the FLT_OTEL_CONF_FUNC_INIT and FLT_OTEL_CONF_FUNC_FREE macros in conf_funcs.h, with per-type custom initialization and cleanup bodies. The utility layer in util.c provides argument counting and concatenation for the configuration parser, sample data to string conversion covering boolean, integer, IPv4, IPv6, string and HTTP method types, and debug helpers for dumping argument arrays and linked list state.
2026-04-12 01:30:57 -04:00
/* 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))
MEDIUM: otel: added CLI commands for runtime filter management Added HAProxy CLI commands that allow runtime inspection and modification of OTel filter settings without requiring a configuration reload. The new cli.c module registers CLI keywords under the "otel" prefix and implements the following commands: flt_otel_cli_parse_status() displays a comprehensive status report of all OTel filter instances including filter ID, proxy, disabled state, hard-error mode, logging state, rate limit, analyzer bits, and SDK diagnostic message count; flt_otel_cli_parse_disabled() enables or disables filtering across all instances; flt_otel_cli_parse_option() toggles the hard-error mode that controls whether errors disable the filter for a stream or are silently ignored; flt_otel_cli_parse_logging() manages the logging state with support for off, on, and dontlog-normal modes; flt_otel_cli_parse_rate() adjusts the sampling rate limit as a floating-point percentage; and flt_otel_cli_parse_debug() sets the debug verbosity level in debug builds. All modifications are applied atomically across every OTel filter instance in every proxy. The CLI initialization is called from flt_otel_ops_init() during filter startup via flt_otel_cli_init(), which registers the keyword table through cli_register_kw(). Supporting changes include the FLT_OTEL_U32_FLOAT macro for converting the internal uint32_t rate representation to a human-readable percentage, the FLT_OTEL_PROXIES_LIST_START/END iteration macros for traversing all OTel filter instances across the proxy list, and flt_otel_filters_dump() for debug logging of filter instances.
2026-04-12 05:31:30 -04:00
#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")
MEDIUM: otel: added configuration and utility layer Added the configuration structures that model the OTel filter's instrumentation hierarchy and the utility functions that support the configuration parser. The configuration is organized as a tree rooted at flt_otel_conf, which holds the proxy reference, filter identity, and lists of groups and scopes. Below it, flt_otel_conf_instr carries the instrumentation settings: tracer handle, rate limiting, hard-error mode, logging state, channel analyzers, and placeholder references to groups and scopes. Groups (flt_otel_conf_group) aggregate scopes by name. Scopes (flt_otel_conf_scope) bind an event to its ACL condition, span context declarations, span definitions and a list of spans scheduled for finishing. Spans (flt_otel_conf_span) carry attributes, events, baggages and status entries, each represented as flt_otel_conf_sample structures that pair a key with concatenated sample-expression arguments. All configuration types share a common header macro (FLT_OTEL_CONF_HDR) that embeds an identifier string, its length, a configuration line number, and a list link. Their init and free functions are generated by the FLT_OTEL_CONF_FUNC_INIT and FLT_OTEL_CONF_FUNC_FREE macros in conf_funcs.h, with per-type custom initialization and cleanup bodies. The utility layer in util.c provides argument counting and concatenation for the configuration parser, sample data to string conversion covering boolean, integer, IPv4, IPv6, string and HTTP method types, and debug helpers for dumping argument arrays and linked list state.
2026-04-12 01:30:57 -04:00
/* Compile-time string length excluding the null terminator. */
#define FLT_OTEL_STR_SIZE(a) (sizeof(a) - 1)
MEDIUM: otel: implemented scope execution and span management Implemented the scope execution engine that creates OTel spans, evaluates sample expressions to collect telemetry data, and manages span lifecycle during request and response processing. The scope runner flt_otel_scope_run() was expanded from a stub into a complete implementation that evaluates ACL conditions on the scope, extracts span contexts from HTTP headers when configured, iterates over the scope's span definitions calling flt_otel_scope_run_span() for each, marks and finishes completed spans, and cleans up unused runtime resources. The span runner flt_otel_scope_run_span() creates OTel spans via the tracer with optional parent references (from other spans or extracted contexts), collects telemetry by calling flt_otel_sample_add() for each configured attribute, event, baggage and status entry, then applies the collected data to the span (attributes, events with their own key-value arrays, baggage items, and status code with description) and injects the span context into HTTP headers when configured. The sample evaluation layer converts HAProxy sample expressions into OTel telemetry data. flt_otel_sample_add() evaluates each sample expression against the stream, converts the result via flt_otel_sample_to_value() which preserves native types (booleans as OTELC_VALUE_BOOL, integers as OTELC_VALUE_INT64, all others as strings), and routes the key-value pair to the appropriate collector based on the sample type (attribute, event, baggage, or status). The key-value arrays grow dynamically using the FLT_OTEL_ATTR_INIT_SIZE and FLT_OTEL_ATTR_INC_SIZE constants. Span finishing is handled in two phases: flt_otel_scope_finish_mark() marks spans and contexts for completion using exact name matching or wildcards ("*" for all, "*req*" for request-direction, "*res*" for response-direction), and flt_otel_scope_finish_marked() ends all marked spans with a common monotonic timestamp and destroys their contexts.
2026-04-12 04:58:38 -04:00
/* 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
MEDIUM: otel: added OpenTelemetry filter skeleton The OpenTelemetry (OTel) filter enables distributed tracing of requests across service boundaries, export of metrics such as request rates, latencies and error counts, and structured logging tied to trace context, giving operators a unified view of HAProxy traffic through any OpenTelemetry-compatible backend. The OTel filter is implemented using the standard HAProxy stream filter API. Stream filters attach to proxies and intercept traffic at each stage of processing: they receive callbacks on stream creation and destruction, channel analyzer events, HTTP header and payload processing, and TCP data forwarding. This allows the filter to collect telemetry data at every stage of the request/response lifecycle without modifying the core proxy logic. This commit added the minimum set of files required for the filter to compile: the addon Makefile with pkg-config-based detection of the opentelemetry-c-wrapper library, header files with configuration constants, utility macros and type definitions, and the source files containing stub filter operation callbacks registered through flt_otel_ops and the "opentelemetry" keyword parser entry point. The filter uses the opentelemetry-c-wrapper library from HAProxy Technologies, which provides a C interface to the OpenTelemetry C++ SDK. This wrapper allows HAProxy, a C codebase, to leverage the full OpenTelemetry observability pipeline without direct C++ dependencies in the HAProxy source tree. https://github.com/haproxytech/opentelemetry-c-wrapper https://github.com/open-telemetry/opentelemetry-cpp Build options: USE_OTEL - enable the OpenTelemetry filter OTEL_DEBUG - compile the filter in debug mode OTEL_INC - force the include path to the C wrapper OTEL_LIB - force the library path to the C wrapper OTEL_RUNPATH - add the C wrapper RUNPATH to the executable Example build with OTel and debug enabled: make -j8 USE_OTEL=1 OTEL_DEBUG=1 TARGET=linux-glibc
2026-04-13 01:48:51 -04:00
/* 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)
MEDIUM: otel: added configuration and utility layer Added the configuration structures that model the OTel filter's instrumentation hierarchy and the utility functions that support the configuration parser. The configuration is organized as a tree rooted at flt_otel_conf, which holds the proxy reference, filter identity, and lists of groups and scopes. Below it, flt_otel_conf_instr carries the instrumentation settings: tracer handle, rate limiting, hard-error mode, logging state, channel analyzers, and placeholder references to groups and scopes. Groups (flt_otel_conf_group) aggregate scopes by name. Scopes (flt_otel_conf_scope) bind an event to its ACL condition, span context declarations, span definitions and a list of spans scheduled for finishing. Spans (flt_otel_conf_span) carry attributes, events, baggages and status entries, each represented as flt_otel_conf_sample structures that pair a key with concatenated sample-expression arguments. All configuration types share a common header macro (FLT_OTEL_CONF_HDR) that embeds an identifier string, its length, a configuration line number, and a list link. Their init and free functions are generated by the FLT_OTEL_CONF_FUNC_INIT and FLT_OTEL_CONF_FUNC_FREE macros in conf_funcs.h, with per-type custom initialization and cleanup bodies. The utility layer in util.c provides argument counting and concatenation for the configuration parser, sample data to string conversion covering boolean, integer, IPv4, IPv6, string and HTTP method types, and debug helpers for dumping argument arrays and linked list state.
2026-04-12 01:30:57 -04:00
/* 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)
MEDIUM: otel: added OpenTelemetry filter skeleton The OpenTelemetry (OTel) filter enables distributed tracing of requests across service boundaries, export of metrics such as request rates, latencies and error counts, and structured logging tied to trace context, giving operators a unified view of HAProxy traffic through any OpenTelemetry-compatible backend. The OTel filter is implemented using the standard HAProxy stream filter API. Stream filters attach to proxies and intercept traffic at each stage of processing: they receive callbacks on stream creation and destruction, channel analyzer events, HTTP header and payload processing, and TCP data forwarding. This allows the filter to collect telemetry data at every stage of the request/response lifecycle without modifying the core proxy logic. This commit added the minimum set of files required for the filter to compile: the addon Makefile with pkg-config-based detection of the opentelemetry-c-wrapper library, header files with configuration constants, utility macros and type definitions, and the source files containing stub filter operation callbacks registered through flt_otel_ops and the "opentelemetry" keyword parser entry point. The filter uses the opentelemetry-c-wrapper library from HAProxy Technologies, which provides a C interface to the OpenTelemetry C++ SDK. This wrapper allows HAProxy, a C codebase, to leverage the full OpenTelemetry observability pipeline without direct C++ dependencies in the HAProxy source tree. https://github.com/haproxytech/opentelemetry-c-wrapper https://github.com/open-telemetry/opentelemetry-cpp Build options: USE_OTEL - enable the OpenTelemetry filter OTEL_DEBUG - compile the filter in debug mode OTEL_INC - force the include path to the C wrapper OTEL_LIB - force the library path to the C wrapper OTEL_RUNPATH - add the C wrapper RUNPATH to the executable Example build with OTel and debug enabled: make -j8 USE_OTEL=1 OTEL_DEBUG=1 TARGET=linux-glibc
2026-04-13 01:48:51 -04:00
#endif /* _OTEL_DEFINE_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/