|
| 1 | +From ec81148de2a5306b6ee5c98ecbbf2a05ccc2a40f Mon Sep 17 00:00:00 2001 |
| 2 | +From: Ludovic Henry <git@ludovic.dev> |
| 3 | +Date: Wed, 16 Sep 2026 23:32:33 +0200 |
| 4 | +Subject: [PATCH] native: build the OTel thread context only where libdatadog |
| 5 | + supports it |
| 6 | + |
| 7 | +libdatadog's libdd-otel-thread-ctx exists to expose a thread-local |
| 8 | +pointer through the TLSDESC dialect, and its build script hard-fails on |
| 9 | +any Linux architecture other than x86_64/aarch64: |
| 10 | + |
| 11 | + panic!("Unsupported architecture `{}` for otel-thread-ctx on Linux. |
| 12 | + Only x86_64 and aarch64 are currently supported.") |
| 13 | + |
| 14 | +src/native declares it under `cfg(target_os = "linux")`, so the whole |
| 15 | +native crate fails to build on riscv64. Narrow every `target_os = |
| 16 | +"linux"` gate around the feature to the two architectures libdatadog |
| 17 | +actually supports, and let the Python wrapper fall back to its existing |
| 18 | +no-op listener when the two native functions are absent. |
| 19 | + |
| 20 | +Rebased onto 4.15.0: upstream split the single update function into |
| 21 | +update_otel_thread_context_from_context/_from_span, and Cargo.toml's |
| 22 | +linux-only dependency block picked up a third, unconditional `libc` |
| 23 | +dependency (used by process_metrics on every Linux arch), so that |
| 24 | +target block is split in two: `libc` stays unconditional for Linux, |
| 25 | +and only the otel-thread-ctx dependencies move to the narrower |
| 26 | +x86_64/aarch64 block. |
| 27 | + |
| 28 | +The proper fix belongs in libdatadog: RISC-V TLSDESC needs GCC 14, |
| 29 | +binutils 2.42 and glibc 2.40, and the manylinux/runner glibc is 2.39, so |
| 30 | +even a compiling shim would not be resolvable at load time today. |
| 31 | + |
| 32 | +Upstream-Status: To upstream [blocked on riscv64 TLSDESC support in libdatadog's libdd-otel-thread-ctx] |
| 33 | + |
| 34 | +Signed-off-by: Ludovic Henry <git@ludovic.dev> |
| 35 | +--- |
| 36 | + ddtrace/internal/opentelemetry/thread_context.py | 10 +++++++++- |
| 37 | + src/native/Cargo.toml | 4 +++- |
| 38 | + src/native/build.rs | 7 ++++++- |
| 39 | + src/native/lib.rs | 4 ++-- |
| 40 | + src/native/library_config.rs | 4 ++-- |
| 41 | + tests/smoke_test.py | 3 ++- |
| 42 | + 6 files changed, 24 insertions(+), 8 deletions(-) |
| 43 | + |
| 44 | +diff --git a/ddtrace/internal/opentelemetry/thread_context.py b/ddtrace/internal/opentelemetry/thread_context.py |
| 45 | +index 90a76ea..6cd3ffc 100644 |
| 46 | +--- a/ddtrace/internal/opentelemetry/thread_context.py |
| 47 | ++++ b/ddtrace/internal/opentelemetry/thread_context.py |
| 48 | +@@ -23,11 +23,19 @@ _ContextSwitchListener = Callable[[], None] |
| 49 | + _ThreadContextListeners = tuple[_ContextActivationListener, _ContextSwitchListener] |
| 50 | + |
| 51 | + |
| 52 | +-if sys.platform == "linux": |
| 53 | ++try: |
| 54 | + from ddtrace.internal.native._native import detach_otel_thread_context |
| 55 | + from ddtrace.internal.native._native import update_otel_thread_context_from_context |
| 56 | + from ddtrace.internal.native._native import update_otel_thread_context_from_span |
| 57 | + |
| 58 | ++ _native_thread_context = sys.platform == "linux" |
| 59 | ++except ImportError: |
| 60 | ++ # libdatadog only builds the TLSDESC shim behind these functions on |
| 61 | ++ # x86_64 and aarch64, so they are absent on other Linux architectures. |
| 62 | ++ _native_thread_context = False |
| 63 | ++ |
| 64 | ++if _native_thread_context: |
| 65 | ++ |
| 66 | + def register_otel_thread_context_listener(tracer: TracerProtocol) -> Optional[_ThreadContextListeners]: |
| 67 | + if not config._otel_thread_context_enabled: |
| 68 | + return None |
| 69 | +diff --git a/src/native/Cargo.toml b/src/native/Cargo.toml |
| 70 | +index ab753f3..aed615e 100644 |
| 71 | +--- a/src/native/Cargo.toml |
| 72 | ++++ b/src/native/Cargo.toml |
| 73 | +@@ -74,9 +74,11 @@ tracing = { version = "0.1", default-features = false } |
| 74 | + pyo3-ffi = { version = "0.28", optional = true } |
| 75 | + |
| 76 | + [target.'cfg(target_os = "linux")'.dependencies] |
| 77 | ++libc = "0.2" |
| 78 | ++ |
| 79 | ++[target.'cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies] |
| 80 | + libdd-library-config = { git = "https://github.com/DataDog/libdatadog", rev = "v43.0.1", features = ["otel-thread-ctx"]} |
| 81 | + libdd-otel-thread-ctx = { git = "https://github.com/DataDog/libdatadog", rev = "v43.0.1" } |
| 82 | +-libc = "0.2" |
| 83 | + |
| 84 | + [target.'cfg(target_os = "macos")'.dependencies] |
| 85 | + libc = "0.2" |
| 86 | +diff --git a/src/native/build.rs b/src/native/build.rs |
| 87 | +index 7aea389..1aef370 100644 |
| 88 | +--- a/src/native/build.rs |
| 89 | ++++ b/src/native/build.rs |
| 90 | +@@ -64,7 +64,12 @@ fn main() { |
| 91 | + pyo3_build_config::add_extension_module_link_args(); |
| 92 | + } |
| 93 | + |
| 94 | +- if env::var("CARGO_CFG_TARGET_OS").ok().as_deref() == Some("linux") { |
| 95 | ++ if env::var("CARGO_CFG_TARGET_OS").ok().as_deref() == Some("linux") |
| 96 | ++ && matches!( |
| 97 | ++ env::var("CARGO_CFG_TARGET_ARCH").ok().as_deref(), |
| 98 | ++ Some("x86_64") | Some("aarch64") |
| 99 | ++ ) |
| 100 | ++ { |
| 101 | + configure_otel_thread_context_export(); |
| 102 | + } |
| 103 | + } |
| 104 | +diff --git a/src/native/lib.rs b/src/native/lib.rs |
| 105 | +index 61cb600..d1a5795 100644 |
| 106 | +--- a/src/native/lib.rs |
| 107 | ++++ b/src/native/lib.rs |
| 108 | +@@ -19,7 +19,7 @@ mod ffe; |
| 109 | + mod http_client; |
| 110 | + mod library_config; |
| 111 | + mod log; |
| 112 | +-#[cfg(target_os = "linux")] |
| 113 | ++#[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "aarch64")))] |
| 114 | + mod otel_thread_ctx; |
| 115 | + mod process_metrics; |
| 116 | + mod py_string; |
| 117 | +@@ -68,7 +68,7 @@ fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> { |
| 118 | + m.add_class::<library_config::PyAnonymousFileHandle>()?; |
| 119 | + m.add_wrapped(wrap_pyfunction!(library_config::store_metadata))?; |
| 120 | + |
| 121 | +- #[cfg(target_os = "linux")] |
| 122 | ++ #[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "aarch64")))] |
| 123 | + { |
| 124 | + m.add_wrapped(wrap_pyfunction!( |
| 125 | + otel_thread_ctx::update_otel_thread_context_from_span |
| 126 | +diff --git a/src/native/library_config.rs b/src/native/library_config.rs |
| 127 | +index 96cd3ae..07019e9 100644 |
| 128 | +--- a/src/native/library_config.rs |
| 129 | ++++ b/src/native/library_config.rs |
| 130 | +@@ -1,4 +1,4 @@ |
| 131 | +-#[cfg(target_os = "linux")] |
| 132 | ++#[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "aarch64")))] |
| 133 | + use libdd_library_config::tracer_metadata::ThreadLocalMetadata; |
| 134 | + use libdd_library_config::{ |
| 135 | + tracer_metadata::{store_tracer_metadata, AnonymousFileHandle, TracerMetadata}, |
| 136 | +@@ -132,7 +132,7 @@ pub fn store_metadata(data: &PyTracerMetadata) -> PyResult<PyAnonymousFileHandle |
| 137 | + service_version: data.service_version.clone(), |
| 138 | + process_tags: data.process_tags.clone(), |
| 139 | + container_id: data.container_id.clone(), |
| 140 | +- #[cfg(target_os = "linux")] |
| 141 | ++ #[cfg(all(target_os = "linux", any(target_arch = "x86_64", target_arch = "aarch64")))] |
| 142 | + threadlocal_metadata: Some(ThreadLocalMetadata { |
| 143 | + attribute_keys: vec![], |
| 144 | + schema_version: None, |
| 145 | +diff --git a/tests/smoke_test.py b/tests/smoke_test.py |
| 146 | +index 0bf60ba..03890f6 100644 |
| 147 | +--- a/tests/smoke_test.py |
| 148 | ++++ b/tests/smoke_test.py |
| 149 | +@@ -82,7 +82,8 @@ if __name__ == "__main__": |
| 150 | + # Skip the test for 32-bit Linux systems |
| 151 | + print("Skipping test, 32-bit DDWAF not ready yet") |
| 152 | + |
| 153 | +- if platform.system() == "Linux": |
| 154 | ++ # libdatadog exports otel_thread_ctx_v1 on x86_64 and aarch64 only. |
| 155 | ++ if platform.system() == "Linux" and platform.machine() in ("x86_64", "aarch64"): |
| 156 | + from ddtrace.internal.native import _native |
| 157 | + |
| 158 | + print("Running OTel thread context symbol smoke test...") |
| 159 | +-- |
| 160 | +2.50.1 (Apple Git-155) |
| 161 | + |
0 commit comments