From deae4e3c06ef6c1f90096debd5f144ce3540b1c3 Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Tue, 30 Mar 2021 13:41:40 +0200 Subject: [PATCH 01/10] Add codeowners Fixes #9 --- CODEOWNERS | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..3a3f62a75 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,18 @@ +##################################################### +# +# List of approvers for this repository +# +##################################################### +# +# Learn about membership in OpenTelemetry community: +# https://github.com/open-telemetry/community/blob/main/community-membership.md +# +# Learn about CODEOWNERS file format: +# https://help.github.com/en/articles/about-code-owners + +instrumentation/httpd/ @TomRoSystems +instrumentation/nginx/ @seemk + +* cpp-approvers + +CODEOWNERS cpp-maintainers From d385db853760e300e600825151c1bc4e8bec3ed8 Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Tue, 30 Mar 2021 15:54:37 +0200 Subject: [PATCH 02/10] Fix team names inside codeowners --- CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 3a3f62a75..eac737aa7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -13,6 +13,6 @@ instrumentation/httpd/ @TomRoSystems instrumentation/nginx/ @seemk -* cpp-approvers +* @open-telemetry/cpp-approvers -CODEOWNERS cpp-maintainers +CODEOWNERS @open-telemetry/cpp-maintainers From ea8944c0307fe6300f71e946522c6e30718f23db Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Tue, 20 Apr 2021 12:45:11 +0200 Subject: [PATCH 03/10] Use CODEOWNERS from otel-cpp-contrib --- CODEOWNERS | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index eac737aa7..000000000 --- a/CODEOWNERS +++ /dev/null @@ -1,18 +0,0 @@ -##################################################### -# -# List of approvers for this repository -# -##################################################### -# -# Learn about membership in OpenTelemetry community: -# https://github.com/open-telemetry/community/blob/main/community-membership.md -# -# Learn about CODEOWNERS file format: -# https://help.github.com/en/articles/about-code-owners - -instrumentation/httpd/ @TomRoSystems -instrumentation/nginx/ @seemk - -* @open-telemetry/cpp-approvers - -CODEOWNERS @open-telemetry/cpp-maintainers From cede96f380a4e950a52dce48f8364949ac2ade5d Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Tue, 11 May 2021 19:53:20 +0200 Subject: [PATCH 04/10] Update opentelemetry-cpp dependency to revision 5278e8c --- instrumentation/httpd/WORKSPACE | 6 +-- instrumentation/httpd/src/otel/mod_otel.cpp | 45 ++++++++++--------- .../httpd/src/otel/opentelemetry.cpp | 11 ++--- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/instrumentation/httpd/WORKSPACE b/instrumentation/httpd/WORKSPACE index 873ba99a8..5e11dcfce 100644 --- a/instrumentation/httpd/WORKSPACE +++ b/instrumentation/httpd/WORKSPACE @@ -3,10 +3,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Load OpentTelemetry-CPP dependency http_archive( name = "io_opentelemetry_cpp", - sha256 = "2621cb0efd9bae78a1f06866cf8e96417446a6a70568ed6f804a6cb91d916db1", - strip_prefix = "opentelemetry-cpp-bd68a22ff5f2343de68f9d56a68bc53ecd69d567", + sha256 = "9fe9b357a144300c4d388ab5ef4940b43b611cca73a733322dd22b9faa97391a", + strip_prefix = "opentelemetry-cpp-5278e8c03586ee1f690916f3e21eab626914c2e0", urls = [ - "https://github.com/open-telemetry/opentelemetry-cpp/archive/bd68a22ff5f2343de68f9d56a68bc53ecd69d567.tar.gz" + "https://github.com/open-telemetry/opentelemetry-cpp/archive/5278e8c03586ee1f690916f3e21eab626914c2e0.tar.gz" ], ) diff --git a/instrumentation/httpd/src/otel/mod_otel.cpp b/instrumentation/httpd/src/otel/mod_otel.cpp index 5556ff035..2485f336b 100644 --- a/instrumentation/httpd/src/otel/mod_otel.cpp +++ b/instrumentation/httpd/src/otel/mod_otel.cpp @@ -37,24 +37,27 @@ using namespace httpd_otel; const char kOpenTelemetryKeyNote[] = "OTEL"; const char kOpenTelemetryKeyOutboundNote[] = "OTEL_PROXY"; -static nostd::string_view HttpdGetter(const apr_table_t &hdrs, nostd::string_view trace_type) +class HttpdCarrier : public opentelemetry::context::propagation::TextMapCarrier { - auto fnd = apr_table_get(&hdrs, std::string(trace_type).c_str()); - return fnd ? fnd : ""; -} - -static void HttpdSetter(apr_table_t &hdrs, - nostd::string_view trace_type, - nostd::string_view trace_description) -{ - apr_table_set(&hdrs, std::string(trace_type).c_str(), - std::string(trace_description).c_str()); -} +public: + apr_table_t& hdrs; + HttpdCarrier(apr_table_t& headers):hdrs(headers){} + virtual nostd::string_view Get(nostd::string_view key) const noexcept override + { + auto fnd = apr_table_get(&hdrs, std::string(key).c_str()); + return fnd ? fnd : ""; + } + virtual void Set(nostd::string_view key, nostd::string_view value) noexcept override + { + apr_table_set(&hdrs, std::string(key).c_str(), + std::string(value).c_str()); + } +}; // propagators -opentelemetry::trace::propagation::HttpTraceContext PropagatorTraceContext; -opentelemetry::trace::propagation::B3Propagator PropagatorB3SingleHeader; -opentelemetry::trace::propagation::B3PropagatorMultiHeader PropagatorB3MultiHeader; +opentelemetry::trace::propagation::HttpTraceContext PropagatorTraceContext; +opentelemetry::trace::propagation::B3Propagator PropagatorB3SingleHeader; +opentelemetry::trace::propagation::B3PropagatorMultiHeader PropagatorB3MultiHeader; // from: // https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#http-server-semantic-conventions @@ -123,16 +126,17 @@ static int opentel_handler(request_rec *r, int /* lookup_uri */ ) if (!config.ignore_inbound && config.propagation != OtelPropagation::NONE) { + HttpdCarrier car(*req->headers_in); opentelemetry::v0::context::Context ctx_new, ctx_cur = opentelemetry::context::RuntimeContext::GetCurrent(); switch (config.propagation) { default: - ctx_new = PropagatorTraceContext.Extract(HttpdGetter, *req->headers_in, ctx_cur); + ctx_new = PropagatorTraceContext.Extract(car, ctx_cur); break; case OtelPropagation::B3_SINGLE_HEADER: case OtelPropagation::B3_MULTI_HEADER: - ctx_new = PropagatorB3SingleHeader.Extract(HttpdGetter, *req->headers_in, ctx_cur); + ctx_new = PropagatorB3SingleHeader.Extract(car, ctx_cur); } req_data->token = opentelemetry::context::RuntimeContext::Attach(ctx_new); } @@ -221,16 +225,17 @@ static int proxy_fixup_handler(request_rec *r) // mod_proxy simply copies request headers from client therefore inject is into headers_in // instead of headers_out + HttpdCarrier car(*req->headers_in); switch (config.propagation) { case OtelPropagation::TRACE_CONTEXT: - PropagatorTraceContext.Inject(HttpdSetter, *req->headers_in, opentelemetry::context::RuntimeContext::GetCurrent()); + PropagatorTraceContext.Inject(car, opentelemetry::context::RuntimeContext::GetCurrent()); break; case OtelPropagation::B3_SINGLE_HEADER: - PropagatorB3SingleHeader.Inject(HttpdSetter, *req->headers_in, opentelemetry::context::RuntimeContext::GetCurrent()); + PropagatorB3SingleHeader.Inject(car, opentelemetry::context::RuntimeContext::GetCurrent()); break; case OtelPropagation::B3_MULTI_HEADER: - PropagatorB3MultiHeader.Inject(HttpdSetter, *req->headers_in, opentelemetry::context::RuntimeContext::GetCurrent()); + PropagatorB3MultiHeader.Inject(car, opentelemetry::context::RuntimeContext::GetCurrent()); break; default: // suppress warning break; diff --git a/instrumentation/httpd/src/otel/opentelemetry.cpp b/instrumentation/httpd/src/otel/opentelemetry.cpp index 2aae4a1e8..ec9ca635c 100644 --- a/instrumentation/httpd/src/otel/opentelemetry.cpp +++ b/instrumentation/httpd/src/otel/opentelemetry.cpp @@ -73,16 +73,17 @@ void initTracer() break; } - std::shared_ptr processor; + std::unique_ptr processor; if (config.batch_opts.max_queue_size) { - processor = std::make_shared( - std::move(exporter), config.batch_opts); + processor = std::unique_ptr( + new sdktrace::BatchSpanProcessor(std::move(exporter), config.batch_opts)); } else { - processor = std::make_shared(std::move(exporter)); + processor = std::unique_ptr( + new sdktrace::SimpleSpanProcessor(std::move(exporter))); } // add custom-configured resources @@ -93,7 +94,7 @@ void initTracer() } auto provider = nostd::shared_ptr( - new sdktrace::TracerProvider(processor, + new sdktrace::TracerProvider(std::move(processor), opentelemetry::sdk::resource::Resource::Create(resAttrs)) ); From 03acc95f81506d17e5a1537bc322c5040df2d42c Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Wed, 12 May 2021 17:15:36 +0200 Subject: [PATCH 05/10] Fix tests to match how attributes are presented (it was broken by #632 commit 179a7f40) --- instrumentation/httpd/WORKSPACE | 6 ++--- .../httpd/tests/01-create-root-span.sh | 22 +++++-------------- instrumentation/httpd/tests/tools.sh | 9 ++++++++ 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/instrumentation/httpd/WORKSPACE b/instrumentation/httpd/WORKSPACE index 5e11dcfce..56dcf663d 100644 --- a/instrumentation/httpd/WORKSPACE +++ b/instrumentation/httpd/WORKSPACE @@ -3,10 +3,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Load OpentTelemetry-CPP dependency http_archive( name = "io_opentelemetry_cpp", - sha256 = "9fe9b357a144300c4d388ab5ef4940b43b611cca73a733322dd22b9faa97391a", - strip_prefix = "opentelemetry-cpp-5278e8c03586ee1f690916f3e21eab626914c2e0", + sha256 = "59e16eab4f534907144882fe70a1ca4514cf720f7b8b6e2a2d999a1b1a9265c8", + strip_prefix = "opentelemetry-cpp-b4584adeaae259df89b33af884c641e70a60a7cf", urls = [ - "https://github.com/open-telemetry/opentelemetry-cpp/archive/5278e8c03586ee1f690916f3e21eab626914c2e0.tar.gz" + "https://github.com/open-telemetry/opentelemetry-cpp/archive/b4584adeaae259df89b33af884c641e70a60a7cf.tar.gz" ], ) diff --git a/instrumentation/httpd/tests/01-create-root-span.sh b/instrumentation/httpd/tests/01-create-root-span.sh index c67cb1524..2d4d0c8a3 100755 --- a/instrumentation/httpd/tests/01-create-root-span.sh +++ b/instrumentation/httpd/tests/01-create-root-span.sh @@ -28,22 +28,12 @@ check_results() { [ "`getSpanField span_id`" != "`getSpanField parent_span_id`" ] || fail "Bad span: span.id same as parent span.id" echo Checking span attributes - declare -A SPAN_ATTRS - # transforms "http.method: GET, http.flavor: http, ..." into SPAN_ATTRS[http.method] = GET - IFS=',' read -ra my_array <<< "`getSpanField attributes`" - for i in "${my_array[@]}"; do - TMP_KEY=${i%%:*} - TMP_KEY=${TMP_KEY# } - TMP_VAL=${i##*:} - TMP_VAL=${TMP_VAL:1} - SPAN_ATTRS[${TMP_KEY}]="${TMP_VAL}" - done - - [[ "${SPAN_ATTRS[http.method]}" == "GET" ]] || fail "Bad span attribiute http.method ${SPAN_ATTRS[http.method]}" - [[ "${SPAN_ATTRS[http.target]}" == "/" ]] || fail "Bad span attribiute http.target ${SPAN_ATTRS[http.target]}" - [[ "${SPAN_ATTRS[http.status_code]}" == "200" ]] || fail "Bad span attribiute http.status_code ${SPAN_ATTRS[http.status_code]}" - [[ "${SPAN_ATTRS[http.flavor]}" == "1.1" ]] || fail "Bad span attribiute http.flavor ${SPAN_ATTRS[http.flavor]}" - [[ "${SPAN_ATTRS[http.scheme]}" == "http" ]] || fail "Bad span attribiute http.scheme ${SPAN_ATTRS[http.scheme]}" + + [[ "`getSpanAttr 'http.method'`" == "GET" ]] || fail "Bad span attribiute http.method ${SPAN_ATTRS[http.method]}" + [[ "`getSpanAttr 'http.target'`" == "/" ]] || fail "Bad span attribiute http.target ${SPAN_ATTRS[http.target]}" + [[ "`getSpanAttr 'http.status_code'`" == "200" ]] || fail "Bad span attribiute http.status_code ${SPAN_ATTRS[http.status_code]}" + [[ "`getSpanAttr 'http.flavor'`" == "1.1" ]] || fail "Bad span attribiute http.flavor ${SPAN_ATTRS[http.flavor]}" + [[ "`getSpanAttr 'http.scheme'`" == "http" ]] || fail "Bad span attribiute http.scheme ${SPAN_ATTRS[http.scheme]}" } run $@ diff --git a/instrumentation/httpd/tests/tools.sh b/instrumentation/httpd/tests/tools.sh index 77e95f4a0..6e2800686 100755 --- a/instrumentation/httpd/tests/tools.sh +++ b/instrumentation/httpd/tests/tools.sh @@ -45,6 +45,15 @@ count() { echo OK Found $TOTAL occurence\(s\) of "$1" } +# returns span attribute +getSpanAttr() { +# grep "attributes :" ${OUTPUT_SPANS} -A 20 + LINE=`grep "attributes :" ${OUTPUT_SPANS} -A 20 | grep " $1" ` + VALUE=`echo $LINE | cut -d ':' -f 2-` + VALUE="${VALUE## }" + echo $VALUE +} + # returns one span field getSpanField() { WHICHONE=${2-1} From d546aed8f6e7a30e4afc2e728769ec5f8d0382b4 Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Wed, 12 May 2021 17:51:48 +0200 Subject: [PATCH 06/10] Remove commented code --- instrumentation/httpd/tests/tools.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/instrumentation/httpd/tests/tools.sh b/instrumentation/httpd/tests/tools.sh index 6e2800686..39a715e9e 100755 --- a/instrumentation/httpd/tests/tools.sh +++ b/instrumentation/httpd/tests/tools.sh @@ -45,9 +45,8 @@ count() { echo OK Found $TOTAL occurence\(s\) of "$1" } -# returns span attribute +# returns one span attribute getSpanAttr() { -# grep "attributes :" ${OUTPUT_SPANS} -A 20 LINE=`grep "attributes :" ${OUTPUT_SPANS} -A 20 | grep " $1" ` VALUE=`echo $LINE | cut -d ':' -f 2-` VALUE="${VALUE## }" From 65070923139e186e20f3aa05f434cc0bf086aef4 Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Thu, 16 Dec 2021 01:55:18 +0100 Subject: [PATCH 07/10] Expose trace to environment variables --- instrumentation/httpd/README.md | 22 ++++++++++++++++++++- instrumentation/httpd/src/otel/mod_otel.cpp | 4 ++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/instrumentation/httpd/README.md b/instrumentation/httpd/README.md index 0395e265d..72b181420 100644 --- a/instrumentation/httpd/README.md +++ b/instrumentation/httpd/README.md @@ -14,6 +14,26 @@ For manual build please check below. Otherwise please use one of the [released versions](/../releases). +### From Docker Image + +To start using mod_otel you can add it following way: +```Dockerfile +FROM httpd +ADD https://github.com/open-telemetry/opentelemetry-cpp-contrib/releases/download/httpd%2Fv0.1.0/ubuntu-20.04_mod-otel.so.zip /tmp +ADD https://raw.githubusercontent.com/open-telemetry/opentelemetry-cpp-contrib/main/instrumentation/httpd/opentelemetry.conf /usr/local/apache2/conf/extra/ + +RUN mv /tmp/ubuntu-20.04_mod-otel.so.zip /usr/local/apache2/modules/mod_otel.so.gz +RUN gzip -d /usr/local/apache2/modules/mod_otel.so.gz + +RUN echo "LoadFile /usr/lib/x86_64-linux-gnu/libstdc++.so.6" >> /usr/local/apache2/conf/httpd.conf +RUN echo "LoadModule otel_module modules/mod_otel.so" >> /usr/local/apache2/conf/httpd.conf +RUN echo "Include conf/extra/opentelemetry.conf" >> /usr/local/apache2/conf/httpd.conf +``` + +### Logging traces + +Once module is enabled you have access to currently processed span via environment variables. Those can be accessed under `%{tracestate}e` and `%{traceparent}e` when using [LogFormat directive](https://httpd.apache.org/docs/2.4/mod/mod_log_config.html#formats). + ### Installation Mod_otel works as a module which is loaded when Apache starts. It is written in C++ therefore standard library has to be included as well. Below is an example of lines which should be added to your configuration file (usually `/etc/httpd/conf.d` or equivalent): @@ -91,7 +111,7 @@ When local changes are made, you need to restart the `httpd` server to load new ### Prerequisites (Ubuntu) -On Ubuntu you need packages listed here: [setup_environment.sh](./setup_environment.sh) which are prerequisites to compile opentelemetry-cpp and here: [setup-buildtools.sh](./setup-buildtools.sh) for apache development stuff. Then just execute [bulid.sh](./build.sh). +On Ubuntu you need packages listed here: [setup-environment.sh](./setup-environment.sh) which are prerequisites to compile opentelemetry-cpp and here: [setup-buildtools.sh](./setup-buildtools.sh) for apache development stuff. Then just execute [bulid.sh](./build.sh). ### Run formatting check diff --git a/instrumentation/httpd/src/otel/mod_otel.cpp b/instrumentation/httpd/src/otel/mod_otel.cpp index a8c85f0bd..0930402a4 100644 --- a/instrumentation/httpd/src/otel/mod_otel.cpp +++ b/instrumentation/httpd/src/otel/mod_otel.cpp @@ -148,6 +148,10 @@ static int opentel_handler(request_rec *r, int /* lookup_uri */ ) req_data->span = span; req_data->StartSpan(GetAttrsFromRequest(req)); + // expose traceparent and tracestate to environment variables + HttpdCarrier env(*req->subprocess_env); + PropagatorTraceContext.Inject(env, opentelemetry::context::RuntimeContext::GetCurrent()); + return DECLINED; } From f952b4bd95f228d3749e0f50ac1220f1788fd472 Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Sat, 18 Dec 2021 02:09:37 +0100 Subject: [PATCH 08/10] Fix setting environment variables and add test --- instrumentation/httpd/README.md | 7 ++- instrumentation/httpd/create-otel-load.sh | 20 ++++++++- instrumentation/httpd/src/otel/mod_otel.cpp | 31 +++++++++++-- .../httpd/tests/05-check-batch-spans.sh | 5 --- .../httpd/tests/07-create-outbound-spans.sh | 1 - .../tests/08-create-outbound-spans-b3.sh | 1 - .../httpd/tests/09-check-environment-vars.sh | 43 +++++++++++++++++++ instrumentation/httpd/tests/tools.sh | 3 +- 8 files changed, 97 insertions(+), 14 deletions(-) create mode 100755 instrumentation/httpd/tests/09-check-environment-vars.sh diff --git a/instrumentation/httpd/README.md b/instrumentation/httpd/README.md index 72b181420..7c3cd7d5d 100644 --- a/instrumentation/httpd/README.md +++ b/instrumentation/httpd/README.md @@ -32,7 +32,12 @@ RUN echo "Include conf/extra/opentelemetry.conf" >> /usr/local/apache2/conf/http ### Logging traces -Once module is enabled you have access to currently processed span via environment variables. Those can be accessed under `%{tracestate}e` and `%{traceparent}e` when using [LogFormat directive](https://httpd.apache.org/docs/2.4/mod/mod_log_config.html#formats). +Once module is enabled you have access to currently processed span via environment variables. Those can be accessed under: +- `%{OTEL_SPANID}e` for SpanID +- `%{OTEL_TRACEID}e` for TraceID +- `%{OTEL_TRACEFLAGS}e` for TraceID +- `%{OTEL_TRACESTATE}e` for TraceState +when using [LogFormat directive](https://httpd.apache.org/docs/2.4/mod/mod_log_config.html#formats). ### Installation diff --git a/instrumentation/httpd/create-otel-load.sh b/instrumentation/httpd/create-otel-load.sh index 44282e55b..2407440ad 100755 --- a/instrumentation/httpd/create-otel-load.sh +++ b/instrumentation/httpd/create-otel-load.sh @@ -2,10 +2,28 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +POSSIBLE_BUILD_OUTPUT=() +POSSIBLE_BUILD_OUTPUT+=("${SCRIPT_DIR}/bazel-out/k8-opt/bin/otel.so") # when build was done with Bazel +POSSIBLE_BUILD_OUTPUT+=("${SCRIPT_DIR}/build/otel_httpd_module.so") # when build was done with CMake + +for LOCATE_OUTPUT in "${POSSIBLE_BUILD_OUTPUT[@]}"; do + if [ -f ${LOCATE_OUTPUT} ]; then + FOUND=${LOCATE_OUTPUT} + echo Found file ${FOUND} + break + fi +done + +if [ -z ${FOUND+x} ]; then + echo "Binary module not found!" + echo "Please run make build-cmake or make build-bazel first" + exit 1 +fi + # create configuration file for httpd (Apache) cat << EOF > opentelemetry.load # C++ Standard library LoadFile /usr/lib/x86_64-linux-gnu/libstdc++.so.6 -LoadModule otel_module $SCRIPT_DIR/bazel-out/k8-opt/bin/otel.so +LoadModule otel_module $FOUND EOF diff --git a/instrumentation/httpd/src/otel/mod_otel.cpp b/instrumentation/httpd/src/otel/mod_otel.cpp index 0930402a4..6fbe38dd2 100644 --- a/instrumentation/httpd/src/otel/mod_otel.cpp +++ b/instrumentation/httpd/src/otel/mod_otel.cpp @@ -26,7 +26,6 @@ #include "http_config.h" #include "http_protocol.h" #include "mod_proxy.h" - namespace { @@ -37,6 +36,10 @@ using namespace httpd_otel; const char kOpenTelemetryKeyNote[] = "OTEL"; const char kOpenTelemetryKeyOutboundNote[] = "OTEL_PROXY"; +const char kEnvVarSpanId[] = "OTEL_SPANID"; +const char kEnvVarTraceId[] = "OTEL_TRACEID"; +const char kEnvVarTraceFlags[] = "OTEL_TRACEFLAGS"; +const char kEnvVarTraceState[] = "OTEL_TRACESTATE"; class HttpdCarrier : public opentelemetry::context::propagation::TextMapCarrier { public: @@ -99,6 +102,28 @@ static void opentel_child_created(apr_pool_t*, server_rec*) initTracer(); } +// populates environment variables which can be used by other parts of httpd +void addEnvVars(apr_table_t *envTable, opentelemetry::trace::SpanContext ctx) +{ + union { + char bfr[40] = {0}; + char flags[1]; + char spanId[16]; + char traceId[32]; + } ; + + if (ctx.trace_flags().IsSampled()) + { + apr_table_set(envTable, kEnvVarTraceFlags, "1"); + } + + ctx.span_id().ToLowerBase16(spanId); + apr_table_set(envTable, kEnvVarSpanId, bfr); + ctx.trace_id().ToLowerBase16(traceId); + apr_table_set(envTable, kEnvVarTraceId, bfr); + apr_table_set(envTable, kEnvVarTraceState, ctx.trace_state()->ToHeader().c_str()); +} + // Starting span as early as possible (quick handler): // http://www.fmc-modeling.org/category/projects/apache/amp/3_3Extending_Apache.html#fig:_Apache:_request-processing_+_Module_callbacks_PN static int opentel_handler(request_rec *r, int /* lookup_uri */ ) @@ -148,9 +173,7 @@ static int opentel_handler(request_rec *r, int /* lookup_uri */ ) req_data->span = span; req_data->StartSpan(GetAttrsFromRequest(req)); - // expose traceparent and tracestate to environment variables - HttpdCarrier env(*req->subprocess_env); - PropagatorTraceContext.Inject(env, opentelemetry::context::RuntimeContext::GetCurrent()); + addEnvVars(req->subprocess_env, span->GetContext()); return DECLINED; } diff --git a/instrumentation/httpd/tests/05-check-batch-spans.sh b/instrumentation/httpd/tests/05-check-batch-spans.sh index 979d85e9e..2bf90d3a2 100755 --- a/instrumentation/httpd/tests/05-check-batch-spans.sh +++ b/instrumentation/httpd/tests/05-check-batch-spans.sh @@ -4,11 +4,6 @@ TEST_NAME="Check that 5 requests creates 5 spans (with batch)" . tools.sh -fail () { - printf '%s\n' "$1" >&2 ## Send message to stderr. Exclude >&2 if you don't want it that way. - exit "${2-1}" ## Return a code specified by $2 or 1 by default. -} - setup_test () { cat << EOF > ${HTTPD_CONFIG} diff --git a/instrumentation/httpd/tests/07-create-outbound-spans.sh b/instrumentation/httpd/tests/07-create-outbound-spans.sh index 848fcbf99..093ee291b 100755 --- a/instrumentation/httpd/tests/07-create-outbound-spans.sh +++ b/instrumentation/httpd/tests/07-create-outbound-spans.sh @@ -65,7 +65,6 @@ run_test() { curl --fail -v -H "${HEADER_1}" -H "${HEADER_2}" ${ENDPOINT_URL}/bar || failHttpd "Unable to download page with proxy enabled" } - check_results() { echo "Checking that exactly two spans were created (client one and server one)" count '{' 2 # total two spans = one incoming and one outgoing diff --git a/instrumentation/httpd/tests/08-create-outbound-spans-b3.sh b/instrumentation/httpd/tests/08-create-outbound-spans-b3.sh index 3cd009adb..e1c8a5a15 100755 --- a/instrumentation/httpd/tests/08-create-outbound-spans-b3.sh +++ b/instrumentation/httpd/tests/08-create-outbound-spans-b3.sh @@ -57,7 +57,6 @@ run_test() { curl --fail -v -H "${HEADER}" ${ENDPOINT_URL}/bar || failHttpd "Unable to download page with proxy enabled" } - check_results() { echo "Checking that exactly two spans were created (client one and server one)" count '{' 2 # total two spans = one incoming and one outgoing diff --git a/instrumentation/httpd/tests/09-check-environment-vars.sh b/instrumentation/httpd/tests/09-check-environment-vars.sh new file mode 100755 index 000000000..b33e12b63 --- /dev/null +++ b/instrumentation/httpd/tests/09-check-environment-vars.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +TEST_NAME="Check that tracestate and traceparent are available as variables" + +. tools.sh + +EXTRA_LOG_FILE=/tmp/apache-test-$$.log + +setup_test () { + +EXTRA_HTTPD_MODS="headers" + +# here we are setting apache mod_header to rewrite environment +# variables back to response header as an extra check +cat << EOF > ${HTTPD_CONFIG} +OpenTelemetryExporter file +OpenTelemetryPath ${OUTPUT_SPANS} +Header set x-env-spanid %{OTEL_SPANID}e +Header set x-env-traceid %{OTEL_TRACEID}e +Header set x-env-traceflags %{OTEL_TRACEFLAGS}e +Header set x-env-tracestate %{OTEL_TRACESTATE}e +LogFormat "span=%{OTEL_SPANID}e trace=%{OTEL_TRACEID}e flags=%{OTEL_TRACEFLAGS}e state=%{OTEL_TRACESTATE}e" otel_format +GlobalLog ${EXTRA_LOG_FILE} otel_format +EOF + +} + +run_test() { + ${CURL_CMD} ${ENDPOINT_URL} || fail "Unable to download main page" +} + +check_results() { + echo Checking that log file contains information + grep --color -E "span=[0-9a-f]{16}" ${EXTRA_LOG_FILE} || fail "SpanID not found in log file" + grep --color -E "trace=[0-9a-f]{32}" ${EXTRA_LOG_FILE} || fail "TraceID not found in log file" + grep --color -E "flags=1" ${EXTRA_LOG_FILE} || fail "TraceFlags not found in log file" +} + +teardown_test() { + rm -rf ${OUTPUT_SPANS} ${EXTRA_LOG_FILE} +} + +run $@ diff --git a/instrumentation/httpd/tests/tools.sh b/instrumentation/httpd/tests/tools.sh index 39a715e9e..9086e4fa1 100755 --- a/instrumentation/httpd/tests/tools.sh +++ b/instrumentation/httpd/tests/tools.sh @@ -150,7 +150,7 @@ run() { setup_test - # setup proxy if handler function was defined inside test script + # start proxy (netcat based) only when handler function was defined inside test script if type proxy &>/dev/null ; then rm -rf ${PROXY_PID_FILE} $0 start_proxy & @@ -178,6 +178,7 @@ run() { # stop apache - this is important as this flushes span file apache2ctl -k stop -c "Include ${HTTPD_CONFIG}" || failHttpd "Apache stop failed" + # stop proxy if it was used by this test if type proxy &>/dev/null ; then echo "Waiting for proxy to stop (PID $!)" rm -rf ${PROXY_PID_FILE} From fc73cde4971218f07c0e05b140aa871b62d0a689 Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Sat, 18 Dec 2021 02:17:12 +0100 Subject: [PATCH 09/10] Small fixes after codereview --- instrumentation/httpd/src/otel/mod_otel.cpp | 1 + instrumentation/httpd/tests/09-check-environment-vars.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation/httpd/src/otel/mod_otel.cpp b/instrumentation/httpd/src/otel/mod_otel.cpp index 6fbe38dd2..8eb166bc3 100644 --- a/instrumentation/httpd/src/otel/mod_otel.cpp +++ b/instrumentation/httpd/src/otel/mod_otel.cpp @@ -26,6 +26,7 @@ #include "http_config.h" #include "http_protocol.h" #include "mod_proxy.h" + namespace { diff --git a/instrumentation/httpd/tests/09-check-environment-vars.sh b/instrumentation/httpd/tests/09-check-environment-vars.sh index b33e12b63..b97c21edb 100755 --- a/instrumentation/httpd/tests/09-check-environment-vars.sh +++ b/instrumentation/httpd/tests/09-check-environment-vars.sh @@ -1,6 +1,6 @@ #!/bin/bash -TEST_NAME="Check that tracestate and traceparent are available as variables" +TEST_NAME="Check that information about currently processed span is available in environment variables" . tools.sh From 06d82a8d0fd89fc8069b6e32101ce69fc8dcdee9 Mon Sep 17 00:00:00 2001 From: Tomasz Rojek Date: Sat, 18 Dec 2021 08:33:38 +0100 Subject: [PATCH 10/10] Remove unused variable --- instrumentation/httpd/src/otel/mod_otel.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/instrumentation/httpd/src/otel/mod_otel.cpp b/instrumentation/httpd/src/otel/mod_otel.cpp index 8eb166bc3..3f7b19c45 100644 --- a/instrumentation/httpd/src/otel/mod_otel.cpp +++ b/instrumentation/httpd/src/otel/mod_otel.cpp @@ -41,6 +41,7 @@ const char kEnvVarSpanId[] = "OTEL_SPANID"; const char kEnvVarTraceId[] = "OTEL_TRACEID"; const char kEnvVarTraceFlags[] = "OTEL_TRACEFLAGS"; const char kEnvVarTraceState[] = "OTEL_TRACESTATE"; + class HttpdCarrier : public opentelemetry::context::propagation::TextMapCarrier { public: @@ -107,8 +108,7 @@ static void opentel_child_created(apr_pool_t*, server_rec*) void addEnvVars(apr_table_t *envTable, opentelemetry::trace::SpanContext ctx) { union { - char bfr[40] = {0}; - char flags[1]; + char bfr[33] = {0}; char spanId[16]; char traceId[32]; } ; @@ -117,11 +117,12 @@ void addEnvVars(apr_table_t *envTable, opentelemetry::trace::SpanContext ctx) { apr_table_set(envTable, kEnvVarTraceFlags, "1"); } - + // to keep bfr null-terminated we start from shorter (spanId) ctx.span_id().ToLowerBase16(spanId); apr_table_set(envTable, kEnvVarSpanId, bfr); ctx.trace_id().ToLowerBase16(traceId); apr_table_set(envTable, kEnvVarTraceId, bfr); + apr_table_set(envTable, kEnvVarTraceState, ctx.trace_state()->ToHeader().c_str()); }