Skip to content

Commit ea65dc2

Browse files
committed
Use RetryingExporter in HTTP trace exporter
This unifies the implementation of the OTLP exporters and the HTTP trace exporter.
1 parent 600506e commit ea65dc2

File tree

2 files changed

+29
-38
lines changed

2 files changed

+29
-38
lines changed

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

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
from io import BytesIO
1919
from os import environ
2020
from typing import Dict, Optional
21-
from time import sleep
2221

2322
import requests
2423

25-
from opentelemetry.exporter.otlp.proto.common._internal import (
26-
_create_exp_backoff_generator,
24+
from opentelemetry.exporter.otlp.proto.common.exporter import (
25+
RetryableExportError,
26+
RetryingExporter,
2727
)
2828
from opentelemetry.exporter.otlp.proto.common.trace_encoder import (
2929
encode_spans,
@@ -121,6 +121,7 @@ def __init__(
121121
{"Content-Encoding": self._compression.value}
122122
)
123123
self._shutdown = False
124+
self._exporter = RetryingExporter(self._export, SpanExportResult)
124125

125126
def _export(self, serialized_data: bytes):
126127
data = serialized_data
@@ -132,14 +133,31 @@ def _export(self, serialized_data: bytes):
132133
elif self._compression == Compression.Deflate:
133134
data = zlib.compress(serialized_data)
134135

135-
return self._session.post(
136+
resp = self._session.post(
136137
url=self._endpoint,
137138
data=data,
138139
verify=self._certificate_file,
139140
timeout=self._timeout,
140141
cert=self._client_cert,
141142
)
142143

144+
if resp.ok:
145+
return SpanExportResult.SUCCESS
146+
147+
if self._retryable(resp):
148+
_logger.warning(
149+
"Transient error %s encountered while exporting span batch",
150+
resp.reason,
151+
)
152+
raise RetryableExportError(None)
153+
154+
_logger.error(
155+
"Failed to export batch code: %s, reason: %s",
156+
resp.status_code,
157+
resp.text,
158+
)
159+
return SpanExportResult.FAILURE
160+
143161
@staticmethod
144162
def _retryable(resp: requests.Response) -> bool:
145163
if resp.status_code == 408:
@@ -151,34 +169,6 @@ def _retryable(resp: requests.Response) -> bool:
151169
def _serialize_spans(self, spans):
152170
return encode_spans(spans).SerializePartialToString()
153171

154-
def _export_serialized_spans(self, serialized_data):
155-
for delay in _create_exp_backoff_generator(
156-
max_value=self._MAX_RETRY_TIMEOUT
157-
):
158-
if delay == self._MAX_RETRY_TIMEOUT:
159-
return SpanExportResult.FAILURE
160-
161-
resp = self._export(serialized_data)
162-
# pylint: disable=no-else-return
163-
if resp.ok:
164-
return SpanExportResult.SUCCESS
165-
elif self._retryable(resp):
166-
_logger.warning(
167-
"Transient error %s encountered while exporting span batch, retrying in %ss.",
168-
resp.reason,
169-
delay,
170-
)
171-
sleep(delay)
172-
continue
173-
else:
174-
_logger.error(
175-
"Failed to export batch code: %s, reason: %s",
176-
resp.status_code,
177-
resp.text,
178-
)
179-
return SpanExportResult.FAILURE
180-
return SpanExportResult.FAILURE
181-
182172
def export(self, spans) -> SpanExportResult:
183173
# After the call to Shutdown subsequent calls to Export are
184174
# not allowed and should return a Failure result.
@@ -187,8 +177,7 @@ def export(self, spans) -> SpanExportResult:
187177
return SpanExportResult.FAILURE
188178

189179
serialized_data = self._serialize_spans(spans)
190-
191-
return self._export_serialized_spans(serialized_data)
180+
return self._exporter.export_with_retry(serialized_data)
192181

193182
def shutdown(self):
194183
if self._shutdown:

exporter/opentelemetry-exporter-otlp-proto-http/tests/test_proto_span_exporter.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ def test_headers_parse_from_env(self):
234234

235235
# pylint: disable=no-self-use
236236
@responses.activate
237-
@patch("opentelemetry.exporter.otlp.proto.http.trace_exporter.sleep")
237+
@patch("opentelemetry.exporter.otlp.proto.common.exporter.sleep")
238238
def test_exponential_backoff(self, mock_sleep):
239239
# return a retryable error
240240
responses.add(
@@ -263,12 +263,14 @@ def test_exponential_backoff(self, mock_sleep):
263263
[call(1), call(2), call(4), call(8), call(16), call(32)]
264264
)
265265

266-
@patch.object(OTLPSpanExporter, "_export", return_value=Mock(ok=True))
267-
def test_2xx_status_code(self, mock_otlp_metric_exporter):
266+
def test_2xx_status_code(self):
268267
"""
269268
Test that any HTTP 2XX code returns a successful result
270269
"""
271270

272271
self.assertEqual(
273-
OTLPSpanExporter().export(MagicMock()), SpanExportResult.SUCCESS
272+
OTLPSpanExporter(
273+
session=Mock(**{"post.return_value": Mock(ok=True)})
274+
).export(MagicMock()),
275+
SpanExportResult.SUCCESS,
274276
)

0 commit comments

Comments
 (0)