Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -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
Expand Down
121 changes: 20 additions & 101 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 0 additions & 24 deletions cmake/FindCURL.cmake

This file was deleted.

46 changes: 28 additions & 18 deletions src/integration/esp_http_client_transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -270,14 +270,13 @@ std::shared_ptr<http_client::HttpClient> 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"
Expand All @@ -287,18 +286,29 @@ namespace ext {
namespace http {
namespace client {

std::shared_ptr<HttpClient> HttpClientFactory::Create() {
return esp_opentelemetry::MakeEspHttpClient();
}
namespace {

std::shared_ptr<HttpClient> HttpClientFactory::Create(
const std::shared_ptr<sdk::common::ThreadInstrumentation>& /*unused*/) {
return esp_opentelemetry::MakeEspHttpClient();
}
class EspHttpClientFactory : public HttpClientFactory {
public:
std::shared_ptr<HttpClient> Create() override {
return esp_opentelemetry::MakeEspHttpClient();
}

std::shared_ptr<HttpClient> Create(
const std::shared_ptr<sdk::common::ThreadInstrumentation>& /*unused*/) override {
return esp_opentelemetry::MakeEspHttpClient();
}

std::shared_ptr<HttpClientSync> CreateSync() override {
return nullptr; // OTLP exporter never calls CreateSync
}
};

} // namespace

std::shared_ptr<HttpClientSync> HttpClientFactory::CreateSync() {
// HttpClientSync is unused by the OTLP exporter; return nullptr.
return nullptr;
std::shared_ptr<HttpClientFactory> GetDefaultHttpClientFactory() {
static auto instance = std::make_shared<EspHttpClientFactory>();
return instance;
}

} // namespace client
Expand Down
1 change: 0 additions & 1 deletion src/integration/esp_http_client_transport.hpp
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion src/integration/esp_opentelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static std::unique_ptr<sdk_trace::SpanExporter> 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<sdk_trace::SpanExporter>(
new otlp_api::OtlpHttpExporter(options));
}
Expand Down
2 changes: 1 addition & 1 deletion third_party/opentelemetry-cpp
Submodule opentelemetry-cpp updated 332 files
Loading