diff options
Diffstat (limited to '')
-rw-r--r-- | test/Makefile.am | 23 | ||||
-rw-r--r-- | test/cfg-dd.json | 5 | ||||
-rw-r--r-- | test/cfg-jaeger.yml | 34 | ||||
-rw-r--r-- | test/cfg-zipkin.json | 4 | ||||
-rw-r--r-- | test/debug.h | 58 | ||||
-rw-r--r-- | test/define.h | 61 | ||||
-rwxr-xr-x | test/get-opentracing-plugins.sh | 45 | ||||
-rw-r--r-- | test/include.h | 67 | ||||
-rw-r--r-- | test/opentracing.c | 771 | ||||
-rw-r--r-- | test/opentracing.h | 42 | ||||
-rw-r--r-- | test/test.c | 485 | ||||
-rw-r--r-- | test/util.c | 118 | ||||
-rw-r--r-- | test/util.h | 33 |
13 files changed, 1746 insertions, 0 deletions
diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..72b61e7 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,23 @@ +## Process this file with automake to produce Makefile.in +## + AM_CPPFLAGS = -I\$(top_builddir)/include -I$(srcdir)/../include @OPENTRACING_C_WRAPPER_CPPFLAGS@ + AM_CFLAGS = @OPENTRACING_C_WRAPPER_CFLAGS@ + AM_LDFLAGS = @OPENTRACING_C_WRAPPER_LDFLAGS@ + +if WANT_DEBUG + bin_PROGRAMS = ot-c-wrapper-test_dbg +ot_c_wrapper_test_dbg_SOURCES = opentracing.c test.c util.c + ot_c_wrapper_test_dbg_LDADD = -lstdc++ -lm @OPENTRACING_C_WRAPPER_LIBS@ $(top_builddir)/src/libopentracing-c-wrapper_dbg.la +ot_c_wrapper_test_dbg_LDFLAGS = @OPENTRACING_C_WRAPPER_LDFLAGS@ + +else + + bin_PROGRAMS = ot-c-wrapper-test +ot_c_wrapper_test_SOURCES = opentracing.c test.c util.c + ot_c_wrapper_test_LDADD = -lstdc++ -lm @OPENTRACING_C_WRAPPER_LIBS@ $(top_builddir)/src/libopentracing-c-wrapper.la +ot_c_wrapper_test_LDFLAGS = @OPENTRACING_C_WRAPPER_LDFLAGS@ +endif + +CLEANFILES = a.out +## +## Makefile.am ends here diff --git a/test/cfg-dd.json b/test/cfg-dd.json new file mode 100644 index 0000000..5763d06 --- /dev/null +++ b/test/cfg-dd.json @@ -0,0 +1,5 @@ +{ + "service": "opentracing-c-wrapper-test", + "agent_host": "localhost", + "agent_port": 8126 +} diff --git a/test/cfg-jaeger.yml b/test/cfg-jaeger.yml new file mode 100644 index 0000000..ca3904f --- /dev/null +++ b/test/cfg-jaeger.yml @@ -0,0 +1,34 @@ +service_name: + opentracing-c-wrapper-test + +### +# When using configuration object to instantiate the tracer, the type of +# sampling can be selected via sampler.type and sampler.param properties. +# Jaeger libraries support the following samplers: +# +# - Constant (sampler.type=const) sampler always makes the same decision for +# all traces. It either samples all traces (sampler.param=1) or none of +# them (sampler.param=0). +# +# - Probabilistic (sampler.type=probabilistic) sampler makes a random sampling +# decision with the probability of sampling equal to the value of +# sampler.param property. For example, with sampler.param=0.1 approximately +# 1 in 10 traces will be sampled. +# +# - Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate +# limiter to ensure that traces are sampled with a certain constant rate. +# For example, when sampler.param=2.0 it will sample requests with the rate +# of 2 traces per second. +# +# - Remote (sampler.type=remote, which is also the default) sampler consults +# Jaeger agent for the appropriate sampling strategy to use in the current +# service. This allows controlling the sampling strategies in the services +# from a central configuration in Jaeger backend, or even dynamically. +# +sampler: + type: ratelimiting + param: 10.0 + +reporter: + logSpans: true + localAgentHostPort: localhost:6831 diff --git a/test/cfg-zipkin.json b/test/cfg-zipkin.json new file mode 100644 index 0000000..e25634f --- /dev/null +++ b/test/cfg-zipkin.json @@ -0,0 +1,4 @@ +{ + "service_name": "opentracing-c-wrapper-test", + "collector_host": "localhost" +} diff --git a/test/debug.h b/test/debug.h new file mode 100644 index 0000000..c8d22b8 --- /dev/null +++ b/test/debug.h @@ -0,0 +1,58 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef TEST_DEBUG_H +#define TEST_DEBUG_H + +#define OT_LOG(f,...) (void)printf("[%4d] " f "\n", thread_id(), ##__VA_ARGS__) + +#ifdef DEBUG +enum DBG_LEVEL_enum { + DBG_LEVEL_FUNC = 0, /* Function debug level. */ + DBG_LEVEL_INFO, /* Generic info level. */ + DBG_LEVEL_DEBUG, /* Generic debug level. */ + DBG_LEVEL_OT, /* OpenTracing debug level. */ + DBG_LEVEL_WORKER, /* Worker debug level. */ + DBG_LEVEL_ENABLED, /* This have to be the last entry. */ +}; + +# define OT_FUNC(f,...) \ + do { \ + if (_nNULL(cfg_debug_level) && (*cfg_debug_level > 0)) \ + OT_LOG("%s(" f ")", __func__, ##__VA_ARGS__); \ + } while (0) +# define OT_DBG(l,f,...) \ + do { \ + if (_nNULL(cfg_debug_level) && (*cfg_debug_level & (1 << DBG_LEVEL_##l))) \ + OT_LOG(" " f, ##__VA_ARGS__); \ + } while (0) + + +extern uint8_t *cfg_debug_level; +#else +# define OT_FUNC(...) do { } while (0) +# define OT_DBG(...) do { } while (0) +#endif /* DEBUG */ + +#endif /* TEST_DEBUG_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ diff --git a/test/define.h b/test/define.h new file mode 100644 index 0000000..68dcf60 --- /dev/null +++ b/test/define.h @@ -0,0 +1,61 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef TEST_DEFINE_H +#define TEST_DEFINE_H + +#ifdef DEBUG +# define OTC_DBG_MEM +#endif + +#ifndef PACKAGE_BUILD +# define PACKAGE_BUILD 0 +#endif + +#define OT_USE_INJECT_CB +#define OT_USE_EXTRACT_CB + +#ifdef __linux__ +# define PRI_PIDT "d" +# define PRI_PTHREADT "lu" +#else +# define PRI_PIDT "ld" +# define PRI_PTHREADT "u" +#endif + +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define _NULL(a) ((a) == NULL) +#define _nNULL(a) ((a) != NULL) +#define TABLESIZE(a) ((int)(sizeof(a) / sizeof((a)[0]))) +#define IN_RANGE(v,a,b) (((v) >= (a)) && ((v) <= (b))) +#define TIMEVAL_DIFF_MS(a,b) (((a)->tv_sec - (b)->tv_sec) * 1000ULL + ((a)->tv_usec - (b)->tv_usec + 500) / 1000) +#define TIMEVAL_DIFF_US(a,b) (((a)->tv_sec - (b)->tv_sec) * 1000000ULL + (a)->tv_usec - (b)->tv_usec) +#define NIBBLE_TO_HEX(a) ((a) + (((a) < 10) ? '0' : ('a' - 10))) +#define SWAP(a,b) do { typeof(a) _a = (a); (a) = (b); (b) = _a; } while (0) +#define OT_VARGS(t,v) otc_value_##t, (v) + +#endif /* TEST_DEFINE_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ diff --git a/test/get-opentracing-plugins.sh b/test/get-opentracing-plugins.sh new file mode 100755 index 0000000..f2fe2d6 --- /dev/null +++ b/test/get-opentracing-plugins.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# +_ARG_DIR="${1:-.}" + + +get () +{ + local _arg_tracer="${1}" + local _arg_version="${2}" + local _arg_url="${3}" + local _arg_file="${4}" + local _var_tmpfile="_tmpfile_" + local _var_plugin="lib${_arg_tracer}_opentracing_plugin-${_arg_version}.so" + + test -e "${_var_plugin}" && return 0 + + wget "https://github.com/${_arg_url}/releases/download/v${_arg_version}/${_arg_file}" -O "${_var_tmpfile}" || { + rm "${_var_tmpfile}" + return 1 + } + + case "$(file ${_var_tmpfile})" in + *shared\ object*) + mv "${_var_tmpfile}" "${_var_plugin}" ;; + + *gzip\ compressed\ data*) + gzip -cd "${_var_tmpfile}" > "${_var_plugin}" + rm "${_var_tmpfile}" ;; + esac +} + + +mkdir -p "${_ARG_DIR}" && cd "${_ARG_DIR}" || exit 1 + +get dd 1.1.2 DataDog/dd-opentracing-cpp linux-amd64-libdd_opentracing_plugin.so.gz +get dd 1.2.0 DataDog/dd-opentracing-cpp linux-amd64-libdd_opentracing_plugin.so.gz + +get jaeger 0.4.2 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so +#et jaeger 0.5.0 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so +#et jaeger 0.6.0 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so + +get lightstep 0.12.0 lightstep/lightstep-tracer-cpp linux-amd64-liblightstep_tracer_plugin.so.gz +get lightstep 0.13.0 lightstep/lightstep-tracer-cpp linux-amd64-liblightstep_tracer_plugin.so.gz + +get zipkin 0.5.2 rnburn/zipkin-cpp-opentracing linux-amd64-libzipkin_opentracing_plugin.so.gz diff --git a/test/include.h b/test/include.h new file mode 100644 index 0000000..328ba72 --- /dev/null +++ b/test/include.h @@ -0,0 +1,67 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef TEST_INCLUDE_H +#define TEST_INCLUDE_H + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <stdbool.h> +#include <errno.h> +#include <unistd.h> +#include <getopt.h> +#include <inttypes.h> +#include <libgen.h> +#include <pthread.h> +#include <sysexits.h> +#include <time.h> +#include <fcntl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef __linux__ +# include <sys/syscall.h> +#endif + +#include "config.h" +#include "define.h" + +#include "opentracing-c-wrapper/define.h" +#include "opentracing-c-wrapper/dbg_malloc.h" +#include "opentracing-c-wrapper/common.h" +#include "opentracing-c-wrapper/util.h" +#include "opentracing-c-wrapper/value.h" +#include "opentracing-c-wrapper/span.h" +#include "opentracing-c-wrapper/propagation.h" +#include "opentracing-c-wrapper/tracer.h" + +#include "version.h" +#include "debug.h" +#include "opentracing.h" +#include "util.h" + +#endif /* TEST_INCLUDE_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ diff --git a/test/opentracing.c b/test/opentracing.c new file mode 100644 index 0000000..2e30fe5 --- /dev/null +++ b/test/opentracing.c @@ -0,0 +1,771 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "include.h" + + +static void ot_text_map_show(const struct otc_text_map *text_map) +{ + OT_FUNC("%p", text_map); + + if (_NULL(text_map)) + return; + + OT_DBG(OT, "%p:{ %p %p %zu/%zu %hhu }", text_map, text_map->key, text_map->value, text_map->count, text_map->size, text_map->is_dynamic); + + if (_nNULL(text_map->key) && _nNULL(text_map->value) && (text_map->count > 0)) { + size_t i; + + for (i = 0; i < text_map->count; i++) + OT_DBG(OT, " \"%s\" -> \"%s\"", text_map->key[i], text_map->value[i]); + } +} + + +/*** + * NAME + * ot_span_init - + * + * ARGUMENTS + * operation_name - + * ref_type - + * ref_ctx_idx - + * ref_span - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_span *ot_span_init(struct otc_tracer *tracer, const char *operation_name, int ref_type, int ref_ctx_idx, const struct otc_span *ref_span) +{ + struct otc_start_span_options options; + struct otc_span_context context = { .idx = ref_ctx_idx, .span = ref_span }; + struct otc_span_reference references = { ref_type, &context }; + struct otc_span *retptr = NULL; + + OT_FUNC("%p, \"%s\", %d, %d, %p", tracer, operation_name, ref_type, ref_ctx_idx, ref_span); + + (void)memset(&options, 0, sizeof(options)); + + if (IN_RANGE(ref_type, otc_span_reference_child_of, otc_span_reference_follows_from)) { + options.references = &references; + options.num_references = 1; + } + + retptr = tracer->start_span_with_options(tracer, operation_name, &options); + if (_NULL(retptr)) + OT_DBG(OT, "cannot init new span"); + else + OT_DBG(OT, "span %p:%zu initialized", retptr, retptr->idx); + + return retptr; +} + + +/*** + * NAME + * ot_span_tag - + * + * ARGUMENTS + * span - + * key - + * type - + * value - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +int ot_span_tag(struct otc_span *span, const char *key, int type, ...) +{ + va_list ap; + struct otc_value ot_value; + int retval = -1; + + OT_FUNC("%p, \"%s\", %d, ...", span, key, type); + + if (_NULL(span)) + return retval; + + va_start(ap, type); + for (retval = 0; _nNULL(key) && IN_RANGE(type, otc_value_bool, otc_value_null); retval++) { + ot_value.type = type; + if (type == otc_value_bool) + ot_value.value.bool_value = va_arg(ap, typeof(ot_value.value.bool_value)); + else if (type == otc_value_double) + ot_value.value.double_value = va_arg(ap, typeof(ot_value.value.double_value)); + else if (type == otc_value_int64) + ot_value.value.int64_value = va_arg(ap, typeof(ot_value.value.int64_value)); + else if (type == otc_value_uint64) + ot_value.value.uint64_value = va_arg(ap, typeof(ot_value.value.uint64_value)); + else if (type == otc_value_string) + ot_value.value.string_value = va_arg(ap, typeof(ot_value.value.string_value)); + else if (type == otc_value_null) + ot_value.value.string_value = va_arg(ap, typeof(ot_value.value.string_value)); + span->set_tag(span, key, &ot_value); + + if (_nNULL(key = va_arg(ap, typeof(key)))) + type = va_arg(ap, typeof(type)); + } + va_end(ap); + + return retval; +} + + +/*** + * NAME + * ot_span_set_baggage - + * + * ARGUMENTS + * span - + * key - + * value - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +int ot_span_set_baggage(struct otc_span *span, const char *key, const char *value, ...) +{ + va_list ap; + int retval = -1; + + OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, value); + + if (_NULL(span)) + return retval; + + va_start(ap, value); + for (retval = 0; _nNULL(key); retval++) { + OT_DBG(OT, "set baggage: \"%s\" \"%s\"", key, value); + + span->set_baggage_item(span, key, value); + + if (_nNULL(key = va_arg(ap, typeof(key)))) + value = va_arg(ap, typeof(value)); + } + va_end(ap); + + return retval; +} + + +/*** + * NAME + * ot_span_baggage - + * + * ARGUMENTS + * span - + * key - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_text_map *ot_span_baggage(const struct otc_span *span, const char *key, ...) +{ + va_list ap; + struct otc_text_map *retptr = NULL; + int i, n; + + OT_FUNC("%p, \"%s\", ...", span, key); + + if (_NULL(span) || _NULL(key)) + return retptr; + + va_start(ap, key); + for (n = 1; _nNULL(va_arg(ap, typeof(key))); n++); + va_end(ap); + + if (_NULL(retptr = otc_text_map_new(NULL, n))) + return retptr; + + va_start(ap, key); + for (i = 0; (i < n) && _nNULL(key); i++) { + char *value; + + if (_nNULL(value = (char *)span->baggage_item(span, key))) { + (void)otc_text_map_add(retptr, key, 0, value, 0, OTC_TEXT_MAP_DUP_KEY); + + OT_DBG(OT, "get baggage[%d]: \"%s\" -> \"%s\"", i, retptr->key[i], retptr->value[i]); + } else { + OT_DBG(OT, "get baggage[%d]: \"%s\" -> invalid key", i, key); + } + + key = va_arg(ap, typeof(key)); + } + va_end(ap); + + return retptr; +} + + +/*** + * NAME + * ot_span_log_kv - + * + * ARGUMENTS + * span - + * key - + * value - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +int ot_span_log_kv(struct otc_span *span, const char *key, const char *value, ...) +{ + va_list ap; + struct otc_log_field log_data[OTC_MAXLOGFIELDS]; + int retval = -1; + + OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, value); + + if (_NULL(span) || _NULL(key) || _NULL(value)) + return retval; + + va_start(ap, value); + for (retval = 0; (retval < TABLESIZE(log_data)) && _nNULL(key); retval++) { + log_data[retval].key = key; + log_data[retval].value.type = otc_value_string; + log_data[retval].value.value.string_value = value; + + if (_nNULL(key = va_arg(ap, typeof(key)))) + value = va_arg(ap, typeof(value)); + } + va_end(ap); + + span->log_fields(span, log_data, retval); + + return retval; +} + + +/*** + * NAME + * ot_span_log - + * + * ARGUMENTS + * span - + * key - + * format - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +int ot_span_log(struct otc_span *span, const char *key, const char *format, ...) +{ + va_list ap; + char value[BUFSIZ]; + + OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, format); + + if (_NULL(span) || _NULL(key) || _NULL(format)) + return -1; + + va_start(ap, format); + (void)vsnprintf(value, sizeof(value), format, ap); + va_end(ap); + + return ot_span_log_kv(span, key, value, NULL); +} + + +#ifdef OT_USE_INJECT_CB + +/*** + * NAME + * ot_text_map_writer_set_cb - + * + * ARGUMENTS + * writer - + * key - + * value - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static otc_propagation_error_code_t ot_text_map_writer_set_cb(struct otc_text_map_writer *writer, const char *key, const char *value) +{ + otc_propagation_error_code_t retval = otc_propagation_error_code_success; + + OT_FUNC("%p, \"%s\", \"%s\"", writer, key, value); + + if (otc_text_map_add(&(writer->text_map), key, 0, value, 0, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1) + retval = otc_propagation_error_code_unknown; + + return retval; +} + +#endif /* OT_USE_INJECT_CB */ + + +#ifdef OT_USE_EXTRACT_CB + +/*** + * NAME + * ot_text_map_reader_foreach_key_cb - + * + * ARGUMENTS + * reader - + * handler - + * arg - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static otc_propagation_error_code_t ot_text_map_reader_foreach_key_cb(struct otc_text_map_reader *reader, otc_propagation_error_code_t (*handler)(void *arg, const char *key, const char *value), void *arg) +{ + size_t i; + otc_propagation_error_code_t retval = otc_propagation_error_code_success; + + OT_FUNC("%p, %p, %p", reader, handler, arg); + + for (i = 0; (retval == otc_propagation_error_code_success) && (i < reader->text_map.count); i++) { + OT_DBG(OT, "\"%s\" -> \"%s\"", reader->text_map.key[i], reader->text_map.value[i]); + + retval = handler(arg, reader->text_map.key[i], reader->text_map.value[i]); + } + + return retval; +} + +#endif /* OT_USE_EXTRACT_CB */ + + +/*** + * NAME + * ot_inject_text_map - + * + * ARGUMENTS + * tracer - + * span - + * carrier - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_span_context *ot_inject_text_map(struct otc_tracer *tracer, const struct otc_span *span, struct otc_text_map_writer *carrier) +{ + struct otc_span_context *retptr = NULL; + int rc; + + OT_FUNC("%p, %p, %p", tracer, span, carrier); + + if (_NULL(span)) + return retptr; + + if (_NULL(retptr = span->span_context((struct otc_span *)span))) + return retptr; + + (void)memset(carrier, 0, sizeof(*carrier)); +#ifdef OT_USE_INJECT_CB + carrier->set = ot_text_map_writer_set_cb; +#endif + + rc = tracer->inject_text_map(tracer, carrier, retptr); + if (rc != otc_propagation_error_code_success) { + OT_LOG(" ERROR: inject_text_map() failed: %d", rc); + + OTC_DBG_FREE(retptr); + } else { + OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy); + } + + OT_DBG(OT, "carrier %p: { { %p %p %zu/%zu %hhu } %p }", carrier, carrier->text_map.key, carrier->text_map.value, carrier->text_map.count, carrier->text_map.size, carrier->text_map.is_dynamic, carrier->set); + ot_text_map_show(&(carrier->text_map)); + + return retptr; +} + + +/*** + * NAME + * ot_extract_text_map - + * + * ARGUMENTS + * tracer - + * carrier - + * text_map - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_span_context *ot_extract_text_map(struct otc_tracer *tracer, struct otc_text_map_reader *carrier, const struct otc_text_map *text_map) +{ + struct otc_span_context *retptr = NULL; + int rc; + + OT_FUNC("%p, %p, %p", tracer, carrier, text_map); + + (void)memset(carrier, 0, sizeof(*carrier)); +#ifdef OT_USE_EXTRACT_CB + carrier->foreach_key = ot_text_map_reader_foreach_key_cb; +#endif + + if (_nNULL(text_map)) + (void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map)); + + OT_DBG(OT, "carrier %p: { { %p %p %zu/%zu %hhu } }", carrier, carrier->text_map.key, carrier->text_map.value, carrier->text_map.count, carrier->text_map.size, carrier->text_map.is_dynamic); + + rc = tracer->extract_text_map(tracer, carrier, &retptr); + if (rc != otc_propagation_error_code_success) { + OT_LOG(" ERROR: extract_text_map() failed: %d", rc); + + OTC_DBG_FREE(retptr); + } + else if (_nNULL(retptr)) { + OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy); + } + + return retptr; +} + + +#ifdef OT_USE_INJECT_CB + +/*** + * NAME + * ot_http_headers_writer_set_cb - + * + * ARGUMENTS + * writer - + * key - + * value - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static otc_propagation_error_code_t ot_http_headers_writer_set_cb(struct otc_http_headers_writer *writer, const char *key, const char *value) +{ + otc_propagation_error_code_t retval = otc_propagation_error_code_success; + + OT_FUNC("%p, \"%s\", \"%s\"", writer, key, value); + + if (otc_text_map_add(&(writer->text_map), key, 0, value, 0, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1) + retval = otc_propagation_error_code_unknown; + + return retval; +} + +#endif /* OT_USE_INJECT_CB */ + + +#ifdef OT_USE_EXTRACT_CB + +/*** + * NAME + * ot_http_headers_reader_foreach_key_cb - + * + * ARGUMENTS + * reader - + * handler - + * arg - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static otc_propagation_error_code_t ot_http_headers_reader_foreach_key_cb(struct otc_http_headers_reader *reader, otc_propagation_error_code_t (*handler)(void *arg, const char *key, const char *value), void *arg) +{ + size_t i; + otc_propagation_error_code_t retval = otc_propagation_error_code_success; + + OT_FUNC("%p, %p, %p", reader, handler, arg); + + for (i = 0; (retval == otc_propagation_error_code_success) && (i < reader->text_map.count); i++) { + OT_DBG(OT, "\"%s\" -> \"%s\"", reader->text_map.key[i], reader->text_map.value[i]); + + retval = handler(arg, reader->text_map.key[i], reader->text_map.value[i]); + } + + return retval; +} + +#endif /* OT_USE_EXTRACT_CB */ + + +/*** + * NAME + * ot_inject_http_headers - + * + * ARGUMENTS + * tracer - + * span - + * carrier - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_span_context *ot_inject_http_headers(struct otc_tracer *tracer, const struct otc_span *span, struct otc_http_headers_writer *carrier) +{ + struct otc_span_context *retptr = NULL; + int rc; + + OT_FUNC("%p, %p, %p", tracer, span, carrier); + + if (_NULL(span)) + return retptr; + + if (_NULL(retptr = span->span_context((struct otc_span *)span))) + return retptr; + + (void)memset(carrier, 0, sizeof(*carrier)); +#ifdef OT_USE_INJECT_CB + carrier->set = ot_http_headers_writer_set_cb; +#endif + + rc = tracer->inject_http_headers(tracer, carrier, retptr); + if (rc != otc_propagation_error_code_success) { + OT_LOG(" ERROR: inject_http_headers() failed: %d", rc); + + OTC_DBG_FREE(retptr); + } else { + OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy); + } + + OT_DBG(OT, "carrier %p: { { %p %p %zu/%zu %hhu } %p }", carrier, carrier->text_map.key, carrier->text_map.value, carrier->text_map.count, carrier->text_map.size, carrier->text_map.is_dynamic, carrier->set); + ot_text_map_show(&(carrier->text_map)); + + return retptr; +} + + +/*** + * NAME + * ot_extract_http_headers - + * + * ARGUMENTS + * tracer - + * carrier - + * text_map - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_span_context *ot_extract_http_headers(struct otc_tracer *tracer, struct otc_http_headers_reader *carrier, const struct otc_text_map *text_map) +{ + struct otc_span_context *retptr = NULL; + int rc; + + OT_FUNC("%p, %p, %p", tracer, carrier, text_map); + + (void)memset(carrier, 0, sizeof(*carrier)); +#ifdef OT_USE_EXTRACT_CB + carrier->foreach_key = ot_http_headers_reader_foreach_key_cb; +#endif + + if (_nNULL(text_map)) + (void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map)); + + OT_DBG(OT, "carrier %p: { { %p %p %zu/%zu %hhu } }", carrier, carrier->text_map.key, carrier->text_map.value, carrier->text_map.count, carrier->text_map.size, carrier->text_map.is_dynamic); + + rc = tracer->extract_http_headers(tracer, carrier, &retptr); + if (rc != otc_propagation_error_code_success) { + OT_LOG(" ERROR: extract_http_headers() failed: %d", rc); + + OTC_DBG_FREE(retptr); + } + else if (_nNULL(retptr)) { + OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy); + } + + return retptr; +} + + +/*** + * NAME + * ot_inject_binary - + * + * ARGUMENTS + * tracer - + * span - + * carrier - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_span_context *ot_inject_binary(struct otc_tracer *tracer, const struct otc_span *span, struct otc_custom_carrier_writer *carrier) +{ + struct otc_span_context *retptr = NULL; + int rc; + + OT_FUNC("%p, %p, %p", tracer, span, carrier); + + if (_NULL(span)) + return retptr; + + if (_NULL(retptr = span->span_context((struct otc_span *)span))) + return retptr; + + (void)memset(carrier, 0, sizeof(*carrier)); + + rc = tracer->inject_binary(tracer, carrier, retptr); + if (rc != otc_propagation_error_code_success) { + OT_LOG(" ERROR: inject_binary() failed: %d", rc); + + OTC_DBG_FREE(retptr); + } else { + OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy); + } + + OT_DBG(OT, "carrier %p: { { %p %zu %hhu } %p }", carrier, carrier->binary_data.data, carrier->binary_data.size, carrier->binary_data.is_dynamic, carrier->inject); + +#ifdef DEBUG + if (carrier->binary_data.data != NULL) { + struct otc_jaeger_trace_context *ctx_jaeger = carrier->binary_data.data; + struct otc_dd_trace_context *ctx_dd = carrier->binary_data.data; + + OT_DBG(OT, "Jaeger trace context: %016" PRIx64 "%016" PRIx64 ":%016" PRIx64 ":%016" PRIx64 ":%02hhx <%s> <%s>", + ctx_jaeger->trace_id[0], ctx_jaeger->trace_id[1], ctx_jaeger->span_id, ctx_jaeger->parent_span_id, ctx_jaeger->flags, + str_hex(ctx_jaeger->baggage, carrier->binary_data.size - sizeof(*ctx_jaeger)), + str_ctrl(ctx_jaeger->baggage, carrier->binary_data.size - sizeof(*ctx_jaeger))); + OT_DBG(OT, "DataDog trace context: <%s> <%s>", + str_hex(ctx_dd->data, carrier->binary_data.size), + str_ctrl(ctx_dd->data, carrier->binary_data.size)); + } +#endif /* DEBUG */ + + return retptr; +} + + +/*** + * NAME + * ot_extract_binary - + * + * ARGUMENTS + * tracer - + * carrier - + * binary_data - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +struct otc_span_context *ot_extract_binary(struct otc_tracer *tracer, struct otc_custom_carrier_reader *carrier, const struct otc_binary_data *binary_data) +{ + struct otc_span_context *retptr = NULL; + int rc; + + OT_FUNC("%p, %p, %p", tracer, carrier, binary_data); + + (void)memset(carrier, 0, sizeof(*carrier)); + + if (_nNULL(binary_data) && _nNULL(binary_data->data) && (binary_data->size > 0)) + (void)memcpy(&(carrier->binary_data), binary_data, sizeof(carrier->binary_data)); + + OT_DBG(OT, "carrier %p: { { %p %zu %hhu } %p }", carrier, carrier->binary_data.data, carrier->binary_data.size, carrier->binary_data.is_dynamic, carrier->extract); + + rc = tracer->extract_binary(tracer, carrier, &retptr); + if (rc != otc_propagation_error_code_success) { + OT_LOG(" ERROR: extract_binary() failed: %d", rc); + + OTC_DBG_FREE(retptr); + } + else if (_nNULL(retptr)) { + OT_DBG(OT, "context %p: { %" PRId64 " %p %p }", retptr, retptr->idx, retptr->span, retptr->destroy); + } + + return retptr; +} + + +/*** + * NAME + * ot_span_finish - + * + * ARGUMENTS + * span - + * ts_finish - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void ot_span_finish(struct otc_span **span, const struct timespec *ts_finish) +{ + struct otc_finish_span_options options; + + OT_FUNC("%p, %p", span, ts_finish); + + if (_NULL(span) || _NULL(*span)) + return; + + (void)memset(&options, 0, sizeof(options)); + + if (_nNULL(ts_finish)) + (void)memcpy(&(options.finish_time.value), ts_finish, sizeof(options.finish_time.value)); + + OT_DBG(OT, "span %p:%zu finished", *span, (*span)->idx); + + (*span)->finish_with_options(*span, &options); + + *span = NULL; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ diff --git a/test/opentracing.h b/test/opentracing.h new file mode 100644 index 0000000..7cb4b99 --- /dev/null +++ b/test/opentracing.h @@ -0,0 +1,42 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef TEST_OPENTRACING_H +#define TEST_OPENTRACING_H + +struct otc_span *ot_span_init(struct otc_tracer *tracer, const char *operation_name, int ref_type, int ref_ctx_idx, const struct otc_span *ref_span); +int ot_span_tag(struct otc_span *span, const char *key, int type, ...); +int ot_span_set_baggage(struct otc_span *span, const char *key, const char *value, ...); +struct otc_text_map *ot_span_baggage(const struct otc_span *span, const char *key, ...); +int ot_span_log_kv(struct otc_span *span, const char *key, const char *value, ...); +int ot_span_log(struct otc_span *span, const char *key, const char *format, ...); +struct otc_span_context *ot_inject_text_map(struct otc_tracer *tracer, const struct otc_span *span, struct otc_text_map_writer *carrier); +struct otc_span_context *ot_extract_text_map(struct otc_tracer *tracer, struct otc_text_map_reader *carrier, const struct otc_text_map *text_map); +struct otc_span_context *ot_inject_http_headers(struct otc_tracer *tracer, const struct otc_span *span, struct otc_http_headers_writer *carrier); +struct otc_span_context *ot_extract_http_headers(struct otc_tracer *tracer, struct otc_http_headers_reader *carrier, const struct otc_text_map *text_map); +struct otc_span_context *ot_inject_binary(struct otc_tracer *tracer, const struct otc_span *span, struct otc_custom_carrier_writer *carrier); +struct otc_span_context *ot_extract_binary(struct otc_tracer *tracer, struct otc_custom_carrier_reader *carrier, const struct otc_binary_data *binary_data); +void ot_span_finish(struct otc_span **span, const struct timespec *ts_finish); + +#endif /* TEST_OPENTRACING_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ diff --git a/test/test.c b/test/test.c new file mode 100644 index 0000000..287e4e2 --- /dev/null +++ b/test/test.c @@ -0,0 +1,485 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "include.h" + + +#define DEFAULT_DEBUG_LEVEL 0 +#define DEFAULT_THREADS_COUNT 1000 + + +typedef unsigned char bool_t; + +enum FLAG_OPT_enum { + FLAG_OPT_HELP = 0x01, + FLAG_OPT_VERSION = 0x02, +}; + +static struct { + uint8_t debug_level; + uint8_t opt_flags; + int runcount; + int runtime_ms; + int threads; + const char *ot_config; + const char *ot_plugin; + struct otc_tracer *ot_tracer; +} cfg = { + .debug_level = DEFAULT_DEBUG_LEVEL, + .runtime_ms = -1, + .threads = DEFAULT_THREADS_COUNT, +}; + +enum OT_SPAN_enum { + OT_SPAN_ROOT = 0, + OP_SPAN_BAGGAGE, + OT_SPAN_PROP_TM, + OT_SPAN_PROP_HH, + OT_SPAN_PROP_BD, + OT_SPAN_MAX, +}; + +struct worker { + pthread_t thread; + int id; + struct otc_span *ot_span[OT_SPAN_MAX]; + int ot_state; + uint64_t count; +}; + +static struct { + const char *name; + struct timeval start_time; + struct worker worker[8192]; + volatile bool_t flag_run; +} prg; + + +uint8_t *cfg_debug_level = &(cfg.debug_level); + + +/*** + * NAME + * thread_id - + * + * ARGUMENTS + * This function takes no arguments. + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +int thread_id(void) +{ + pthread_t id; + int i; + + id = pthread_self(); + + for (i = 0; i < MIN(cfg.threads, TABLESIZE(prg.worker)); i++) + if (pthread_equal(prg.worker[i].thread, id)) + return i + 1; + + return 0; +} + + +/*** + * NAME + * worker_finish_all_spans - + * + * ARGUMENTS + * worker - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static void worker_finish_all_spans(struct worker *worker) +{ + struct timespec ts; + int i; + + OT_FUNC("%p", worker); + + (void)clock_gettime(CLOCK_MONOTONIC, &ts); + + for (i = 0; i < TABLESIZE(worker->ot_span); i++) + if (_nNULL(worker->ot_span[i])) + ot_span_finish(worker->ot_span + i, &ts); +} + + +/*** + * NAME + * worker_thread - + * + * ARGUMENTS + * data - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +__attribute__((noreturn)) static void *worker_thread(void *data) +{ + struct otc_text_map_writer tm_wr; + struct otc_http_headers_writer hh_wr; + struct otc_custom_carrier_writer cc_wr; + struct otc_span_context *context; + struct timeval now; + char name[16]; + struct worker *worker = data; +#ifdef DEBUG + int n = 0; +#endif + + OT_FUNC("%p", data); + +#ifdef __linux__ + OT_DBG(WORKER, "Worker started, thread id: %" PRI_PTHREADT, syscall(SYS_gettid)); +#else + OT_DBG(WORKER, "Worker started, thread id: %" PRI_PTHREADT, worker->thread); +#endif + + (void)gettimeofday(&now, NULL); + (void)srandom(now.tv_usec); + + (void)snprintf(name, sizeof(name), "test/wrk: %d", worker->id); + (void)pthread_setname_np(worker->thread, name); + + while (!prg.flag_run) { + nsleep(0, 10000000); + +#ifdef DEBUG + n++; +#endif + } + + OT_DBG(DEBUG, "waiting loop count: %d", n); + + for ( ; 1; worker->ot_state++) { + if (worker->ot_state != 0) + /* Do nothing. */; + else if ((cfg.runtime_ms > 0) && (TIMEVAL_DIFF_MS(&now, &(prg.start_time)) >= (uint)cfg.runtime_ms)) + break; + else if ((cfg.runcount > 0) && ((uint)cfg.runcount <= worker->count)) + break; + + if (worker->ot_state == 0) { + worker->ot_span[OT_SPAN_ROOT] = ot_span_init(cfg.ot_tracer, "root span", -1, -1, NULL); + } + else if (worker->ot_state == 1) { + worker->ot_span[OP_SPAN_BAGGAGE] = ot_span_init(cfg.ot_tracer, "span #1", otc_span_reference_child_of, -1, worker->ot_span[OT_SPAN_ROOT]); + } + else if (worker->ot_state == 2) { + (void)ot_span_set_baggage(worker->ot_span[OP_SPAN_BAGGAGE], "baggage_1", "value_1", "baggage_2", "value_2", NULL); + } + else if (worker->ot_state == 3) { + if (_nNULL(context = ot_inject_text_map(cfg.ot_tracer, worker->ot_span[OP_SPAN_BAGGAGE], &tm_wr))) + context->destroy(&context); + } + else if (worker->ot_state == 4) { + struct otc_text_map_reader tm_rd; + struct otc_text_map *text_map = &(tm_wr.text_map); + + if (_nNULL(context = ot_extract_text_map(cfg.ot_tracer, &tm_rd, text_map))) { + worker->ot_span[OT_SPAN_PROP_TM] = ot_span_init(cfg.ot_tracer, "text map propagation", otc_span_reference_child_of, context->idx, NULL); + context->destroy(&context); + } + otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); + } + else if (worker->ot_state == 5) { + struct otc_text_map *baggage = ot_span_baggage(worker->ot_span[OP_SPAN_BAGGAGE], "baggage_1", "baggage_2", NULL); + + otc_text_map_destroy(&baggage, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); + } + else if (worker->ot_state == 6) { + if (_nNULL(context = ot_inject_http_headers(cfg.ot_tracer, worker->ot_span[OP_SPAN_BAGGAGE], &hh_wr))) + context->destroy(&context); + } + else if (worker->ot_state == 7) { + struct otc_http_headers_reader hh_rd; + struct otc_text_map *text_map = &(hh_wr.text_map); + + if (_nNULL(context = ot_extract_http_headers(cfg.ot_tracer, &hh_rd, text_map))) { + worker->ot_span[OT_SPAN_PROP_HH] = ot_span_init(cfg.ot_tracer, "http headers propagation", otc_span_reference_child_of, context->idx, NULL); + context->destroy(&context); + } + otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); + } + else if (worker->ot_state == 8) { + if (_nNULL(context = ot_inject_binary(cfg.ot_tracer, worker->ot_span[OP_SPAN_BAGGAGE], &cc_wr))) + context->destroy(&context); + } + else if (worker->ot_state == 9) { + struct otc_custom_carrier_reader cc_rd; + struct otc_binary_data *binary_data = &(cc_wr.binary_data); + + if (_nNULL(context = ot_extract_binary(cfg.ot_tracer, &cc_rd, binary_data))) { + worker->ot_span[OT_SPAN_PROP_BD] = ot_span_init(cfg.ot_tracer, "binary data propagation", otc_span_reference_child_of, context->idx, NULL); + context->destroy(&context); + } + otc_binary_data_destroy(&binary_data); + } + else if (worker->ot_state == 10) { + (void)ot_span_tag(worker->ot_span[OT_SPAN_ROOT], "tag_1", OT_VARGS(string, "value_1"), "tag_2", OT_VARGS(string, "value_2"), NULL); + } + else if (worker->ot_state == 11) { + (void)ot_span_log_kv(worker->ot_span[OT_SPAN_PROP_TM], "log_1", "content_1", "log_2", "content_2", NULL); + } + else { + worker_finish_all_spans(worker); + + worker->ot_state = -1; + worker->count++; + } + + nsleep(0, ((random() % 100) + 1) * 10000); + (void)gettimeofday(&now, NULL); + } + + pthread_exit(NULL); +} + + +/*** + * NAME + * worker_run - + * + * ARGUMENTS + * This function takes no arguments. + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static int worker_run(void) +{ + struct timeval now; + char ot_infbuf[BUFSIZ]; + uint64_t total_count = 0; + int i, num_threads = 0, retval = EX_OK; + + OT_FUNC(""); + + (void)pthread_setname_np(pthread_self(), "test/wrk: main"); + + for (i = 0; i < cfg.threads; i++) { + prg.worker[i].id = i + 1; + + if (pthread_create(&(prg.worker[i].thread), NULL, worker_thread, prg.worker + i) != 0) + (void)fprintf(stderr, "ERROR: Failed to start thread for worker %d: %m\n", prg.worker[i].id); + else + num_threads++; + } + + prg.flag_run = 1; + + (void)gettimeofday(&now, NULL); + OT_DBG(WORKER, "%d threads started in %llu ms", num_threads, TIMEVAL_DIFF_MS(&now, &(prg.start_time))); + + for (i = 0; i < cfg.threads; i++) { + if (pthread_join(prg.worker[i].thread, NULL) != 0) + (void)fprintf(stderr, "ERROR: Failed to join worker thread %d: %m\n", prg.worker[i].id); + else + OT_LOG("worker %d count: %" PRIu64, i, prg.worker[i].count); + + total_count += prg.worker[i].count; + } + + OT_LOG("%d worker(s) total count: %" PRIu64, cfg.threads, total_count); + + cfg.ot_tracer->close(cfg.ot_tracer); + + otc_statistics(ot_infbuf, sizeof(ot_infbuf)); + OT_LOG("OpenTracing statistics: %s", ot_infbuf); + + return retval; +} + + +/*** + * NAME + * usage - + * + * ARGUMENTS + * program_name - + * flag_verbose - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +static void usage(const char *program_name, bool_t flag_verbose) +{ + (void)printf("\nUsage: %s { -h --help }\n", program_name); + (void)printf(" %s { -V --version }\n", program_name); + (void)printf(" %s { [ -R --runcount=VALUE ] | [ -r --runtime=TIME ] } [OPTION]...\n\n", program_name); + + if (flag_verbose) { + (void)printf("Options are:\n"); + (void)printf(" -c, --config=FILE Specify the configuration for the used tracer.\n"); +#ifdef DEBUG + (void)printf(" -d, --debug=LEVEL Enable and specify the debug mode level (default: %d).\n", DEFAULT_DEBUG_LEVEL); +#endif + (void)printf(" -h, --help Show this text.\n"); + (void)printf(" -p, --plugin=FILE Specify the OpenTracing compatible plugin library.\n"); + (void)printf(" -R, --runcount=VALUE Execute this program a certain number of passes (0 = unlimited).\n"); + (void)printf(" -r, --runtime=TIME Run this program for a certain amount of time (ms, 0 = unlimited).\n"); + (void)printf(" -t, --threads=VALUE Specify the number of threads (default: %d).\n", DEFAULT_THREADS_COUNT); + (void)printf(" -V, --version Show program version.\n\n"); + (void)printf("Copyright 2020 HAProxy Technologies\n"); + (void)printf("SPDX-License-Identifier: Apache-2.0\n\n"); + } else { + (void)printf("For help type: %s -h\n\n", program_name); + } +} + + +int main(int argc, char **argv) +{ + static const struct option longopts[] = { + { "config", required_argument, NULL, 'c' }, +#ifdef DEBUG + { "debug", required_argument, NULL, 'd' }, +#endif + { "help", no_argument, NULL, 'h' }, + { "plugin", required_argument, NULL, 'p' }, + { "runcount", required_argument, NULL, 'R' }, + { "runtime", required_argument, NULL, 'r' }, + { "threads", required_argument, NULL, 't' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; +#ifdef OTC_DBG_MEM + static struct otc_dbg_mem_data dbg_mem_data[1000000]; + struct otc_dbg_mem dbg_mem; +#endif + const char *shortopts = "c:d:hp:R:r:t:V"; + struct timeval now; + int c, longopts_idx = -1, retval = EX_OK; + bool_t flag_error = 0; + char ot_errbuf[BUFSIZ]; + + (void)gettimeofday(&(prg.start_time), NULL); + + prg.name = basename(argv[0]); + +#ifdef OTC_DBG_MEM + retval = otc_dbg_mem_init(&dbg_mem, dbg_mem_data, TABLESIZE(dbg_mem_data), 0xff); + if (retval == -1) { + (void)fprintf(stderr, "ERROR: cannot initialize memory debugger\n"); + + return retval; + } +#endif + + while ((c = getopt_long(argc, argv, shortopts, longopts, &longopts_idx)) != EOF) { + if (c == 'c') + cfg.ot_config = optarg; +#ifdef DEBUG + else if (c == 'd') + cfg.debug_level = atoi(optarg) & UINT8_C(0xff); +#endif + else if (c == 'h') + cfg.opt_flags |= FLAG_OPT_HELP; + else if (c == 'p') + cfg.ot_plugin = optarg; + else if (c == 'R') + cfg.runcount = atoi(optarg); + else if (c == 'r') + cfg.runtime_ms = atoi(optarg); + else if (c == 't') + cfg.threads = atoi(optarg); + else if (c == 'V') + cfg.opt_flags |= FLAG_OPT_VERSION; + else + retval = EX_USAGE; + } + + if (cfg.opt_flags & FLAG_OPT_HELP) { + usage(prg.name, 1); + } + else if (cfg.opt_flags & FLAG_OPT_VERSION) { + (void)printf("\n%s v%s [build %d] by %s, %s\n\n", prg.name, PACKAGE_VERSION, PACKAGE_BUILD, PACKAGE_AUTHOR, __DATE__); + } + else { + if ((cfg.runcount < 0) && (cfg.runtime_ms < 0)) { + (void)fprintf(stderr, "ERROR: run count/time value not set\n"); + flag_error = 1; + } + + if (!IN_RANGE(cfg.threads, 1, TABLESIZE(prg.worker))) { + (void)fprintf(stderr, "ERROR: invalid number of threads '%d'\n", cfg.threads); + flag_error = 1; + } + + if (_NULL(cfg.ot_plugin) || _NULL(cfg.ot_config)) { + (void)fprintf(stderr, "ERROR: the OpenTracing configuration not set\n"); + flag_error = 1; + } + + if (flag_error) + usage(prg.name, 0); + } + + cfg_debug_level = &(cfg.debug_level); + + OT_FUNC("%d, %p", argc, argv); + + if (flag_error || (cfg.opt_flags & (FLAG_OPT_HELP | FLAG_OPT_VERSION))) + return flag_error ? EX_USAGE : EX_OK; + + if (_NULL(cfg.ot_tracer = otc_tracer_load(cfg.ot_plugin, ot_errbuf, sizeof(ot_errbuf)))) { + (void)fprintf(stderr, "ERROR: %s\n", (*ot_errbuf == '\0') ? "Unable to load tracing library" : ot_errbuf); + + retval = EX_SOFTWARE; + } + else if (otc_tracer_start(cfg.ot_config, NULL, ot_errbuf, sizeof(ot_errbuf)) == -1) { + (void)fprintf(stderr, "ERROR: %s\n", (*ot_errbuf == '\0') ? "Unable to start tracing" : ot_errbuf); + + retval = EX_SOFTWARE; + } + else { + retval = worker_run(); + } + + (void)gettimeofday(&now, NULL); + OT_DBG(INFO, "Program runtime: %llu ms", TIMEVAL_DIFF_MS(&now, &(prg.start_time))); + + OTC_DBG_MEMINFO(); + + return retval; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ diff --git a/test/util.c b/test/util.c new file mode 100644 index 0000000..91c1af7 --- /dev/null +++ b/test/util.c @@ -0,0 +1,118 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "include.h" + + +/*** + * NAME + * nsleep - + * + * ARGUMENTS + * sec - + * nsec - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * This function does not return a value. + */ +void nsleep (uint sec, uint nsec) +{ + struct timespec ts1 = { sec, nsec }, ts2, *req = &ts1, *rem = &ts2; + + while ((nanosleep (req, rem) == -1) && (errno == EINTR)) + SWAP(req, rem); +} + + +/*** + * NAME + * str_hex - + * + * ARGUMENTS + * data - + * size - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +const char *str_hex(const void *data, size_t size) +{ + static __thread char retbuf[BUFSIZ]; + const uint8_t *ptr = data; + size_t i; + + if (_NULL(data)) + return "(null)"; + else if (size == 0) + return "()"; + + for (i = 0, size <<= 1; (i < (sizeof(retbuf) - 2)) && (i < size); ptr++) { + retbuf[i++] = NIBBLE_TO_HEX(*ptr >> 4); + retbuf[i++] = NIBBLE_TO_HEX(*ptr & 0x0f); + } + + retbuf[i] = '\0'; + + return retbuf; +} + + +/*** + * NAME + * str_ctrl - + * + * ARGUMENTS + * data - + * size - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +const char *str_ctrl(const void *data, size_t size) +{ + static __thread char retbuf[BUFSIZ]; + const uint8_t *ptr = data; + size_t i, n = 0; + + if (_NULL(data)) + return "(null)"; + else if (size == 0) + return "()"; + + for (i = 0; (n < (sizeof(retbuf) - 1)) && (i < size); i++) + retbuf[n++] = IN_RANGE(ptr[i], 0x20, 0x7e) ? ptr[i] : '.'; + + retbuf[n] = '\0'; + + return retbuf; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ diff --git a/test/util.h b/test/util.h new file mode 100644 index 0000000..689a042 --- /dev/null +++ b/test/util.h @@ -0,0 +1,33 @@ +/*** + * Copyright 2020 HAProxy Technologies + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef TEST_UTIL_H +#define TEST_UTIL_H + +int thread_id(void); +void nsleep (uint sec, uint nsec); +const char *str_hex(const void *data, size_t size); +const char *str_ctrl(const void *data, size_t size); + +#endif /* TEST_UTIL_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + * + * vi: noexpandtab shiftwidth=8 tabstop=8 + */ |