diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py index b965061c5cb..7034806a1a9 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py @@ -321,15 +321,17 @@ def _export(self, data: TypingSequence[SDKDataT]) -> ExportResultT: ) logger.warning( - "Transient error %s encountered while exporting span batch, retrying in %ss.", + "Transient error %s encountered while exporting %s, retrying in %ss.", error.code(), + data.__class__.__name__, delay, ) sleep(delay) continue else: logger.error( - "Failed to export span batch, error code: %s", + "Failed to export %s, error code: %s", + data.__class__.__name__, error.code(), ) diff --git a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py index a7627b237c9..5533bf2c110 100644 --- a/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py +++ b/exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py @@ -12,13 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. +from logging import WARNING +from types import MethodType +from typing import Sequence from unittest import TestCase -from unittest.mock import patch +from unittest.mock import Mock, patch from grpc import Compression from opentelemetry.exporter.otlp.proto.grpc.exporter import ( + ExportServiceRequestT, InvalidCompressionValueException, + OTLPExporterMixin, + RpcError, + SDKDataT, + StatusCode, environ_to_compression, ) @@ -47,3 +55,57 @@ def test_environ_to_compression(self): ) with self.assertRaises(InvalidCompressionValueException): environ_to_compression("test_invalid") + + @patch("opentelemetry.exporter.otlp.proto.grpc.exporter.expo") + def test_export_warning(self, mock_expo): + + mock_expo.configure_mock(**{"return_value": [0]}) + + rpc_error = RpcError() + + def code(self): + return None + + rpc_error.code = MethodType(code, rpc_error) + + class OTLPMockExporter(OTLPExporterMixin): + + _result = Mock() + _stub = Mock( + **{"return_value": Mock(**{"Export.side_effect": rpc_error})} + ) + + def _translate_data( + self, data: Sequence[SDKDataT] + ) -> ExportServiceRequestT: + pass + + otlp_mock_exporter = OTLPMockExporter() + + with self.assertLogs(level=WARNING) as warning: + # pylint: disable=protected-access + otlp_mock_exporter._export(Mock()) + self.assertEqual( + warning.records[0].message, + "Failed to export Mock, error code: None", + ) + + def code(self): # pylint: disable=function-redefined + return StatusCode.CANCELLED + + def trailing_metadata(self): + return {} + + rpc_error.code = MethodType(code, rpc_error) + rpc_error.trailing_metadata = MethodType(trailing_metadata, rpc_error) + + with self.assertLogs(level=WARNING) as warning: + # pylint: disable=protected-access + otlp_mock_exporter._export(Mock()) + self.assertEqual( + warning.records[0].message, + ( + "Transient error StatusCode.CANCELLED encountered " + "while exporting Mock, retrying in 0s." + ), + )