diff --git a/addons/otel/Makefile b/addons/otel/Makefile index feddc6596..53c17b2fe 100644 --- a/addons/otel/Makefile +++ b/addons/otel/Makefile @@ -52,6 +52,7 @@ endif OPTIONS_OBJS += \ addons/otel/src/conf.o \ + addons/otel/src/event.o \ addons/otel/src/filter.o \ addons/otel/src/parser.o \ addons/otel/src/util.o diff --git a/addons/otel/include/event.h b/addons/otel/include/event.h new file mode 100644 index 000000000..8553a4ec4 --- /dev/null +++ b/addons/otel/include/event.h @@ -0,0 +1,135 @@ +/* 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 +}; + +/* 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. */ +}; + + +/* 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]; + +#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 index 2dbca001c..713eea4d0 100644 --- a/addons/otel/include/filter.h +++ b/addons/otel/include/filter.h @@ -3,6 +3,12 @@ #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_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, @@ -12,7 +18,8 @@ enum FLT_OTEL_RET_enum { }; -extern const char *otel_flt_id; +extern const char *otel_flt_id; +extern struct flt_ops flt_otel_ops; #endif /* _OTEL_FILTER_H_ */ diff --git a/addons/otel/include/include.h b/addons/otel/include/include.h index a3e6c500f..e57d305a9 100644 --- a/addons/otel/include/include.h +++ b/addons/otel/include/include.h @@ -27,6 +27,7 @@ #include "config.h" #include "define.h" +#include "event.h" #include "conf.h" #include "conf_funcs.h" #include "filter.h" diff --git a/addons/otel/include/parser.h b/addons/otel/include/parser.h index d0c42c2dd..7ef1954e3 100644 --- a/addons/otel/include/parser.h +++ b/addons/otel/include/parser.h @@ -3,8 +3,163 @@ #ifndef _OTEL_PARSER_H_ #define _OTEL_PARSER_H_ -#define FLT_OTEL_SCOPE "OTEL" -#define FLT_OTEL_OPT_NAME "opentelemetry" +#define FLT_OTEL_SCOPE "OTEL" + +/* + * filter FLT_OTEL_OPT_NAME FLT_OTEL_OPT_FILTER_ID FLT_OTEL_OPT_CONFIG + */ +#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_CTX_AUTONAME "-" +#define FLT_OTEL_PARSE_CTX_IGNORE_NAME '-' +#define FLT_OTEL_PARSE_CTX_USE_HEADERS "use-headers" +#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", " ") \ + FLT_OTEL_PARSE_INSTR_DEF( ACL, 0, CHAR, 3, 0, "acl", " [flags] [operator] ...") \ + FLT_OTEL_PARSE_INSTR_DEF( LOG, 0, CHAR, 2, 0, "log", " { global | [len ] [format ] [ []] }") \ + FLT_OTEL_PARSE_INSTR_DEF( CONFIG, 0, NONE, 2, 2, "config", " ") \ + FLT_OTEL_PARSE_INSTR_DEF( GROUPS, 0, NONE, 2, 0, "groups", " ...") \ + FLT_OTEL_PARSE_INSTR_DEF( SCOPES, 0, NONE, 2, 0, "scopes", " ...") \ + FLT_OTEL_PARSE_INSTR_DEF( RATE_LIMIT, 0, NONE, 2, 2, "rate-limit", " ") \ + 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", " ") + +#define FLT_OTEL_PARSE_GROUP_DEFINES \ + FLT_OTEL_PARSE_GROUP_DEF( ID, 0, CHAR, 2, 2, "otel-group", " ") \ + FLT_OTEL_PARSE_GROUP_DEF(SCOPES, 0, NONE, 2, 0, "scopes", " ...") + +#define FLT_OTEL_PARSE_SCOPE_INJECT_HELP " [use-headers]" +#define FLT_OTEL_PARSE_SCOPE_EXTRACT_HELP " [use-headers]" + +/* + * The first argument of the FLT_OTEL_PARSE_SCOPE_STATUS_DEF() macro is defined + * as otelc_span_status_t in . + */ +#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" ) + +/* + * 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", " ") \ + FLT_OTEL_PARSE_SCOPE_DEF( SPAN, 0, NONE, 2, 7, "span", " [] [root]") \ + FLT_OTEL_PARSE_SCOPE_DEF( ATTRIBUTE, 1, NONE, 3, 0, "attribute", " ...") \ + FLT_OTEL_PARSE_SCOPE_DEF( EVENT, 1, NONE, 4, 0, "event", " ...") \ + FLT_OTEL_PARSE_SCOPE_DEF( BAGGAGE, 1, VAR, 3, 0, "baggage", " ...") \ + 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", " [ ...]") \ + FLT_OTEL_PARSE_SCOPE_DEF( FINISH, 0, NONE, 2, 0, "finish", " ...") \ + FLT_OTEL_PARSE_SCOPE_DEF(IDLE_TIMEOUT, 0, NONE, 2, 2, "idle-timeout", "