mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-10 00:57:02 +02:00
Due to a recent change in the handling of haproxy variables, their use for OpenTracing context transfer has been excluded from the compilation process. The use of variables can be re-enabled if the newly defined variable OT_USE_VARS is set to 1 when calling the 'make' utility. However, this should not be used for now as the compilation will end in error. This change prevents the use of haproxy variables to convey the OpenTracing context. This means that the 'use-vars' parameter cannot be used in the OpenTracing filter configuration for 'inject' and 'extract' operations. An example configuration that uses this feature is in the test/ctx directory, while the script to run that test is test/run-ctx.sh. Then, the 'sess.ot.uuid' variable is no longer set when initializing the OpenTracing session. This means that this variable can still be used in the OpenTracing configuration, but its contents will be empty.
339 lines
10 KiB
C
339 lines
10 KiB
C
/***
|
|
* Copyright 2020 HAProxy Technologies
|
|
*
|
|
* This file is part of the HAProxy OpenTracing filter.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
#include "include.h"
|
|
|
|
|
|
#define FLT_OT_EVENT_DEF(a,b,c,d,e,f) { AN_##b##_##a, SMP_OPT_DIR_##b, SMP_VAL_FE_##c, SMP_VAL_BE_##d, e, f },
|
|
const struct flt_ot_event_data flt_ot_event_data[FLT_OT_EVENT_MAX] = { FLT_OT_EVENT_DEFINES };
|
|
#undef FLT_OT_EVENT_DEF
|
|
|
|
|
|
/***
|
|
* NAME
|
|
* flt_ot_scope_run_span -
|
|
*
|
|
* ARGUMENTS
|
|
* s -
|
|
* f -
|
|
* chn -
|
|
* dir -
|
|
* span -
|
|
* data -
|
|
* conf_span -
|
|
* ts -
|
|
* err -
|
|
*
|
|
* DESCRIPTION
|
|
* -
|
|
*
|
|
* RETURN VALUE
|
|
* Returns a negative value if an error occurs, 0 if it needs to wait,
|
|
* any other value otherwise.
|
|
*/
|
|
static int flt_ot_scope_run_span(struct stream *s, struct filter *f, struct channel *chn, uint dir, struct flt_ot_scope_span *span, struct flt_ot_scope_data *data, const struct flt_ot_conf_span *conf_span, const struct timespec *ts, char **err)
|
|
{
|
|
struct flt_ot_conf *conf = FLT_OT_CONF(f);
|
|
int retval = FLT_OT_RET_OK;
|
|
|
|
FLT_OT_FUNC("%p, %p, %p, %u, %p, %p, %p, %p, %p:%p", s, f, chn, dir, span, data, conf_span, ts, FLT_OT_DPTR_ARGS(err));
|
|
|
|
if (span == NULL)
|
|
FLT_OT_RETURN(retval);
|
|
|
|
if (span->span == NULL) {
|
|
span->span = ot_span_init(conf->tracer->tracer, span->id, ts, NULL, span->ref_type, FLT_OT_DEREF(span->ref_ctx, idx, -1), span->ref_span, data->tags, data->num_tags, err);
|
|
if (span->span == NULL)
|
|
retval = FLT_OT_RET_ERROR;
|
|
}
|
|
else if (data->num_tags > 0)
|
|
if (ot_span_tag(span->span, data->tags, data->num_tags) == -1)
|
|
retval = FLT_OT_RET_ERROR;
|
|
|
|
if ((span->span != NULL) && (data->baggage != NULL))
|
|
if (ot_span_set_baggage(span->span, data->baggage) == -1)
|
|
retval = FLT_OT_RET_ERROR;
|
|
|
|
if ((span->span != NULL) && (data->num_log_fields > 0))
|
|
if (ot_span_log(span->span, data->log_fields, data->num_log_fields) == -1)
|
|
retval = FLT_OT_RET_ERROR;
|
|
|
|
if ((span->span != NULL) && (conf_span->ctx_id != NULL)) {
|
|
struct otc_http_headers_writer writer;
|
|
struct otc_text_map *text_map = NULL;
|
|
struct otc_span_context *span_ctx;
|
|
|
|
span_ctx = ot_inject_http_headers(conf->tracer->tracer, span->span, &writer, err);
|
|
if (span_ctx != NULL) {
|
|
int i = 0;
|
|
|
|
if (conf_span->ctx_flags & (FLT_OT_CTX_USE_VARS | FLT_OT_CTX_USE_HEADERS)) {
|
|
for (text_map = &(writer.text_map); i < text_map->count; i++) {
|
|
#ifdef USE_OT_VARS
|
|
if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_VARS))
|
|
/* Do nothing. */;
|
|
else if (flt_ot_var_register(FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], err) == -1)
|
|
retval = FLT_OT_RET_ERROR;
|
|
else if (flt_ot_var_set(s, FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], text_map->value[i], dir, err) == -1)
|
|
retval = FLT_OT_RET_ERROR;
|
|
#endif
|
|
|
|
if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_HEADERS))
|
|
/* Do nothing. */;
|
|
else if (flt_ot_http_header_set(chn, conf_span->ctx_id, text_map->key[i], text_map->value[i], err) == -1)
|
|
retval = FLT_OT_RET_ERROR;
|
|
}
|
|
}
|
|
|
|
span_ctx->destroy(&span_ctx);
|
|
otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
|
|
}
|
|
}
|
|
|
|
FLT_OT_RETURN(retval);
|
|
}
|
|
|
|
|
|
/***
|
|
* NAME
|
|
* flt_ot_scope_run -
|
|
*
|
|
* ARGUMENTS
|
|
* s -
|
|
* f -
|
|
* chn -
|
|
* conf_scope -
|
|
* ts -
|
|
* dir -
|
|
* err -
|
|
*
|
|
* DESCRIPTION
|
|
* -
|
|
*
|
|
* RETURN VALUE
|
|
* Returns a negative value if an error occurs, 0 if it needs to wait,
|
|
* any other value otherwise.
|
|
*/
|
|
int flt_ot_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_ot_conf_scope *conf_scope, const struct timespec *ts, uint dir, char **err)
|
|
{
|
|
struct flt_ot_conf *conf = FLT_OT_CONF(f);
|
|
struct flt_ot_conf_context *conf_ctx;
|
|
struct flt_ot_conf_span *conf_span;
|
|
struct flt_ot_conf_str *finish;
|
|
struct timespec ts_now;
|
|
int retval = FLT_OT_RET_OK;
|
|
|
|
FLT_OT_FUNC("%p, %p, %p, %p, %p, %u, %p:%p", s, f, chn, conf_scope, ts, dir, FLT_OT_DPTR_ARGS(err));
|
|
|
|
FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
|
|
FLT_OT_DBG(3, "run scope '%s' %d", conf_scope->id, conf_scope->event);
|
|
FLT_OT_DBG_CONF_SCOPE("run scope ", conf_scope);
|
|
|
|
if (ts == NULL) {
|
|
(void)clock_gettime(CLOCK_MONOTONIC, &ts_now);
|
|
|
|
ts = &ts_now;
|
|
}
|
|
|
|
if (conf_scope->cond != NULL) {
|
|
enum acl_test_res res;
|
|
int rc;
|
|
|
|
res = acl_exec_cond(conf_scope->cond, s->be, s->sess, s, dir | SMP_OPT_FINAL);
|
|
rc = acl_pass(res);
|
|
if (conf_scope->cond->pol == ACL_COND_UNLESS)
|
|
rc = !rc;
|
|
|
|
FLT_OT_DBG(3, "the ACL rule %s", rc ? "matches" : "does not match");
|
|
|
|
/*
|
|
* If the rule does not match, the current scope is skipped.
|
|
*
|
|
* If it is a root span, further processing of the session is
|
|
* disabled. As soon as the first span is encountered which
|
|
* is marked as root, further search is interrupted.
|
|
*/
|
|
if (!rc) {
|
|
list_for_each_entry(conf_span, &(conf_scope->spans), list)
|
|
if (conf_span->flag_root) {
|
|
FLT_OT_DBG(0, "session disabled");
|
|
|
|
FLT_OT_RT_CTX(f->ctx)->flag_disabled = 1;
|
|
|
|
_HA_ATOMIC_ADD(conf->cnt.disabled + 0, 1);
|
|
|
|
break;
|
|
}
|
|
|
|
FLT_OT_RETURN(retval);
|
|
}
|
|
}
|
|
|
|
list_for_each_entry(conf_ctx, &(conf_scope->contexts), list) {
|
|
struct otc_text_map *text_map = NULL;
|
|
|
|
FLT_OT_DBG(3, "run context '%s' -> '%s'", conf_scope->id, conf_ctx->id);
|
|
FLT_OT_DBG_CONF_CONTEXT("run context ", conf_ctx);
|
|
|
|
/*
|
|
* The OpenTracing context is read from the HTTP header
|
|
* or from HAProxy variables.
|
|
*/
|
|
if (conf_ctx->flags & FLT_OT_CTX_USE_HEADERS)
|
|
text_map = flt_ot_http_headers_get(chn, conf_ctx->id, conf_ctx->id_len, err);
|
|
#ifdef USE_OT_VARS
|
|
else
|
|
text_map = flt_ot_vars_get(s, FLT_OT_VARS_SCOPE, conf_ctx->id, dir, err);
|
|
#endif
|
|
|
|
if (text_map != NULL) {
|
|
if (flt_ot_scope_context_init(f->ctx, conf->tracer->tracer, conf_ctx->id, conf_ctx->id_len, text_map, dir, err) == NULL)
|
|
retval = FLT_OT_RET_ERROR;
|
|
|
|
otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
|
|
} else {
|
|
retval = FLT_OT_RET_ERROR;
|
|
}
|
|
}
|
|
|
|
list_for_each_entry(conf_span, &(conf_scope->spans), list) {
|
|
struct flt_ot_scope_data data;
|
|
struct flt_ot_scope_span *span;
|
|
struct flt_ot_conf_sample *sample;
|
|
|
|
FLT_OT_DBG(3, "run span '%s' -> '%s'", conf_scope->id, conf_span->id);
|
|
FLT_OT_DBG_CONF_SPAN("run span ", conf_span);
|
|
|
|
(void)memset(&data, 0, sizeof(data));
|
|
|
|
span = flt_ot_scope_span_init(f->ctx, conf_span->id, conf_span->id_len, conf_span->ref_type, conf_span->ref_id, conf_span->ref_id_len, dir, err);
|
|
if (span == NULL)
|
|
retval = FLT_OT_RET_ERROR;
|
|
|
|
list_for_each_entry(sample, &(conf_span->tags), list) {
|
|
FLT_OT_DBG(3, "adding tag '%s' -> '%s'", sample->key, sample->value);
|
|
|
|
if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_TAG, err) == FLT_OT_RET_ERROR)
|
|
retval = FLT_OT_RET_ERROR;
|
|
}
|
|
|
|
list_for_each_entry(sample, &(conf_span->logs), list) {
|
|
FLT_OT_DBG(3, "adding log '%s' -> '%s'", sample->key, sample->value);
|
|
|
|
if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_LOG, err) == FLT_OT_RET_ERROR)
|
|
retval = FLT_OT_RET_ERROR;
|
|
}
|
|
|
|
list_for_each_entry(sample, &(conf_span->baggages), list) {
|
|
FLT_OT_DBG(3, "adding baggage '%s' -> '%s'", sample->key, sample->value);
|
|
|
|
if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_BAGGAGE, err) == FLT_OT_RET_ERROR)
|
|
retval = FLT_OT_RET_ERROR;
|
|
}
|
|
|
|
if (retval != FLT_OT_RET_ERROR)
|
|
if (flt_ot_scope_run_span(s, f, chn, dir, span, &data, conf_span, ts, err) == FLT_OT_RET_ERROR)
|
|
retval = FLT_OT_RET_ERROR;
|
|
|
|
flt_ot_scope_data_free(&data);
|
|
}
|
|
|
|
list_for_each_entry(finish, &(conf_scope->finish), list)
|
|
if (flt_ot_scope_finish_mark(f->ctx, finish->str, finish->str_len) == -1)
|
|
retval = FLT_OT_RET_ERROR;
|
|
|
|
flt_ot_scope_finish_marked(f->ctx, ts);
|
|
flt_ot_scope_free_unused(f->ctx, chn);
|
|
|
|
FLT_OT_RETURN(retval);
|
|
}
|
|
|
|
|
|
/***
|
|
* NAME
|
|
* flt_ot_event_run -
|
|
*
|
|
* ARGUMENTS
|
|
* s -
|
|
* f -
|
|
* chn -
|
|
* event -
|
|
* err -
|
|
*
|
|
* DESCRIPTION
|
|
* -
|
|
*
|
|
* RETURN VALUE
|
|
* Returns a negative value if an error occurs, 0 if it needs to wait,
|
|
* any other value otherwise.
|
|
*/
|
|
int flt_ot_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err)
|
|
{
|
|
struct flt_ot_conf *conf = FLT_OT_CONF(f);
|
|
struct flt_ot_conf_scope *conf_scope;
|
|
struct timespec ts;
|
|
int retval = FLT_OT_RET_OK;
|
|
|
|
FLT_OT_FUNC("%p, %p, %p, %d, %p:%p", s, f, chn, event, FLT_OT_DPTR_ARGS(err));
|
|
|
|
FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
|
|
FLT_OT_DBG(3, "run event '%s' %d", flt_ot_event_data[event].name, event);
|
|
|
|
#ifdef DEBUG_OT
|
|
_HA_ATOMIC_ADD(conf->cnt.event[event].htx + (htx_is_empty(htxbuf(&(chn->buf))) ? 1 : 0), 1);
|
|
#endif
|
|
|
|
FLT_OT_RT_CTX(f->ctx)->analyzers |= flt_ot_event_data[event].an_bit;
|
|
|
|
/* All spans should be created/completed at the same time. */
|
|
(void)clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
/*
|
|
* It is possible that there are defined multiple scopes that use the
|
|
* same event. Therefore, there must not be a 'break' here, ie an
|
|
* exit from the 'for' loop.
|
|
*/
|
|
list_for_each_entry(conf_scope, &(conf->scopes), list) {
|
|
if (conf_scope->event != event)
|
|
/* Do nothing. */;
|
|
else if (!conf_scope->flag_used)
|
|
FLT_OT_DBG(3, "scope '%s' %d not used", conf_scope->id, conf_scope->event);
|
|
else if (flt_ot_scope_run(s, f, chn, conf_scope, &ts, flt_ot_event_data[event].smp_opt_dir, err) == FLT_OT_RET_ERROR)
|
|
retval = FLT_OT_RET_ERROR;
|
|
}
|
|
|
|
#ifdef USE_OT_VARS
|
|
flt_ot_vars_dump(s);
|
|
#endif
|
|
flt_ot_http_headers_dump(chn);
|
|
|
|
FLT_OT_DBG(3, "event = %d, chn = %p, s->req = %p, s->res = %p", event, chn, &(s->req), &(s->res));
|
|
|
|
FLT_OT_RETURN(retval);
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-indent-level: 8
|
|
* c-basic-offset: 8
|
|
* End:
|
|
*
|
|
* vi: noexpandtab shiftwidth=8 tabstop=8
|
|
*/
|