diff --git a/.gitmodules b/.gitmodules index d578e6c..2d527fe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "third_party/opentelemetry-cpp"] path = third_party/opentelemetry-cpp - url = https://github.com/open-telemetry/opentelemetry-cpp.git + url = https://github.com/ltowarek/opentelemetry-cpp.git [submodule "third_party/abseil-cpp"] path = third_party/abseil-cpp url = https://github.com/abseil/abseil-cpp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ce8616..28264ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,12 +19,10 @@ set(ESP_OPENTELEMETRY_SRCS # NOTE: esp_http_client_transport.cpp is intentionally *not* listed # here. When CONFIG_ESP_OPENTELEMETRY_TRACING_ENABLED is on, it is -# compiled as the sole source of the vendored -# `opentelemetry_http_client_curl` target (see the set_property(... -# SOURCES ...) call below), so it sits on the opentelemetry-cpp side of -# the link graph instead of our component. This keeps the factory free -# functions in the same translation unit opentelemetry-cpp expects them -# in and avoids compiling the file twice. +# compiled into the opentelemetry_http_client_esp STATIC target below +# and PRIVATE-linked into opentelemetry_exporter_otlp_http_client so +# the HttpClientFactory symbols resolve at the right point on the link +# line without being compiled twice. # The opentelemetry-cpp api/ tree is header-only and compiles without the # SDK. Expose it as part of the component's public include path so the @@ -82,82 +80,9 @@ if(CONFIG_ESP_OPENTELEMETRY_TRACING_ENABLED) set(WITH_STL "CXX17" CACHE STRING "" FORCE) set(WITH_OTLP_HTTP_COMPRESSION OFF CACHE BOOL "" FORCE) set(OPENTELEMETRY_INSTALL OFF CACHE BOOL "" FORCE) - - # Advertise a stub libcurl so opentelemetry-cpp's cmake/curl.cmake - # takes the find_package path and skips FetchContent of curl - # itself. curl cannot be cross-compiled to Xtensa cleanly - # (autoprobes for hostent/off_t/recv/send all fail), and we never - # link the curl-based HTTP transport anyway — our custom - # esp_http_client-based HttpClient is installed at runtime. - list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") - - # WITH_OTLP_HTTP=ON unconditionally pulls curl in as the SDK's default - # HttpClient backend. We provide our own esp_http_client-based - # transport via esp_opentelemetry::MakeEspHttpClient(), so nothing - # calls the curl path at runtime — but otel-cpp still drags curl into - # the build graph, and curl's CMake insists on finding a TLS backend - # (OpenSSL by default, which isn't present on the Xtensa sysroot). - # Disable every TLS backend and let curl build without SSL. The - # resulting libcurl is never linked into the final image because - # HttpClientFactory::Create() is only referenced from OtlpHttpClient's - # default constructor, which we never call. - set(CURL_ENABLE_SSL OFF CACHE BOOL "" FORCE) - set(CURL_USE_OPENSSL OFF CACHE BOOL "" FORCE) - set(CURL_USE_MBEDTLS OFF CACHE BOOL "" FORCE) - set(CURL_USE_BEARSSL OFF CACHE BOOL "" FORCE) - set(CURL_USE_WOLFSSL OFF CACHE BOOL "" FORCE) - set(CURL_USE_GNUTLS OFF CACHE BOOL "" FORCE) - set(CURL_USE_NSS OFF CACHE BOOL "" FORCE) - set(CURL_USE_SCHANNEL OFF CACHE BOOL "" FORCE) - set(CURL_USE_SECTRANSP OFF CACHE BOOL "" FORCE) - set(CURL_USE_LIBSSH2 OFF CACHE BOOL "" FORCE) - set(CURL_USE_LIBPSL OFF CACHE BOOL "" FORCE) - set(CURL_ENABLE_EXPORT_TARGET OFF CACHE BOOL "" FORCE) - set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE) - set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE) - set(CURL_DISABLE_NTLM ON CACHE BOOL "" FORCE) - set(USE_NGHTTP2 OFF CACHE BOOL "" FORCE) - set(HTTP_ONLY ON CACHE BOOL "" FORCE) - - # curl's CMake runs check_type_size() for off_t and curl_off_t. - # These probes fail under the Xtensa cross-compile (no standalone - # sysroot to link against), leaving SIZEOF_CURL_OFF_T undefined. - # curl_setup.h then evaluates `#if (SIZEOF_CURL_OFF_T < 8)` as - # `#if (0 < 8)` and errors out. Pre-populate the cache so the - # probes are skipped. ESP-IDF's newlib has 32-bit off_t; curl_off_t - # is always int64_t (8 bytes). - set(SIZEOF_OFF_T 4 CACHE INTERNAL "Size of off_t on Xtensa/newlib") - set(SIZEOF_CURL_OFF_T 8 CACHE INTERNAL "Size of curl_off_t (always int64_t)") - - # curl's CMake runs check_c_source_compiles for recv/send signatures; - # these fail on Xtensa cross-compile. Pre-populate the results so - # curl_setup.h finds HAVE_RECV/HAVE_SEND and defines sread/swrite. - # ESP-IDF's lwIP provides BSD-compatible recv/send signatures. - set(HAVE_RECV 1 CACHE INTERNAL "") - set(RECV_TYPE_ARG1 "int" CACHE INTERNAL "") - set(RECV_TYPE_ARG2 "void *" CACHE INTERNAL "") - set(RECV_TYPE_ARG3 "size_t" CACHE INTERNAL "") - set(RECV_TYPE_ARG4 "int" CACHE INTERNAL "") - set(RECV_TYPE_RETV "ssize_t" CACHE INTERNAL "") - set(HAVE_SEND 1 CACHE INTERNAL "") - set(SEND_TYPE_ARG1 "int" CACHE INTERNAL "") - set(SEND_TYPE_ARG2 "const void *" CACHE INTERNAL "") - set(SEND_TYPE_ARG3 "size_t" CACHE INTERNAL "") - set(SEND_TYPE_ARG4 "int" CACHE INTERNAL "") - set(SEND_TYPE_RETV "ssize_t" CACHE INTERNAL "") - - # ESP-IDF's newlib/lwIP provides ssize_t (typedef int). curl's - # check_type_size("ssize_t") fails on cross-compile, causing it to - # emit `#define ssize_t long` in curl_config.h — which collides - # with lwIP's `typedef int ssize_t`. Pre-populate the result. - set(SIZEOF_SSIZE_T 4 CACHE INTERNAL "sizeof(ssize_t) on Xtensa/newlib") - set(HAVE_SIZEOF_SSIZE_T 1 CACHE INTERNAL "ssize_t exists in ESP-IDF newlib") - - # Similarly pre-populate other type sizes that curl probes. - set(SIZEOF_SIZE_T 4 CACHE INTERNAL "sizeof(size_t) on Xtensa") - set(SIZEOF_LONG 4 CACHE INTERNAL "sizeof(long) on Xtensa") - set(SIZEOF_INT 4 CACHE INTERNAL "sizeof(int) on Xtensa") - set(SIZEOF_TIME_T 4 CACHE INTERNAL "sizeof(time_t) on Xtensa/newlib") + # Skip libcurl entirely; we supply HttpClientFactory via + # opentelemetry_http_client_esp below. + set(WITH_HTTP_CLIENT_CURL OFF CACHE BOOL "" FORCE) # Materialize Abseil + libprotobuf + the synthesized Protobuf package # config *before* opentelemetry-cpp's CMake runs. Without this, the @@ -179,25 +104,19 @@ if(CONFIG_ESP_OPENTELEMETRY_TRACING_ENABLED) _esp_opentelemetry_apply_int_override( ${CMAKE_CURRENT_LIST_DIR}/third_party/opentelemetry-cpp) - # Replace the sources of the stock `opentelemetry_http_client_curl` - # target with our esp_http_client-backed factory. The curl sources - # cannot be cross-compiled (libcurl is a stub), and the public - # OtlpHttpExporter constructor only consumes an OtlpHttpClient - # constructed via HttpClientFactory — so redirecting the factory - # here gives the stock SDK a working transport on ESP-IDF without - # touching any vendored file. - if(TARGET opentelemetry_http_client_curl) - set_property(TARGET opentelemetry_http_client_curl - PROPERTY SOURCES - "${CMAKE_CURRENT_LIST_DIR}/src/integration/esp_http_client_transport.cpp") - # Link against the ESP-IDF component target so all transitive - # include dirs (esp_http_client, esp_event, esp_common, log, - # freertos, lwip, ...) propagate automatically. - target_link_libraries(opentelemetry_http_client_curl PRIVATE - idf::esp_http_client) - target_include_directories(opentelemetry_http_client_curl PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/src/integration") - endif() + # Provide the esp_http_client-backed HttpClientFactory that the OTLP HTTP + # exporter calls through. WITH_HTTP_CLIENT_CURL=OFF leaves the exporter + # without a linked factory; we supply one here via a named STATIC target + # PRIVATE-linked into the exporter so the factory symbols sit in the right + # place on the link line. + add_library(opentelemetry_http_client_esp STATIC + "${CMAKE_CURRENT_LIST_DIR}/src/integration/esp_http_client_transport.cpp") + target_link_libraries(opentelemetry_http_client_esp PRIVATE + idf::esp_http_client opentelemetry_ext opentelemetry_sdk) + target_include_directories(opentelemetry_http_client_esp PRIVATE + "${CMAKE_CURRENT_LIST_DIR}/src/integration") + target_link_libraries(opentelemetry_exporter_otlp_http_client PRIVATE + opentelemetry_http_client_esp) # Target-level .pb.cc files produced by opentelemetry-proto at # configure time use the generated google/protobuf/*.pb.h that diff --git a/README.md b/README.md index 1975af6..f56b6cc 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ The `src/integration/` subtree contains code that is deliberately ESP32-specific | File | What it provides | |------|-----------------| -| `src/integration/esp_http_client_transport.cpp` | `HttpClientFactory` backed by `esp_http_client`, replacing libcurl for the OTLP/HTTP exporter | +| `src/integration/esp_http_client_transport.cpp` | `HttpClientFactory` backed by `esp_http_client`; libcurl is excluded via `WITH_HTTP_CLIENT_CURL=OFF` | | `src/integration/esp_opentelemetry.cpp` | `esp_opentelemetry_setup()` / `esp_opentelemetry_tracer()` — ESP-friendly wiring of exporter, processor, resource, and W3C propagator via Kconfig | ## Tested OTel C++ SDK features diff --git a/cmake/FindCURL.cmake b/cmake/FindCURL.cmake deleted file mode 100644 index aa11ec0..0000000 --- a/cmake/FindCURL.cmake +++ /dev/null @@ -1,24 +0,0 @@ -# Stub FindCURL module for ESP-IDF / Xtensa builds. -# -# opentelemetry-cpp's cmake/curl.cmake requires a CURL::libcurl target -# when WITH_OTLP_HTTP=ON, because the SDK's default HTTP client -# (OtlpHttpClient) is implemented on top of libcurl. We replace that -# transport at runtime with an esp_http_client-based one registered -# through opentelemetry::ext::http::client::HttpClientFactory, so the -# curl code path is never reached — but opentelemetry-cpp still -# resolves the CMake dependency at configure time. -# -# Building real libcurl for Xtensa is possible but expensive and -# fragile (requires shims for struct hostent, off_t probes, TLS -# backend disablement, etc.). Instead we advertise a dummy -# CURL::libcurl that satisfies the CMake dependency. The -# opentelemetry_http_client_curl target's sources are then replaced -# with our esp_http_client-backed transport (see CMakeLists.txt). - -set(CURL_FOUND TRUE) -set(CURL_VERSION "0.0.0-esp-opentelemetry-cpp-stub") -set(CURL_VERSION_STRING "${CURL_VERSION}") - -if(NOT TARGET CURL::libcurl) - add_library(CURL::libcurl INTERFACE IMPORTED GLOBAL) -endif() diff --git a/src/integration/esp_http_client_transport.cpp b/src/integration/esp_http_client_transport.cpp index 5a92125..4002d35 100644 --- a/src/integration/esp_http_client_transport.cpp +++ b/src/integration/esp_http_client_transport.cpp @@ -203,7 +203,7 @@ class EspSession : public http_client::Session, if (uri.empty()) return url_; if (uri.rfind("http://", 0) == 0 || uri.rfind("https://", 0) == 0) return uri; // uri is a relative path; strip any existing path from url_ to get the base - // (mirrors curl transport: host_ = scheme://host:port/) + // uri is relative; strip path from url_ to get scheme://host:port auto scheme_end = url_.find("://"); if (scheme_end == std::string::npos) return url_; auto path_start = url_.find('/', scheme_end + 3); @@ -270,14 +270,13 @@ std::shared_ptr MakeEspHttpClient() { } // namespace esp_opentelemetry -// --- Replace the default opentelemetry-cpp HTTP transport factory ----------- +// --- esp_http_client-backed HttpClientFactory ---------------------------- // -// opentelemetry_http_client_curl ships three free functions that the -// OTLP exporter calls via HttpClientFactory::Create / CreateSync. The -// default implementation uses libcurl. We build the same target from -// this source file instead (see CMakeLists.txt), redirecting the factory -// to our esp_http_client-backed client. This avoids cross-compiling libcurl -// for Xtensa while keeping the opentelemetry-cpp link graph intact. +// Implements GetDefaultHttpClientFactory() so the OTLP HTTP exporter obtains +// an esp_http_client-backed transport. Compiled into opentelemetry_http_client_esp +// (see CMakeLists.txt), which is PRIVATE-linked into +// opentelemetry_exporter_otlp_http_client. WITH_HTTP_CLIENT_CURL=OFF ensures no +// libcurl backend is built; this target is the sole HttpClientFactory provider. #include "opentelemetry/ext/http/client/http_client_factory.h" #include "opentelemetry/sdk/common/thread_instrumentation.h" @@ -287,18 +286,29 @@ namespace ext { namespace http { namespace client { -std::shared_ptr HttpClientFactory::Create() { - return esp_opentelemetry::MakeEspHttpClient(); -} +namespace { -std::shared_ptr HttpClientFactory::Create( - const std::shared_ptr& /*unused*/) { - return esp_opentelemetry::MakeEspHttpClient(); -} +class EspHttpClientFactory : public HttpClientFactory { +public: + std::shared_ptr Create() override { + return esp_opentelemetry::MakeEspHttpClient(); + } + + std::shared_ptr Create( + const std::shared_ptr& /*unused*/) override { + return esp_opentelemetry::MakeEspHttpClient(); + } + + std::shared_ptr CreateSync() override { + return nullptr; // OTLP exporter never calls CreateSync + } +}; + +} // namespace -std::shared_ptr HttpClientFactory::CreateSync() { - // HttpClientSync is unused by the OTLP exporter; return nullptr. - return nullptr; +std::shared_ptr GetDefaultHttpClientFactory() { + static auto instance = std::make_shared(); + return instance; } } // namespace client diff --git a/src/integration/esp_http_client_transport.hpp b/src/integration/esp_http_client_transport.hpp index 0c475b7..3f58671 100644 --- a/src/integration/esp_http_client_transport.hpp +++ b/src/integration/esp_http_client_transport.hpp @@ -1,5 +1,4 @@ // esp_http_client-backed HTTP client for opentelemetry-cpp's OTLP exporter. -// Replaces the default libcurl transport in the firmware image. #pragma once diff --git a/src/integration/esp_opentelemetry.cpp b/src/integration/esp_opentelemetry.cpp index 239c204..685b9e1 100644 --- a/src/integration/esp_opentelemetry.cpp +++ b/src/integration/esp_opentelemetry.cpp @@ -59,7 +59,7 @@ static std::unique_ptr MakeExporter( options.compression = "none"; // HTTP transport is supplied by our esp_http_client-backed // HttpClientFactory (esp_http_client_transport.cpp), - // linked in as the `opentelemetry_http_client_curl` target. + // compiled into the opentelemetry_http_client_esp target. return std::unique_ptr( new otlp_api::OtlpHttpExporter(options)); } diff --git a/third_party/opentelemetry-cpp b/third_party/opentelemetry-cpp index 2d80af1..e308513 160000 --- a/third_party/opentelemetry-cpp +++ b/third_party/opentelemetry-cpp @@ -1 +1 @@ -Subproject commit 2d80af1b1d26e300d9c0f7f51fa360f22c773523 +Subproject commit e30851355e2e4081e1b564978d89020171eb75c3