Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package
python-opentelemetry-exporter-otlp-proto-grpc for openSUSE:Factory checked in
at 2026-03-30 18:30:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing
/work/SRC/openSUSE:Factory/python-opentelemetry-exporter-otlp-proto-grpc (Old)
and
/work/SRC/openSUSE:Factory/.python-opentelemetry-exporter-otlp-proto-grpc.new.1999
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-opentelemetry-exporter-otlp-proto-grpc"
Mon Mar 30 18:30:44 2026 rev:12 rq:1343483 version:1.40.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-opentelemetry-exporter-otlp-proto-grpc/python-opentelemetry-exporter-otlp-proto-grpc.changes
2026-01-06 17:43:48.847738220 +0100
+++
/work/SRC/openSUSE:Factory/.python-opentelemetry-exporter-otlp-proto-grpc.new.1999/python-opentelemetry-exporter-otlp-proto-grpc.changes
2026-03-30 18:33:47.589313891 +0200
@@ -1,0 +2,11 @@
+Mon Mar 23 22:06:45 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 1.40.0:
+ * Fix re-initialization of gRPC channel on UNAVAILABLE error
+ * Allow loading all resource detectors by setting
+ `OTEL_EXPERIMENTAL_RESOURCE_DETECTORS` to `*`
+ * Regenerate opentelemetry-proto code with v1.9.0 release
+ * Add python 3.14 support
+ * Silence events API warnings for internal users
+
+-------------------------------------------------------------------
Old:
----
opentelemetry_exporter_otlp_proto_grpc-1.39.1.tar.gz
New:
----
opentelemetry_exporter_otlp_proto_grpc-1.40.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-opentelemetry-exporter-otlp-proto-grpc.spec ++++++
--- /var/tmp/diff_new_pack.rREylo/_old 2026-03-30 18:33:48.377346836 +0200
+++ /var/tmp/diff_new_pack.rREylo/_new 2026-03-30 18:33:48.381347003 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-opentelemetry-exporter-otlp-proto-grpc
#
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-opentelemetry-exporter-otlp-proto-grpc
-Version: 1.39.1
+Version: 1.40.0
Release: 0
Summary: OpenTelemetry Collector Protobuf over gRPC Exporter
License: Apache-2.0
++++++ opentelemetry_exporter_otlp_proto_grpc-1.39.1.tar.gz ->
opentelemetry_exporter_otlp_proto_grpc-1.40.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/PKG-INFO
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/PKG-INFO
--- old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/PKG-INFO 2020-02-02
01:00:00.000000000 +0100
+++ new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/PKG-INFO 2020-02-02
01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: opentelemetry-exporter-otlp-proto-grpc
-Version: 1.39.1
+Version: 1.40.0
Summary: OpenTelemetry Collector Protobuf over gRPC Exporter
Project-URL: Homepage,
https://github.com/open-telemetry/opentelemetry-python/tree/main/exporter/opentelemetry-exporter-otlp-proto-grpc
Project-URL: Repository, https://github.com/open-telemetry/opentelemetry-python
@@ -18,14 +18,16 @@
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.9
Requires-Dist: googleapis-common-protos~=1.57
Requires-Dist: grpcio<2.0.0,>=1.63.2; python_version < '3.13'
-Requires-Dist: grpcio<2.0.0,>=1.66.2; python_version >= '3.13'
+Requires-Dist: grpcio<2.0.0,>=1.66.2; python_version == '3.13'
+Requires-Dist: grpcio<2.0.0,>=1.75.1; python_version >= '3.14'
Requires-Dist: opentelemetry-api~=1.15
-Requires-Dist: opentelemetry-exporter-otlp-proto-common==1.39.1
-Requires-Dist: opentelemetry-proto==1.39.1
-Requires-Dist: opentelemetry-sdk~=1.39.1
+Requires-Dist: opentelemetry-exporter-otlp-proto-common==1.40.0
+Requires-Dist: opentelemetry-proto==1.40.0
+Requires-Dist: opentelemetry-sdk~=1.40.0
Requires-Dist: typing-extensions>=4.6.0
Provides-Extra: gcp-auth
Requires-Dist: opentelemetry-exporter-credential-provider-gcp>=0.59b0; extra
== 'gcp-auth'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/pyproject.toml
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/pyproject.toml
--- old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/pyproject.toml
2020-02-02 01:00:00.000000000 +0100
+++ new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/pyproject.toml
2020-02-02 01:00:00.000000000 +0100
@@ -24,15 +24,17 @@
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
]
dependencies = [
"googleapis-common-protos ~= 1.57",
"grpcio >= 1.63.2, < 2.0.0; python_version < '3.13'",
- "grpcio >= 1.66.2, < 2.0.0; python_version >= '3.13'",
+ "grpcio >= 1.66.2, < 2.0.0; python_version == '3.13'",
+ "grpcio >= 1.75.1, < 2.0.0; python_version >= '3.14'",
"opentelemetry-api ~= 1.15",
- "opentelemetry-proto == 1.39.1",
- "opentelemetry-sdk ~= 1.39.1",
- "opentelemetry-exporter-otlp-proto-common == 1.39.1",
+ "opentelemetry-proto == 1.40.0",
+ "opentelemetry-sdk ~= 1.40.0",
+ "opentelemetry-exporter-otlp-proto-common == 1.40.0",
"typing-extensions >= 4.6.0",
]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py
---
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py
2020-02-02 01:00:00.000000000 +0100
+++
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/src/opentelemetry/exporter/otlp/proto/grpc/__init__.py
2020-02-02 01:00:00.000000000 +0100
@@ -50,7 +50,7 @@
# Resource can be required for some backends, e.g. Jaeger
# If resource wouldn't be set - traces wouldn't appears in Jaeger
- resource = Resource(attributes={
+ resource = Resource.create({
"service.name": "service"
})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py
---
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py
2020-02-02 01:00:00.000000000 +0100
+++
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py
2020-02-02 01:00:00.000000000 +0100
@@ -12,7 +12,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""OTLP Exporter"""
+"""OTLP Exporter
+
+This module provides a mixin class for OTLP exporters that send telemetry data
+to an OTLP-compatible receiver via gRPC. It includes a configurable
reconnection
+logic to handle transient collector outages.
+
+"""
import random
import threading
@@ -251,9 +257,11 @@
if certificate_file:
client_key_file = environ.get(client_key_file_env_key)
client_certificate_file = environ.get(client_certificate_file_env_key)
- return _load_credentials(
+ credentials = _load_credentials(
certificate_file, client_key_file, client_certificate_file
)
+ if credentials is not None:
+ return credentials
return ssl_channel_credentials()
@@ -261,10 +269,15 @@
class OTLPExporterMixin(
ABC, Generic[SDKDataT, ExportServiceRequestT, ExportResultT, ExportStubT]
):
- """OTLP span exporter
+ """OTLP gRPC exporter mixin.
+
+ This class provides the base functionality for OTLP exporters that send
+ telemetry data (spans or metrics) to an OTLP-compatible receiver via gRPC.
+ It includes a configurable reconnection mechanism to handle transient
+ receiver outages.
Args:
- endpoint: OpenTelemetry Collector receiver endpoint
+ endpoint: OTLP-compatible receiver endpoint
insecure: Connection type
credentials: ChannelCredentials object for server authentication
headers: Headers to send when exporting
@@ -308,6 +321,8 @@
if parsed_url.netloc:
self._endpoint = parsed_url.netloc
+ self._insecure = insecure
+ self._credentials = credentials
self._headers = headers or environ.get(OTEL_EXPORTER_OTLP_HEADERS)
if isinstance(self._headers, str):
temp_headers = parse_env_headers(self._headers, liberal=True)
@@ -336,37 +351,52 @@
)
self._collector_kwargs = None
- compression = (
+ self._compression = (
environ_to_compression(OTEL_EXPORTER_OTLP_COMPRESSION)
if compression is None
else compression
) or Compression.NoCompression
- if insecure:
- self._channel = insecure_channel(
- self._endpoint,
- compression=compression,
- options=self._channel_options,
- )
- else:
+ self._channel = None
+ self._client = None
+
+ self._shutdown_in_progress = threading.Event()
+ self._shutdown = False
+
+ if not self._insecure:
self._credentials = _get_credentials(
- credentials,
+ self._credentials,
_OTEL_PYTHON_EXPORTER_OTLP_GRPC_CREDENTIAL_PROVIDER,
OTEL_EXPORTER_OTLP_CERTIFICATE,
OTEL_EXPORTER_OTLP_CLIENT_KEY,
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE,
)
+
+ self._initialize_channel_and_stub()
+
+ def _initialize_channel_and_stub(self):
+ """
+ Create a new gRPC channel and stub.
+
+ This method is used during initialization and by the reconnection
+ mechanism to reinitialize the channel on transient errors.
+ """
+ if self._insecure:
+ self._channel = insecure_channel(
+ self._endpoint,
+ compression=self._compression,
+ options=self._channel_options,
+ )
+ else:
+ assert self._credentials is not None
self._channel = secure_channel(
self._endpoint,
self._credentials,
- compression=compression,
+ compression=self._compression,
options=self._channel_options,
)
self._client = self._stub(self._channel) # type: ignore
[reportCallIssue]
- self._shutdown_in_progress = threading.Event()
- self._shutdown = False
-
@abstractmethod
def _translate_data(
self,
@@ -388,6 +418,8 @@
deadline_sec = time() + self._timeout
for retry_num in range(_MAX_RETRYS):
try:
+ if self._client is None:
+ return self._result.FAILURE
self._client.Export(
request=self._translate_data(data),
metadata=self._headers,
@@ -407,6 +439,26 @@
retry_info.retry_delay.seconds
+ retry_info.retry_delay.nanos / 1.0e9
)
+
+ # For UNAVAILABLE errors, reinitialize the channel to force
reconnection
+ if error.code() == StatusCode.UNAVAILABLE and retry_num == 0:
# type: ignore
+ logger.debug(
+ "Reinitializing gRPC channel for %s exporter due to
UNAVAILABLE error",
+ self._exporting,
+ )
+ try:
+ if self._channel:
+ self._channel.close()
+ except Exception as e:
+ logger.debug(
+ "Error closing channel for %s exporter to %s: %s",
+ self._exporting,
+ self._endpoint,
+ str(e),
+ )
+ # Enable channel reconnection for subsequent calls
+ self._initialize_channel_and_stub()
+
if (
error.code() not in _RETRYABLE_ERROR_CODES # type: ignore
[reportAttributeAccessIssue]
or retry_num + 1 == _MAX_RETRYS
@@ -436,12 +488,19 @@
return self._result.FAILURE # type: ignore [reportReturnType]
def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
+ """
+ Shut down the exporter.
+
+ Args:
+ timeout_millis: Timeout in milliseconds for shutting down the
exporter.
+ """
if self._shutdown:
logger.warning("Exporter already shutdown, ignoring call")
return
self._shutdown = True
self._shutdown_in_progress.set()
- self._channel.close()
+ if self._channel:
+ self._channel.close()
@property
@abstractmethod
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/src/opentelemetry/exporter/otlp/proto/grpc/version/__init__.py
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/src/opentelemetry/exporter/otlp/proto/grpc/version/__init__.py
---
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/src/opentelemetry/exporter/otlp/proto/grpc/version/__init__.py
2020-02-02 01:00:00.000000000 +0100
+++
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/src/opentelemetry/exporter/otlp/proto/grpc/version/__init__.py
2020-02-02 01:00:00.000000000 +0100
@@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = "1.39.1"
+__version__ = "1.40.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/tests/test_otlp_exporter_mixin.py
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/tests/test_otlp_exporter_mixin.py
---
old/opentelemetry_exporter_otlp_proto_grpc-1.39.1/tests/test_otlp_exporter_mixin.py
2020-02-02 01:00:00.000000000 +0100
+++
new/opentelemetry_exporter_otlp_proto_grpc-1.40.0/tests/test_otlp_exporter_mixin.py
2020-02-02 01:00:00.000000000 +0100
@@ -15,13 +15,16 @@
import threading
import time
import unittest
-from concurrent.futures import ThreadPoolExecutor
+from concurrent.futures import ( # pylint: disable=no-name-in-module
+ ThreadPoolExecutor,
+)
from logging import WARNING, getLogger
from platform import system
from typing import Any, Optional, Sequence
from unittest import TestCase
from unittest.mock import Mock, patch
+import grpc
from google.protobuf.duration_pb2 import ( # pylint: disable=no-name-in-module
Duration,
)
@@ -89,8 +92,8 @@
def _exporting(self):
return "traces"
- def shutdown(self, timeout_millis=30_000):
- return OTLPExporterMixin.shutdown(self, timeout_millis)
+ def shutdown(self, timeout_millis: float = 30_000, **kwargs):
+ return OTLPExporterMixin.shutdown(self, timeout_millis, **kwargs)
class TraceServiceServicerWithExportParams(TraceServiceServicer):
@@ -511,6 +514,16 @@
self.assertEqual(mock_trace_service.num_requests, 2)
self.assertAlmostEqual(after - before, 1.4, 1)
+ def test_channel_options_set_correctly(self):
+ """Test that gRPC channel options are set correctly for keepalive and
reconnection"""
+ # This test verifies that the channel is created with the right options
+ # We patch grpc.insecure_channel to ensure it is called without errors
+ with patch(
+ "opentelemetry.exporter.otlp.proto.grpc.exporter.insecure_channel"
+ ) as mock_channel:
+ OTLPSpanExporterForTesting(insecure=True)
+ self.assertTrue(mock_channel.called)
+
def test_otlp_headers_from_env(self):
# pylint: disable=protected-access
# This ensures that there is no other header than standard user-agent.
@@ -534,3 +547,27 @@
warning.records[-1].message,
"Failed to export traces to localhost:4317, error code:
StatusCode.ALREADY_EXISTS",
)
+
+ def test_unavailable_reconnects(self):
+ """Test that the exporter reconnects on UNAVAILABLE error"""
+ add_TraceServiceServicer_to_server(
+ TraceServiceServicerWithExportParams(StatusCode.UNAVAILABLE),
+ self.server,
+ )
+
+ # Spy on grpc.insecure_channel to verify it's called for reconnection
+ with patch(
+ "opentelemetry.exporter.otlp.proto.grpc.exporter.insecure_channel",
+ side_effect=grpc.insecure_channel,
+ ) as mock_insecure_channel:
+ # Mock sleep to avoid waiting
+ with patch("time.sleep"):
+ # We expect FAILURE because the server keeps returning
UNAVAILABLE
+ # but we want to verify reconnection attempts happened
+ self.exporter.export([self.span])
+
+ # Verify that we attempted to reinitialize the channel (called
insecure_channel)
+ # Since the initial channel was created in setUp (unpatched), this call
+ # must be from the reconnection logic.
+ self.assertTrue(mock_insecure_channel.called)
+ # Verify that reconnection enabled flag is set