Git Product home page Git Product logo

nginx-otel's Introduction

NGINX Native OpenTelemetry (OTel) Module

What is OpenTelemetry

OpenTelemetry (OTel) is an observability framework for monitoring, tracing, troubleshooting, and optimizing applications. OTel enables the collection of telemetry data from a deployed application stack.

What is the NGINX Native OTel Module

The ngx_otel_module dynamic module enables NGINX Open Source or NGINX Plus to send telemetry data to an OTel collector. It provides support for W3C trace context propagation, OpenTelemetry Protocol (OTLP)/gRPC trace exports and offers several benefits over exiting OTel modules, including:

Better Performance

3rd-party OTel implementations reduce performance of request processing by as much as 50% when tracing is enabled. The NGINX Native module limits this impact to approximately 10-15%.

Easy Provisioning

Setup and configuration can be done right in NGINX configuration files.

Dynamic, Variable-Based Control

The ability to control trace parameters dynamically using cookies, tokens, and variables. Please see our Ratio-based Tracing example for more details.

Additionally, NGINX Plus, available as part of a commercial subscription, enables dynamic control of sampling parameters via the NGINX Plus API and key-value store modules.

Installing

Prebuilt packages of the module are available for easy installation. Follow these steps to install NGINX Open Source with the OTel module. See list of compatible operating systems.

Adding Package Repositories and Installing NGINX Open Source

Follow the official NGINX Open Source installation steps to set up package repositories for your specific operating system and install NGINX.

Important: To ensure module compatibility, you must use officially distributed NGINX binaries. Compatibility with community distributed binaries, commonly available through various operating system vendors, is not guaranteed.

Installing the OTel Module from Packages

Once remote package repositories have been added and local package records have been updated, you may install the OTel module (nginx-module-otel) for your specific operating system. As an example, run the following commands to install on:

RedHat, RHEL and Derivatives

sudo yum install nginx-module-otel

Debian, Ubuntu and derivatives

sudo apt install nginx-module-otel

Enabling the OTel Module

Following the installation steps above will install the module into /etc/nginx/modules by default. Load the module by adding the following line to the top of the main NGINX configuration file, located at /etc/nginx/nginx.conf.

load_module modules/ngx_otel_module.so;

Configuring the Module

For a complete list of directives, embedded variables, default span attributes and sample configurations, please refer to the ngx_otel_module documentation.

Examples

Use these examples to configure some common use-cases for OTel tracing.

Simple Tracing

This example sends telemetry data for all http requests.

http {
    otel_exporter {
        endpoint localhost:4317;
    }

    otel_trace on;

    server {
        location / {
            proxy_pass http://backend;
        }
    }
}

Parent-based Tracing

In this example, we inherit trace contexts from incoming requests and record spans only if a parent span is sampled. We also propagate trace contexts and sampling decisions to upstream servers.

http {
    server {
        location / {
            otel_trace $otel_parent_sampled;
            otel_trace_context propagate;

            proxy_pass http://backend;
        }
    }
}

Ratio-based Tracing

In this ratio-based example, tracing is configured for a percentage of traffic (in this case 10%):

http {
    # trace 10% of requests
    split_clients $otel_trace_id $ratio_sampler {
        10%     on;
        *       off;
    }

    # or we can trace 10% of user sessions
    split_clients $cookie_sessionid $session_sampler {
        10%     on;
        *       off;
    }

    server {
        location / {
            otel_trace $ratio_sampler;
            otel_trace_context inject;

            proxy_pass http://backend;
        }
    }
}

Collecting and Viewing Traces

There are several methods and available software packages for viewing traces. For a quick start, Jaeger provides an all-in-one container to collect, process and view OTel trace data. Follow these steps to download, install, launch and use Jaeger's OTel services.

Building

Follow these steps to build the ngx_otel_module dynamic module on Ubuntu or Debian based systems:

Install build tools and dependencies.

sudo apt install cmake build-essential libssl-dev zlib1g-dev libpcre3-dev
sudo apt install pkg-config libc-ares-dev libre2-dev # for gRPC

For the next step, you will need the configure script that is packaged with the NGINX source code. There are several methods for obtaining NGINX sources. You may choose to download them or clone them directly from the NGINX Github repository.

Important: To ensure compatibility, the ngx_otel_module and the NGINX binary that it will be used with, will need to be built using the same NGINX source code and operating system. We will build and install NGINX from obtained sources in a later step. When obtaining NGINX sources from Github, please ensure that you switch to the branch that you intend to use with the module binary. For simplicity, we will assume that the main branch will be used for the remainder of this tutorial.

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.

cd nginx
auto/configure --with-compat

Exit the NGINX directory and clone the ngx_otel_module repository.

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.

cd nginx-otel
mkdir build
cd build
cmake -DNGX_OTEL_NGINX_BUILD_DIR=/path/to/configured/nginx/objs ..
make

Compilation will produce a binary named ngx_otel_module.so.

Installing from Built Binaries

Important: The built ngx_otel_module.so dynamic module binary will ONLY be compatible with the same version of NGINX source code that was used to build it. To guarantee proper operation, you will need to build and install NGINX from sources obtained in previous steps on the same operating system.

Follow instructions related to compiling and installing NGINX. Skip procedures for downloading source code.

By default, this will install NGINX into /usr/local/nginx. The following steps assume this directory structure.

Copy the ngx_otel_module.so dynamic module binary to /usr/local/nginx/modules.

Load the module by adding the following line to the top of the main NGINX configuration file, located at /usr/local/nginx/conf/nginx.conf.

load_module modules/ngx_otel_module.so;

Community

Contributing

Get involved with the project by contributing! Please see our contributing guide for details.

Change Log

See our release page to keep track of updates.

License

Apache License, Version 2.0

© F5, Inc. 2023

nginx-otel's People

Contributors

dependabot[bot] avatar dplotnikov-f5 avatar jimf5 avatar mtbchef avatar ninaforsyth avatar p-pautov avatar route443 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nginx-otel's Issues

Emit two spans (server and client)

Is your feature request related to a problem? Please describe

This module should emit two spans:

  • A server span (the part that receives the external request)
  • A client span which is nested in the server span

This is according to the specification of Open Telemetry. I have this scenaria

  • Frontend (emits client span)
  • Nginx with Otel module as proxy (emits server span, should emit both as described)
  • Backend (emits server span)

The problem now is, that components like Tempo Metrics Generator does not connect the Nginx with the actual backend, because it expects a client->server connection.

Describe the solution you'd like

Emit two spans as describe before

Describe alternatives you've considered

No other alternatives.

How to build the nginx-otel-module using configure with add-dynamic-module

Describe the bug

We build NGINX from source code and add nginx-otel as dynamic module, but the following error is thrown:

adding module in /tmp/nginx/nginx-otel
-- The C compiler identification is GNU 8.5.0
-- The CXX compiler identification is GNU 8.5.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Error at CMakeLists.txt:64 (find_package):
  By not providing "Findopentelemetry-cpp.cmake" in CMAKE_MODULE_PATH this
  project has asked CMake to find a package configuration file provided by
  "opentelemetry-cpp", but CMake did not find one.

  Could not find a package configuration file provided by "opentelemetry-cpp"
  with any of the following names:

    opentelemetry-cppConfig.cmake
    opentelemetry-cpp-config.cmake

  Add the installation prefix of "opentelemetry-cpp" to CMAKE_PREFIX_PATH or
  set "opentelemetry-cpp_DIR" to a directory containing one of the above
  files.  If "opentelemetry-cpp" provides a separate development package or
  SDK, be sure it has been installed.

