mirror of
https://github.com/haproxy/haproxy.git
synced 2026-04-15 21:59:41 -04:00
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
This commit is contained in:
parent
b8145fa5d4
commit
cd14abf9f3
13 changed files with 932 additions and 1 deletions
12
Makefile
12
Makefile
|
|
@ -60,6 +60,7 @@
|
|||
# USE_OBSOLETE_LINKER : use when the linker fails to emit __start_init/__stop_init
|
||||
# USE_THREAD_DUMP : use the more advanced thread state dump system. Automatic.
|
||||
# USE_OT : enable the OpenTracing filter
|
||||
# USE_OTEL : enable the OpenTelemetry filter
|
||||
# USE_MEMORY_PROFILING : enable the memory profiler. Linux-glibc only.
|
||||
# USE_LIBATOMIC : force to link with/without libatomic. Automatic.
|
||||
# USE_PTHREAD_EMULATION : replace pthread's rwlocks with ours
|
||||
|
|
@ -128,6 +129,10 @@
|
|||
# OT_LIB : force the lib path to libopentracing-c-wrapper
|
||||
# OT_RUNPATH : add RUNPATH for libopentracing-c-wrapper to haproxy executable
|
||||
# OT_USE_VARS : allows the use of variables for the OpenTracing context
|
||||
# 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 RUNPATH for libopentelemetry-c-wrapper to haproxy executable
|
||||
# IGNOREGIT : ignore GIT commit versions if set.
|
||||
# VERSION : force haproxy version reporting.
|
||||
# SUBVERS : add a sub-version (eg: platform, model, ...).
|
||||
|
|
@ -347,7 +352,7 @@ use_opts = USE_EPOLL USE_KQUEUE USE_NETFILTER USE_POLL \
|
|||
USE_CPU_AFFINITY USE_TFO USE_NS USE_DL USE_RT USE_LIBATOMIC \
|
||||
USE_MATH USE_DEVICEATLAS USE_51DEGREES \
|
||||
USE_WURFL USE_OBSOLETE_LINKER USE_PRCTL USE_PROCCTL \
|
||||
USE_THREAD_DUMP USE_EVPORTS USE_OT USE_QUIC USE_PROMEX \
|
||||
USE_THREAD_DUMP USE_EVPORTS USE_OT USE_OTEL USE_QUIC USE_PROMEX \
|
||||
USE_MEMORY_PROFILING USE_SHM_OPEN \
|
||||
USE_STATIC_PCRE USE_STATIC_PCRE2 \
|
||||
USE_PCRE USE_PCRE_JIT USE_PCRE2 USE_PCRE2_JIT \
|
||||
|
|
@ -862,6 +867,10 @@ ifneq ($(USE_OT:0=),)
|
|||
include addons/ot/Makefile
|
||||
endif
|
||||
|
||||
ifneq ($(USE_OTEL:0=),)
|
||||
include addons/otel/Makefile
|
||||
endif
|
||||
|
||||
# better keep this one close to the end, as several libs above may need it
|
||||
ifneq ($(USE_DL:0=),)
|
||||
DL_LDFLAGS = -ldl
|
||||
|
|
@ -1170,6 +1179,7 @@ clean:
|
|||
$(Q)rm -f addons/51degrees/*.[oas] addons/51degrees/dummy/*.[oas] addons/51degrees/dummy/*/*.[oas]
|
||||
$(Q)rm -f addons/deviceatlas/*.[oas] addons/deviceatlas/dummy/*.[oas] addons/deviceatlas/dummy/*.o
|
||||
$(Q)rm -f addons/deviceatlas/dummy/Os/*.o
|
||||
$(Q)rm -f addons/otel/src/*.[oas]
|
||||
$(Q)rm -f addons/ot/src/*.[oas]
|
||||
$(Q)rm -f addons/wurfl/*.[oas] addons/wurfl/dummy/*.[oas]
|
||||
$(Q)rm -f admin/*/*.[oas] admin/*/*/*.[oas]
|
||||
|
|
|
|||
1
addons/otel/AUTHORS
Normal file
1
addons/otel/AUTHORS
Normal file
|
|
@ -0,0 +1 @@
|
|||
Miroslav Zagorac <mzagorac@haproxy.com>
|
||||
1
addons/otel/MAINTAINERS
Normal file
1
addons/otel/MAINTAINERS
Normal file
|
|
@ -0,0 +1 @@
|
|||
Miroslav Zagorac <mzagorac@haproxy.com>
|
||||
57
addons/otel/Makefile
Normal file
57
addons/otel/Makefile
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# 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_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/filter.o \
|
||||
addons/otel/src/parser.o
|
||||
|
||||
OTEL_CFLAGS := $(OTEL_CFLAGS) -Iaddons/otel/include $(OTEL_DEFINE)
|
||||
17
addons/otel/include/config.h
Normal file
17
addons/otel/include/config.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef _OTEL_CONFIG_H_
|
||||
#define _OTEL_CONFIG_H_
|
||||
|
||||
#define FLT_OTEL_DEBUG_LEVEL 0b11101111111 /* Default debug bitmask. */
|
||||
|
||||
#endif /* _OTEL_CONFIG_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
18
addons/otel/include/define.h
Normal file
18
addons/otel/include/define.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef _OTEL_DEFINE_H_
|
||||
#define _OTEL_DEFINE_H_
|
||||
|
||||
/* 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)
|
||||
|
||||
#endif /* _OTEL_DEFINE_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
26
addons/otel/include/filter.h
Normal file
26
addons/otel/include/filter.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef _OTEL_FILTER_H_
|
||||
#define _OTEL_FILTER_H_
|
||||
|
||||
/* 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,
|
||||
};
|
||||
|
||||
|
||||
extern const char *otel_flt_id;
|
||||
|
||||
#endif /* _OTEL_FILTER_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
42
addons/otel/include/include.h
Normal file
42
addons/otel/include/include.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/* 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>
|
||||
|
||||
#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 "define.h"
|
||||
#include "filter.h"
|
||||
#include "parser.h"
|
||||
|
||||
#endif /* _OTEL_INCLUDE_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
18
addons/otel/include/parser.h
Normal file
18
addons/otel/include/parser.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef _OTEL_PARSER_H_
|
||||
#define _OTEL_PARSER_H_
|
||||
|
||||
#define FLT_OTEL_SCOPE "OTEL"
|
||||
#define FLT_OTEL_OPT_NAME "opentelemetry"
|
||||
|
||||
#endif /* _OTEL_PARSER_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
666
addons/otel/src/filter.c
Normal file
666
addons/otel/src/filter.c
Normal file
|
|
@ -0,0 +1,666 @@
|
|||
/* 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";
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", p, fconf);
|
||||
|
||||
OTELC_RETURN_INT(0);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", p, fconf);
|
||||
|
||||
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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", p, fconf);
|
||||
|
||||
OTELC_RETURN_INT(0);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", p, fconf);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
#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 have 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", s, f);
|
||||
|
||||
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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", s, f);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p", s, f, be);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", s, f);
|
||||
|
||||
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_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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", s, f);
|
||||
|
||||
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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p", s, f, chn);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p, 0x%08x", s, f, chn, an_bit);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p, 0x%08x", s, f, chn, an_bit);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p", s, f, chn);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p", s, f, msg);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
#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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p, %u, %u", s, f, msg, offset, len);
|
||||
|
||||
OTELC_RETURN_INT(len);
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p", s, f, msg);
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %hd, %p", s, f, status, msg);
|
||||
|
||||
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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p", s, f, msg);
|
||||
|
||||
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)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p, %u, %u", s, f, chn, offset, len);
|
||||
|
||||
OTELC_RETURN_INT(len);
|
||||
}
|
||||
|
||||
#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
|
||||
*/
|
||||
73
addons/otel/src/parser.c
Normal file
73
addons/otel/src/parser.c
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/* 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
|
||||
|
||||
|
||||
/***
|
||||
* 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.
|
||||
* Verifies that insecure-fork-wanted is enabled, then 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)
|
||||
{
|
||||
int 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)
|
||||
OTELC_RETURN_INT(retval);
|
||||
);
|
||||
#endif
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
@ -92,6 +92,7 @@ enum {
|
|||
ARGC_TCK, /* tcp-check expression */
|
||||
ARGC_CFG, /* configuration expression */
|
||||
ARGC_CLI, /* CLI expression*/
|
||||
ARGC_OTEL, /* opentelemetry scope args */
|
||||
};
|
||||
|
||||
/* flags used when compiling and executing regex */
|
||||
|
|
|
|||
|
|
@ -1471,6 +1471,7 @@ int smp_resolve_args(struct proxy *p, char **err)
|
|||
case ARGC_TCK: where = "in tcp-check expression in"; break;
|
||||
case ARGC_CFG: where = "in configuration expression in"; break;
|
||||
case ARGC_CLI: where = "in CLI expression in"; break;
|
||||
case ARGC_OTEL: where = "in otel-scope directive in"; break;
|
||||
}
|
||||
|
||||
/* set a few default settings */
|
||||
|
|
|
|||
Loading…
Reference in a new issue