mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-04-18 20:22:48 +02:00
MEDIUM: otel: added HTTP header operations for context propagation
Added the HTTP header manipulation layer that enables span context injection into and extraction from HAProxy's HTX message buffers, completing the end-to-end context propagation path. The new http.c module implements three public functions: flt_otel_http_headers_get() extracts HTTP headers matching a name prefix from the channel's HTX buffer into an otelc_text_map structure, stripping the prefix and separator dash from header names before storage; flt_otel_http_header_set() constructs a full header name from a prefix and suffix joined by a dash, removes all existing occurrences, and optionally adds the header with a new value; and flt_otel_http_headers_remove() removes all headers matching a given prefix. A debug-only flt_otel_http_headers_dump() logs all HTTP headers from a channel at NOTICE level. The scope runner in event.c now extracts propagation contexts from HTTP headers before processing spans: for each configured extract context, it calls flt_otel_http_headers_get() to read matching headers into a text map, then passes the text map to flt_otel_scope_context_init() which extracts the OTel span context from the carrier. After span execution, the span runner injects the span context back into HTTP headers via flt_otel_inject_http_headers() followed by flt_otel_http_header_set() for each propagation key. The unused resource cleanup in flt_otel_scope_free_unused() now also removes contexts that failed extraction by deleting their associated HTTP headers via flt_otel_http_headers_remove() before freeing the scope context structure.
This commit is contained in:
parent
ea9d05de02
commit
8effcac6f5
@ -54,6 +54,7 @@ OPTIONS_OBJS += \
|
||||
addons/otel/src/conf.o \
|
||||
addons/otel/src/event.o \
|
||||
addons/otel/src/filter.o \
|
||||
addons/otel/src/http.o \
|
||||
addons/otel/src/otelc.o \
|
||||
addons/otel/src/parser.o \
|
||||
addons/otel/src/pool.o \
|
||||
|
||||
31
addons/otel/include/http.h
Normal file
31
addons/otel/include/http.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#ifndef _OTEL_HTTP_H_
|
||||
#define _OTEL_HTTP_H_
|
||||
|
||||
#ifndef DEBUG_OTEL
|
||||
# define flt_otel_http_headers_dump(...) while (0)
|
||||
#else
|
||||
/* Dump all HTTP headers from a channel for debugging. */
|
||||
void flt_otel_http_headers_dump(const struct channel *chn);
|
||||
#endif
|
||||
|
||||
/* Extract HTTP headers matching a prefix into a text map. */
|
||||
struct otelc_text_map *flt_otel_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err);
|
||||
|
||||
/* Set or replace an HTTP header in a channel. */
|
||||
int flt_otel_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err);
|
||||
|
||||
/* Remove all HTTP headers matching a prefix from a channel. */
|
||||
int flt_otel_http_headers_remove(struct channel *chn, const char *prefix, char **err);
|
||||
|
||||
#endif /* _OTEL_HTTP_H_ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
@ -32,6 +32,7 @@
|
||||
#include "conf.h"
|
||||
#include "conf_funcs.h"
|
||||
#include "filter.h"
|
||||
#include "http.h"
|
||||
#include "otelc.h"
|
||||
#include "parser.h"
|
||||
#include "pool.h"
|
||||
|
||||
@ -77,6 +77,27 @@ static int flt_otel_scope_run_span(struct stream *s, struct filter *f, struct ch
|
||||
if (OTELC_OPS(span->span, set_status, data->status.code, data->status.description) == -1)
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
/* Inject span context into HTTP headers. */
|
||||
if (conf_span->ctx_id != NULL) {
|
||||
struct otelc_http_headers_writer writer;
|
||||
struct otelc_text_map *text_map = NULL;
|
||||
|
||||
if (flt_otel_inject_http_headers(span->span, &writer) != FLT_OTEL_RET_ERROR) {
|
||||
int i = 0;
|
||||
|
||||
if (conf_span->ctx_flags & FLT_OTEL_CTX_USE_HEADERS) {
|
||||
for (text_map = &(writer.text_map); i < text_map->count; i++) {
|
||||
if (!(conf_span->ctx_flags & FLT_OTEL_CTX_USE_HEADERS))
|
||||
/* Do nothing. */;
|
||||
else if (flt_otel_http_header_set(chn, conf_span->ctx_id, text_map->key[i], text_map->value[i], err) == FLT_OTEL_RET_ERROR)
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
otelc_text_map_destroy(&text_map);
|
||||
}
|
||||
}
|
||||
|
||||
OTELC_RETURN_INT(retval);
|
||||
}
|
||||
|
||||
@ -110,13 +131,12 @@ static int flt_otel_scope_run_span(struct stream *s, struct filter *f, struct ch
|
||||
*/
|
||||
int flt_otel_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_otel_conf_scope *conf_scope, const struct timespec *ts_steady, const struct timespec *ts_system, uint dir, char **err)
|
||||
{
|
||||
#ifdef FLT_OTEL_USE_COUNTERS
|
||||
struct flt_otel_conf *conf = FLT_OTEL_CONF(f);
|
||||
#endif
|
||||
struct flt_otel_conf_span *conf_span;
|
||||
struct flt_otel_conf_str *span_to_finish;
|
||||
struct timespec ts_now_steady, ts_now_system;
|
||||
int retval = FLT_OTEL_RET_OK;
|
||||
struct flt_otel_conf *conf = FLT_OTEL_CONF(f);
|
||||
struct flt_otel_conf_context *conf_ctx;
|
||||
struct flt_otel_conf_span *conf_span;
|
||||
struct flt_otel_conf_str *span_to_finish;
|
||||
struct timespec ts_now_steady, ts_now_system;
|
||||
int retval = FLT_OTEL_RET_OK;
|
||||
|
||||
OTELC_FUNC("%p, %p, %p, %p, %p, %p, %u, %p:%p", s, f, chn, conf_scope, ts_steady, ts_system, dir, OTELC_DPTR_ARGS(err));
|
||||
|
||||
@ -172,6 +192,29 @@ int flt_otel_scope_run(struct stream *s, struct filter *f, struct channel *chn,
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract and initialize OpenTelemetry propagation contexts. */
|
||||
list_for_each_entry(conf_ctx, &(conf_scope->contexts), list) {
|
||||
struct otelc_text_map *text_map = NULL;
|
||||
|
||||
OTELC_DBG(DEBUG, "run context '%s' -> '%s'", conf_scope->id, conf_ctx->id);
|
||||
FLT_OTEL_DBG_CONF_CONTEXT("run context ", conf_ctx);
|
||||
|
||||
/*
|
||||
* The OpenTelemetry context is read from the HTTP headers.
|
||||
*/
|
||||
if (conf_ctx->flags & FLT_OTEL_CTX_USE_HEADERS)
|
||||
text_map = flt_otel_http_headers_get(chn, conf_ctx->id, conf_ctx->id_len, err);
|
||||
|
||||
if (text_map != NULL) {
|
||||
if (flt_otel_scope_context_init(f->ctx, conf->instr->tracer, conf_ctx->id, conf_ctx->id_len, text_map, dir, err) == NULL)
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
otelc_text_map_destroy(&text_map);
|
||||
} else {
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process configured spans: resolve links and collect samples. */
|
||||
list_for_each_entry(conf_span, &(conf_scope->spans), list) {
|
||||
struct flt_otel_scope_data data;
|
||||
@ -298,6 +341,8 @@ int flt_otel_event_run(struct stream *s, struct filter *f, struct channel *chn,
|
||||
retval = FLT_OTEL_RET_ERROR;
|
||||
}
|
||||
|
||||
flt_otel_http_headers_dump(chn);
|
||||
|
||||
OTELC_DBG(DEBUG, "event = %d %s, chn = %p, s->req = %p, s->res = %p", event, flt_otel_event_data[event].an_name, chn, &(s->req), &(s->res));
|
||||
|
||||
OTELC_RETURN_INT(retval);
|
||||
|
||||
@ -895,6 +895,8 @@ static int flt_otel_ops_attach(struct stream *s, struct filter *f)
|
||||
#endif
|
||||
FLT_OTEL_LOG(LOG_INFO, "%08x %08x", f->pre_analyzers, f->post_analyzers);
|
||||
|
||||
flt_otel_http_headers_dump(&(s->req));
|
||||
|
||||
OTELC_RETURN_INT(FLT_OTEL_RET_OK);
|
||||
}
|
||||
|
||||
|
||||
324
addons/otel/src/http.c
Normal file
324
addons/otel/src/http.c
Normal file
@ -0,0 +1,324 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "../include/include.h"
|
||||
|
||||
|
||||
#ifdef DEBUG_OTEL
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_http_headers_dump - debug HTTP headers dump
|
||||
*
|
||||
* SYNOPSIS
|
||||
* void flt_otel_http_headers_dump(const struct channel *chn)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* chn - channel to dump HTTP headers from
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Dumps all HTTP headers from the channel's HTX buffer. Iterates over HTX
|
||||
* blocks, logging each header name-value pair at NOTICE level. Processing
|
||||
* stops at the end-of-headers marker.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* This function does not return a value.
|
||||
*/
|
||||
void flt_otel_http_headers_dump(const struct channel *chn)
|
||||
{
|
||||
const struct htx *htx;
|
||||
int32_t pos;
|
||||
|
||||
OTELC_FUNC("%p", chn);
|
||||
|
||||
if (chn == NULL)
|
||||
OTELC_RETURN();
|
||||
|
||||
htx = htxbuf(&(chn->buf));
|
||||
|
||||
if (htx_is_empty(htx))
|
||||
OTELC_RETURN();
|
||||
|
||||
/* Walk HTX blocks and log each header until end-of-headers. */
|
||||
for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
|
||||
struct htx_blk *blk = htx_get_blk(htx, pos);
|
||||
enum htx_blk_type type = htx_get_blk_type(blk);
|
||||
|
||||
if (type == HTX_BLK_HDR) {
|
||||
struct ist n = htx_get_blk_name(htx, blk);
|
||||
struct ist v = htx_get_blk_value(htx, blk);
|
||||
|
||||
OTELC_DBG(NOTICE, "'%.*s: %.*s'", (int)n.len, n.ptr, (int)v.len, v.ptr);
|
||||
}
|
||||
else if (type == HTX_BLK_EOH)
|
||||
break;
|
||||
}
|
||||
|
||||
OTELC_RETURN();
|
||||
}
|
||||
|
||||
#endif /* DEBUG_OTEL */
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_http_headers_get - HTTP header extraction to text map
|
||||
*
|
||||
* SYNOPSIS
|
||||
* struct otelc_text_map *flt_otel_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* chn - channel containing HTTP headers
|
||||
* prefix - header name prefix to match (or NULL for all)
|
||||
* len - length of the prefix string
|
||||
* err - indirect pointer to error message string
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Extracts HTTP headers matching a <prefix> from the channel's HTX buffer
|
||||
* into a newly allocated text map. When <prefix> is NULL or its length is
|
||||
* zero, all headers are extracted. If the prefix starts with
|
||||
* FLT_OTEL_PARSE_CTX_IGNORE_NAME, prefix matching is bypassed. The prefix
|
||||
* (including the separator dash) is stripped from header names before storing
|
||||
* in the text map. Empty header values are replaced with an empty string to
|
||||
* avoid misinterpretation by otelc_text_map_add(). This function is used by
|
||||
* the "extract" keyword to read span context from incoming request headers.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns a pointer to the populated text map, or NULL on failure or when
|
||||
* no matching headers are found.
|
||||
*/
|
||||
struct otelc_text_map *flt_otel_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err)
|
||||
{
|
||||
const struct htx *htx;
|
||||
size_t prefix_len = (!OTELC_STR_IS_VALID(prefix) || (len == 0)) ? 0 : (len + 1);
|
||||
int32_t pos;
|
||||
struct otelc_text_map *retptr = NULL;
|
||||
|
||||
OTELC_FUNC("%p, \"%s\", %zu, %p:%p", chn, OTELC_STR_ARG(prefix), len, OTELC_DPTR_ARGS(err));
|
||||
|
||||
if (chn == NULL)
|
||||
OTELC_RETURN_PTR(retptr);
|
||||
|
||||
/*
|
||||
* The keyword 'inject' allows you to define the name of the OpenTelemetry
|
||||
* context without using a prefix. In that case all HTTP headers are
|
||||
* transferred because it is not possible to separate them from the
|
||||
* OpenTelemetry context (this separation is usually done via a prefix).
|
||||
*
|
||||
* When using the 'extract' keyword, the context name must be specified.
|
||||
* To allow all HTTP headers to be extracted, the first character of
|
||||
* that name must be set to FLT_OTEL_PARSE_CTX_IGNORE_NAME.
|
||||
*/
|
||||
if (OTELC_STR_IS_VALID(prefix) && (*prefix == FLT_OTEL_PARSE_CTX_IGNORE_NAME))
|
||||
prefix_len = 0;
|
||||
|
||||
htx = htxbuf(&(chn->buf));
|
||||
|
||||
for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
|
||||
struct htx_blk *blk = htx_get_blk(htx, pos);
|
||||
enum htx_blk_type type = htx_get_blk_type(blk);
|
||||
|
||||
if (type == HTX_BLK_HDR) {
|
||||
struct ist v, n = htx_get_blk_name(htx, blk);
|
||||
|
||||
if ((prefix_len == 0) || ((n.len >= prefix_len) && (strncasecmp(n.ptr, prefix, len) == 0))) {
|
||||
if (retptr == NULL) {
|
||||
retptr = OTELC_TEXT_MAP_NEW(NULL, 8);
|
||||
if (retptr == NULL) {
|
||||
FLT_OTEL_ERR("failed to create HTTP header data");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
v = htx_get_blk_value(htx, blk);
|
||||
|
||||
/*
|
||||
* In case the data of the HTTP header is not
|
||||
* specified, v.ptr will have some non-null
|
||||
* value and v.len will be equal to 0. The
|
||||
* otelc_text_map_add() function will not
|
||||
* interpret this well. In this case v.ptr
|
||||
* is set to an empty string.
|
||||
*/
|
||||
if (v.len == 0)
|
||||
v = ist("");
|
||||
|
||||
/*
|
||||
* Here, an HTTP header (which is actually part
|
||||
* of the span context is added to the text_map.
|
||||
*
|
||||
* Before adding, the prefix is removed from the
|
||||
* HTTP header name.
|
||||
*/
|
||||
if (OTELC_TEXT_MAP_ADD(retptr, n.ptr + prefix_len, n.len - prefix_len, v.ptr, v.len, OTELC_TEXT_MAP_AUTO) == -1) {
|
||||
FLT_OTEL_ERR("failed to add HTTP header data");
|
||||
|
||||
otelc_text_map_destroy(&retptr);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == HTX_BLK_EOH)
|
||||
break;
|
||||
}
|
||||
|
||||
OTELC_TEXT_MAP_DUMP(retptr, "extracted HTTP headers");
|
||||
|
||||
if ((retptr != NULL) && (retptr->count == 0)) {
|
||||
OTELC_DBG(NOTICE, "WARNING: no HTTP headers found");
|
||||
|
||||
otelc_text_map_destroy(&retptr);
|
||||
}
|
||||
|
||||
OTELC_RETURN_PTR(retptr);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_http_header_set - HTTP header set or remove
|
||||
*
|
||||
* SYNOPSIS
|
||||
* int flt_otel_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* chn - channel containing HTTP headers
|
||||
* prefix - header name prefix (or NULL)
|
||||
* name - header name suffix (or NULL)
|
||||
* value - header value to set (or NULL to remove only)
|
||||
* err - indirect pointer to error message string
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Sets or removes an HTTP header in the channel's HTX buffer. The full
|
||||
* header name is constructed by combining <prefix> and <name> with a dash
|
||||
* separator; if only one is provided, it is used directly. All existing
|
||||
* occurrences of the header are removed first. If <name> is NULL, all
|
||||
* headers starting with <prefix> are removed. If <value> is non-NULL, the
|
||||
* header is then added with the new value. A NULL <value> causes only the
|
||||
* removal, with no subsequent addition.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns 0 on success, or FLT_OTEL_RET_ERROR on failure.
|
||||
*/
|
||||
int flt_otel_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err)
|
||||
{
|
||||
struct http_hdr_ctx ctx = { .blk = NULL };
|
||||
struct ist ist_name;
|
||||
struct buffer *buffer = NULL;
|
||||
struct htx *htx;
|
||||
int retval = FLT_OTEL_RET_ERROR;
|
||||
|
||||
OTELC_FUNC("%p, \"%s\", \"%s\", \"%s\", %p:%p", chn, OTELC_STR_ARG(prefix), OTELC_STR_ARG(name), OTELC_STR_ARG(value), OTELC_DPTR_ARGS(err));
|
||||
|
||||
if ((chn == NULL) || (!OTELC_STR_IS_VALID(prefix) && !OTELC_STR_IS_VALID(name)))
|
||||
OTELC_RETURN_INT(retval);
|
||||
|
||||
htx = htxbuf(&(chn->buf));
|
||||
|
||||
/*
|
||||
* Very rare (about 1% of cases), htx is empty.
|
||||
* In order to avoid segmentation fault, we exit this function.
|
||||
*/
|
||||
if (htx_is_empty(htx)) {
|
||||
FLT_OTEL_ERR("HTX is empty");
|
||||
|
||||
OTELC_RETURN_INT(retval);
|
||||
}
|
||||
|
||||
if (!OTELC_STR_IS_VALID(prefix)) {
|
||||
ist_name = ist2((char *)name, strlen(name));
|
||||
}
|
||||
else if (!OTELC_STR_IS_VALID(name)) {
|
||||
ist_name = ist2((char *)prefix, strlen(prefix));
|
||||
}
|
||||
else {
|
||||
buffer = flt_otel_trash_alloc(0, err);
|
||||
if (buffer == NULL)
|
||||
OTELC_RETURN_INT(retval);
|
||||
|
||||
(void)chunk_printf(buffer, "%s-%s", prefix, name);
|
||||
|
||||
ist_name = ist2(buffer->area, buffer->data);
|
||||
}
|
||||
|
||||
/* Remove all occurrences of the header. */
|
||||
while (http_find_header(htx, ist(""), &ctx, 1) == 1) {
|
||||
struct ist n = htx_get_blk_name(htx, ctx.blk);
|
||||
#ifdef DEBUG_OTEL
|
||||
struct ist v = htx_get_blk_value(htx, ctx.blk);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the <name> parameter is not set, then remove all headers
|
||||
* that start with the contents of the <prefix> parameter.
|
||||
*/
|
||||
if (!OTELC_STR_IS_VALID(name))
|
||||
n.len = ist_name.len;
|
||||
|
||||
if (isteqi(n, ist_name))
|
||||
if (http_remove_header(htx, &ctx) == 1)
|
||||
OTELC_DBG(DEBUG, "HTTP header '%.*s: %.*s' removed", (int)n.len, n.ptr, (int)v.len, v.ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the value pointer has a value of NULL, the HTTP header is not set
|
||||
* after deletion.
|
||||
*/
|
||||
if (value == NULL) {
|
||||
retval = 0;
|
||||
}
|
||||
else if (http_add_header(htx, ist_name, ist(value)) == 1) {
|
||||
retval = 0;
|
||||
|
||||
OTELC_DBG(DEBUG, "HTTP header '%s: %s' added", ist_name.ptr, value);
|
||||
}
|
||||
else {
|
||||
FLT_OTEL_ERR("failed to set HTTP header '%s: %s'", ist_name.ptr, value);
|
||||
}
|
||||
|
||||
flt_otel_trash_free(&buffer);
|
||||
|
||||
OTELC_RETURN_INT(retval);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* NAME
|
||||
* flt_otel_http_headers_remove - HTTP headers removal by prefix
|
||||
*
|
||||
* SYNOPSIS
|
||||
* int flt_otel_http_headers_remove(struct channel *chn, const char *prefix, char **err)
|
||||
*
|
||||
* ARGUMENTS
|
||||
* chn - channel containing HTTP headers
|
||||
* prefix - header name prefix to match for removal
|
||||
* err - indirect pointer to error message string
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Removes all HTTP headers matching the given <prefix> from the channel's HTX
|
||||
* buffer. This is a convenience wrapper around flt_otel_http_header_set()
|
||||
* with NULL <name> and <value> arguments.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns 0 on success, or FLT_OTEL_RET_ERROR on failure.
|
||||
*/
|
||||
int flt_otel_http_headers_remove(struct channel *chn, const char *prefix, char **err)
|
||||
{
|
||||
int retval;
|
||||
|
||||
OTELC_FUNC("%p, \"%s\", %p:%p", chn, OTELC_STR_ARG(prefix), OTELC_DPTR_ARGS(err));
|
||||
|
||||
retval = flt_otel_http_header_set(chn, prefix, NULL, NULL, err);
|
||||
|
||||
OTELC_RETURN_INT(retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*
|
||||
* vi: noexpandtab shiftwidth=8 tabstop=8
|
||||
*/
|
||||
@ -685,6 +685,22 @@ void flt_otel_scope_free_unused(struct flt_otel_runtime_context *rt_ctx, struct
|
||||
flt_otel_scope_span_free(&span);
|
||||
}
|
||||
|
||||
/* Remove contexts that failed extraction and clean up their traces. */
|
||||
if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
|
||||
struct flt_otel_scope_context *ctx, *ctx_back;
|
||||
|
||||
list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
|
||||
if (ctx->context == NULL) {
|
||||
/*
|
||||
* All headers associated with the context in
|
||||
* question should be deleted.
|
||||
*/
|
||||
(void)flt_otel_http_headers_remove(chn, ctx->id, NULL);
|
||||
|
||||
flt_otel_scope_context_free(&ctx);
|
||||
}
|
||||
}
|
||||
|
||||
FLT_OTEL_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
|
||||
|
||||
OTELC_RETURN();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user