I don't find it anywhere in the docs that another library should be required to build the module?

The commands we are executing:

# Download Nginx source
wget -nv https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz -O nginx.tar.gz
tar -xzf nginx.tar.gz && mv -f nginx-$NGINX_VERSION nginx

# Download nginx-otel
wget -nv https://github.com/nginxinc/nginx-otel/archive/refs/tags/v$NGINX_OTEL_VERSION.tar.gz -O nginx-otel.tar.gz
mkdir nginx-otel
tar -xzf nginx-otel.tar.gz -C nginx-otel --strip-components 1

cd nginx
# Process configuration to compile Nginx, based on parameters from RHEL:8 nginx version
# (using nginx -V, which returns the arguments for ./configure).
./configure --prefix=/etc/nginx \
    --sbin-path=/usr/local/sbin/nginx \
    --modules-path=modules \
    --conf-path=/etc/nginx/conf/nginx.conf \
    --error-log-path=/dev/stderr \
    --http-log-path=/dev/stdout \
    --http-client-body-temp-path=/var/tmp/nginx/client_body \
    --http-proxy-temp-path=/var/tmp/nginx/proxy \
    --http-fastcgi-temp-path=/var/tmp/nginx/fastcgi \
    --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
    --http-scgi-temp-path=/var/tmp/nginx/scgi \
    --pid-path=/var/run/nginx/nginx.pid \
    --lock-path=/var/run/nginx/nginx.lock \
    --user=nginx \
    --group=nginx \
    --with-file-aio \
    --with-ipv6 \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_auth_request_module \
    --with-http_realip_module \
    --with-stream_ssl_preread_module \
    --with-http_addition_module \
    --with-http_xslt_module=dynamic \
    --with-http_image_filter_module=dynamic \
    --with-http_sub_module \
    --with-http_dav_module \
    --with-http_flv_module \
    --with-http_mp4_module \
    --with-http_gunzip_module \
    --with-http_gzip_static_module \
    --with-http_random_index_module \
    --with-http_secure_link_module \
    --with-http_degradation_module \
    --with-http_slice_module \
    --with-http_stub_status_module \
    --with-http_perl_module=dynamic \
    --with-http_stub_status_module \
    --with-mail=dynamic \
    --with-mail_ssl_module \
    --with-pcre= \
    --with-pcre-jit \
    --with-stream=dynamic \
    --with-stream_ssl_module \
    --with-debug \
    --with-cc-opt="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic" \
    --with-ld-opt="-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E" \
    --with-pcre="${cwd}/pcre2" \
    --with-pcre-opt="-fPIC" \
    --with-zlib="${cwd}/zlib" \
    --with-zlib-opt="-fPIC" \
    --with-openssl="${cwd}/openssl" \
    --with-openssl-opt="enable-ec_nistp_64_gcc_128 enable-tls1_3 no-ssl2 no-ssl3 no-weak-ssl-ciphers -DOPENSSL_NO_HEARTBEATS" \
    --add-dynamic-module="${cwd}/ngx_brotli" \
    --add-dynamic-module="${cwd}/ngx_devel_kit" \
    --add-dynamic-module="${cwd}/set-misc-nginx-module" \
    --add-dynamic-module="${cwd}/nginx-otel"

# Prepared, so make the puppy
make && make install

How to combine Nginx trace spans with backend service call trace spans into a single trace.

Describe the bug

I am trying to make a call to user service from Nginx -> UserService -> Calculator service to perform an addition operation. I am using the docker image: nginx:otel

There are two separate traces coming one for unknown_service:nginx: and another UserRequestService: HTTP GET

unknown_service:nginx: screenshot as below
image

UserRequestService screenshot as below
image

A clear and concise description of what the bug is.
nginx and user service trace span are coming separately, they should comes together.

To reproduce

Steps to reproduce the behavior:

  1. Run below docker-compose
    Docker compose file
    otel-config.yaml file
    nginx.conf file

  2. docker-compose up

  3. call URL from browser "http://localhost:8082/api/UserRequest/add?num1=5&num2=24"

Expected behavior

Nginx trace span should come with User Service span.
E.g.
nginx -> proxy to the backend (User Service) -> Calculator Service

Your environment

  • Version/release of this project or specific commit
  • Target deployment platform

Additional context

Add any other context about the problem here.

I have tried Parent-based Tracing, but it give only User Service -> Calculator Service trace
image

nginx-otel build fails on FreeBSD after `devel/protobuf` update to 24.4

Describe the bug

OTEL module build fails on FreeBSD 13.2 after devel/protobuf update to 24.4

Initially build fails with following error:

/usr/local/poudriere/ports/local/www/nginx-devel/work/nginx-otel-dc52126//src/http_module.cpp:8:10: fatal error: 'google/protobuf/stubs/logging.h' file not found
#include <google/protobuf/stubs/logging.h>
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

A trivial patch with removing the header file shows another error:

