From 3a655dfa8ad9b01bb1eea864bb6721716f165128 Mon Sep 17 00:00:00 2001 From: "Sergey A. Osokin" Date: Mon, 2 Dec 2024 16:24:01 -0500 Subject: [PATCH 01/10] Remove cmake from the build process While I'm here change the name of the module to ngx_otel_module. --- CMakeLists.txt | 159 ----------- README.md | 33 +-- config | 261 ++++++++++++++++++- config.make | 47 +++- src/modules.c | 14 - src/{http_module.cpp => ngx_otel_module.cpp} | 20 +- 6 files changed, 323 insertions(+), 211 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 src/modules.c rename src/{http_module.cpp => ngx_otel_module.cpp} (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 7a74f0a..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,159 +0,0 @@ -cmake_minimum_required(VERSION 3.16.3) -project(nginx-otel) - -set(NGX_OTEL_NGINX_BUILD_DIR "" - CACHE PATH "Nginx build (objs) dir") -set(NGX_OTEL_NGINX_DIR "${NGX_OTEL_NGINX_BUILD_DIR}/.." - CACHE PATH "Nginx source dir") - -set(NGX_OTEL_GRPC e241f37befe7ba4688effd84bfbf99b0f681a2f7 # v1.49.4 - CACHE STRING "gRPC tag to download or 'package' to use preinstalled") -set(NGX_OTEL_SDK 11d5d9e0d8fd8ba876c8994714cc2647479b6574 # v1.11.0 - CACHE STRING "OTel SDK tag to download or 'package' to use preinstalled") -set(NGX_OTEL_PROTO_DIR "" CACHE PATH "OTel proto files root") -set(NGX_OTEL_DEV OFF CACHE BOOL "Enforce compiler warnings") - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE RelWithDebInfo) -endif() - -set(CMAKE_CXX_VISIBILITY_PRESET hidden) - -if(NGX_OTEL_GRPC STREQUAL "package") - find_package(protobuf REQUIRED) - find_package(gRPC REQUIRED) -else() - include(FetchContent) - - FetchContent_Declare( - grpc - GIT_REPOSITORY https://github.com/grpc/grpc - GIT_TAG ${NGX_OTEL_GRPC} - GIT_SUBMODULES third_party/protobuf third_party/abseil-cpp third_party/re2 - GIT_SHALLOW ON) - - set(gRPC_USE_PROTO_LITE ON CACHE INTERNAL "") - set(gRPC_INSTALL OFF CACHE INTERNAL "") - set(gRPC_USE_SYSTEMD OFF CACHE INTERNAL "") - set(gRPC_DOWNLOAD_ARCHIVES OFF CACHE INTERNAL "") - set(gRPC_CARES_PROVIDER package CACHE INTERNAL "") - set(gRPC_SSL_PROVIDER package CACHE INTERNAL "") - set(gRPC_ZLIB_PROVIDER package CACHE INTERNAL "") - - set(protobuf_INSTALL OFF CACHE INTERNAL "") - - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - - FetchContent_MakeAvailable(grpc) - - # reconsider once https://github.com/grpc/grpc/issues/36023 is done - target_compile_definitions(grpc PRIVATE GRPC_NO_XDS GRPC_NO_RLS) - - set_property(DIRECTORY ${grpc_SOURCE_DIR} - PROPERTY EXCLUDE_FROM_ALL YES) - - add_library(gRPC::grpc++ ALIAS grpc++) - add_executable(gRPC::grpc_cpp_plugin ALIAS grpc_cpp_plugin) -endif() - -if(NGX_OTEL_SDK STREQUAL "package") - find_package(opentelemetry-cpp REQUIRED) -else() - include(FetchContent) - - FetchContent_Declare( - otelcpp - GIT_REPOSITORY https://github.com/open-telemetry/opentelemetry-cpp - GIT_TAG ${NGX_OTEL_SDK} - GIT_SUBMODULES third_party/opentelemetry-proto - GIT_SHALLOW ON) - - set(BUILD_TESTING OFF CACHE INTERNAL "") - set(WITH_EXAMPLES OFF CACHE INTERNAL "") - - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) - - FetchContent_MakeAvailable(otelcpp) - - set_property(DIRECTORY ${otelcpp_SOURCE_DIR} - PROPERTY EXCLUDE_FROM_ALL YES) - - if(NOT NGX_OTEL_PROTO_DIR) - set(NGX_OTEL_PROTO_DIR - "${otelcpp_SOURCE_DIR}/third_party/opentelemetry-proto") - endif() - - add_library(opentelemetry-cpp::trace ALIAS opentelemetry_trace) -endif() - -set(PROTO_DIR ${NGX_OTEL_PROTO_DIR}) -set(PROTOS - "${PROTO_DIR}/opentelemetry/proto/common/v1/common.proto" - "${PROTO_DIR}/opentelemetry/proto/resource/v1/resource.proto" - "${PROTO_DIR}/opentelemetry/proto/trace/v1/trace.proto" - "${PROTO_DIR}/opentelemetry/proto/collector/trace/v1/trace_service.proto") - -set(PROTO_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") -set(PROTO_SOURCES - "${PROTO_OUT_DIR}/opentelemetry/proto/common/v1/common.pb.cc" - "${PROTO_OUT_DIR}/opentelemetry/proto/resource/v1/resource.pb.cc" - "${PROTO_OUT_DIR}/opentelemetry/proto/trace/v1/trace.pb.cc" - "${PROTO_OUT_DIR}/opentelemetry/proto/collector/trace/v1/trace_service.pb.cc" - "${PROTO_OUT_DIR}/opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.cc") - -# generate protobuf code for lite runtime -add_custom_command( - OUTPUT ${PROTO_SOURCES} - COMMAND protobuf::protoc - --proto_path ${PROTO_DIR} - --cpp_out lite:${PROTO_OUT_DIR} - --grpc_out ${PROTO_OUT_DIR} - --plugin protoc-gen-grpc=$ - ${PROTOS} - # remove inconsequential UTF8 check during serialization to aid performance - COMMAND sed -i.bak -E - -e [[/ ::(PROTOBUF_NAMESPACE_ID|google::protobuf)::internal::WireFormatLite::VerifyUtf8String\(/,/\);/d]] - ${PROTO_SOURCES} - DEPENDS ${PROTOS} protobuf::protoc gRPC::grpc_cpp_plugin - VERBATIM) - -if (NGX_OTEL_DEV) - set(CMAKE_CXX_STANDARD 11) - set(CMAKE_CXX_EXTENSIONS OFF) - - add_compile_options(-Wall -Wtype-limits -Werror) -endif() - -add_library(ngx_otel_module MODULE - src/http_module.cpp - src/grpc_log.cpp - src/modules.c - ${PROTO_SOURCES}) - -# avoid 'lib' prefix in binary name -set_target_properties(ngx_otel_module PROPERTIES PREFIX "") - -# can't use OTel's WITH_ABSEIL until cmake 3.24, as it triggers find_package() -target_compile_definitions(ngx_otel_module PRIVATE HAVE_ABSEIL) - -if (APPLE) - target_link_options(ngx_otel_module PRIVATE -undefined dynamic_lookup) -endif() - -target_include_directories(ngx_otel_module PRIVATE - ${NGX_OTEL_NGINX_BUILD_DIR} - ${NGX_OTEL_NGINX_DIR}/src/core - ${NGX_OTEL_NGINX_DIR}/src/event - ${NGX_OTEL_NGINX_DIR}/src/event/modules - ${NGX_OTEL_NGINX_DIR}/src/event/quic - ${NGX_OTEL_NGINX_DIR}/src/os/unix - ${NGX_OTEL_NGINX_DIR}/src/http - ${NGX_OTEL_NGINX_DIR}/src/http/modules - ${NGX_OTEL_NGINX_DIR}/src/http/v2 - ${NGX_OTEL_NGINX_DIR}/src/http/v3 - ${PROTO_OUT_DIR}) - -target_link_libraries(ngx_otel_module - opentelemetry-cpp::trace - gRPC::grpc++) diff --git a/README.md b/README.md index 1f84fe0..9edb977 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ Follow these steps to build the `ngx_otel_module` dynamic module on Ubuntu or De Install build tools and dependencies. ```bash -sudo apt install cmake build-essential libssl-dev zlib1g-dev libpcre3-dev +sudo apt install build-essential libssl-dev zlib1g-dev libpcre3-dev sudo apt install pkg-config libc-ares-dev libre2-dev # for gRPC ``` @@ -134,13 +134,6 @@ For the next step, you will need the `configure` script that is packaged with th git clone https://github.com/nginx/nginx.git ``` -Configure NGINX to generate files necessary for dynamic module compilation. These files will be placed into the `nginx/objs` directory. - -**Important:** If you did not obtain NGINX source code via the clone method in the previous step, you will need to adjust paths in the following commands to conform to your specific directory structure. -```bash -cd nginx -auto/configure --with-compat -``` Exit the NGINX directory and clone the `ngx_otel_module` repository. ```bash @@ -148,14 +141,24 @@ cd .. git clone https://github.com/nginxinc/nginx-otel.git ``` -Configure and build the NGINX OTel module. - -**Important**: replace the path in the `cmake` command with the path to the `nginx/objs` directory from above. +Set up `NGX_OTEL_PROTO_DIR` variable to point it into root of `opentelemetry-proto`: ```bash -cd nginx-otel -mkdir build -cd build -cmake -DNGX_OTEL_NGINX_BUILD_DIR=/path/to/configured/nginx/objs .. +export NGX_OTEL_PROTO_DIR=/opt/local/include +``` + +Configure and build the NGINX OTel module as usual: + +- for a built-in module: +```bash +cd nginx +./configure --with-http_ssl_module --add-module=../nginx-otel +make +``` + +- for a dynamic module: +```bash +cd nginx +./configure --with-http_ssl_module --add-dynamic-module=../nginx-otel make ``` diff --git a/config b/config index 75378e2..2f1da1e 100644 --- a/config +++ b/config @@ -1,9 +1,256 @@ ngx_addon_name=ngx_otel_module +ngx_module_type=HTTP +ngx_module_name=$ngx_addon_name +ngx_module_incs= +ngx_module_deps=" \ + $ngx_addon_dir/src/batch_exporter.hpp \ + $ngx_addon_dir/src/grpc_log.hpp \ + $ngx_addon_dir/src/ngx.hpp \ + $ngx_addon_dir/src/str_view.hpp \ + $ngx_addon_dir/src/trace_context.hpp \ + $ngx_addon_dir/src/trace_service_client.hpp \ +" +ngx_module_srcs=" \ + $ngx_addon_dir/src/grpc_log.cpp \ + $ngx_addon_dir/src/ngx_otel_module.cpp \ + objs/opentelemetry/proto/common/v1/common.pb.cc \ + objs/opentelemetry/proto/resource/v1/resource.pb.cc \ + objs/opentelemetry/proto/trace/v1/trace.pb.cc \ + objs/opentelemetry/proto/collector/trace/v1/trace_service.pb.cc \ + objs/opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.cc \ +" -cmake -D NGX_OTEL_NGINX_BUILD_DIR=$NGX_OBJS \ - -D CMAKE_LIBRARY_OUTPUT_DIRECTORY=$PWD/$NGX_OBJS \ - -D "CMAKE_C_FLAGS=$NGX_CC_OPT" \ - -D "CMAKE_CXX_FLAGS=$NGX_CC_OPT" \ - -D "CMAKE_MODULE_LINKER_FLAGS=$NGX_LD_OPT" \ - $NGX_OTEL_CMAKE_OPTS \ - -S $ngx_addon_dir -B $NGX_OBJS/otel || exit 1 +ngx_feature="c-ares" +ngx_feature_name="" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path="/usr/include" +ngx_feature_libs="-lcares" +ngx_feature_test="ares_version(NULL);" +. auto/feature + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="libcares in /usr/local/" + ngx_feature_path="/usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lcares" + else + ngx_feature_libs="-L/usr/local/lib -lcares" + fi + + . auto/feature +fi + +if [ $ngx_found = yes ]; then + ngx_module_libs="$ngx_module_libs -lcares" +fi + +unset ngx_found + +### C++ feature test is unavailable in nginx + +CXX=${CXX:-c++} +CXXFLAGS="$CXXFLAGS --std=c++17" +CXX_TEST_FLAGS=${CXX_TEST_FLAGS:---std=c++17} + +autocppfeature() +{ + echo $ngx_n "checking for $ngx_feature ...$ngx_c" + +cat << END >> $NGX_AUTOCONF_ERR +---------------------------------------- +checking for $ngx_feature + +END + + ngx_found=no + + if test -n "$ngx_feature_name"; then + ngx_have_feature=`echo $ngx_feature_name \ + | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ` + fi + + if test -n "$ngx_feature_path"; then + for ngx_temp in $ngx_feature_path; do + ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp" + done + fi + +cat << END > $NGX_AUTOTEST.cpp + +$ngx_feature_incs + +int main(void) { + $ngx_feature_test; + return 0; +} + +END + + ngx_test="$CXX $CXX_TEST_FLAGS $CXX_AUX_FLAGS $ngx_feature_inc_path \ + -o $NGX_AUTOTEST $NGX_AUTOTEST.cpp $NGX_TEST_LD_OPT $ngx_feature_libs" + + ngx_feature_inc_path= + + eval "/bin/sh -c \"$ngx_test\" >> $NGX_AUTOCONF_ERR 2>&1" + + if [ -x $NGX_AUTOTEST ]; then + + echo " found" + ngx_found=yes + + if test -n "$ngx_feature_name"; then + have=$ngx_have_feature . auto/have + fi + + else + echo " not found" + echo "----------" >> $NGX_AUTOCONF_ERR + cat $NGX_AUTOTEST.cpp >> $NGX_AUTOCONF_ERR + echo "----------" >> $NGX_AUTOCONF_ERR + echo $ngx_test >> $NGX_AUTOCONF_ERR + echo "----------" >> $NGX_AUTOCONF_ERR + fi + + rm -rf $NGX_AUTOTEST* +} + +ngx_feature="re2" +ngx_feature_name="" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path="/usr/include" +ngx_feature_libs="-lre2" +ngx_feature_test="RE2::FullMatch(\"hello\", \"h.*o\");" + +autocppfeature + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="re2 in /usr/local/" + ngx_feature_path="/usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lre2" + else + ngx_feature_libs="-L/usr/local/lib -lre2" + fi + + autocppfeature +fi + +if [ $ngx_found = yes ]; then + ngx_module_libs="$ngx_module_libs -lre2" +fi + +ngx_feature="opentelemetry-cpp" +ngx_feature_name="" +ngx_feature_run=no +ngx_feature_incs="#include + typedef opentelemetry::nostd::string_view StrView;" +ngx_feature_path="/usr/include" +ngx_feature_libs="-lopentelemetry_common" +ngx_feature_test="using namespace std; + StrView str, prefix; + str.substr(0, prefix.size());" + +autocppfeature + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="opentelemetry in /usr/local/" + ngx_feature_path="/usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lopentelemetry_common" + else + ngx_feature_libs="-L/usr/local/lib -lopentelemetry_common -lopentelemetry_resources -lopentelemetry_trace" + fi + + autocppfeature +fi + +if [ $ngx_found = yes ]; then + ngx_module_libs="$ngx_module_libs -lopentelemetry_common -lopentelemetry_resources -lopentelemetry_trace" +fi + +#if [ ! -d $prefix/include/opentelemetry/proto ]; then +# echo "Need to install opentelemetry-proto." +# exit 2 +#fi + +ngx_feature="protobuf" +ngx_feature_name="" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path="/usr/include" +ngx_feature_libs="-lprotobuf" +ngx_feature_test="using namespace google::protobuf; + google::protobuf::internal::VersionString(0);" + +autocppfeature + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="protobuf in /usr/local/" + ngx_feature_path="/usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lprotobuf" + else + ngx_feature_libs="-L/usr/local/lib -lprotobuf" + fi + + autocppfeature +fi + +if [ $ngx_found = yes ]; then + ngx_module_libs="$ngx_module_libs -lprotobuf" +fi + +ngx_feature="grpc" +ngx_feature_name="" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path="/usr/include" +ngx_feature_libs="-lgrpc -lgpr -lgrpc++" +ngx_feature_test="gpr_log_verbosity_init();" + +autocppfeature + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="grpc in /usr/local/" + ngx_feature_path="/usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lgrpc -lgpr -lgrpc++" + else + ngx_feature_libs="-L/usr/local/lib -lgrpc -lgpr -lgrpc++" + fi + + autocppfeature +fi + +if [ $ngx_found = yes ]; then + ngx_module_libs="$ngx_module_libs -lgrpc -lgpr -lgrpc++" +fi + +ngx_module_libs="$ngx_module_libs -lz -lm -lrt -lssl -lcrypto" + +. auto/module + +CORE_INCS="$CORE_INCS $ngx_feature_path" +OTEL_NGX_SRCS="$ngx_module_srcs" diff --git a/config.make b/config.make index a7cce9f..a066be3 100644 --- a/config.make +++ b/config.make @@ -1,10 +1,45 @@ -cat << END >> $NGX_MAKEFILE +if [ ! "`which protoc 2>/dev/null`" ]; then + echo "Need to install protoc." + exit 2 +else + PROTOC=`which protoc` +fi -modules: ngx_otel_module +if [ ! "`which grpc_cpp_plugin 2>/dev/null`" ]; then + echo "Need to install grpc tools." + exit 2 +else + GRPC_CPP=`which grpc_cpp_plugin` +fi -ngx_otel_module: - \$(MAKE) -C $NGX_OBJS/otel +mkdir -p objs -.PHONY: ngx_otel_module +if [ -z $NGX_OTEL_PROTO_DIR ]; then + echo "Need to set \$NGX_OTEL_PROTO_DIR variable." + exit 2 +fi -END +if [ ! -d $NGX_OTEL_PROTO_DIR ]; then + echo "\$NGX_OTEL_PROTO_DIR is set to unavailable directory." + exit 2 +fi + +find $NGX_OTEL_PROTO_DIR/opentelemetry/proto -type f -name '*.proto' | \ + xargs $PROTOC \ + --proto_path $NGX_OTEL_PROTO_DIR \ + --cpp_out=objs \ + --grpc_out=objs \ + --plugin=protoc-gen-grpc=$GRPC_CPP + +find objs -name '*.pb.cc' | \ + xargs sed -i.bak -e "/ ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(/,/);/d" + +for src_file in $OTEL_NGX_SRCS; do + obj_file="$NGX_OBJS/addon/src/`basename $src_file .cpp`.o" + echo "$obj_file : CFLAGS += $CXXFLAGS -Wno-missing-field-initializers -Wno-conditional-uninitialized -fPIC -fvisibility=hidden -DHAVE_ABSEIL -Dngx_otel_module_EXPORTS" >> $NGX_MAKEFILE +done + +for src_file in $OTEL_NGX_SRCS; do + obj_file="$NGX_OBJS/addon/v1/`basename $src_file .cc`.o" + echo "$obj_file : CFLAGS += $CXXFLAGS -Wno-missing-field-initializers -Wno-conditional-uninitialized -fPIC -fvisibility=hidden -DHAVE_ABSEIL -Dngx_otel_module_EXPORTS" >> $NGX_MAKEFILE +done diff --git a/src/modules.c b/src/modules.c deleted file mode 100644 index 419d594..0000000 --- a/src/modules.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -extern ngx_module_t gHttpModule; - -ngx_module_t* ngx_modules[] = { - &gHttpModule, - NULL -}; - -char* ngx_module_names[] = { - "ngx_http_otel_module", - NULL -}; diff --git a/src/http_module.cpp b/src/ngx_otel_module.cpp similarity index 97% rename from src/http_module.cpp rename to src/ngx_otel_module.cpp index df5702e..566376a 100644 --- a/src/http_module.cpp +++ b/src/ngx_otel_module.cpp @@ -8,7 +8,7 @@ #include -extern ngx_module_t gHttpModule; +extern ngx_module_t ngx_otel_module; namespace { @@ -168,18 +168,18 @@ bool iremovePrefix(ngx_str_t* str, StrView p) MainConf* getMainConf(ngx_conf_t* cf) { return static_cast( - (MainConfBase*)ngx_http_conf_get_module_main_conf(cf, gHttpModule)); + (MainConfBase*)ngx_http_conf_get_module_main_conf(cf, ngx_otel_module)); } MainConf* getMainConf(ngx_cycle_t* cycle) { return static_cast( - (MainConfBase*)ngx_http_cycle_get_module_main_conf(cycle, gHttpModule)); + (MainConfBase*)ngx_http_cycle_get_module_main_conf(cycle, ngx_otel_module)); } LocationConf* getLocationConf(ngx_http_request_t* r) { - return (LocationConf*)ngx_http_get_module_loc_conf(r, gHttpModule); + return (LocationConf*)ngx_http_get_module_loc_conf(r, ngx_otel_module); } void cleanupOtelCtx(void* data) @@ -188,7 +188,7 @@ void cleanupOtelCtx(void* data) OtelCtx* getOtelCtx(ngx_http_request_t* r) { - auto ctx = (OtelCtx*)ngx_http_get_module_ctx(r, gHttpModule); + auto ctx = (OtelCtx*)ngx_http_get_module_ctx(r, ngx_otel_module); // restore module context if it was reset by e.g. internal redirect if (ctx == NULL && (r->internal || r->filter_finalize)) { @@ -196,7 +196,7 @@ OtelCtx* getOtelCtx(ngx_http_request_t* r) for (auto cln = r->pool->cleanup; cln; cln = cln->next) { if (cln->handler == cleanupOtelCtx) { ctx = (OtelCtx*)cln->data; - ngx_http_set_ctx(r, ctx, gHttpModule); + ngx_http_set_ctx(r, ctx, ngx_otel_module); break; } } @@ -217,7 +217,7 @@ OtelCtx* createOtelCtx(ngx_http_request_t* r) storage->handler = cleanupOtelCtx; auto ctx = new (storage->data) OtelCtx{}; - ngx_http_set_ctx(r, ctx, gHttpModule); + ngx_http_set_ctx(r, ctx, ngx_otel_module); return ctx; } @@ -932,7 +932,7 @@ char* mergeLocationConf(ngx_conf_t* cf, void* parent, void* child) return NGX_CONF_OK; } -ngx_http_module_t gHttpModuleCtx = { +ngx_http_module_t ngx_otel_moduleCtx = { addVariables, /* preconfiguration */ initModule, /* postconfiguration */ @@ -948,9 +948,9 @@ ngx_http_module_t gHttpModuleCtx = { } -ngx_module_t gHttpModule = { +ngx_module_t ngx_otel_module = { NGX_MODULE_V1, - &gHttpModuleCtx, /* module context */ + &ngx_otel_moduleCtx, /* module context */ gCommands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ From 323e7fd3284d16c32b94adf0e7f9eef1dcbd7f24 Mon Sep 17 00:00:00 2001 From: Eugene <54681898+jimf5@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:53:38 -0800 Subject: [PATCH 02/10] Verify custom resource attributes support (#32). Co-authored-by: p-pautov <37922380+p-pautov@users.noreply.github.com> --- tests/test_otel.py | 32 +++++++++++++++++++++++++++++--- tests/trace_service.py | 14 +++++++++----- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/tests/test_otel.py b/tests/test_otel.py index 10ce2fe..11caa85 100644 --- a/tests/test_otel.py +++ b/tests/test_otel.py @@ -28,7 +28,7 @@ http { } otel_trace on; - otel_service_name test_service; + {{ resource_attrs }} server { listen 127.0.0.1:18443 ssl; @@ -240,7 +240,7 @@ def test_context(client, trace_service, parent, path): @pytest.mark.parametrize( "nginx_config", - [({"interval": "200ms", "scheme": "http://"})], + [{"interval": "200ms", "scheme": "http://"}], indirect=True, ) @pytest.mark.parametrize("batch_count", [1, 3]) @@ -257,8 +257,34 @@ def test_batches(client, trace_service, batch_count): assert len(trace_service.batches) == batch_count for batch in trace_service.batches: - assert get_attr(batch[0].resource, "service.name") == "test_service" + assert ( + get_attr(batch[0].resource, "service.name") + == "unknown_service:nginx" + ) assert len(batch[0].scope_spans[0].spans) == batch_size time.sleep(0.3) # wait for +1 request to be flushed trace_service.batches.clear() + + +@pytest.mark.parametrize( + "nginx_config", + [ + { + "resource_attrs": """ + otel_service_name "test_service"; + otel_resource_attr my.name "my name"; + otel_resource_attr my.service "my service"; + """, + } + ], + indirect=True, +) +def test_custom_resource_attributes(client, trace_service): + assert client.get("http://127.0.0.1:18080/ok").status_code == 200 + + batch = trace_service.get_batch() + + assert get_attr(batch.resource, "service.name") == "test_service" + assert get_attr(batch.resource, "my.name") == "my name" + assert get_attr(batch.resource, "my.service") == "my service" diff --git a/tests/trace_service.py b/tests/trace_service.py index 9f094f9..3b191a1 100644 --- a/tests/trace_service.py +++ b/tests/trace_service.py @@ -14,16 +14,20 @@ class TraceService(trace_service_pb2_grpc.TraceServiceServicer): self.batches.append(request.resource_spans) return trace_service_pb2.ExportTracePartialSuccess() - def get_span(self): + def get_batch(self): for _ in range(10): if len(self.batches): break time.sleep(0.001) + assert len(self.batches) == 1 + assert len(self.batches[0]) == 1 + return self.batches.pop()[0] - assert len(self.batches) == 1, "No spans received" - span = self.batches[0][0].scope_spans[0].spans.pop() - self.batches.clear() - return span + def get_span(self): + batch = self.get_batch() + assert len(batch.scope_spans) == 1 + assert len(batch.scope_spans[0].spans) == 1 + return batch.scope_spans[0].spans.pop() @pytest.fixture(scope="module") From 3b6667c808458d8c2e4c5eeec1e2c713f748ab8b Mon Sep 17 00:00:00 2001 From: Pavel Pautov Date: Thu, 21 Nov 2024 13:57:43 -0800 Subject: [PATCH 03/10] Fail early if "trusted_certificate" is a directory. Previously, the error was caused by enormous std::string allocation. --- src/ngx_otel_module.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ngx_otel_module.cpp b/src/ngx_otel_module.cpp index 566376a..65d0b92 100644 --- a/src/ngx_otel_module.cpp +++ b/src/ngx_otel_module.cpp @@ -711,7 +711,8 @@ char* addResourceAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) return NGX_CONF_OK; } -char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) { +char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) +{ auto path = ((ngx_str_t*)cf->args->elts)[1]; auto mcf = getMainConf(cf); @@ -727,11 +728,13 @@ char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) { return (char*)NGX_CONF_ERROR; } file.exceptions(std::ios::failbit | std::ios::badbit); - file.seekg(0, std::ios::end); - size_t size = file.tellg(); - mcf->trustedCert.resize(size); + file.peek(); // trigger early error for dirs + + size_t size = file.seekg(0, std::ios::end).tellg(); file.seekg(0); - file.read(&mcf->trustedCert[0], mcf->trustedCert.size()); + + mcf->trustedCert.resize(size); + file.read(&mcf->trustedCert[0], size); } catch (const std::exception& e) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to read \"%V\": %s", &path, e.what()); From a23ffa955c2573ec1492f48f9a00c3839d46669c Mon Sep 17 00:00:00 2001 From: Pavel Pautov Date: Thu, 21 Nov 2024 21:46:01 -0800 Subject: [PATCH 04/10] Consolidate transport related parameters into a struct. Also, replace leftover cast with getMainConf(). --- src/batch_exporter.hpp | 4 ++-- src/ngx_otel_module.cpp | 11 +++++++---- src/trace_service_client.hpp | 16 +++++++++++----- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/batch_exporter.hpp b/src/batch_exporter.hpp index cb3e075..a2e65b1 100644 --- a/src/batch_exporter.hpp +++ b/src/batch_exporter.hpp @@ -111,10 +111,10 @@ public: int attrSize{0}; }; - BatchExporter(StrView target, bool ssl, const std::string& trustedCert, + BatchExporter(const Target& target, size_t batchSize, size_t batchCount, const std::map& resourceAttrs) : - batchSize(batchSize), client(std::string(target), ssl, trustedCert) + batchSize(batchSize), client(target) { free.reserve(batchCount); while (batchCount-- > 0) { diff --git a/src/ngx_otel_module.cpp b/src/ngx_otel_module.cpp index 65d0b92..4f78aee 100644 --- a/src/ngx_otel_module.cpp +++ b/src/ngx_otel_module.cpp @@ -576,10 +576,13 @@ ngx_int_t initWorkerProcess(ngx_cycle_t* cycle) } try { + Target target; + target.endpoint = std::string(toStrView(mcf->endpoint)); + target.ssl = mcf->ssl; + target.trustedCert = mcf->trustedCert; + gExporter.reset(new BatchExporter( - toStrView(mcf->endpoint), - mcf->ssl, - mcf->trustedCert, + target, mcf->batchSize, mcf->batchCount, mcf->resourceAttrs)); @@ -772,7 +775,7 @@ void* createMainConf(ngx_conf_t* cf) char* initMainConf(ngx_conf_t* cf, void* conf) { - auto mcf = (MainConf*)conf; + auto mcf = getMainConf(cf); ngx_conf_init_msec_value(mcf->interval, 5000); ngx_conf_init_size_value(mcf->batchSize, 512); diff --git a/src/trace_service_client.hpp b/src/trace_service_client.hpp index d248f00..485143c 100644 --- a/src/trace_service_client.hpp +++ b/src/trace_service_client.hpp @@ -8,6 +8,12 @@ namespace otel_proto_trace = opentelemetry::proto::collector::trace::v1; +struct Target { + std::string endpoint; + bool ssl; + std::string trustedCert; +}; + class TraceServiceClient { public: typedef otel_proto_trace::ExportTraceServiceRequest Request; @@ -17,18 +23,18 @@ public: typedef std::function ResponseCb; - TraceServiceClient(const std::string& target, bool ssl, - const std::string& trustedCert) + TraceServiceClient(const Target& target) { std::shared_ptr creds; - if (ssl) { + if (target.ssl) { grpc::SslCredentialsOptions options; - options.pem_root_certs = trustedCert; + options.pem_root_certs = target.trustedCert; + creds = grpc::SslCredentials(options); } else { creds = grpc::InsecureChannelCredentials(); } - auto channel = grpc::CreateChannel(target, creds); + auto channel = grpc::CreateChannel(target.endpoint, creds); channel->GetState(true); // trigger 'connecting' state stub = TraceService::NewStub(channel); From d0385c8f682d0edce27933724d1f64f67d742d80 Mon Sep 17 00:00:00 2001 From: Pavel Pautov Date: Mon, 2 Dec 2024 21:07:38 -0800 Subject: [PATCH 05/10] Support sending custom headers to export endpoint (fix #62). The headers are configured by "header" directive in "otel_exporter" block, e.g. otel_exporter { endpoint localhost:4317; header X-API-Token "token value"; } --- src/ngx_otel_module.cpp | 36 +++++++++++++++++++++++++++++++++++- src/trace_service_client.hpp | 23 ++++++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/ngx_otel_module.cpp b/src/ngx_otel_module.cpp index 4f78aee..2a38c5a 100644 --- a/src/ngx_otel_module.cpp +++ b/src/ngx_otel_module.cpp @@ -30,6 +30,7 @@ struct MainConf : MainConfBase { std::map resourceAttrs; bool ssl; std::string trustedCert; + Target::HeaderVec headers; }; struct SpanAttr { @@ -49,6 +50,7 @@ char* setExporter(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); char* addResourceAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); char* addSpanAttr(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); +char* addExporterHeader(ngx_conf_t* cf, ngx_command_t* cmd, void* conf); namespace Propagation { @@ -120,6 +122,10 @@ ngx_command_t gExporterCommands[] = { NGX_CONF_TAKE1, setTrustedCertificate }, + { ngx_string("header"), + NGX_CONF_TAKE2, + addExporterHeader }, + { ngx_string("interval"), NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -580,6 +586,7 @@ ngx_int_t initWorkerProcess(ngx_cycle_t* cycle) target.endpoint = std::string(toStrView(mcf->endpoint)); target.ssl = mcf->ssl; target.trustedCert = mcf->trustedCert; + target.headers = mcf->headers; gExporter.reset(new BatchExporter( target, @@ -651,7 +658,7 @@ char* setExporter(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) continue; } - if (cf->args->nelts != 2) { + if (cf->args->nelts != static_cast(ffs(cmd->type))) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid number of arguments in \"%V\" " "directive of \"otel_exporter\"", name); @@ -747,6 +754,33 @@ char* setTrustedCertificate(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) return NGX_CONF_OK; } +char* addExporterHeader(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) +{ + auto args = (ngx_str_t*)cf->args->elts; + + // don't force on users lower case name requirement of gRPC + ngx_strlow(args[1].data, args[1].data, args[1].len); + + try { + // validate header here to avoid runtime assert failure in gRPC + auto name = toStrView(args[1]); + if (!Target::validateHeaderName(name)) { + return (char*)"has invalid header name"; + } + auto value = toStrView(args[2]); + if (!Target::validateHeaderValue(value)) { + return (char*)"has invalid header value"; + } + + getMainConf(cf)->headers.emplace_back(name, value); + } catch (const std::exception& e) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "OTel: %s", e.what()); + return (char*)NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + void* createMainConf(ngx_conf_t* cf) { auto cln = ngx_pool_cleanup_add(cf->pool, sizeof(MainConf)); diff --git a/src/trace_service_client.hpp b/src/trace_service_client.hpp index 485143c..4ed92e7 100644 --- a/src/trace_service_client.hpp +++ b/src/trace_service_client.hpp @@ -9,9 +9,24 @@ namespace otel_proto_trace = opentelemetry::proto::collector::trace::v1; struct Target { + typedef std::vector> HeaderVec; + std::string endpoint; bool ssl; std::string trustedCert; + HeaderVec headers; + + static bool validateHeaderName(StrView name) + { + return grpc_header_key_is_legal( + grpc_slice_from_static_buffer(name.data(), name.size())); + } + + static bool validateHeaderValue(StrView value) + { + return grpc_header_nonbin_value_is_legal( + grpc_slice_from_static_buffer(value.data(), value.size())); + } }; class TraceServiceClient { @@ -23,7 +38,7 @@ public: typedef std::function ResponseCb; - TraceServiceClient(const Target& target) + TraceServiceClient(const Target& target) : headers(target.headers) { std::shared_ptr creds; if (target.ssl) { @@ -44,6 +59,10 @@ public: { std::unique_ptr call{new ActiveCall{}}; + for (auto& header : headers) { + call->context.AddMetadata(header.first, header.second); + } + call->request = std::move(req); call->cb = std::move(cb); @@ -113,6 +132,8 @@ private: ResponseCb cb; }; + Target::HeaderVec headers; + std::unique_ptr stub; grpc::CompletionQueue queue; From 0aec04198c533742686f5c054e4899cba0478d4f Mon Sep 17 00:00:00 2001 From: Pavel Pautov Date: Thu, 19 Dec 2024 21:28:17 -0800 Subject: [PATCH 06/10] Verify custom exporter headers support (#62). --- tests/test_otel.py | 25 +++++++++++++++++++++++++ tests/trace_service.py | 11 ++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/tests/test_otel.py b/tests/test_otel.py index 11caa85..513c1f1 100644 --- a/tests/test_otel.py +++ b/tests/test_otel.py @@ -25,6 +25,8 @@ http { interval {{ interval or "1ms" }}; batch_size 3; batch_count 3; + + {{ exporter_opts }} } otel_trace on; @@ -288,3 +290,26 @@ def test_custom_resource_attributes(client, trace_service): assert get_attr(batch.resource, "service.name") == "test_service" assert get_attr(batch.resource, "my.name") == "my name" assert get_attr(batch.resource, "my.service") == "my service" + + +@pytest.mark.parametrize( + "nginx_config", + [ + { + "exporter_opts": """ + header X-API-TOKEN api.value; + header Authorization "Basic value"; + """, + } + ], + indirect=True, +) +@pytest.mark.parametrize("trace_service", ["skip_otelcol"], indirect=True) +def test_exporter_headers(client, trace_service): + assert client.get("http://127.0.0.1:18080/ok").status_code == 200 + + assert trace_service.get_span().name == "/ok" + + headers = dict(trace_service.last_metadata) + assert headers["x-api-token"] == "api.value" + assert headers["authorization"] == "Basic value" diff --git a/tests/trace_service.py b/tests/trace_service.py index 3b191a1..f47b104 100644 --- a/tests/trace_service.py +++ b/tests/trace_service.py @@ -12,6 +12,7 @@ class TraceService(trace_service_pb2_grpc.TraceServiceServicer): def Export(self, request, context): self.batches.append(request.resource_spans) + self.last_metadata = context.invocation_metadata() return trace_service_pb2.ExportTracePartialSuccess() def get_batch(self): @@ -31,13 +32,17 @@ class TraceService(trace_service_pb2_grpc.TraceServiceServicer): @pytest.fixture(scope="module") -def trace_service(pytestconfig, logger): +def trace_service(request, pytestconfig, logger): server = grpc.server(concurrent.futures.ThreadPoolExecutor()) trace_service = TraceService() trace_service_pb2_grpc.add_TraceServiceServicer_to_server( trace_service, server ) - listen_addr = f"127.0.0.1:{24317 if pytestconfig.option.otelcol else 14317}" + trace_service.use_otelcol = ( + pytestconfig.option.otelcol + and getattr(request, "param", "") != "skip_otelcol" + ) + listen_addr = f"127.0.0.1:{24317 if trace_service.use_otelcol else 14317}" server.add_insecure_port(listen_addr) logger.info(f"Starting trace service at {listen_addr}...") server.start() @@ -48,7 +53,7 @@ def trace_service(pytestconfig, logger): @pytest.fixture(scope="module") def otelcol(pytestconfig, testdir, logger, trace_service): - if pytestconfig.option.otelcol is None: + if not trace_service.use_otelcol: yield return From 38cae30841b87ab6df994a54846548ff0a8325db Mon Sep 17 00:00:00 2001 From: Eugene Grebenschikov Date: Fri, 20 Dec 2024 17:24:27 -0800 Subject: [PATCH 07/10] Verify export via TLS (#12). Co-authored-by: Pavel Pautov --- tests/conftest.py | 19 ++++++++++--------- tests/test_otel.py | 20 ++++++++++++++++++-- tests/trace_service.py | 20 ++++++++++++++++---- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 7978759..25933e4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,7 +19,7 @@ def pytest_addoption(parser): parser.addoption("--globals", default="") -def self_signed_cert(test_dir, name): +def self_signed_cert(name): k = crypto.PKey() k.generate_key(crypto.TYPE_RSA, 2048) cert = crypto.X509() @@ -29,11 +29,9 @@ def self_signed_cert(test_dir, name): cert.gmtime_adj_notAfter(365 * 86400) # 365 days cert.set_pubkey(k) cert.sign(k, "sha512") - (test_dir / f"{name}.key").write_text( - crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8") - ) - (test_dir / f"{name}.crt").write_text( - crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8") + return ( + crypto.dump_privatekey(crypto.FILETYPE_PEM, k), + crypto.dump_certificate(crypto.FILETYPE_PEM, cert), ) @@ -66,7 +64,7 @@ def nginx_config(request, pytestconfig, testdir, logger): @pytest.fixture(scope="module") -def nginx(testdir, pytestconfig, nginx_config, certs, logger, otelcol): +def nginx(testdir, pytestconfig, nginx_config, cert, logger, otelcol): (testdir / "nginx.conf").write_text(nginx_config) logger.info("Starting nginx...") proc = subprocess.Popen( @@ -96,5 +94,8 @@ def nginx(testdir, pytestconfig, nginx_config, certs, logger, otelcol): @pytest.fixture(scope="module") -def certs(testdir): - self_signed_cert(testdir, "localhost") +def cert(testdir): + key, cert = self_signed_cert("localhost") + (testdir / "localhost.key").write_text(key.decode("utf-8")) + (testdir / "localhost.crt").write_text(cert.decode("utf-8")) + yield (key, cert) diff --git a/tests/test_otel.py b/tests/test_otel.py index 513c1f1..fef771a 100644 --- a/tests/test_otel.py +++ b/tests/test_otel.py @@ -21,7 +21,7 @@ http { ssl_certificate_key localhost.key; otel_exporter { - endpoint {{ scheme }}127.0.0.1:14317; + endpoint {{ endpoint or "127.0.0.1:14317" }}; interval {{ interval or "1ms" }}; batch_size 3; batch_count 3; @@ -242,7 +242,7 @@ def test_context(client, trace_service, parent, path): @pytest.mark.parametrize( "nginx_config", - [{"interval": "200ms", "scheme": "http://"}], + [{"interval": "200ms", "endpoint": "http://127.0.0.1:14317"}], indirect=True, ) @pytest.mark.parametrize("batch_count", [1, 3]) @@ -313,3 +313,19 @@ def test_exporter_headers(client, trace_service): headers = dict(trace_service.last_metadata) assert headers["x-api-token"] == "api.value" assert headers["authorization"] == "Basic value" + + +@pytest.mark.parametrize( + "nginx_config", + [ + { + "endpoint": "https://localhost:14318", + "exporter_opts": "trusted_certificate localhost.crt;", + } + ], + indirect=True, +) +def test_tls_export(client, trace_service): + assert client.get("http://127.0.0.1:18080/ok").status_code == 200 + + assert trace_service.get_span().name == "/ok" diff --git a/tests/trace_service.py b/tests/trace_service.py index f47b104..5ef2bc6 100644 --- a/tests/trace_service.py +++ b/tests/trace_service.py @@ -32,7 +32,7 @@ class TraceService(trace_service_pb2_grpc.TraceServiceServicer): @pytest.fixture(scope="module") -def trace_service(request, pytestconfig, logger): +def trace_service(request, pytestconfig, logger, cert): server = grpc.server(concurrent.futures.ThreadPoolExecutor()) trace_service = TraceService() trace_service_pb2_grpc.add_TraceServiceServicer_to_server( @@ -44,6 +44,10 @@ def trace_service(request, pytestconfig, logger): ) listen_addr = f"127.0.0.1:{24317 if trace_service.use_otelcol else 14317}" server.add_insecure_port(listen_addr) + if not trace_service.use_otelcol: + creds = grpc.ssl_server_credentials([cert]) + server.add_secure_port("127.0.0.1:14318", creds) + listen_addr += " and 127.0.0.1:14318" logger.info(f"Starting trace service at {listen_addr}...") server.start() yield trace_service @@ -52,18 +56,26 @@ def trace_service(request, pytestconfig, logger): @pytest.fixture(scope="module") -def otelcol(pytestconfig, testdir, logger, trace_service): +def otelcol(pytestconfig, testdir, logger, trace_service, cert): if not trace_service.use_otelcol: yield return (testdir / "otel-config.yaml").write_text( - """receivers: + f"""receivers: otlp: protocols: grpc: endpoint: 127.0.0.1:14317 + otlp/tls: + protocols: + grpc: + endpoint: 127.0.0.1:14318 + tls: + cert_file: {testdir}/localhost.crt + key_file: {testdir}/localhost.key + exporters: otlp: endpoint: 127.0.0.1:24317 @@ -73,7 +85,7 @@ exporters: service: pipelines: traces: - receivers: [otlp] + receivers: [otlp, otlp/tls] exporters: [otlp] telemetry: metrics: From 22d6380458c115b75ec7ed7d759bb47231f3d1f6 Mon Sep 17 00:00:00 2001 From: Pavel Pautov Date: Thu, 27 Mar 2025 19:35:53 -0700 Subject: [PATCH 08/10] Add CI workflow for Alpine Linux. The workflow uses Nginx build system with OS provided gRPC. --- .github/workflows/alpine.yml | 45 ++++++++++++++++++++++++++++++++++++ .github/workflows/ubuntu.yml | 2 +- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/alpine.yml diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml new file mode 100644 index 0000000..8dc0cef --- /dev/null +++ b/.github/workflows/alpine.yml @@ -0,0 +1,45 @@ +name: Alpine build + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + container: alpine + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install dependencies + run: | + apk add build-base openssl-dev zlib-dev pcre2-dev \ + cmake git grpc-dev protobuf-dev \ + python3 + - name: Checkout nginx + uses: actions/checkout@v4 + with: + repository: nginx/nginx + path: nginx + - name: Build nginx + working-directory: nginx + run: | + auto/configure --with-compat --with-http_ssl_module \ + --with-http_v2_module --with-http_v3_module + make -j $(nproc) + - name: Build module + working-directory: nginx + run: | + NGX_OTEL_CMAKE_OPTS="-D NGX_OTEL_GRPC=package" \ + auto/configure --with-compat --add-dynamic-module=.. + make -j $(nproc) modules + - name: Install test dependencies + run: | + python -m venv tests-venv + tests-venv/bin/pip install -r tests/requirements.txt + - name: Run tests + run: | + tests-venv/bin/pytest tests --maxfail=10 --nginx=nginx/objs/nginx \ + --module=nginx/objs/ngx_otel_module.so diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0f328d2..07be30e 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -7,7 +7,7 @@ on: pull_request: jobs: - build-module: + test: runs-on: ubuntu-22.04 steps: - name: Checkout repository From 9400f5a8695e2b5ee6f605f8a665d8e5a92cdc0b Mon Sep 17 00:00:00 2001 From: daroche <94007359+daroche@users.noreply.github.com> Date: Tue, 5 Aug 2025 19:07:59 +0200 Subject: [PATCH 09/10] hacks to build on nix --- config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config b/config index 2f1da1e..0e5dbc7 100644 --- a/config +++ b/config @@ -179,7 +179,7 @@ if [ $ngx_found = no ]; then fi if [ $ngx_found = yes ]; then - ngx_module_libs="$ngx_module_libs -lopentelemetry_common -lopentelemetry_resources -lopentelemetry_trace" + ngx_module_libs="$ngx_module_libs -lopentelemetry_common -lopentelemetry_resources -lopentelemetry_trace $(pkg-config --libs absl_log absl_log_internal_check_op absl_cord absl_log_initialize) -lstdc++" fi #if [ ! -d $prefix/include/opentelemetry/proto ]; then From a6678297623e948a8d95bdfb4e8aea5a2189f4e3 Mon Sep 17 00:00:00 2001 From: daroche <94007359+daroche@users.noreply.github.com> Date: Fri, 8 Aug 2025 21:54:47 +0200 Subject: [PATCH 10/10] add span schema information --- src/batch_exporter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/batch_exporter.hpp b/src/batch_exporter.hpp index a2e65b1..bc889fa 100644 --- a/src/batch_exporter.hpp +++ b/src/batch_exporter.hpp @@ -128,6 +128,7 @@ public: } auto scopeSpans = resourceSpans->add_scope_spans(); + scopeSpans->set_schema_url("https://opentelemetry.io/schemas/1.16.0"); scopeSpans->mutable_scope()->set_name("nginx"); scopeSpans->mutable_scope()->set_version(NGINX_VERSION);