mirror of
https://github.com/haproxy/haproxy.git
synced 2026-04-13 04:46:15 -04:00
MEDIUM: otel: added context propagation via carrier interfaces
Added the span context injection and extraction layer that bridges the OTel C wrapper's propagation API with HAProxy's HTTP headers and text map carriers. The new otelc.c module implements four public functions that wrap the OTel C wrapper's context propagation methods: flt_otel_inject_text_map() and flt_otel_inject_http_headers() serialize a span's context into a text map or HTTP headers carrier for outbound propagation, while flt_otel_extract_text_map() and flt_otel_extract_http_headers() deserialize an inbound carrier into an otelc_span_context for parent linking. Each direction uses a pair of callbacks registered on the carrier structure. The injection writers (flt_otel_text_map_writer_set_cb and flt_otel_http_headers_writer_set_cb) store key-value pairs emitted by the SDK into the carrier's text map via OTELC_TEXT_MAP_ADD(). The extraction readers (flt_otel_text_map_reader_foreach_key_cb and flt_otel_http_headers_reader_foreach_key_cb) iterate the carrier's text map entries and pass each pair to the SDK's handler callback. The scope context initialization in flt_otel_scope_context_init() now calls flt_otel_extract_http_headers() to extract the span context from the provided text map carrier and stores it in the scope context structure, making extracted contexts available for parent linking in subsequent span creation.
This commit is contained in:
parent
bab0ea7b77
commit
ea9d05de02
5 changed files with 329 additions and 1 deletions
|
|
@ -54,6 +54,7 @@ OPTIONS_OBJS += \
|
|||
addons/otel/src/conf.o \
|
||||
addons/otel/src/event.o \
|
||||
addons/otel/src/filter.o \
|
||||
addons/otel/src/otelc.o \
|
||||
addons/otel/src/parser.o \
|
||||
addons/otel/src/pool.o \
|
||||
addons/otel/src/scope.o \
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "conf.h"
|
||||
#include "conf_funcs.h"
|
||||
#include "filter.h"
|
||||
#include "otelc.h"
|
||||
#include "parser.h"
|
||||
#include "pool.h"
|
||||
#include "scope.h"
|
||||
|
|
|
|||
27
addons/otel/include/otelc.h
Normal file
27
addons/otel/include/otelc.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef _OTEL_OTELC_H_
|
||||
#define _OTEL_OTELC_H_
|
||||
|
||||
/* Inject span context into a text map carrier. */
|
||||
int flt_otel_inject_text_map(const struct otelc_span *span, struct otelc_text_map_writer *carrier);
|
||||
|
||||
/* Inject span context into an HTTP headers carrier. */
|
||||
int flt_otel_inject_http_headers(const struct otelc_span *span, struct otelc_http_headers_writer *carrier);
|
||||
|
||||
/* Extract span context from a text map carrier. */
|
||||
struct otelc_span_context *flt_otel_extract_text_map(struct otelc_tracer *tracer, struct otelc_text_map_reader *carrier, const struct otelc_text_map *text_map);
|
||||
|
||||
/* Extract span context from an HTTP headers carrier. */
|
||||
struct otelc_span_context *flt_otel_extract_http_headers(struct otelc_tracer *tracer, struct otelc_http_headers_reader *carrier, const struct otelc_text_map *text_map);
|
||||
|
||||
#endif /* _OTEL_OTELC_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
289
addons/otel/src/otelc.c
Normal file
289
addons/otel/src/otelc.c
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "../include/include.h"
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_text_map_writer_set_cb - text map injection writer callback
|
||||
*
|
||||
* SYNOPSIS
|
||||
* static int flt_otel_text_map_writer_set_cb(struct otelc_text_map_writer *writer, const char *key, const char *value)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* writer - text map writer instance
|
||||
* key - context key name
|
||||
* value - context key value
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Writer callback for text map injection. Called by the OTel C wrapper
|
||||
* library during span context injection to store each key-value pair in the
|
||||
* <writer>'s text map.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns the result of OTELC_TEXT_MAP_ADD().
|
||||
*/
|
||||
static int flt_otel_text_map_writer_set_cb(struct otelc_text_map_writer *writer, const char *key, const char *value)
|
||||
{
|
||||
OTELC_FUNC("%p, \"%s\", \"%s\"", writer, OTELC_STR_ARG(key), OTELC_STR_ARG(value));
|
||||
|
||||
OTELC_RETURN_INT(OTELC_TEXT_MAP_ADD(&(writer->text_map), key, 0, value, 0, OTELC_TEXT_MAP_AUTO));
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_http_headers_writer_set_cb - HTTP headers injection writer callback
|
||||
*
|
||||
* SYNOPSIS
|
||||
* static int flt_otel_http_headers_writer_set_cb(struct otelc_http_headers_writer *writer, const char *key, const char *value)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* writer - HTTP headers writer instance
|
||||
* key - context key name
|
||||
* value - context key value
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Writer callback for HTTP headers injection. Called by the OTel C wrapper
|
||||
* library during span context injection to store each key-value pair in the
|
||||
* <writer>'s text map.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns the result of OTELC_TEXT_MAP_ADD().
|
||||
*/
|
||||
static int flt_otel_http_headers_writer_set_cb(struct otelc_http_headers_writer *writer, const char *key, const char *value)
|
||||
{
|
||||
OTELC_FUNC("%p, \"%s\", \"%s\"", writer, OTELC_STR_ARG(key), OTELC_STR_ARG(value));
|
||||
|
||||
OTELC_RETURN_INT(OTELC_TEXT_MAP_ADD(&(writer->text_map), key, 0, value, 0, OTELC_TEXT_MAP_AUTO));
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_inject_text_map - text map context injection
|
||||
*
|
||||
* SYNOPSIS
|
||||
* int flt_otel_inject_text_map(const struct otelc_span *span, struct otelc_text_map_writer *carrier)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* span - span instance to inject context from
|
||||
* carrier - text map writer carrier
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Injects the span context into a text map carrier. Initializes the
|
||||
* <carrier> structure, sets the writer callback to
|
||||
* flt_otel_text_map_writer_set_cb(), and delegates to the <span>'s
|
||||
* inject_text_map() method.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns the result of the <span>'s inject_text_map() method,
|
||||
* or FLT_OTEL_RET_ERROR if arguments are NULL.
|
||||
*/
|
||||
int flt_otel_inject_text_map(const struct otelc_span *span, struct otelc_text_map_writer *carrier)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", span, carrier);
|
||||
|
||||
if ((span == NULL) || (carrier == NULL))
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
|
||||
|
||||
(void)memset(carrier, 0, sizeof(*carrier));
|
||||
carrier->set = flt_otel_text_map_writer_set_cb;
|
||||
|
||||
OTELC_RETURN_INT(OTELC_OPS(span, inject_text_map, carrier));
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_inject_http_headers - HTTP headers context injection
|
||||
*
|
||||
* SYNOPSIS
|
||||
* int flt_otel_inject_http_headers(const struct otelc_span *span, struct otelc_http_headers_writer *carrier)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* span - span instance to inject context from
|
||||
* carrier - HTTP headers writer carrier
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Injects the span context into an HTTP headers carrier. Initializes the
|
||||
* <carrier> structure, sets the writer callback to
|
||||
* flt_otel_http_headers_writer_set_cb(), and delegates to the <span>'s
|
||||
* inject_http_headers() method.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns the result of the <span>'s inject_http_headers() method,
|
||||
* or FLT_OTEL_RET_ERROR if arguments are NULL.
|
||||
*/
|
||||
int flt_otel_inject_http_headers(const struct otelc_span *span, struct otelc_http_headers_writer *carrier)
|
||||
{
|
||||
OTELC_FUNC("%p, %p", span, carrier);
|
||||
|
||||
if ((span == NULL) || (carrier == NULL))
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_ERROR);
|
||||
|
||||
(void)memset(carrier, 0, sizeof(*carrier));
|
||||
carrier->set = flt_otel_http_headers_writer_set_cb;
|
||||
|
||||
OTELC_RETURN_INT(OTELC_OPS(span, inject_http_headers, carrier));
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_text_map_reader_foreach_key_cb - text map extraction reader callback
|
||||
*
|
||||
* SYNOPSIS
|
||||
* static int flt_otel_text_map_reader_foreach_key_cb(const struct otelc_text_map_reader *reader, int (*handler)(void *arg, const char *key, const char *value), void *arg)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* reader - text map reader instance
|
||||
* handler - callback function invoked for each key-value pair
|
||||
* arg - opaque argument passed to the handler
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Reader callback for text map extraction. Iterates over all key-value
|
||||
* pairs in the <reader>'s text map and invokes <handler> for each. Iteration
|
||||
* stops if the <handler> returns -1.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns the last <handler> return value, or 0 if the text map is empty.
|
||||
*/
|
||||
static int flt_otel_text_map_reader_foreach_key_cb(const struct otelc_text_map_reader *reader, int (*handler)(void *arg, const char *key, const char *value), void *arg)
|
||||
{
|
||||
size_t i;
|
||||
int retval = 0;
|
||||
|
||||
OTELC_FUNC("%p, %p, %p", reader, handler, arg);
|
||||
|
||||
for (i = 0; (retval != -1) && (i < reader->text_map.count); i++) {
|
||||
OTELC_DBG(OTELC, "\"%s\" -> \"%s\"", OTELC_STR_ARG(reader->text_map.key[i]), OTELC_STR_ARG(reader->text_map.value[i]));
|
||||
|
||||
retval = handler(arg, reader->text_map.key[i], reader->text_map.value[i]);
|
||||
}
|
||||
|
||||
OTELC_RETURN_INT(retval);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_http_headers_reader_foreach_key_cb - HTTP headers extraction reader callback
|
||||
*
|
||||
* SYNOPSIS
|
||||
* static int flt_otel_http_headers_reader_foreach_key_cb(const struct otelc_http_headers_reader *reader, int (*handler)(void *arg, const char *key, const char *value), void *arg)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* reader - HTTP headers reader instance
|
||||
* handler - callback function invoked for each key-value pair
|
||||
* arg - opaque argument passed to the handler
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Reader callback for HTTP headers extraction. Iterates over all key-value
|
||||
* pairs in the <reader>'s text map and invokes <handler> for each. Iteration
|
||||
* stops if the <handler> returns -1.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns the last <handler> return value, or 0 if the text map is empty.
|
||||
*/
|
||||
static int flt_otel_http_headers_reader_foreach_key_cb(const struct otelc_http_headers_reader *reader, int (*handler)(void *arg, const char *key, const char *value), void *arg)
|
||||
{
|
||||
size_t i;
|
||||
int retval = 0;
|
||||
|
||||
OTELC_FUNC("%p, %p, %p", reader, handler, arg);
|
||||
|
||||
for (i = 0; (retval != -1) && (i < reader->text_map.count); i++) {
|
||||
OTELC_DBG(OTELC, "\"%s\" -> \"%s\"", OTELC_STR_ARG(reader->text_map.key[i]), OTELC_STR_ARG(reader->text_map.value[i]));
|
||||
|
||||
retval = handler(arg, reader->text_map.key[i], reader->text_map.value[i]);
|
||||
}
|
||||
|
||||
OTELC_RETURN_INT(retval);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_extract_text_map - text map context extraction
|
||||
*
|
||||
* SYNOPSIS
|
||||
* struct otelc_span_context *flt_otel_extract_text_map(struct otelc_tracer *tracer, struct otelc_text_map_reader *carrier, const struct otelc_text_map *text_map)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* tracer - OTel tracer instance
|
||||
* carrier - text map reader carrier
|
||||
* text_map - text map containing the context data (or NULL)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Extracts a span context from a text map carrier via the <tracer>.
|
||||
* Initializes the <carrier> structure, sets the foreach_key callback to
|
||||
* flt_otel_text_map_reader_foreach_key_cb(), and copies the <text_map> data
|
||||
* into the <carrier>. Delegates to the <tracer>'s extract_text_map() method.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns a pointer to the extracted span context, or NULL on failure.
|
||||
*/
|
||||
struct otelc_span_context *flt_otel_extract_text_map(struct otelc_tracer *tracer, struct otelc_text_map_reader *carrier, const struct otelc_text_map *text_map)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p", tracer, carrier, text_map);
|
||||
|
||||
if ((tracer == NULL) || (carrier == NULL))
|
||||
OTELC_RETURN_PTR(NULL);
|
||||
|
||||
(void)memset(carrier, 0, sizeof(*carrier));
|
||||
carrier->foreach_key = flt_otel_text_map_reader_foreach_key_cb;
|
||||
|
||||
if (text_map != NULL)
|
||||
(void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map));
|
||||
|
||||
OTELC_RETURN_PTR(OTELC_OPS(tracer, extract_text_map, carrier));
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_extract_http_headers - HTTP headers context extraction
|
||||
*
|
||||
* SYNOPSIS
|
||||
* struct otelc_span_context *flt_otel_extract_http_headers(struct otelc_tracer *tracer, struct otelc_http_headers_reader *carrier, const struct otelc_text_map *text_map)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* tracer - OTel tracer instance
|
||||
* carrier - HTTP headers reader carrier
|
||||
* text_map - text map containing the context data (or NULL)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Extracts a span context from an HTTP headers carrier via the <tracer>.
|
||||
* Initializes the <carrier> structure, sets the foreach_key callback to
|
||||
* flt_otel_http_headers_reader_foreach_key_cb(), and copies the <text_map>
|
||||
* data into the <carrier>. Delegates to the <tracer>'s
|
||||
* extract_http_headers() method.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns a pointer to the extracted span context, or NULL on failure.
|
||||
*/
|
||||
struct otelc_span_context *flt_otel_extract_http_headers(struct otelc_tracer *tracer, struct otelc_http_headers_reader *carrier, const struct otelc_text_map *text_map)
|
||||
{
|
||||
OTELC_FUNC("%p, %p, %p", tracer, carrier, text_map);
|
||||
|
||||
if ((tracer == NULL) || (carrier == NULL))
|
||||
OTELC_RETURN_PTR(NULL);
|
||||
|
||||
(void)memset(carrier, 0, sizeof(*carrier));
|
||||
carrier->foreach_key = flt_otel_http_headers_reader_foreach_key_cb;
|
||||
|
||||
if (text_map != NULL)
|
||||
(void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map));
|
||||
|
||||
OTELC_RETURN_PTR(OTELC_OPS(tracer, extract_http_headers, carrier));
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
|
|
@ -271,7 +271,9 @@ void flt_otel_scope_span_free(struct flt_otel_scope_span **ptr)
|
|||
*/
|
||||
struct flt_otel_scope_context *flt_otel_scope_context_init(struct flt_otel_runtime_context *rt_ctx, struct otelc_tracer *tracer, const char *id, size_t id_len, const struct otelc_text_map *text_map, uint dir, char **err)
|
||||
{
|
||||
struct flt_otel_scope_context *retptr = NULL;
|
||||
struct otelc_http_headers_reader reader;
|
||||
struct otelc_span_context *span_ctx;
|
||||
struct flt_otel_scope_context *retptr = NULL;
|
||||
|
||||
OTELC_FUNC("%p, %p, \"%s\", %zu, %p, %u, %p:%p", rt_ctx, tracer, OTELC_STR_ARG(id), id_len, text_map, dir, OTELC_DPTR_ARGS(err));
|
||||
|
||||
|
|
@ -290,10 +292,18 @@ struct flt_otel_scope_context *flt_otel_scope_context_init(struct flt_otel_runti
|
|||
if (retptr == NULL)
|
||||
OTELC_RETURN_PTR(retptr);
|
||||
|
||||
span_ctx = flt_otel_extract_http_headers(tracer, &reader, text_map);
|
||||
if (span_ctx == NULL) {
|
||||
flt_otel_scope_context_free(&retptr);
|
||||
|
||||
OTELC_RETURN_PTR(retptr);
|
||||
}
|
||||
|
||||
/* Populate the new scope context and insert it into the list. */
|
||||
retptr->id = id;
|
||||
retptr->id_len = id_len;
|
||||
retptr->smp_opt_dir = dir;
|
||||
retptr->context = span_ctx;
|
||||
LIST_INSERT(&(rt_ctx->contexts), &(retptr->list));
|
||||
|
||||
FLT_OTEL_DBG_SCOPE_CONTEXT("new context ", retptr);
|
||||
|
|
|
|||
Loading…
Reference in a new issue