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
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ VCPKG="66c0373dc7fca549e5803087b9487edfe3aca0a1" # 2026.01.16 Release
# ci/docker/python-*-windows-*.dockerfile or the vcpkg config.
# This is a workaround for our CI problem that "archery docker build" doesn't
# use pulled built images in dev/tasks/python-wheels/github.windows.yml.
PYTHON_WHEEL_WINDOWS_IMAGE_REVISION=2026-02-07
PYTHON_WHEEL_WINDOWS_TEST_IMAGE_REVISION=2026-02-07
PYTHON_WHEEL_WINDOWS_IMAGE_REVISION=2026-02-25
PYTHON_WHEEL_WINDOWS_TEST_IMAGE_REVISION=2026-02-25

# Use conanio/${CONAN_BASE}:{CONAN_VERSION} for "docker compose run --rm conan".
# See https://github.com/conan-io/conan-docker-tools#readme and
Expand Down
1 change: 1 addition & 0 deletions ci/docker/python-wheel-manylinux.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ RUN --mount=type=secret,id=github_repository_owner \
--x-feature=flight \
--x-feature=gcs \
--x-feature=json \
--x-feature=opentelemetry \
--x-feature=orc \
--x-feature=parquet \
--x-feature=s3 && \
Expand Down
1 change: 1 addition & 0 deletions ci/docker/python-wheel-musllinux.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ RUN --mount=type=secret,id=github_repository_owner \
--x-feature=flight \
--x-feature=gcs \
--x-feature=json \
--x-feature=opentelemetry \
--x-feature=orc \
--x-feature=parquet \
--x-feature=s3 && \
Expand Down
1 change: 1 addition & 0 deletions ci/docker/python-wheel-windows-vs2022-base.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ RUN vcpkg install `
--x-feature=flight `
--x-feature=gcs `
--x-feature=json `
--x-feature=opentelemetry `
--x-feature=orc `
--x-feature=parquet `
--x-feature=s3
2 changes: 2 additions & 0 deletions ci/scripts/python_wheel_macos_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ echo "=== (${PYTHON_VERSION}) Building Arrow C++ libraries ==="
: ${ARROW_WITH_BROTLI:=ON}
: ${ARROW_WITH_BZ2:=ON}
: ${ARROW_WITH_LZ4:=ON}
: ${ARROW_WITH_OPENTELEMETRY:=ON}
: ${ARROW_WITH_SNAPPY:=ON}
: ${ARROW_WITH_ZLIB:=ON}
: ${ARROW_WITH_ZSTD:=ON}
Expand Down Expand Up @@ -125,6 +126,7 @@ cmake \
-DARROW_WITH_BROTLI=${ARROW_WITH_BROTLI} \
-DARROW_WITH_BZ2=${ARROW_WITH_BZ2} \
-DARROW_WITH_LZ4=${ARROW_WITH_LZ4} \
-DARROW_WITH_OPENTELEMETRY=${ARROW_WITH_OPENTELEMETRY} \
-DARROW_WITH_SNAPPY=${ARROW_WITH_SNAPPY} \
-DARROW_WITH_ZLIB=${ARROW_WITH_ZLIB} \
-DARROW_WITH_ZSTD=${ARROW_WITH_ZSTD} \
Expand Down
2 changes: 2 additions & 0 deletions ci/scripts/python_wheel_windows_build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ set ARROW_TENSORFLOW=ON
set ARROW_WITH_BROTLI=ON
set ARROW_WITH_BZ2=ON
set ARROW_WITH_LZ4=ON
set ARROW_WITH_OPENTELEMETRY=ON
set ARROW_WITH_SNAPPY=ON
set ARROW_WITH_ZLIB=ON
set ARROW_WITH_ZSTD=ON
Expand Down Expand Up @@ -94,6 +95,7 @@ cmake ^
-DARROW_WITH_BROTLI=%ARROW_WITH_BROTLI% ^
-DARROW_WITH_BZ2=%ARROW_WITH_BZ2% ^
-DARROW_WITH_LZ4=%ARROW_WITH_LZ4% ^
-DARROW_WITH_OPENTELEMETRY=%ARROW_WITH_OPENTELEMETRY% ^
-DARROW_WITH_SNAPPY=%ARROW_WITH_SNAPPY% ^
-DARROW_WITH_ZLIB=%ARROW_WITH_ZLIB% ^
-DARROW_WITH_ZSTD=%ARROW_WITH_ZSTD% ^
Expand Down
10 changes: 9 additions & 1 deletion ci/scripts/python_wheel_xlinux_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ function check_arrow_visibility {
# Filter out Arrow symbols and see if anything remains.
# '_init' and '_fini' symbols may or not be present, we don't care.
# (note we must ignore the grep exit status when no match is found)
grep ' T ' nm_arrow.log | grep -v -E '(arrow|\b_init\b|\b_fini\b)' | cat - > visible_symbols.log
local allowed_symbols='(arrow|\b_init\b|\b_fini\b)'
# OpenTelemetry symbols are intentionally exported for features like
# automatic span linking. See cpp/src/arrow/symbols.map for more details.
if [[ "${ARROW_WITH_OPENTELEMETRY:-OFF}" == "ON" ]]; then
allowed_symbols="${allowed_symbols}|(opentelemetry)"
fi
grep ' T ' nm_arrow.log | grep -v -E "${allowed_symbols}" | cat - > visible_symbols.log

if [[ -f visible_symbols.log && `cat visible_symbols.log | wc -l` -eq 0 ]]; then
return 0
Expand Down Expand Up @@ -65,6 +71,7 @@ echo "=== (${PYTHON_VERSION}) Building Arrow C++ libraries ==="
: ${ARROW_WITH_BROTLI:=ON}
: ${ARROW_WITH_BZ2:=ON}
: ${ARROW_WITH_LZ4:=ON}
: ${ARROW_WITH_OPENTELEMETRY:=ON}
: ${ARROW_WITH_SNAPPY:=ON}
: ${ARROW_WITH_ZLIB:=ON}
: ${ARROW_WITH_ZSTD:=ON}
Expand Down Expand Up @@ -124,6 +131,7 @@ cmake \
-DARROW_WITH_BROTLI=${ARROW_WITH_BROTLI} \
-DARROW_WITH_BZ2=${ARROW_WITH_BZ2} \
-DARROW_WITH_LZ4=${ARROW_WITH_LZ4} \
-DARROW_WITH_OPENTELEMETRY=${ARROW_WITH_OPENTELEMETRY} \
-DARROW_WITH_SNAPPY=${ARROW_WITH_SNAPPY} \
-DARROW_WITH_ZLIB=${ARROW_WITH_ZLIB} \
-DARROW_WITH_ZSTD=${ARROW_WITH_ZSTD} \
Expand Down
11 changes: 11 additions & 0 deletions ci/vcpkg/vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@
]
}
]
},
"opentelemetry": {
"description": "OpenTelemetry support",
"dependencies": [
{
"name": "opentelemetry-cpp",
"features": [
"otlp-http"
]
}
]
}
}
}
2 changes: 1 addition & 1 deletion cpp/src/arrow/flight/server_tracing_middleware.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class TracingServerMiddlewareFactory : public ServerMiddlewareFactory {
options.kind = otel::trace::SpanKind::kServer;
options.parent = otel::trace::GetSpan(new_otel_context)->GetContext();

auto tracer = otel::trace::Provider::GetTracerProvider()->GetTracer("arrow");
auto tracer = arrow::internal::tracing::GetTracer();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lidavidm I am not entirely sure why this is necessary but using the example middleware.py enabling otel as updated below with a running server:

$ export OTEL_SERVICE_NAME=arrow-raul
$ ARROW_TRACING_BACKEND=otlp_http python examples/flight/middleware.py server --listen grpc://localhost:5050 --otel

and client:

python examples/flight/middleware.py  client grpc://localhost:5050

I wasn't able to get traces unless I update this to use arrow::internal::tracing::GetTracer. Example of local traces with the built wheel and this changes:

Image

Initially I thought it might be due to the addition of CMAKE_INTERPROCEDURAL_OPTIMIZATION to the wheels but I've validated is unrelated.

Without this change I haven't been able to get opentelemetry traces using the flight.TracingServerMiddlewareFactory

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it's been a while since I've worked with OTel...possibly the OTel trace provider isn't being configured (vs the hardcoded Arrow one)? The Arrow util is about equivalent, but does some static initialization first

Copy link
Member Author

@raulcd raulcd Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, that was my feeling too, either not being initialized or something to do with libarrow.so and libarrow_flight.so both linking opentelementry statically and getting their own copy of the static opentelemetry provider that's why I thought CMAKE_INTERPROCEDUREAL_OPTIMIZATION might be related (but proved it wasn't).
The Arrow util one should cross the shared object boundary and use the already initialized one (or initialize it) which I think is correct.
I just wanted to validate the change looks ok to you or whether do you think it would be better to keep investigating and try to configure when calling MakeTracingServerMiddlewareFactory instead of using the one initialized via libarrow.so?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is OK.

auto method_name = ToString(info.method);
auto span = tracer->StartSpan(
method_name,
Expand Down
10 changes: 6 additions & 4 deletions cpp/src/arrow/util/tracing_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "arrow/util/config.h"

#ifdef ARROW_WITH_OPENTELEMETRY
// Avoid for example defining max() macro
# include "arrow/util/windows_compatibility.h"
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4522)
Expand Down Expand Up @@ -123,13 +125,13 @@ struct Scope {
opentelemetry::trace::Scope scope_impl;
};

opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span>& UnwrapSpan(
ARROW_EXPORT opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span>& UnwrapSpan(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These symbols seem to be required to be exported for Windows:

2026-02-25T17:46:03.6802906Z   
2026-02-25T17:46:03.6803059Z   Finished searching libraries
2026-02-25T17:46:03.6813183Z unity_3_cxx.obj : error LNK2001: unresolved external symbol "class opentelemetry::v1::nostd::shared_ptr<class opentelemetry::v1::trace::Span> & __cdecl arrow::internal::tracing::RewrapSpan(class arrow::util::tracing::SpanDetails *,class opentelemetry::v1::nostd::shared_ptr<class opentelemetry::v1::trace::Span>)" (?RewrapSpan@tracing@internal@arrow@@YAAEAV?$shared_ptr@VSpan@trace@v1@opentelemetry@@@nostd@v1@opentelemetry@@PEAVSpanDetails@1util@3@V4567@@Z) [C:\arrow-build\src\arrow\acero\arrow_acero_shared.vcxproj]
2026-02-25T17:46:03.6817761Z unity_2_cxx.obj : error LNK2001: unresolved external symbol "class opentelemetry::v1::nostd::shared_ptr<class opentelemetry::v1::trace::Span> & __cdecl arrow::internal::tracing::UnwrapSpan(class arrow::util::tracing::SpanDetails *)" (?UnwrapSpan@tracing@internal@arrow@@YAAEAV?$shared_ptr@VSpan@trace@v1@opentelemetry@@@nostd@v1@opentelemetry@@PEAVSpanDetails@1util@3@@Z) [C:\arrow-build\src\arrow\acero\arrow_acero_shared.vcxproj]
2026-02-25T17:46:03.6820710Z C:\arrow-build\release\Release\arrow_acero.dll : fatal error LNK1120: 2 unresolved externals [C:\arrow-build\src\arrow\acero\arrow_acero_shared.vcxproj]

::arrow::util::tracing::SpanDetails* span);

const opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span>& UnwrapSpan(
const ::arrow::util::tracing::SpanDetails* span);
ARROW_EXPORT const opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span>&
UnwrapSpan(const ::arrow::util::tracing::SpanDetails* span);

opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span>& RewrapSpan(
ARROW_EXPORT opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span>& RewrapSpan(
::arrow::util::tracing::SpanDetails* span,
opentelemetry::nostd::shared_ptr<opentelemetry::trace::Span> ot_span);

Expand Down
1 change: 1 addition & 0 deletions dev/tasks/python-wheels/github.osx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ jobs:
--x-feature=flight \
--x-feature=gcs \
--x-feature=json \
--x-feature=opentelemetry \
--x-feature=orc \
--x-feature=parquet \
--x-feature=s3
Expand Down
10 changes: 9 additions & 1 deletion python/examples/flight/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,25 @@ def main():
"simply call the given server for the response. Demonstrates "
"propagation of the trace ID between servers."),
)
server.add_argument(
"--otel",
action="store_true",
help="Use OpenTelemetry instrumentation."
)

args = parser.parse_args()
if not getattr(args, "command"):
parser.print_help()
return 1

if args.command == "server":
middleware = {"trace": TracingServerMiddlewareFactory()}
if args.otel:
middleware["otel"] = flight.TracingServerMiddlewareFactory()
server = FlightServer(
args.delegate,
location=args.listen,
middleware={"trace": TracingServerMiddlewareFactory()})
middleware=middleware)
server.serve()
elif args.command == "client":
client = flight.connect(
Expand Down
3 changes: 2 additions & 1 deletion python/pyarrow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def parse_git(root, **kwargs):
MonthDayNano, VersionInfo, build_info, cpp_build_info,
cpp_version, cpp_version_info, runtime_info,
cpu_count, set_cpu_count, enable_signal_handlers,
io_thread_count, set_io_thread_count)
io_thread_count, is_opentelemetry_enabled, set_io_thread_count)


def show_versions():
Expand Down Expand Up @@ -135,6 +135,7 @@ def print_entry(label, value):
for module in modules:
status = "Enabled" if _module_is_available(module) else "-"
print(f" {module: <20}: {status: <8}")
print(f" {'opentelemetry': <20}: {'Enabled' if is_opentelemetry_enabled() else '-': <8}")

print("\nFilesystems:")
filesystems = ["AzureFileSystem", "GcsFileSystem",
Expand Down
7 changes: 4 additions & 3 deletions python/pyarrow/includes/libarrow_python.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,12 @@ cdef extern from "arrow/python/benchmark.h" namespace "arrow::py::benchmark":
cdef extern from "arrow/python/gdb.h" namespace "arrow::gdb" nogil:
void GdbTestSession "arrow::gdb::TestSession"()

cdef extern from "arrow/python/helpers.h" namespace "arrow::py::internal":
c_bool IsThreadingEnabled()

cdef extern from "arrow/python/config.h" namespace "arrow::py":
cdef cppclass CBuildInfo "arrow::py::BuildInfo":
c_string build_type

const CBuildInfo& GetBuildInfo "arrow::py::GetBuildInfo"()

cdef extern from "arrow/python/config.h" namespace "arrow::py::internal":
c_bool IsOpenTelemetryEnabled()
c_bool IsThreadingEnabled()
7 changes: 7 additions & 0 deletions python/pyarrow/lib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ def set_cpu_count(int count):
check_status(SetCpuThreadPoolCapacity(count))


def is_opentelemetry_enabled() -> bool:
"""
Returns True if OpenTelemetry is enabled in libarrow.
"""
return libarrow_python.IsOpenTelemetryEnabled()


def is_threading_enabled() -> bool:
"""
Returns True if threading is enabled in libarrow.
Expand Down
22 changes: 22 additions & 0 deletions python/pyarrow/src/arrow/python/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "arrow/python/config.h"
#include "arrow/python/config_internal.h"

#include "arrow/util/config.h"

namespace arrow {
namespace py {

Expand All @@ -29,6 +31,26 @@ const BuildInfo kBuildInfo = {

} // namespace

namespace internal {

bool IsOpenTelemetryEnabled() {
#ifdef ARROW_WITH_OPENTELEMETRY
return true;
#else
return false;
#endif
}

bool IsThreadingEnabled() {
#ifdef ARROW_ENABLE_THREADING
return true;
#else
return false;
#endif
}

} // namespace internal

const BuildInfo& GetBuildInfo() { return kBuildInfo; }

} // namespace py
Expand Down
11 changes: 10 additions & 1 deletion python/pyarrow/src/arrow/python/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,14 @@ struct BuildInfo {
ARROW_PYTHON_EXPORT
const BuildInfo& GetBuildInfo();

namespace internal {

ARROW_PYTHON_EXPORT
bool IsOpenTelemetryEnabled();

ARROW_PYTHON_EXPORT
bool IsThreadingEnabled();

} // namespace internal
} // namespace py
} // namespace arrow
} // namespace arrow
9 changes: 0 additions & 9 deletions python/pyarrow/src/arrow/python/helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
#include "arrow/python/decimal.h"
#include "arrow/type_fwd.h"
#include "arrow/util/checked_cast.h"
#include "arrow/util/config.h"
#include "arrow/util/float16.h"
#include "arrow/util/logging.h"

Expand Down Expand Up @@ -491,14 +490,6 @@ void DebugPrint(PyObject* obj) {
PySys_WriteStderr("%s\n", repr.c_str());
}

bool IsThreadingEnabled() {
#ifdef ARROW_ENABLE_THREADING
return true;
#else
return false;
#endif
}

} // namespace internal
} // namespace py
} // namespace arrow
3 changes: 0 additions & 3 deletions python/pyarrow/src/arrow/python/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,6 @@ Status IntegerScalarToFloat32Safe(PyObject* obj, float* result);
// \brief Print Python object __repr__
void DebugPrint(PyObject* obj);

ARROW_PYTHON_EXPORT
bool IsThreadingEnabled();

} // namespace internal
} // namespace py
} // namespace arrow
33 changes: 32 additions & 1 deletion python/pyarrow/tests/test_flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import pathlib
import signal
import struct
import subprocess
import sys
import tempfile
import threading
import time
Expand All @@ -36,7 +38,7 @@
import pytest
import pyarrow as pa

from pyarrow.lib import IpcReadOptions, ReadStats, tobytes
from pyarrow.lib import IpcReadOptions, ReadStats, is_opentelemetry_enabled, tobytes
from pyarrow.util import find_free_port
from pyarrow.tests import util

Expand Down Expand Up @@ -2644,6 +2646,35 @@ def test_tracing():
pass


def test_tracing_server_middleware_emits_traces():
# Validate that we are able to emit traces to stdout when
# ARROW_TRACING_BACKEND=ostream
if not is_opentelemetry_enabled():
pytest.skip("Arrow not built with OpenTelemetry")
code = """if 1:
import pyarrow.flight as flight
from pyarrow.flight import FlightServerBase, FlightClient

class SimpleServer(FlightServerBase):
def do_action(self, context, action):
return []

with SimpleServer(
middleware={"otel": flight.TracingServerMiddlewareFactory()}
) as server:
with FlightClient(('localhost', server.port)) as client:
list(client.do_action((b"", b"")))
"""
env = os.environ.copy()
env['ARROW_TRACING_BACKEND'] = "ostream"
env['OTEL_SERVICE_NAME'] = "pyarrow-testing-service"
res = subprocess.run([sys.executable, "-c", code], env=env,
capture_output=True)
assert res.returncode == 0, res.stderr
msg = "Expected service name in trace output"
assert b"service.name: pyarrow-testing-service" in res.stdout, msg


def test_do_put_does_not_crash_when_schema_is_none():
client = FlightClient('grpc+tls://localhost:9643',
disable_server_verification=True)
Expand Down
Loading