cc -c -fPIC -O2 -pipe -fstack-protector-strong -fno-strict-aliasing   --std=c++17 -Wno-missing-field-initializers -Wno-conditional-uninitialized -fPIC -fvisibility=hidden -DHAVE_ABSEIL -Dngx_otel_module_EXPORTS -I src/core  -I src/event  -I src/event/modules  -I src/event/quic  -I src/os/unix  -I /usr/local/include  -I objs  -I src/http  -I src/http/modules  -I src/http/v2  -I src/http/v3  -o objs/addon/src/http_module.o  /usr/local/poudriere/ports/local/www/nginx-devel/work/nginx-otel-dc52126//src/http_module.cpp
/usr/local/poudriere/ports/local/www/nginx-devel/work/nginx-otel-dc52126//src/http_module.cpp:509:43: error: no type named 'LogLevel' in namespace 'google::protobuf'
void protobufLogHandler(google::protobuf::LogLevel logLevel,
                        ~~~~~~~~~~~~~~~~~~^
/usr/local/poudriere/ports/local/www/nginx-devel/work/nginx-otel-dc52126//src/http_module.cpp:514:36: error: use of undeclared identifier 'LOGLEVEL_FATAL'
    ngx_uint_t level = logLevel == LOGLEVEL_FATAL   ? NGX_LOG_EMERG :
                                   ^
/usr/local/poudriere/ports/local/www/nginx-devel/work/nginx-otel-dc52126//src/http_module.cpp:515:36: error: use of undeclared identifier 'LOGLEVEL_ERROR'
                       logLevel == LOGLEVEL_ERROR   ? NGX_LOG_ERR :
                                   ^
/usr/local/poudriere/ports/local/www/nginx-devel/work/nginx-otel-dc52126//src/http_module.cpp:516:36: error: use of undeclared identifier 'LOGLEVEL_WARNING'
                       logLevel == LOGLEVEL_WARNING ? NGX_LOG_WARN :
                                   ^
/usr/local/poudriere/ports/local/www/nginx-devel/work/nginx-otel-dc52126//src/http_module.cpp:544:23: error: no type named 'SetLogHandler' in namespace 'google::protobuf'
    google::protobuf::SetLogHandler(protobufLogHandler);
    ~~~~~~~~~~~~~~~~~~^
5 errors generated.
*** [objs/addon/src/http_module.o] Error code 1

To reproduce

  1. Install FreeBSD
  2. Update ports tree
  3. Try to build www/nginx-devel with OTEL module enabled

Expected behavior

Successful "green" build.

Your environment

FreeBSD 13.2-p7, protobuf version 24.4

Additional context

Add any other context about the problem here.

Enabling/disabling tracing cannot be done after redirect

Describe the bug

When redirecting a request from one location to another, I cannot turn tracing on or off in the "child" location. It can only be turned on/off in the root location. I can set span attributes in the child location, which properly sets the attributes in the span.

It seems that the decision to sample or not is decided before a redirect happens. The problem here is that I could redirect to different child location blocks depending on the request, and I only want tracing for a specific child, not all children.

Note: this also affects otel_trace_context.

To reproduce

When sending requests to /:

The following config will not enable tracing:

      server {
        listen 80;

        location / {
          try_files /dev/null /child;
        }

        location /child {
          otel_trace on;
          otel_span_attr "testkey" "val";
          return 200 "ok";
        }
      }

The following config will enable tracing and set the span attribute:

      server {
        listen 80;

        location / {
          otel_trace on;
          try_files /dev/null /child;
        }

        location /child {
          otel_span_attr "testkey" "val";
          return 200 "ok";
        }
      }

The following config will not disable tracing:

      server {
        listen 80;

        location / {
          otel_trace on;
          try_files /dev/null /child;
        }

        location /child {
          otel_trace off;
          return 200 "ok";
        }
      }

May be somewhat related to #47?

Expected behavior

I want to be able to make a sampling decision on a trace after a redirect happens. In simpler terms, I want to be able to set otel_trace and otel_trace_context in a redirected location. The following config should work.

      server {
        listen 80;

        location / {
          try_files /dev/null /child;
        }

        location /child {
          otel_trace on;
          otel_trace_context propagate;
          return 200 "ok";
        }
      }

The question becomes, is this possible with nginx? Can the trace headers be sent through the parent location to the child location if otel_trace_context is only set on the child?

Your environment

  • nginx 1.27.0
  • NGINX Gateway Fabric 1.3.0

Workaround for NGF specifically

Attempted to dynamically set the tracing settings in the parent location by using an NJS module or map. One problem with this is that otel_trace_context does not accept variable input. The NGINX Gateway Fabric API currently allows users to set this field, so we wouldn't be able to support it going forward using this workaround (we would have to remove it from our API and hardcode a value).

The workaround has also proven a bit messy trying to use maps or modules to properly get the right tracing settings for a particular redirected location, based on the current architecture of the NGF control plane. It still may be possible to find a proper workaround that fits our code design, but it would be much easier if the module worked as desired, allowing NGF to use it directly in a redirected location instead of fumbling around with numerous maps and variables that could add a much larger risk for bugs.

Fails to build from source with GCC 13

Describe the bug

Current code (0da0f15) fails to build from source on GCC 13, e.g. Ubuntu 23.10.

To reproduce

Run the build as documented on Ubuntu 23.10 machine (or any other that has GCC 13).

Additional context

Build log:

root@acb12774a011:~/nginx-otel/build# make
...
[  4%] Linking CXX static library libabsl_random_seed_sequences.a
[  4%] Built target absl_random_seed_sequences
[  4%] Building CXX object _deps/grpc-build/third_party/abseil-cpp/absl/strings/CMakeFiles/absl_str_format_internal.dir/internal/str_format/arg.cc.o
[  4%] Building CXX object _deps/grpc-build/third_party/abseil-cpp/absl/strings/CMakeFiles/absl_str_format_internal.dir/internal/str_format/bind.cc.o
[  5%] Building CXX object _deps/grpc-build/third_party/abseil-cpp/absl/strings/CMakeFiles/absl_str_format_internal.dir/internal/str_format/extension.cc.o
In file included from /root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.cc:16:
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:34:6: warning: elaborated-type-specifier for a scoped enum must not use the 'class' keyword
   34 | enum class FormatConversionChar : uint8_t;
      | ~~~~ ^~~~~
      |      -----
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:34:33: error: found ':' in nested-name-specifier, expected '::'
   34 | enum class FormatConversionChar : uint8_t;
      |                                 ^
      |                                 ::
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:34:12: error: 'FormatConversionChar' has not been declared
   34 | enum class FormatConversionChar : uint8_t;
      |            ^~~~~~~~~~~~~~~~~~~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:35:6: warning: elaborated-type-specifier for a scoped enum must not use the 'class' keyword
   35 | enum class FormatConversionCharSet : uint64_t;
      | ~~~~ ^~~~~
      |      -----
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:35:36: error: found ':' in nested-name-specifier, expected '::'
   35 | enum class FormatConversionCharSet : uint64_t;
      |                                    ^
      |                                    ::
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:35:12: error: 'FormatConversionCharSet' has not been declared
   35 | enum class FormatConversionCharSet : uint64_t;
      |            ^~~~~~~~~~~~~~~~~~~~~~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:131:6: warning: elaborated-type-specifier for a scoped enum must not use the 'class' keyword
  131 | enum class Flags : uint8_t {
      | ~~~~ ^~~~~
      |      -----
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:131:18: error: found ':' in nested-name-specifier, expected '::'
  131 | enum class Flags : uint8_t {
      |                  ^
      |                  ::
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:131:12: error: 'Flags' has not been declared
  131 | enum class Flags : uint8_t {
      |            ^~~~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:131:28: error: expected unqualified-id before '{' token
  131 | enum class Flags : uint8_t {
      |                            ^
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:143:11: error: 'Flags' does not name a type
  143 | constexpr Flags operator|(Flags a, Flags b) {
      |           ^~~~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:147:30: error: 'Flags' was not declared in this scope
  147 | constexpr bool FlagsContains(Flags haystack, Flags needle) {
      |                              ^~~~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:147:46: error: 'Flags' was not declared in this scope
  147 | constexpr bool FlagsContains(Flags haystack, Flags needle) {
      |                                              ^~~~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:147:58: error: expression list treated as compound expression in initializer [-fpermissive]
  147 | constexpr bool FlagsContains(Flags haystack, Flags needle) {
      |                                                          ^
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:152:27: error: 'Flags' was not declared in this scope
  152 | std::string FlagsToString(Flags v);
      |                           ^~~~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:154:51: error: 'Flags' has not been declared
  154 | inline std::ostream& operator<<(std::ostream& os, Flags v) {
      |                                                   ^~~~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h: In function 'std::ostream& absl::lts_20211102::str_format_internal::operator<<(std::ostream&, int)':
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:155:29: error: no match for call to '(std::string {aka std::__cxx11::basic_string<char>}) (int&)'
  155 |   return os << FlagsToString(v);
      |                ~~~~~~~~~~~~~^~~
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h: At global scope:
/root/nginx-otel/build/_deps/grpc-src/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h:187:8: warning: elaborated-type-specifier for a scoped enum must not use the 'class' keyword
  187 |   enum class Enum : uint8_t {
      |   ~~~~ ^~~~~
      |        -----
...

How to build the nginx-otel module on a RHEL / CentOS based system

Describe the bug

I am trying to build the nginx-otel module by first building nginx from source with ./configure --with-compat and then executing the commands in the README.md, but they fail because a lot of the packages mentioned are not available:

Error: Unable to find a match: build-essential libssl-dev zlib1g-dev libpcre3-dev libc-ares-dev libre2-dev

Is there a guide somewhere on how to build this for CentOS based servers?

Ability to statically build the module

Maybe I'm doing my build wrong but I can't build an nginx with otel module statically linked in.
It would be nice if the build chain can support this mode too (addon).

Regards

Add client spans around calls to upstream

Is your feature request related to a problem? Please describe

Services usually have a server span upon request entry and client span (span.kind = client) around calls to upstream.

This helps with a few things:

  1. You can diagnose whether time is being spent or errors in the service itself or its upstreams.
  2. Tracing products use this information for useful visualisations e.g. "inferred services" for services that haven't adopted tracing it still shows up as a dependency.

Describe the solution you'd like

  1. Output a new span on each calls to upstream
  2. Allow adding attributes/baggage only to that client span

Describe alternatives you've considered

Putting a proxy between nginx and its upstreams.

Unable to install on Docker nginx image

Describe the bug

Cannot install this module into the official Docker nginx images.
Have tried both nginxinc/nginx-unprivileged:1.25.3 and nginx:1.25.3
Receive error message Unable to locate package nginx-module-otel when trying to build the Docker container, as shown below.

 > [gateway 2/9] RUN apt update && apt install nginx-module-otel:
0.831
0.831 WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
0.831
1.185 Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]
1.330 Get:2 http://deb.debian.org/debian bookworm-updates InRelease [52.1 kB]
1.524 Get:3 http://deb.debian.org/debian-security bookworm-security InRelease [48.0 kB]
1.911 Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8787 kB]
5.141 Get:5 http://deb.debian.org/debian bookworm-updates/main amd64 Packages [12.7 kB]
5.345 Get:6 http://deb.debian.org/debian-security bookworm-security/main amd64 Packages [134 kB]
10.69 Fetched 9185 kB in 10s (949 kB/s)
10.69 Reading package lists...
14.53 Building dependency tree...
16.01 Reading state information...
16.18 All packages are up to date.
16.23
16.23 WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
16.23
16.24 Reading package lists...
20.54 Building dependency tree...
21.51 Reading state information...
21.56 E: Unable to locate package nginx-module-otel

To reproduce

Steps to reproduce the behavior:
Try to install this otel module in an official nginx Docker container using the most basic Dockerfile.

Dockerfile:

FROM nginx:1.25.3

RUN apt update \
&& apt install nginx-module-otel

CMD sh -c 'nginx -g "daemon off;"'

docker-compose up -d gateway --build

Expected behavior

I expect the module to install.

Your environment

nginx official docker image 1.25.3
https://hub.docker.com/layers/library/nginx/1.25.3/images/sha256-161ef4b1bf7effb350a2a9625cb2b59f69d54ec6059a8a155a1438d0439c593c?context=explore

Additional context

Honor OTEL_RESOURCE_ATTRIBUTES environment variable

In my Kubernetes setup every pod gets OTEL_RESOURCE_ATTRIBUTES environment variable set which contains everything needed to troubleshoot/monitor our microservices. Every app instrumented with Open Telemetry automatically picks up these resource attributes. But Nginx does not. As a result, through it emits spans and participated in distributed tracing, it doesn't contain everything.

Describe the solution you'd like

nginx-otel module to honor OTEL_RESOURCE_ATTRIBUTES environment variable and emits them as Resource object.

According to Open Telemetry spec, all producers must honor this environment variable.

Describe alternatives you've considered

The closest - with otel_span_attr it is potentially possible to inject needed information as span attribute. But this still will not be resource attribute and as a result not aligned with the rest of applications. This also will require nginx.conf changes every time we decide to add something to OTEL_RESOURCE_ATTRIBUTES.

Add opentelemetry_ignore_paths directive to the module

Is your feature request related to a problem? Please describe

I would like to exclude certain paths from creating spans. These calls are made to nginx internally using the vts module, and do not have strict location blocks for these paths:

/{status_uri}/format/json
/{status_uri}/control?cmd=status&...

Describe the solution you'd like

Implement the opentelemetry_ignore_paths directive as supported by the upstream otel_ngx module

Describe alternatives you've considered

Because the calls mentioned above do not have strict location blocks, I cannot use the otel_trace off; option to suppress span creation.

Additional context

I'm happy to use other alternatives as suggested by the team if they exist.

Unable to install OpenTelemetry module package

Unable to locate package nginx-plus-module-otel

I have followed the step to Install the OpenTelemetry module package by referring document
https://docs.nginx.com/nginx/admin-guide/dynamic-modules/opentelemetry/

and getting error as below
image

To reproduce

Steps to reproduce the behavior:

  1. I have run the Nginx latest image in docker using console.
docker run -it --rm -d -p 8080:80 --name web nginx

image

  1. Get into the container and trying to Install the OpenTelemetry module package.
apt-get install nginx-plus-module-otel

Expected behavior

OpenTelemetry module package should be install successfully.

error: ‘struct ngx_table_elt_t’ has no member named ‘next’

Describe the bug

When trying to compile the otel module using the default main git Nginx repo,
almost finishing the compilation I get this error:

[100%] Linking CXX static library libgrpc++.a
[100%] Built target grpc++
[100%] Generating opentelemetry/proto/common/v1/common.pb.cc, opentelemetry/proto/resource/v1/resource.pb.cc, opentelemetry/proto/trace/v1/trace.pb.cc, opentelemetry/proto/collector/trace/v1/trace_service.pb.cc, opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.cc
Scanning dependencies of target ngx_otel_module
[100%] Building C object CMakeFiles/ngx_otel_module.dir/src/modules.c.o
[100%] Building CXX object CMakeFiles/ngx_otel_module.dir/opentelemetry/proto/resource/v1/resource.pb.cc.o
[100%] Building CXX object CMakeFiles/ngx_otel_module.dir/src/http_module.cpp.o
[100%] Building CXX object CMakeFiles/ngx_otel_module.dir/opentelemetry/proto/common/v1/common.pb.cc.o
[100%] Building CXX object CMakeFiles/ngx_otel_module.dir/opentelemetry/proto/trace/v1/trace.pb.cc.o
[100%] Building CXX object CMakeFiles/ngx_otel_module.dir/opentelemetry/proto/collector/trace/v1/trace_service.pb.cc.o
[100%] Building CXX object CMakeFiles/ngx_otel_module.dir/opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.cc.o
/home/linuxmint/vr-nginx-otel/nginx-otel/src/http_module.cpp: In function ‘ngx_int_t {anonymous}::setHeader(ngx_http_request_t*, StrView, StrView)’:
/home/linuxmint/vr-nginx-otel/nginx-otel/src/http_module.cpp:254:17: error: ‘struct ngx_table_elt_t’ has no member named ‘next’
  254 |         header->next = NULL;
      |                 ^~~~
make[2]: *** [CMakeFiles/ngx_otel_module.dir/build.make:85: CMakeFiles/ngx_otel_module.dir/src/http_module.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
make[1]: *** [CMakeFiles/Makefile2:1055: CMakeFiles/ngx_otel_module.dir/all] Error 2
make: *** [Makefile:130: all] Error 2

To reproduce

Steps to reproduce the behavior:

#!/bin/bash

# Prepare files
mkdir ~/nginx-otel-github;
cd ~/nginx-otel-github;
git clone https://github.com/nginx/nginx.git
git clone https://github.com/nginxinc/nginx-otel.git && mkdir nginx-otel/build

# Compile
cd nginx && auto/configure --with-compat;
cd ../nginx-otel/build;
cmake -DNGX_OTEL_NGINX_BUILD_DIR=~/nginx-otel-github/nginx/objs ..;
make

Expected behavior

To have a binary named ngx_otel_module.so

Your environment

Here is my distro used

$ cat /etc/lsb-release 
DISTRIB_ID=LinuxMint
DISTRIB_RELEASE=20.3
DISTRIB_CODENAME=una
DISTRIB_DESCRIPTION="Linux Mint 20.3 Una"

$ uname -a
Linux linuxmint203 5.4.0-162-generic #179-Ubuntu SMP Mon Aug 14 08:51:31 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

Here are the dependencies installed

$ sudo apt list cmake build-essential libssl-dev zlib1g-dev libpcre3-dev pkg-config libc-ares-dev libre2-dev
Listing... Done
build-essential/focal-updates,now 12.8ubuntu1.1 amd64 [installed]
build-essential/focal-updates 12.8ubuntu1.1 i386
cmake/focal-updates,now 3.16.3-1ubuntu1.20.04.1 amd64 [installed]
cmake/focal-updates 3.16.3-1ubuntu1.20.04.1 i386
libc-ares-dev/focal-updates,focal-security,now 1.15.0-1ubuntu0.3 amd64 [installed]
libc-ares-dev/focal-updates,focal-security 1.15.0-1ubuntu0.3 i386
libpcre3-dev/focal-updates,focal-security,now 2:8.39-12ubuntu0.1 amd64 [installed]
libpcre3-dev/focal-updates,focal-security 2:8.39-12ubuntu0.1 i386
libre2-dev/focal,now 20200101+dfsg-1build1 amd64 [installed]
libre2-dev/focal 20200101+dfsg-1build1 i386
libssl-dev/focal-updates,focal-security,now 1.1.1f-1ubuntu2.19 amd64 [installed]
libssl-dev/focal-updates,focal-security 1.1.1f-1ubuntu2.19 i386
pkg-config/focal,now 0.29.1-0ubuntu4 amd64 [installed]
pkg-config/focal 0.29.1-0ubuntu4 i386
zlib1g-dev/focal-updates,focal-security,now 1:1.2.11.dfsg-2ubuntu1.5 amd64 [installed]
zlib1g-dev/focal-updates,focal-security 1:1.2.11.dfsg-2ubuntu1.5 i386

Additional context

Just as a note, that I also tried specifically the nginx v1.20.1, but same error, at the same point happen too.

E: Unable to locate package nginx-module-otel

Describe the bug

While configuring the OTel module, I am unable to locate package nginx-module-otel. I tried building the module on Ubuntu system.

To reproduce

Steps to reproduce the behavior:

E: Unable to locate package nginx-module-otel

Expected behavior

This module should be created modules/ngx_otel_module.so

Your environment

NAME="Ubuntu"
VERSION_ID="23.10"
VERSION="23.10 (Mantic Minotaur)"
VERSION_CODENAME=mantic
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=mantic
LOGO=ubuntu-logo

Additional context

Add any other context about the problem here.

Compile errors when building on mac

Describe the bug

I've been trying to build on mac for the past few hours, worked through a few bugs to get further in the script I'll outline below but couldn't get to a green build:

To reproduce

brew install c-ares # only thing I didn't already have it needed

git clone https://github.com/nginx/nginx.git
git clone https://github.com/nginxinc/nginx-otel.git

cd nginx 
auto/configure --with-compat

cd ../nginx-otel
mkdir build && cd build
cmake -DNGX_OTEL_NGINX_BUILD_DIR=$(pwd)/../../nginx/objs ..
make

Error 1 (cmake line)

Targets not yet defined: absl::nullability, absl::prefetch, absl::common_policy_traits, absl::node_slot_policy...

To fix, I added find_package(absl CONFIG REQUIRED) to line 4 of CMakeLists.txt.

Error 2 (make line)

/tmp/nginx-otel/build/_deps/grpc-src/include/grpcpp/impl/codegen/security/auth_context.h:40:19: error: 'iterator<std::input_iterator_tag, const std::pair<grpc::string_ref, grpc::string_ref>>' is deprecated [-Werror,-Wdeprecated-declarations]

To fix, I commented out line 105 in CMakeLists.txt to disable warnings (add_compile_options(-Wall -Wtype-limits -Werror))

Error 3 unsolved (make line)

[100%] Linking CXX shared module ngx_otel_module.so
ld: Undefined symbols:
  _ngx_array_push, referenced from:
      (anonymous namespace)::initModule(ngx_conf_s*) in http_module.cpp.o
      (anonymous namespace)::initModule(ngx_conf_s*) in http_module.cpp.o
      (anonymous namespace)::addSpanAttr(ngx_conf_s*, ngx_command_s*, void*) in http_module.cpp.o
  _ngx_cached_time, referenced from:
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
  _ngx_conf_log_error, referenced from:
      (anonymous namespace)::mergeLocationConf(ngx_conf_s*, void*, void*) in http_module.cpp.o
      (anonymous namespace)::setExporter(ngx_conf_s*, ngx_command_s*, void*) in http_module.cpp.o
      (anonymous namespace)::setExporter(ngx_conf_s*, ngx_command_s*, void*)::$_2::__invoke(ngx_conf_s*, ngx_command_s*, void*) in http_module.cpp.o
  _ngx_conf_parse, referenced from:
      (anonymous namespace)::setExporter(ngx_conf_s*, ngx_command_s*, void*) in http_module.cpp.o
  _ngx_conf_set_enum_slot, referenced from:
      (anonymous namespace)::gCommands in http_module.cpp.o
  _ngx_conf_set_msec_slot, referenced from:
      (anonymous namespace)::gExporterCommands in http_module.cpp.o
  _ngx_conf_set_size_slot, referenced from:
      (anonymous namespace)::gExporterCommands in http_module.cpp.o
      (anonymous namespace)::gExporterCommands in http_module.cpp.o
  _ngx_conf_set_str_slot, referenced from:
      (anonymous namespace)::gCommands in http_module.cpp.o
      (anonymous namespace)::gExporterCommands in http_module.cpp.o
  _ngx_connection_local_sockaddr, referenced from:
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
  _ngx_current_msec, referenced from:
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*) in http_module.cpp.o
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*)::$_3::__invoke(ngx_event_s*) in http_module.cpp.o
  _ngx_cycle, referenced from:
      (anonymous namespace)::grpcLogHandler(gpr_log_func_args*) in http_module.cpp.o
      (anonymous namespace)::protobufLogHandler(google::protobuf::LogLevel, char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&) in http_module.cpp.o
      BatchExporter::sendBatch(opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest&)::'lambda'(opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest, opentelemetry::proto::collector::trace::v1::ExportTraceServiceResponse, grpc::Status)::operator()(opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest, opentelemetry::proto::collector::trace::v1::ExportTraceServiceResponse, grpc::Status) const in http_module.cpp.o
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*)::$_3::__invoke(ngx_event_s*) in http_module.cpp.o
  _ngx_event_timer_rbtree, referenced from:
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*) in http_module.cpp.o
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*) in http_module.cpp.o
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*)::$_3::__invoke(ngx_event_s*) in http_module.cpp.o
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*)::$_3::__invoke(ngx_event_s*) in http_module.cpp.o
  _ngx_hash_find, referenced from:
      (anonymous namespace)::setHeader(ngx_http_request_s*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::string_view) in http_module.cpp.o
  _ngx_hash_key, referenced from:
      (anonymous namespace)::ensureOtelCtx(ngx_http_request_s*) in http_module.cpp.o
      (anonymous namespace)::ensureOtelCtx(ngx_http_request_s*) in http_module.cpp.o
      (anonymous namespace)::setHeader(ngx_http_request_s*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::string_view) in http_module.cpp.o
  _ngx_http_add_variable, referenced from:
      (anonymous namespace)::addVariables(ngx_conf_s*) in http_module.cpp.o
      (anonymous namespace)::addVariables(ngx_conf_s*) in http_module.cpp.o
      (anonymous namespace)::addVariables(ngx_conf_s*) in http_module.cpp.o
      (anonymous namespace)::addVariables(ngx_conf_s*) in http_module.cpp.o
  _ngx_http_compile_complex_value, referenced from:
      (anonymous namespace)::addSpanAttr(ngx_conf_s*, ngx_command_s*, void*) in http_module.cpp.o
  _ngx_http_complex_value, referenced from:
      (anonymous namespace)::onRequestStart(ngx_http_request_s*) in http_module.cpp.o
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
  _ngx_http_core_module, referenced from:
      (anonymous namespace)::initModule(ngx_conf_s*) in http_module.cpp.o
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
      (anonymous namespace)::setHeader(ngx_http_request_s*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::string_view) in http_module.cpp.o
  _ngx_http_module, referenced from:
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*) in http_module.cpp.o
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*)::$_3::__invoke(ngx_event_s*) in http_module.cpp.o
  _ngx_http_set_complex_value_slot, referenced from:
      (anonymous namespace)::gCommands in http_module.cpp.o
      (anonymous namespace)::gCommands in http_module.cpp.o
  _ngx_inet_get_port, referenced from:
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
  _ngx_list_push, referenced from:
      (anonymous namespace)::setHeader(ngx_http_request_s*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::string_view) in http_module.cpp.o
  _ngx_log_error_core, referenced from:
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*) in http_module.cpp.o
      (anonymous namespace)::exitWorkerProcess(ngx_cycle_s*) in http_module.cpp.o
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
      (anonymous namespace)::onRequestEnd(ngx_http_request_s*) in http_module.cpp.o
      (anonymous namespace)::grpcLogHandler(gpr_log_func_args*) in http_module.cpp.o
      (anonymous namespace)::protobufLogHandler(google::protobuf::LogLevel, char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&) in http_module.cpp.o
      BatchExporter::sendBatch(opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest&)::'lambda'(opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest, opentelemetry::proto::collector::trace::v1::ExportTraceServiceResponse, grpc::Status)::operator()(opentelemetry::proto::collector::trace::v1::ExportTraceServiceRequest, opentelemetry::proto::collector::trace::v1::ExportTraceServiceResponse, grpc::Status) const in http_module.cpp.o
      ...
  _ngx_palloc, referenced from:
      (anonymous namespace)::setHeader(ngx_http_request_s*, opentelemetry::v1::nostd::string_view, opentelemetry::v1::nostd::string_view) in http_module.cpp.o
      (anonymous namespace)::addSpanAttr(ngx_conf_s*, ngx_command_s*, void*) in http_module.cpp.o
  _ngx_pcalloc, referenced from:
      (anonymous namespace)::createMainConf(ngx_conf_s*) in http_module.cpp.o
      (anonymous namespace)::createLocationConf(ngx_conf_s*) in http_module.cpp.o
  _ngx_pnalloc, referenced from:
      long (anonymous namespace)::hexIdVar<opentelemetry::v1::trace::TraceId>(ngx_http_request_s*, ngx_variable_value_t*, unsigned long) in http_module.cpp.o
      long (anonymous namespace)::hexIdVar<opentelemetry::v1::trace::SpanId>(ngx_http_request_s*, ngx_variable_value_t*, unsigned long) in http_module.cpp.o
      (anonymous namespace)::onRequestStart(ngx_http_request_s*) in http_module.cpp.o
  _ngx_pool_cleanup_add, referenced from:
      (anonymous namespace)::ensureOtelCtx(ngx_http_request_s*) in http_module.cpp.o
  _ngx_rbtree_delete, referenced from:
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*) in http_module.cpp.o
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*)::$_3::__invoke(ngx_event_s*) in http_module.cpp.o
  _ngx_rbtree_insert, referenced from:
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*) in http_module.cpp.o
      (anonymous namespace)::initWorkerProcess(ngx_cycle_s*)::$_3::__invoke(ngx_event_s*) in http_module.cpp.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [ngx_otel_module.so] Error 1
