blob: 0cb6b1d72722ce317f15090ec62eefd7a72e084d [file] [log] [blame]
Miroslav Zagorac70230c62020-12-09 16:54:31 +01001/***
2 * Copyright 2020 HAProxy Technologies
3 *
4 * This file is part of the HAProxy OpenTracing filter.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20#include "include.h"
21
22
23#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 },
24const struct flt_ot_event_data flt_ot_event_data[FLT_OT_EVENT_MAX] = { FLT_OT_EVENT_DEFINES };
25#undef FLT_OT_EVENT_DEF
26
27
28/***
29 * NAME
30 * flt_ot_scope_run_span -
31 *
32 * ARGUMENTS
33 * s -
34 * f -
35 * chn -
36 * dir -
37 * span -
38 * data -
39 * conf_span -
40 * ts -
41 * err -
42 *
43 * DESCRIPTION
44 * -
45 *
46 * RETURN VALUE
47 * Returns a negative value if an error occurs, 0 if it needs to wait,
48 * any other value otherwise.
49 */
50static 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)
51{
52 struct flt_ot_conf *conf = FLT_OT_CONF(f);
53 int retval = FLT_OT_RET_OK;
54
55 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));
56
57 if (span == NULL)
58 FLT_OT_RETURN(retval);
59
60 if (span->span == NULL) {
61 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);
62 if (span->span == NULL)
63 retval = FLT_OT_RET_ERROR;
64 }
65 else if (data->num_tags > 0)
66 if (ot_span_tag(span->span, data->tags, data->num_tags) == -1)
67 retval = FLT_OT_RET_ERROR;
68
69 if ((span->span != NULL) && (data->baggage != NULL))
70 if (ot_span_set_baggage(span->span, data->baggage) == -1)
71 retval = FLT_OT_RET_ERROR;
72
73 if ((span->span != NULL) && (data->num_log_fields > 0))
74 if (ot_span_log(span->span, data->log_fields, data->num_log_fields) == -1)
75 retval = FLT_OT_RET_ERROR;
76
77 if ((span->span != NULL) && (conf_span->ctx_id != NULL)) {
78 struct otc_http_headers_writer writer;
79 struct otc_text_map *text_map = NULL;
80 struct otc_span_context *span_ctx;
81
82 span_ctx = ot_inject_http_headers(conf->tracer->tracer, span->span, &writer, err);
83 if (span_ctx != NULL) {
84 int i = 0;
85
86 if (conf_span->ctx_flags & (FLT_OT_CTX_USE_VARS | FLT_OT_CTX_USE_HEADERS)) {
87 for (text_map = &(writer.text_map); i < text_map->count; i++) {
Miroslav Zagorac4cb2c832021-09-08 20:56:05 +020088#ifdef USE_OT_VARS
Miroslav Zagorac70230c62020-12-09 16:54:31 +010089 if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_VARS))
90 /* Do nothing. */;
91 else if (flt_ot_var_register(FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], err) == -1)
92 retval = FLT_OT_RET_ERROR;
93 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)
94 retval = FLT_OT_RET_ERROR;
Miroslav Zagorac4cb2c832021-09-08 20:56:05 +020095#endif
Miroslav Zagorac70230c62020-12-09 16:54:31 +010096
97 if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_HEADERS))
98 /* Do nothing. */;
99 else if (flt_ot_http_header_set(chn, conf_span->ctx_id, text_map->key[i], text_map->value[i], err) == -1)
100 retval = FLT_OT_RET_ERROR;
101 }
102 }
103
104 span_ctx->destroy(&span_ctx);
105 otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
106 }
107 }
108
109 FLT_OT_RETURN(retval);
110}
111
112
113/***
114 * NAME
115 * flt_ot_scope_run -
116 *
117 * ARGUMENTS
118 * s -
119 * f -
120 * chn -
121 * conf_scope -
122 * ts -
123 * dir -
124 * err -
125 *
126 * DESCRIPTION
127 * -
128 *
129 * RETURN VALUE
130 * Returns a negative value if an error occurs, 0 if it needs to wait,
131 * any other value otherwise.
132 */
133int 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)
134{
135 struct flt_ot_conf *conf = FLT_OT_CONF(f);
136 struct flt_ot_conf_context *conf_ctx;
137 struct flt_ot_conf_span *conf_span;
138 struct flt_ot_conf_str *finish;
139 struct timespec ts_now;
140 int retval = FLT_OT_RET_OK;
141
142 FLT_OT_FUNC("%p, %p, %p, %p, %p, %u, %p:%p", s, f, chn, conf_scope, ts, dir, FLT_OT_DPTR_ARGS(err));
143
144 FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
145 FLT_OT_DBG(3, "run scope '%s' %d", conf_scope->id, conf_scope->event);
146 FLT_OT_DBG_CONF_SCOPE("run scope ", conf_scope);
147
148 if (ts == NULL) {
149 (void)clock_gettime(CLOCK_MONOTONIC, &ts_now);
150
151 ts = &ts_now;
152 }
153
154 if (conf_scope->cond != NULL) {
155 enum acl_test_res res;
156 int rc;
157
158 res = acl_exec_cond(conf_scope->cond, s->be, s->sess, s, dir | SMP_OPT_FINAL);
159 rc = acl_pass(res);
160 if (conf_scope->cond->pol == ACL_COND_UNLESS)
161 rc = !rc;
162
163 FLT_OT_DBG(3, "the ACL rule %s", rc ? "matches" : "does not match");
164
165 /*
166 * If the rule does not match, the current scope is skipped.
167 *
168 * If it is a root span, further processing of the session is
169 * disabled. As soon as the first span is encountered which
170 * is marked as root, further search is interrupted.
171 */
172 if (!rc) {
173 list_for_each_entry(conf_span, &(conf_scope->spans), list)
174 if (conf_span->flag_root) {
175 FLT_OT_DBG(0, "session disabled");
176
177 FLT_OT_RT_CTX(f->ctx)->flag_disabled = 1;
178
179 _HA_ATOMIC_ADD(conf->cnt.disabled + 0, 1);
180
181 break;
182 }
183
184 FLT_OT_RETURN(retval);
185 }
186 }
187
188 list_for_each_entry(conf_ctx, &(conf_scope->contexts), list) {
Miroslav Zagorac4cb2c832021-09-08 20:56:05 +0200189 struct otc_text_map *text_map = NULL;
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100190
191 FLT_OT_DBG(3, "run context '%s' -> '%s'", conf_scope->id, conf_ctx->id);
192 FLT_OT_DBG_CONF_CONTEXT("run context ", conf_ctx);
193
194 /*
195 * The OpenTracing context is read from the HTTP header
196 * or from HAProxy variables.
197 */
198 if (conf_ctx->flags & FLT_OT_CTX_USE_HEADERS)
199 text_map = flt_ot_http_headers_get(chn, conf_ctx->id, conf_ctx->id_len, err);
Miroslav Zagorac4cb2c832021-09-08 20:56:05 +0200200#ifdef USE_OT_VARS
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100201 else
202 text_map = flt_ot_vars_get(s, FLT_OT_VARS_SCOPE, conf_ctx->id, dir, err);
Miroslav Zagorac4cb2c832021-09-08 20:56:05 +0200203#endif
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100204
205 if (text_map != NULL) {
206 if (flt_ot_scope_context_init(f->ctx, conf->tracer->tracer, conf_ctx->id, conf_ctx->id_len, text_map, dir, err) == NULL)
207 retval = FLT_OT_RET_ERROR;
208
209 otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
210 } else {
211 retval = FLT_OT_RET_ERROR;
212 }
213 }
214
215 list_for_each_entry(conf_span, &(conf_scope->spans), list) {
216 struct flt_ot_scope_data data;
217 struct flt_ot_scope_span *span;
218 struct flt_ot_conf_sample *sample;
219
220 FLT_OT_DBG(3, "run span '%s' -> '%s'", conf_scope->id, conf_span->id);
221 FLT_OT_DBG_CONF_SPAN("run span ", conf_span);
222
223 (void)memset(&data, 0, sizeof(data));
224
225 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);
226 if (span == NULL)
227 retval = FLT_OT_RET_ERROR;
228
229 list_for_each_entry(sample, &(conf_span->tags), list) {
230 FLT_OT_DBG(3, "adding tag '%s' -> '%s'", sample->key, sample->value);
231
232 if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_TAG, err) == FLT_OT_RET_ERROR)
233 retval = FLT_OT_RET_ERROR;
234 }
235
236 list_for_each_entry(sample, &(conf_span->logs), list) {
237 FLT_OT_DBG(3, "adding log '%s' -> '%s'", sample->key, sample->value);
238
239 if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_LOG, err) == FLT_OT_RET_ERROR)
240 retval = FLT_OT_RET_ERROR;
241 }
242
243 list_for_each_entry(sample, &(conf_span->baggages), list) {
244 FLT_OT_DBG(3, "adding baggage '%s' -> '%s'", sample->key, sample->value);
245
246 if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_BAGGAGE, err) == FLT_OT_RET_ERROR)
247 retval = FLT_OT_RET_ERROR;
248 }
249
250 if (retval != FLT_OT_RET_ERROR)
251 if (flt_ot_scope_run_span(s, f, chn, dir, span, &data, conf_span, ts, err) == FLT_OT_RET_ERROR)
252 retval = FLT_OT_RET_ERROR;
253
254 flt_ot_scope_data_free(&data);
255 }
256
257 list_for_each_entry(finish, &(conf_scope->finish), list)
258 if (flt_ot_scope_finish_mark(f->ctx, finish->str, finish->str_len) == -1)
259 retval = FLT_OT_RET_ERROR;
260
261 flt_ot_scope_finish_marked(f->ctx, ts);
262 flt_ot_scope_free_unused(f->ctx, chn);
263
264 FLT_OT_RETURN(retval);
265}
266
267
268/***
269 * NAME
270 * flt_ot_event_run -
271 *
272 * ARGUMENTS
273 * s -
274 * f -
275 * chn -
276 * event -
277 * err -
278 *
279 * DESCRIPTION
280 * -
281 *
282 * RETURN VALUE
283 * Returns a negative value if an error occurs, 0 if it needs to wait,
284 * any other value otherwise.
285 */
286int flt_ot_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err)
287{
288 struct flt_ot_conf *conf = FLT_OT_CONF(f);
289 struct flt_ot_conf_scope *conf_scope;
290 struct timespec ts;
291 int retval = FLT_OT_RET_OK;
292
293 FLT_OT_FUNC("%p, %p, %p, %d, %p:%p", s, f, chn, event, FLT_OT_DPTR_ARGS(err));
294
295 FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
296 FLT_OT_DBG(3, "run event '%s' %d", flt_ot_event_data[event].name, event);
297
298#ifdef DEBUG_OT
299 _HA_ATOMIC_ADD(conf->cnt.event[event].htx + (htx_is_empty(htxbuf(&(chn->buf))) ? 1 : 0), 1);
300#endif
301
302 FLT_OT_RT_CTX(f->ctx)->analyzers |= flt_ot_event_data[event].an_bit;
303
304 /* All spans should be created/completed at the same time. */
305 (void)clock_gettime(CLOCK_MONOTONIC, &ts);
306
307 /*
308 * It is possible that there are defined multiple scopes that use the
309 * same event. Therefore, there must not be a 'break' here, ie an
310 * exit from the 'for' loop.
311 */
312 list_for_each_entry(conf_scope, &(conf->scopes), list) {
313 if (conf_scope->event != event)
314 /* Do nothing. */;
315 else if (!conf_scope->flag_used)
316 FLT_OT_DBG(3, "scope '%s' %d not used", conf_scope->id, conf_scope->event);
317 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)
318 retval = FLT_OT_RET_ERROR;
319 }
320
Miroslav Zagorac4cb2c832021-09-08 20:56:05 +0200321#ifdef USE_OT_VARS
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100322 flt_ot_vars_dump(s);
Miroslav Zagorac4cb2c832021-09-08 20:56:05 +0200323#endif
Miroslav Zagorac70230c62020-12-09 16:54:31 +0100324 flt_ot_http_headers_dump(chn);
325
326 FLT_OT_DBG(3, "event = %d, chn = %p, s->req = %p, s->res = %p", event, chn, &(s->req), &(s->res));
327
328 FLT_OT_RETURN(retval);
329}
330
331/*
332 * Local variables:
333 * c-indent-level: 8
334 * c-basic-offset: 8
335 * End:
336 *
337 * vi: noexpandtab shiftwidth=8 tabstop=8
338 */