Skip to content

Commit fe26ada

Browse files
authored
Fix warning message for OTLP gRPC exporter mixin (#2781)
* Fix warning message for OTLP gRPC exporter mixin Fixes #2780 * Refactor export parameter type * Add changelog entry * Use fixed warning messages for traces and metrics * Use subclass-specific error messages * Fix test cases * Fix lint
1 parent dbcec9f commit fe26ada

File tree

9 files changed

+126
-11
lines changed

9 files changed

+126
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.12.0rc2-0.32b0...HEAD)
99

10-
10+
- Fix OTLP gRPC exporter warning message
11+
([#2781](https://github.com/open-telemetry/opentelemetry-python/pull/2781))
1112
- Fix tracing decorator with late configuration
1213
([#2754](https://github.com/open-telemetry/opentelemetry-python/pull/2754))
1314

14-
1515
## [1.12.0rc2-0.32b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0rc2-0.32b0) - 2022-07-04
1616

17-
18-
1917
- Fix instrument name and unit regexes
2018
([#2796](https://github.com/open-telemetry/opentelemetry-python/pull/2796))
2119
- Add optional sessions parameter to all Exporters leveraging requests.Session

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/_log_exporter/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,7 @@ def export(self, batch: Sequence[LogData]) -> LogExportResult:
154154

155155
def shutdown(self) -> None:
156156
pass
157+
158+
@property
159+
def _exporting(self) -> str:
160+
return "logs"

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
"""OTLP Exporter"""
1616

17-
import logging
17+
from logging import getLogger
1818
from abc import ABC, abstractmethod
1919
from collections.abc import Sequence
2020
from os import environ
@@ -23,6 +23,7 @@
2323
from typing import Sequence as TypingSequence
2424
from typing import TypeVar
2525
from urllib.parse import urlparse
26+
from opentelemetry.sdk.trace import ReadableSpan
2627

2728
from backoff import expo
2829
from google.rpc.error_details_pb2 import RetryInfo
@@ -52,8 +53,9 @@
5253
)
5354
from opentelemetry.sdk.resources import Resource as SDKResource
5455
from opentelemetry.util.re import parse_headers
56+
from opentelemetry.sdk.metrics.export import MetricsData
5557

56-
logger = logging.getLogger(__name__)
58+
logger = getLogger(__name__)
5759
SDKDataT = TypeVar("SDKDataT")
5860
ResourceDataT = TypeVar("ResourceDataT")
5961
TypingResourceT = TypeVar("TypingResourceT")
@@ -277,8 +279,19 @@ def _translate_attributes(self, attributes) -> TypingSequence[KeyValue]:
277279
logger.exception(error)
278280
return output
279281

280-
def _export(self, data: TypingSequence[SDKDataT]) -> ExportResultT:
281-
282+
def _export(
283+
self, data: Union[TypingSequence[ReadableSpan], MetricsData]
284+
) -> ExportResultT:
285+
286+
# FIXME remove this check if the export type for traces
287+
# gets updated to a class that represents the proto
288+
# TracesData and use the code below instead.
289+
# logger.warning(
290+
# "Transient error %s encountered while exporting %s, retrying in %ss.",
291+
# error.code(),
292+
# data.__class__.__name__,
293+
# delay,
294+
# )
282295
max_value = 64
283296
# expo returns a generator that yields delay values which grow
284297
# exponentially. Once delay is greater than max_value, the yielded
@@ -321,15 +334,20 @@ def _export(self, data: TypingSequence[SDKDataT]) -> ExportResultT:
321334
)
322335

323336
logger.warning(
324-
"Transient error %s encountered while exporting span batch, retrying in %ss.",
337+
(
338+
"Transient error %s encountered while exporting "
339+
"%s, retrying in %ss."
340+
),
325341
error.code(),
342+
self._exporting,
326343
delay,
327344
)
328345
sleep(delay)
329346
continue
330347
else:
331348
logger.error(
332-
"Failed to export span batch, error code: %s",
349+
"Failed to export %s, error code: %s",
350+
self._exporting,
333351
error.code(),
334352
)
335353

@@ -342,3 +360,12 @@ def _export(self, data: TypingSequence[SDKDataT]) -> ExportResultT:
342360

343361
def shutdown(self) -> None:
344362
pass
363+
364+
@property
365+
@abstractmethod
366+
def _exporting(self) -> str:
367+
"""
368+
Returns a string that describes the overall exporter, to be used in
369+
warning messages.
370+
"""
371+
pass

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/metric_exporter/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,7 @@ def export(
206206

207207
def shutdown(self, timeout_millis: float = 30_000, **kwargs) -> None:
208208
pass
209+
210+
@property
211+
def _exporting(self) -> str:
212+
return "metrics"

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/trace_exporter/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,7 @@ def _translate_data(
289289

290290
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
291291
return self._export(spans)
292+
293+
@property
294+
def _exporting(self):
295+
return "traces"

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/logs/test_otlp_logs_exporter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ def setUp(self):
161161
def tearDown(self):
162162
self.server.stop(None)
163163

164+
def test_exporting(self):
165+
# pylint: disable=protected-access
166+
self.assertEqual(self.exporter._exporting, "logs")
167+
164168
@patch(
165169
"opentelemetry.exporter.otlp.proto.grpc.exporter.ssl_channel_credentials"
166170
)

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/metrics/test_otlp_metrics_exporter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@ def setUp(self):
298298
def tearDown(self):
299299
self.server.stop(None)
300300

301+
def test_exporting(self):
302+
# pylint: disable=protected-access
303+
self.assertEqual(self.exporter._exporting, "metrics")
304+
301305
@patch(
302306
"opentelemetry.exporter.otlp.proto.grpc.exporter.ssl_channel_credentials"
303307
)

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_exporter_mixin.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,21 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from logging import WARNING
16+
from types import MethodType
17+
from typing import Sequence
1518
from unittest import TestCase
16-
from unittest.mock import patch
19+
from unittest.mock import Mock, patch
1720

1821
from grpc import Compression
1922

2023
from opentelemetry.exporter.otlp.proto.grpc.exporter import (
24+
ExportServiceRequestT,
2125
InvalidCompressionValueException,
26+
OTLPExporterMixin,
27+
RpcError,
28+
SDKDataT,
29+
StatusCode,
2230
environ_to_compression,
2331
)
2432

@@ -47,3 +55,61 @@ def test_environ_to_compression(self):
4755
)
4856
with self.assertRaises(InvalidCompressionValueException):
4957
environ_to_compression("test_invalid")
58+
59+
@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.expo")
60+
def test_export_warning(self, mock_expo):
61+
62+
mock_expo.configure_mock(**{"return_value": [0]})
63+
64+
rpc_error = RpcError()
65+
66+
def code(self):
67+
return None
68+
69+
rpc_error.code = MethodType(code, rpc_error)
70+
71+
class OTLPMockExporter(OTLPExporterMixin):
72+
73+
_result = Mock()
74+
_stub = Mock(
75+
**{"return_value": Mock(**{"Export.side_effect": rpc_error})}
76+
)
77+
78+
def _translate_data(
79+
self, data: Sequence[SDKDataT]
80+
) -> ExportServiceRequestT:
81+
pass
82+
83+
@property
84+
def _exporting(self) -> str:
85+
return "mock"
86+
87+
otlp_mock_exporter = OTLPMockExporter()
88+
89+
with self.assertLogs(level=WARNING) as warning:
90+
# pylint: disable=protected-access
91+
otlp_mock_exporter._export(Mock())
92+
self.assertEqual(
93+
warning.records[0].message,
94+
"Failed to export mock, error code: None",
95+
)
96+
97+
def code(self): # pylint: disable=function-redefined
98+
return StatusCode.CANCELLED
99+
100+
def trailing_metadata(self):
101+
return {}
102+
103+
rpc_error.code = MethodType(code, rpc_error)
104+
rpc_error.trailing_metadata = MethodType(trailing_metadata, rpc_error)
105+
106+
with self.assertLogs(level=WARNING) as warning:
107+
# pylint: disable=protected-access
108+
otlp_mock_exporter._export([])
109+
self.assertEqual(
110+
warning.records[0].message,
111+
(
112+
"Transient error StatusCode.CANCELLED encountered "
113+
"while exporting mock, retrying in 0s."
114+
),
115+
)

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ def setUp(self):
217217
def tearDown(self):
218218
self.server.stop(None)
219219

220+
def test_exporting(self):
221+
# pylint: disable=protected-access
222+
self.assertEqual(self.exporter._exporting, "traces")
223+
220224
@patch.dict(
221225
"os.environ",
222226
{

0 commit comments

Comments
 (0)