make[1]: *** [CMakeFiles/ngx_otel_module.dir/all] Error 2
make: *** [all] Error 2

Wasn't able to get passed this one, any ideas?

Expected behavior

Being possible to compile on Mac.

Your environment

  • Version/release of this project or specific commit: aac5678
  • Target deployment platform: Mac M2 Sonama 14.1

Thanks!

Broke nginx

Describe the bug

Sometimes nginx crashed

To reproduce

Steps to reproduce the behavior:

install nginx

nginx -v
nginx version: nginx/1.25.1 (nginx-plus-r30)

install nginx-plus-module-otel
Version: 30+0.1-1~jammy

enable it and tried to send traces to jaeger.
sometimes happened this

/var/log/nginx/error.log-1701637201.gz:2023/12/04 00:03:45 [alert] 3166959#3166959: worker process 2505010 exited on signal 11 (core dumped)
/var/log/nginx/error.log-1701637201.gz:2023/12/04 00:03:46 [alert] 3166959#3166959: worker process 2504758 exited on signal 11 (core dumped)
/var/log/nginx/error.log-1701637201.gz:2023/12/04 00:03:46 [alert] 3166959#3166959: worker process 1643798 exited on signal 11 (core dumped)
/var/log/nginx/error.log-1701637201.gz:2023/12/04 00:03:49 [alert] 3166959#3166959: worker process 2505016 exited on signal 11 (core dumped)
/var/log/nginx/error.log-1701637201.gz:2023/12/04 00:03:49 [alert] 3166959#3166959: worker process 2504822 exited on signal 11 (core dumped)

gdb shows this

Core was generated by `nginx: worker process                   '.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  ngx_list_push (l=0x56350a2eb618) at src/core/ngx_list.c:38
38	src/core/ngx_list.c: No such file or directory.
[Current thread is 1 (Thread 0x7f3842ce0740 (LWP 533524))]
(gdb) bt
#0  ngx_list_push (l=0x56350a2eb618) at src/core/ngx_list.c:38
#1  0x00007f381836cd82 in (anonymous namespace)::setHeader (r=0x56350a2eb5b0, name=..., value=...)
    at ./debian/build-nginx/extra/nginx-otel-0.1/src/http_module.cpp:246
#2  0x00007f381836dc57 in (anonymous namespace)::inject (tc=..., r=0x56350a2eb5b0)
    at ./debian/build-nginx/extra/prebuilt/include/opentelemetry/nostd/string_view.h:39
#3  (anonymous namespace)::onRequestStart (r=0x56350a2eb5b0) at ./debian/build-nginx/extra/nginx-otel-0.1/src/http_module.cpp:341
#4  0x00005634edd48461 in ngx_http_core_rewrite_phase (r=0x56350a2eb5b0, ph=<optimized out>)
    at src/http/ngx_http_core_module.c:1005
#5  0x00005634edd43c1d in ngx_http_core_run_phases (r=0x56350a2eb5b0) at src/http/ngx_http_core_module.c:951
#6  0x00005634edd586cb in ngx_http_process_request_line (rev=0x5634fac59cd0) at src/http/ngx_http_request.c:1343
#7  0x00005634edd24b93 in ngx_epoll_process_events (cycle=<optimized out>, timer=<optimized out>, flags=1)
    at src/event/modules/ngx_epoll_module.c:901
#8  0x00005634edd1b884 in ngx_process_events_and_timers (cycle=cycle@entry=0x5634f4e66fb0) at src/event/ngx_event.c:343
#9  0x00005634edd2100b in ngx_worker_process_cycle (cycle=cycle@entry=0x5634f4e66fb0, data=data@entry=0x2)
    at src/os/unix/ngx_process_cycle.c:751
#10 0x00005634edd181d2 in ngx_spawn_process (cycle=cycle@entry=0x5634f4e66fb0,
    proc=proc@entry=0x5634edd20f70 <ngx_worker_process_cycle>, data=data@entry=0x2,
    name=name@entry=0x5634ede3b9e8 "worker process", respawn=respawn@entry=-4) at src/os/unix/ngx_process.c:199
#11 0x00005634edd18c08 in ngx_start_worker_processes (cycle=cycle@entry=0x5634f4e66fb0, n=10, type=type@entry=-4)
    at src/os/unix/ngx_process_cycle.c:355
#12 0x00005634edd2000a in ngx_master_process_cycle (cycle=0x5634f4e66fb0) at src/os/unix/ngx_process_cycle.c:245
#13 0x00005634edcf1ad9 in main (argc=<optimized out>, argv=<optimized out>) at src/core/nginx.c:384

Expected behavior

A clear and concise description of what you expected to happen.

Your environment

# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.3 LTS"

uname -srvmpio
Linux 5.15.0-79-generic #86-Ubuntu SMP Mon Jul 10 16:07:21 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

Add the option of enabling TLS for sending traces

Is your feature request related to a problem? Please describe

We would like to enforce TLS for sending our traces. But we are not able to do it for nginx traces as nginx-otel does not have any config option to enable it.

Describe the solution you'd like

Beeing able to specify:

  • that we want to send our traces over TLS
  • toggle an insecure mode in order to disable certificate verification

Describe alternatives you've considered

None.

Additional context

None.

Large module size

Describe the bug

I builded module follow by documentation and module have size about 145M
144531296 Nov 8 00:31 ngx_otel_module.so
In Nginx+ repo this module have size about 5.5M.
I know 2 people, that builded it module and thye have similar module size too.

To reproduce

Steps to reproduce the behavior:

build module e.g. https://gitlab.com/burianov/nginx-aio/-/blob/main/Dockerfile.nginx.nginx_otel?ref_type=heads
loook module size

ls -la /usr/local/nginx/modules/
144531296 Nov  8 00:31 ngx_otel_module.so

Expected behavior

Self compiled module size may be similar to Nginx+

Your environment

Ubuntu 22.04.3 LTS (Jammy Jellyfish) in docker 24.0.7
module version fc7e69a
Nginx release-1.25.3

How to change the unknown_service:nginx to nginx_service

Describe the bug

How to set the otel_service_name name; and which section I need to add in nginx configuration?

The documentation did not make it clear where to set this in the nginx configuration.
https://nginx.org/en/docs/ngx_otel_module.html#otel_trace_context

image

To reproduce

Steps to reproduce the behavior:

Run below docker-compose
Docker compose file
otel-config.yaml file
nginx.conf file

docker-compose up

call URL from browser "http://localhost:8082/api/UserRequest/add?num1=5&num2=24"

Expected behavior

In a Jaeger UI nginx service name should be shown as 'nginx_service'

Your environment

  • Version/release of this project or specific commit
  • Target deployment platform

Additional context

Please Provide me sample of otel_service_name name; in nginx.conf

HTTP support OLTP receivers support

Is your feature request related to a problem? Please describe

Looks like currently the module only support sending OTEL data via GRPC OLTP receivers , would be nice to support HTTP as there are many OTEL users which relay in HTTP instead of GRPC due some load balancers.

Describe the solution you'd like

Into the otel_exporter configuration you can set protocol explicitly working with GRPC as default

 otel_exporter {
        endpoint localhost:4317;
        protocol http
    }

Any Guide to move from `opentelemetry-cpp-contrib` to this

Is your feature request related to a problem? Please describe

We are currently using the Open Telemetry Web Module for NGINX and its kind of a pain to deploy, not super maintained etc. In our testing, this is much easier to use/deploy, but it doesn't work with out currently app set.

Describe the solution you'd like

Something to document the main differences/gotchas when migrating.

Describe alternatives you've considered

N/A

Additional context

Basic Example, we have NGINX running in docker, acting as a proxy to a Python Fast API App with uvicorn.

So for the Open Telemetry Web Module you just do something like

load_module /opt/opentelemetry-webserver-sdk/WebServerModule/Nginx/1.24.0/ngx_http_opentelemetry_module.so;

http {
  ...
  include /etc/nginx/conf.d/opentelemetry_module.conf;

  server {
      ...
      proxy_pass http://${APP_HOST}:${APP_PORT};

Where the opentelemetry_module.conf file just sets up where you are tracing too, and service names.

NginxModuleEnabled ON;
NginxModuleOtelSpanExporter otlp;
NginxModuleOtelExporterEndpoint ${COLLECTOR_HOST}:4317;
NginxModuleServiceName ${SERVICE_NAME};
NginxModuleServiceNamespace ${TREX_ENV};
NginxModuleServiceInstanceId ${DEPLOYMENT_ID};
NginxModuleResolveBackends ON;
NginxModuleTraceAsError ${TRACE_ERRORS};

The equivalent setup with nginx-otel is something like

load_module modules/ngx_otel_module.so;
http {
  otel_exporter {
      endpoint ${COLLECTOR_HOST}:4317;
  }

  otel_service_name ${SERVICE_NAME};
  otel_trace on;

  server {
    ...
    location / {
      proxy_pass http://${APP_HOST}:${APP_PORT};

This does work in the sense that I get nginx traces. The problem is they are no longer associated between nginx and the fronting application.

Trace id's

FastAPI - d6547050b9ce70d614328b6e47ea283c
NGINX   - 208243709646b4a141b0436be8c1bee5

Im sure the problem is on my side, but I cant really find documentation on how to tie this together, or move from OTLP Web Module to the nginx-otel module.

Fails to build with Protobuf v22+

Describe the bug

Protobuf v22 has a breaking change in logging that breaks how nginx-otel uses it.
https://github.com/protocolbuffers/protobuf/releases/tag/v22.0

protobuf-dev no longer includes a logging.h, and no longer provides google::protobuf::LogLevel or google::protobuf::SetLogHandler.

Error when building with protobuf v23.4:

/opt/nginx-otel-main/src/http_module.cpp:510:6: error: variable or field 'protobufLogHandler' declared void
  510 | void protobufLogHandler(google::protobuf::LogLevel logLevel,
      |      ^~~~~~~~~~~~~~~~~~
/opt/nginx-otel-main/src/http_module.cpp:510:43: error: 'LogLevel' is not a member of 'google::protobuf'
  510 | void protobufLogHandler(google::protobuf::LogLevel logLevel,
      |                                           ^~~~~~~~
/opt/nginx-otel-main/src/http_module.cpp:511:5: error: expected primary-expression before 'const'
  511 |     const char* filename, int line, const std::string& msg)
      |     ^~~~~
/opt/nginx-otel-main/src/http_module.cpp:511:27: error: expected primary-expression before 'int'
  511 |     const char* filename, int line, const std::string& msg)
      |                           ^~~
/opt/nginx-otel-main/src/http_module.cpp:511:37: error: expected primary-expression before 'const'
  511 |     const char* filename, int line, const std::string& msg)
      |                                     ^~~~~
/opt/nginx-otel-main/src/http_module.cpp: In function 'ngx_int_t {anonymous}::initModule(ngx_conf_t*)':
/opt/nginx-otel-main/src/http_module.cpp:545:23: error: 'SetLogHandler' is not a member of 'google::protobuf'
  545 |     google::protobuf::SetLogHandler(protobufLogHandler);
      |                       ^~~~~~~~~~~~~
/opt/nginx-otel-main/src/http_module.cpp:545:37: error: 'protobufLogHandler' was not declared in this scope
  545 |     google::protobuf::SetLogHandler(protobufLogHandler);
      |                                     ^~~~~~~~~~~~~~~~~~
make[2]: *** [CMakeFiles/ngx_otel_module.dir/build.make:76: CMakeFiles/ngx_otel_module.dir/src/http_module.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/ngx_otel_module.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

Your environment

Building from source with Alpine edge in docker.

FROM docker.io/library/alpine:20230901 as otel-module-builder
# Build nginx OpenTelemetry module
# https://github.com/nginxinc/nginx-otel
WORKDIR /opt

RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && apk update
RUN apk add \
    cmake build-base openssl-dev zlib-dev pcre-dev \
    pkgconfig c-ares-dev re2-dev \
    opentelemetry-cpp-dev grpc-dev protobuf-dev \
    unzip

RUN wget https://github.com/nginx/nginx/archive/refs/tags/release-1.25.2.zip; unzip release-1.25.2.zip; mv nginx-release-1.25.2 nginx
WORKDIR /opt/nginx
RUN auto/configure --with-compat

WORKDIR /opt
RUN wget https://github.com/nginxinc/nginx-otel/archive/refs/heads/main.zip; unzip main.zip
COPY configs/nginx-otel-CMakeLists.txt /opt/nginx-otel-main/CMakeLists.txt
RUN sed -i \
    's!#include <google/protobuf/stubs/logging.h>!#include <google/protobuf/stubs/common.h>!' \
    /opt/nginx-otel-main/src/http_module.cpp # Fix link to old version of protobuf?
WORKDIR /opt/nginx-otel-main/build
RUN cmake -DNGX_OTEL_NGINX_BUILD_DIR=/opt/nginx/objs ..
RUN make -j 8

I overrode CMakeLists manually because building opentelemetry-cpp from source was slow.

# nginx-otel-CMakeLists.txt
cmake_minimum_required(VERSION 3.24.0)
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_FETCH_DEPS ON CACHE BOOL "Download dependencies")
set(NGX_OTEL_PROTO_DIR  "" CACHE PATH "OTel proto files root")

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif()

set(CMAKE_CXX_VISIBILITY_PRESET hidden)

find_package(opentelemetry-cpp REQUIRED)
find_package(protobuf REQUIRED)
find_package(gRPC REQUIRED)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)

add_compile_options(-Wall -Wtype-limits -Werror)

add_library(ngx_otel_module MODULE
    src/http_module.cpp
    src/modules.c)

# avoid 'lib' prefix in binary name
set_target_properties(ngx_otel_module PROPERTIES PREFIX "")

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
    /usr/include/opentelemetry/proto/)

target_link_libraries(ngx_otel_module
    opentelemetry-cpp::trace
    gRPC::grpc++)

Support arbitrary resource attributes

Is your feature request related to a problem? Please describe

Currently the traces that are logged via this module don't have environment metadata which means I cannot filter traces by environment in Elastic APM. e.g. development/test/staging/production

This feature and why it's useful is explained perfectly in this opentelemetry doco

Describe the solution you'd like

Just like we can set otel_service_name as per nginx-otel doco
I'd like to be able to set the environment with a directive called otel_service_environment

Bonus if you include service.node.name and service.version too.

Describe alternatives you've considered

Adding the value using a resource processor within the otel-collector, which works, but isn't right IMO.

[Question] How to add Request/Response body as a Span Attribute in the trace ?

Describe the bug

As the title suggest I am looking for a way to add Request/Response body as a Span Attribute in the trace. Can someone give me an example on how to do so ?

Apologies & Regards

PS: I tried to connect to the Slack channel to ask this question, but I wan't able to. Thus asking the question here.

Possibility to ignore long lasting connections

Is your feature request related to a problem? Please describe

Currently we are struggling with long traces because the client establish a MQTT connection towards the server with nginx in the middle. We would like to filter out these kind of requests and drop creating spans for them since they typically don't end until the client process terminates. In Jaeger it looks like this:
image

Describe the solution you'd like

I would like to be able to configure that for certain URL prefixes I would like the otel-nginx integration to drop generating spans even though the trace itself is marked as sampled. In the .NET SDK for ASP.NET there is a filter method which is possible to use.

Describe alternatives you've considered

The only possible implementation is that when a trace is created and this trace is going to hit the MQTT endpoint, I can mark this as not sampled. The challenge is that this is not possible for our use case.

Additional context

I think that other long lasting connection technologies will encounter the same issue.

CMAKE 3.27 fails to build the module

The cmake version 3.27 and above can't construct a valid build.make file as the path to protobuf::protoc compiler is incorrect. That fails the compilation process.

In case of cmake 3.25 the contents of .../angie/objs/otel/CMakeFiles_ngx_otel_module.dir/build.make is valid and works OK
But in case of cmake 3.27 the protoc compiler path is unexpanded in final build.make file and is stated as protobuf::protoc which causes an error during compilation. File compiler_depend.make is also empty while with cmake 3.25 it contains a lot of data.

To reproduce

Steps to reproduce the behavior:
Make module with Angie 1.4/Nginx and use cmake >3.27 in a toolchain.

Your environment

Yocto 4 (nanbield) with cmake 3.27

Rewrite doesn't generate a trace

Describe the bug

Hi, i have an nginx configurated with some location.

[...]
location /test {
    otel_trace on;
    otel_trace_context propagate;
    index index.html
}

location /api {
    rewrite /api/(.*) /private_api/$1 break;
    otel_trace on;
    otel_trace_context propagate;
    proxy_pass $api;
    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
}
[...]

I also have a rewrite confs :

rewrite ^/api/(.*) /api/$1  break;
rewrite ^/[^/]+(/.*)$ $1 break;
rewrite ^/[^/]+/(api/.*)$ /$1 break;

When i hit /test the trace are succesfully created
But with /client_name/api/... there is no trace.

I think that otel don't want to create a trace because he detect /client_name/api/ and not /api/ after the

Expected behavior

I want a trace for location after the rewrite
(before: /client_name/api/ -> after: /api/)

Your environment

FROM nginxinc/nginx-unprivileged:1.25.4-bookworm

[...]

USER root
RUN apt update
RUN apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring -y
RUN curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
RUN echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" \
    | tee /etc/apt/sources.list.d/nginx.list

RUN apt update
RUN apt install nginx-module-otel -y
USER nginx
EXPOSE 80 443
[...]

### Additional context

Add any other context about the problem here.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.