mirror of
https://github.com/haproxy/haproxy.git
synced 2026-04-13 04:46:15 -04:00
MINOR: otel: added span link support
Added span link support, allowing a span to reference other spans or
extracted contexts without establishing a parent relationship.
Introduced the flt_otel_conf_link structure and added a links list to
flt_otel_conf_span. The parser accepted both an inline syntax on the span
declaration line ("span <name> link <target>") and a standalone multi-
argument form ("link <span> ..."), each creating a conf_link entry
appended to the span's link list.
At runtime, each configured link name was resolved against the active
spans and extracted contexts in the runtime context. Resolved references
were collected into flt_otel_scope_data_link entries and passed to the C
wrapper add_link API during span creation.
Initialization, cleanup, and debug dump routines were added for the link
data structures at both configuration and runtime levels.
This commit is contained in:
parent
d8e69f07dc
commit
eaa05d2af3
9 changed files with 178 additions and 12 deletions
|
|
@ -47,12 +47,13 @@
|
|||
#define FLT_OTEL_DBG_CONF_CONTEXT(h,p) \
|
||||
OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "0x%02hhx }", (p), FLT_OTEL_CONF_HDR_ARGS(p, id), (p)->flags)
|
||||
|
||||
#define FLT_OTEL_DBG_CONF_SPAN(h,p) \
|
||||
OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "'%s' %zu %s' %zu %hhu 0x%02hhx %s %s %s %s }", \
|
||||
(p), FLT_OTEL_CONF_HDR_ARGS(p, id), FLT_OTEL_STR_HDR_ARGS(p, ref_id), \
|
||||
FLT_OTEL_STR_HDR_ARGS(p, ctx_id), (p)->flag_root, (p)->ctx_flags, \
|
||||
flt_otel_list_dump(&((p)->attributes)), flt_otel_list_dump(&((p)->events)), \
|
||||
flt_otel_list_dump(&((p)->baggages)), flt_otel_list_dump(&((p)->statuses)))
|
||||
#define FLT_OTEL_DBG_CONF_SPAN(h,p) \
|
||||
OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "'%s' %zu %s' %zu %hhu 0x%02hhx %s %s %s %s %s }", \
|
||||
(p), FLT_OTEL_CONF_HDR_ARGS(p, id), FLT_OTEL_STR_HDR_ARGS(p, ref_id), \
|
||||
FLT_OTEL_STR_HDR_ARGS(p, ctx_id), (p)->flag_root, (p)->ctx_flags, \
|
||||
flt_otel_list_dump(&((p)->links)), flt_otel_list_dump(&((p)->attributes)), \
|
||||
flt_otel_list_dump(&((p)->events)), flt_otel_list_dump(&((p)->baggages)), \
|
||||
flt_otel_list_dump(&((p)->statuses)))
|
||||
|
||||
#define FLT_OTEL_DBG_CONF_SCOPE(h,p) \
|
||||
OTELC_DBG_STRUCT(DEBUG, h, h FLT_OTEL_CONF_HDR_FMT "%hhu %d %u %s %p %s %s %s }", (p), \
|
||||
|
|
@ -138,6 +139,11 @@ struct flt_otel_conf_context {
|
|||
uint8_t flags; /* The type of storage from which the span context is extracted. */
|
||||
};
|
||||
|
||||
/* flt_otel_conf_span->links */
|
||||
struct flt_otel_conf_link {
|
||||
FLT_OTEL_CONF_HDR(span); /* The list containing link names. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Span configuration within a scope.
|
||||
* flt_otel_conf_scope->spans
|
||||
|
|
@ -148,6 +154,7 @@ struct flt_otel_conf_span {
|
|||
FLT_OTEL_CONF_STR(ctx_id); /* The span context name, if used. */
|
||||
uint8_t ctx_flags; /* The type of storage used for the span context. */
|
||||
bool flag_root; /* Whether this is a root span. */
|
||||
struct list links; /* The set of linked span names. */
|
||||
struct list attributes; /* The set of key:value attributes. */
|
||||
struct list events; /* The set of events with key-value attributes. */
|
||||
struct list baggages; /* The set of key:value baggage items. */
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ FLT_OTEL_CONF_FUNC_DECL(str)
|
|||
FLT_OTEL_CONF_FUNC_DECL(ph)
|
||||
FLT_OTEL_CONF_FUNC_DECL(sample_expr)
|
||||
FLT_OTEL_CONF_FUNC_DECL(sample)
|
||||
FLT_OTEL_CONF_FUNC_DECL(link)
|
||||
FLT_OTEL_CONF_FUNC_DECL(context)
|
||||
FLT_OTEL_CONF_FUNC_DECL(span)
|
||||
FLT_OTEL_CONF_FUNC_DECL(scope)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#define FLT_OTEL_PARSE_SPAN_ROOT "root"
|
||||
#define FLT_OTEL_PARSE_SPAN_PARENT "parent"
|
||||
#define FLT_OTEL_PARSE_SPAN_LINK "link"
|
||||
#define FLT_OTEL_PARSE_CTX_AUTONAME "-"
|
||||
#define FLT_OTEL_PARSE_CTX_IGNORE_NAME '-'
|
||||
#define FLT_OTEL_PARSE_CTX_USE_HEADERS "use-headers"
|
||||
|
|
@ -73,7 +74,8 @@
|
|||
*/
|
||||
#define FLT_OTEL_PARSE_SCOPE_DEFINES \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( ID, 0, CHAR, 2, 2, "otel-scope", " <name>") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( SPAN, 0, NONE, 2, 7, "span", " <name> [<reference>] [root]") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( SPAN, 0, NONE, 2, 7, "span", " <name> [<reference>] [<link>] [root]") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( LINK, 1, NONE, 2, 0, "link", " <span> ...") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( ATTRIBUTE, 1, NONE, 3, 0, "attribute", " <key> <sample> ...") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( EVENT, 1, NONE, 4, 0, "event", " <name> <key> <sample> ...") \
|
||||
FLT_OTEL_PARSE_SCOPE_DEF( BAGGAGE, 1, VAR, 3, 0, "baggage", " <key> <sample> ...") \
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@
|
|||
|
||||
#define FLT_OTEL_DBG_SCOPE_DATA_KV_FMT "%p:{ %p %zu %zu }"
|
||||
#define FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS(p) &(p), (p).attr, (p).cnt, (p).size
|
||||
#define FLT_OTEL_DBG_SCOPE_DATA(h,p) \
|
||||
OTELC_DBG(DEBUG, h "%p:{ " FLT_OTEL_DBG_SCOPE_DATA_KV_FMT " " FLT_OTEL_DBG_SCOPE_DATA_KV_FMT " %s }", (p), \
|
||||
FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS((p)->baggage), FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS((p)->attributes), \
|
||||
flt_otel_list_dump(&((p)->events)))
|
||||
#define FLT_OTEL_DBG_SCOPE_DATA(h,p) \
|
||||
OTELC_DBG(DEBUG, h "%p:{ " FLT_OTEL_DBG_SCOPE_DATA_KV_FMT " " FLT_OTEL_DBG_SCOPE_DATA_KV_FMT " %s %s }", (p), \
|
||||
FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS((p)->baggage), FLT_OTEL_DBG_SCOPE_DATA_KV_ARGS((p)->attributes), \
|
||||
flt_otel_list_dump(&((p)->events)), flt_otel_list_dump(&((p)->links)))
|
||||
|
||||
#define FLT_OTEL_DBG_RUNTIME_CONTEXT(h,p) \
|
||||
OTELC_DBG(DEBUG, h "%p:{ %p %p '%s' %hhu %hhu 0x%02hhx 0x%08x %u %d %s %s }", (p), \
|
||||
|
|
@ -64,15 +64,25 @@ struct flt_otel_scope_data_event {
|
|||
struct list list; /* Used to chain this structure. */
|
||||
};
|
||||
|
||||
/* Span link referencing another span or span context. */
|
||||
struct flt_otel_scope_data_link {
|
||||
struct otelc_span *span; /* Linked span, or NULL. */
|
||||
struct otelc_span_context *context; /* Linked span context, or NULL. */
|
||||
struct list list; /* Used to chain this structure. */
|
||||
};
|
||||
|
||||
/* Span status code and description. */
|
||||
struct flt_otel_scope_data_status {
|
||||
int code; /* OTELC_SPAN_STATUS_* value. */
|
||||
char *description; /* Span status description string. */
|
||||
};
|
||||
|
||||
/* Aggregated runtime data collected during scope execution. */
|
||||
struct flt_otel_scope_data {
|
||||
struct flt_otel_scope_data_kv baggage; /* Defined scope baggage. */
|
||||
struct flt_otel_scope_data_kv attributes; /* Defined scope attributes. */
|
||||
struct list events; /* Defined scope events. */
|
||||
struct list links; /* Defined scope links. */
|
||||
struct flt_otel_scope_data_status status; /* Defined scope status. */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,53 @@ FLT_OTEL_CONF_FUNC_FREE(str, str,
|
|||
)
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_conf_link_init - conf_link structure allocation
|
||||
*
|
||||
* SYNOPSIS
|
||||
* struct flt_otel_conf_link *flt_otel_conf_link_init(const char *id, int line, struct list *head, char **err)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* id - identifier string to duplicate
|
||||
* line - configuration file line number
|
||||
* head - list to append to (or NULL)
|
||||
* err - indirect pointer to error message string
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Allocates and initializes a conf_link structure for a span link
|
||||
* reference. The <id> string is duplicated and stored as the linked
|
||||
* span name. If <head> is non-NULL, the structure is appended to
|
||||
* the list.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns a pointer to the initialized structure, or NULL on failure.
|
||||
*/
|
||||
FLT_OTEL_CONF_FUNC_INIT(link, span, )
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_conf_link_free - conf_link structure deallocation
|
||||
*
|
||||
* SYNOPSIS
|
||||
* void flt_otel_conf_link_free(struct flt_otel_conf_link **ptr)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* ptr - a pointer to the address of a structure
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Deallocates memory used by the flt_otel_conf_link structure and its
|
||||
* contents, then removes it from the list of structures of that type.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* This function does not return a value.
|
||||
*/
|
||||
FLT_OTEL_CONF_FUNC_FREE(link, span,
|
||||
FLT_OTEL_DBG_CONF_HDR("- conf_link free ", *ptr, span);
|
||||
)
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_conf_ph_init - conf_ph placeholder structure allocation
|
||||
|
|
@ -401,6 +448,7 @@ FLT_OTEL_CONF_FUNC_FREE(context, id,
|
|||
* Returns a pointer to the initialized structure, or NULL on failure.
|
||||
*/
|
||||
FLT_OTEL_CONF_FUNC_INIT(span, id,
|
||||
LIST_INIT(&(retptr->links));
|
||||
LIST_INIT(&(retptr->attributes));
|
||||
LIST_INIT(&(retptr->events));
|
||||
LIST_INIT(&(retptr->baggages));
|
||||
|
|
@ -430,6 +478,7 @@ FLT_OTEL_CONF_FUNC_FREE(span, id,
|
|||
|
||||
OTELC_SFREE((*ptr)->ref_id);
|
||||
OTELC_SFREE((*ptr)->ctx_id);
|
||||
FLT_OTEL_LIST_DESTROY(link, &((*ptr)->links));
|
||||
FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->attributes));
|
||||
FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->events));
|
||||
FLT_OTEL_LIST_DESTROY(sample, &((*ptr)->baggages));
|
||||
|
|
|
|||
|
|
@ -54,6 +54,18 @@ static int flt_otel_scope_run_span(struct stream *s, struct filter *f, struct ch
|
|||
OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
|
||||
}
|
||||
|
||||
/* Add all resolved span links to the current span. */
|
||||
if (!LIST_ISEMPTY(&(data->links))) {
|
||||
struct flt_otel_scope_data_link *link;
|
||||
|
||||
list_for_each_entry(link, &(data->links), list) {
|
||||
OTELC_DBG(DEBUG, "adding link %p %p", link->span, link->context);
|
||||
|
||||
if (OTELC_OPS(span->span, add_link, link->span, link->context, NULL, 0) == -1)
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set baggage key-value pairs on the span. */
|
||||
if (data->baggage.attr != NULL)
|
||||
if (OTELC_OPS(span->span, set_baggage_kv_n, data->baggage.attr, data->baggage.cnt) == -1)
|
||||
|
|
@ -245,6 +257,61 @@ int flt_otel_scope_run(struct stream *s, struct filter *f, struct channel *chn,
|
|||
if (span == NULL)
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
/*
|
||||
* Resolve configured span links against the runtime context.
|
||||
* Each link name is looked up first in the active spans, then
|
||||
* in the extracted contexts.
|
||||
*/
|
||||
if (!LIST_ISEMPTY(&(conf_span->links))) {
|
||||
struct flt_otel_runtime_context *rt_ctx = FLT_OTEL_RT_CTX(f->ctx);
|
||||
struct flt_otel_conf_link *conf_link;
|
||||
|
||||
list_for_each_entry(conf_link, &(conf_span->links), list) {
|
||||
struct flt_otel_scope_data_link *data_link;
|
||||
struct otelc_span *link_span = NULL;
|
||||
struct otelc_span_context *link_ctx = NULL;
|
||||
struct flt_otel_scope_span *sc_span;
|
||||
struct flt_otel_scope_context *sc_ctx;
|
||||
|
||||
/* Try to find a matching span first. */
|
||||
list_for_each_entry(sc_span, &(rt_ctx->spans), list)
|
||||
if (FLT_OTEL_CONF_STR_CMP(sc_span->id, conf_link->span)) {
|
||||
link_span = sc_span->span;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* If no span found, try to find a matching context. */
|
||||
if (link_span == NULL) {
|
||||
list_for_each_entry(sc_ctx, &(rt_ctx->contexts), list)
|
||||
if (FLT_OTEL_CONF_STR_CMP(sc_ctx->id, conf_link->span)) {
|
||||
link_ctx = sc_ctx->context;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((link_span == NULL) && (link_ctx == NULL)) {
|
||||
OTELC_DBG(NOTICE, "WARNING: cannot find linked span/context '%s'", conf_link->span);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
data_link = OTELC_CALLOC(1, sizeof(*data_link));
|
||||
if (data_link == NULL) {
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
data_link->span = link_span;
|
||||
data_link->context = link_ctx;
|
||||
LIST_APPEND(&(data.links), &(data_link->list));
|
||||
|
||||
OTELC_DBG(DEBUG, "resolved link '%s' -> %p %p", conf_link->span, link_span, link_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(sample, &(conf_span->attributes), list) {
|
||||
OTELC_DBG(DEBUG, "adding attribute '%s' -> '%s'", sample->key, sample->fmt_string);
|
||||
|
||||
|
|
|
|||
|
|
@ -955,6 +955,14 @@ static int flt_otel_parse_cfg_scope(const char *file, int line, char **args, int
|
|||
else
|
||||
FLT_OTEL_PARSE_ERR(&err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
|
||||
}
|
||||
else if (FLT_OTEL_PARSE_KEYWORD(i, FLT_OTEL_PARSE_SPAN_LINK)) {
|
||||
if (FLT_OTEL_ARG_ISVALID(i + 1)) {
|
||||
if (flt_otel_conf_link_init(args[++i], line, &(flt_otel_current_span->links), &err) == NULL)
|
||||
retval |= ERR_ABORT | ERR_ALERT;
|
||||
} else {
|
||||
FLT_OTEL_PARSE_ERR(&err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
FLT_OTEL_PARSE_ERR(&err, "'%s' : invalid argument (use '%s%s')", args[i], pdata->name, pdata->usage);
|
||||
}
|
||||
|
|
@ -968,6 +976,11 @@ static int flt_otel_parse_cfg_scope(const char *file, int line, char **args, int
|
|||
OTELC_DBG(DEBUG, "new span '%s' without reference", flt_otel_current_span->id);
|
||||
}
|
||||
}
|
||||
else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_LINK) {
|
||||
for (i = 1; !(retval & ERR_CODE) && FLT_OTEL_ARG_ISVALID(i); i++)
|
||||
if (flt_otel_conf_link_init(args[i], line, &(flt_otel_current_span->links), &err) == NULL)
|
||||
retval |= ERR_ABORT | ERR_ALERT;
|
||||
}
|
||||
else if (pdata->keyword == FLT_OTEL_PARSE_SCOPE_ATTRIBUTE) {
|
||||
retval = flt_otel_parse_cfg_sample(file, line, args, 2, 0, NULL, &(flt_otel_current_span->attributes), &err);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -418,6 +418,17 @@ void flt_otel_scope_data_dump(const struct flt_otel_scope_data *data)
|
|||
OTELC_DBG(WORKER, "}");
|
||||
}
|
||||
|
||||
if (LIST_ISEMPTY(&(data->links))) {
|
||||
OTELC_DBG(WORKER, "links %p:{ }", &(data->links));
|
||||
} else {
|
||||
struct flt_otel_scope_data_link *link;
|
||||
|
||||
OTELC_DBG(WORKER, "links %p:{", &(data->links));
|
||||
list_for_each_entry(link, &(data->links), list)
|
||||
OTELC_DBG(WORKER, " %p %p", link->span, link->context);
|
||||
OTELC_DBG(WORKER, "}");
|
||||
}
|
||||
|
||||
if ((data->status.code == 0) && (data->status.description == NULL))
|
||||
OTELC_DBG(WORKER, "status %p:{ }", &(data->status));
|
||||
else
|
||||
|
|
@ -453,6 +464,7 @@ void flt_otel_scope_data_init(struct flt_otel_scope_data *ptr)
|
|||
|
||||
(void)memset(ptr, 0, sizeof(*ptr));
|
||||
LIST_INIT(&(ptr->events));
|
||||
LIST_INIT(&(ptr->links));
|
||||
|
||||
OTELC_RETURN();
|
||||
}
|
||||
|
|
@ -479,6 +491,7 @@ void flt_otel_scope_data_init(struct flt_otel_scope_data *ptr)
|
|||
void flt_otel_scope_data_free(struct flt_otel_scope_data *ptr)
|
||||
{
|
||||
struct flt_otel_scope_data_event *event, *event_back;
|
||||
struct flt_otel_scope_data_link *link, *link_back;
|
||||
|
||||
OTELC_FUNC("%p", ptr);
|
||||
|
||||
|
|
@ -495,6 +508,9 @@ void flt_otel_scope_data_free(struct flt_otel_scope_data *ptr)
|
|||
OTELC_SFREE(event->name);
|
||||
OTELC_SFREE(event);
|
||||
}
|
||||
/* Free all resolved link entries. */
|
||||
list_for_each_entry_safe(link, link_back, &(ptr->links), list)
|
||||
OTELC_SFREE(link);
|
||||
OTELC_SFREE(ptr->status.description);
|
||||
|
||||
(void)memset(ptr, 0, sizeof(*ptr));
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
otel-event on-http-body-request
|
||||
|
||||
otel-scope frontend_http_request
|
||||
span "Frontend HTTP request" parent "HTTP body request"
|
||||
span "Frontend HTTP request" parent "HTTP body request" link "HAProxy session"
|
||||
attribute "http.method" method
|
||||
attribute "http.url" url
|
||||
attribute "http.version" str("HTTP/") req.ver
|
||||
|
|
@ -147,6 +147,7 @@
|
|||
|
||||
otel-scope server_session_start
|
||||
span "Server session" parent "HAProxy session"
|
||||
link "HAProxy session" "Client session"
|
||||
finish "Process sticking rules request"
|
||||
otel-event on-server-session-start
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue