Skip to content

Commit 7f71515

Browse files
authored
Add support for OTEL_EXPORTER_JAEGER_TIMEOUT (open-telemetry#1863)
1 parent ea4cdfe commit 7f71515

File tree

7 files changed

+74
-78
lines changed

7 files changed

+74
-78
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3535
([#1829](https://github.com/open-telemetry/opentelemetry-python/pull/1829))
3636
- Lazily read/configure limits and allow limits to be unset.
3737
([#1839](https://github.com/open-telemetry/opentelemetry-python/pull/1839))
38+
- Added support for OTEL_EXPORTER_JAEGER_TIMEOUT
39+
([#1863](https://github.com/open-telemetry/opentelemetry-python/pull/1863))
3840

3941
### Changed
4042
- Fixed OTLP gRPC exporter silently failing if scheme is not specified in endpoint.

exporter/opentelemetry-exporter-jaeger-proto-grpc/src/opentelemetry/exporter/jaeger/proto/grpc/__init__.py

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
5757
- :envvar:`OTEL_EXPORTER_JAEGER_ENDPOINT`
5858
- :envvar:`OTEL_EXPORTER_JAEGER_CERTIFICATE`
59+
- :envvar:`OTEL_EXPORTER_JAEGER_TIMEOUT`
5960
6061
API
6162
---
@@ -68,7 +69,7 @@
6869
from os import environ
6970
from typing import Optional
7071

71-
from grpc import ChannelCredentials, insecure_channel, secure_channel
72+
from grpc import ChannelCredentials, RpcError, insecure_channel, secure_channel
7273

7374
from opentelemetry import trace
7475
from opentelemetry.exporter.jaeger.proto.grpc import util
@@ -85,11 +86,13 @@
8586
)
8687
from opentelemetry.sdk.environment_variables import (
8788
OTEL_EXPORTER_JAEGER_ENDPOINT,
89+
OTEL_EXPORTER_JAEGER_TIMEOUT,
8890
)
8991
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
9092
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
9193

9294
DEFAULT_GRPC_COLLECTOR_ENDPOINT = "localhost:14250"
95+
DEFAULT_EXPORT_TIMEOUT = 10
9396

9497
logger = logging.getLogger(__name__)
9598

@@ -103,6 +106,7 @@ class JaegerExporter(SpanExporter):
103106
insecure: True if collector has no encryption or authentication
104107
credentials: Credentials for server authentication.
105108
max_tag_value_length: Max length string attribute values can have. Set to None to disable.
109+
timeout: Maximum time the Jaeger exporter should wait for each batch export.
106110
"""
107111

108112
def __init__(
@@ -111,13 +115,15 @@ def __init__(
111115
insecure: Optional[bool] = None,
112116
credentials: Optional[ChannelCredentials] = None,
113117
max_tag_value_length: Optional[int] = None,
118+
timeout: Optional[int] = None,
114119
):
115120
self._max_tag_value_length = max_tag_value_length
116121

117-
self.collector_endpoint = _parameter_setter(
118-
param=collector_endpoint,
119-
env_variable=environ.get(OTEL_EXPORTER_JAEGER_ENDPOINT),
120-
default=None,
122+
self.collector_endpoint = collector_endpoint or environ.get(
123+
OTEL_EXPORTER_JAEGER_ENDPOINT, DEFAULT_GRPC_COLLECTOR_ENDPOINT
124+
)
125+
self._timeout = timeout or int(
126+
environ.get(OTEL_EXPORTER_JAEGER_TIMEOUT, DEFAULT_EXPORT_TIMEOUT)
121127
)
122128
self._grpc_client = None
123129
self.insecure = insecure
@@ -131,16 +137,15 @@ def __init__(
131137

132138
@property
133139
def _collector_grpc_client(self) -> Optional[CollectorServiceStub]:
134-
endpoint = self.collector_endpoint or DEFAULT_GRPC_COLLECTOR_ENDPOINT
135140

136141
if self._grpc_client is None:
137142
if self.insecure:
138143
self._grpc_client = CollectorServiceStub(
139-
insecure_channel(endpoint)
144+
insecure_channel(self.collector_endpoint)
140145
)
141146
else:
142147
self._grpc_client = CollectorServiceStub(
143-
secure_channel(endpoint, self.credentials)
148+
secure_channel(self.collector_endpoint, self.credentials)
144149
)
145150
return self._grpc_client
146151

@@ -161,25 +166,16 @@ def export(self, spans) -> SpanExportResult:
161166
jaeger_spans = translator._translate(pb_translator)
162167
batch = model_pb2.Batch(spans=jaeger_spans)
163168
request = PostSpansRequest(batch=batch)
164-
self._collector_grpc_client.PostSpans(request)
165-
166-
return SpanExportResult.SUCCESS
169+
try:
170+
self._collector_grpc_client.PostSpans(
171+
request, timeout=self._timeout
172+
)
173+
return SpanExportResult.SUCCESS
174+
except RpcError as error:
175+
logger.warning(
176+
"Failed to export batch. Status code: %s", error.code()
177+
)
178+
return SpanExportResult.FAILURE
167179

168180
def shutdown(self):
169181
pass
170-
171-
172-
def _parameter_setter(param, env_variable, default):
173-
"""Returns value according to the provided data.
174-
175-
Args:
176-
param: Constructor parameter value
177-
env_variable: Environment variable related to the parameter
178-
default: Constructor parameter default value
179-
"""
180-
if param is None:
181-
res = env_variable or default
182-
else:
183-
res = param
184-
185-
return res

exporter/opentelemetry-exporter-jaeger-proto-grpc/tests/test_jaeger_exporter_protobuf.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from opentelemetry.sdk.environment_variables import (
3333
OTEL_EXPORTER_JAEGER_CERTIFICATE,
3434
OTEL_EXPORTER_JAEGER_ENDPOINT,
35+
OTEL_EXPORTER_JAEGER_TIMEOUT,
3536
OTEL_RESOURCE_ATTRIBUTES,
3637
)
3738
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
@@ -71,6 +72,7 @@ def test_constructor_by_environment_variables(self):
7172
OTEL_EXPORTER_JAEGER_CERTIFICATE: os.path.dirname(__file__)
7273
+ "/certs/cred.cert",
7374
OTEL_RESOURCE_ATTRIBUTES: "service.name=my-opentelemetry-jaeger",
75+
OTEL_EXPORTER_JAEGER_TIMEOUT: "5",
7476
},
7577
)
7678

@@ -81,6 +83,7 @@ def test_constructor_by_environment_variables(self):
8183
self.assertEqual(exporter.service_name, service)
8284
self.assertIsNotNone(exporter._collector_grpc_client)
8385
self.assertEqual(exporter.collector_endpoint, collector_endpoint)
86+
self.assertEqual(exporter._timeout, 5)
8487
self.assertIsNotNone(exporter.credentials)
8588
env_patch.stop()
8689

exporter/opentelemetry-exporter-jaeger-thrift/src/opentelemetry/exporter/jaeger/thrift/__init__.py

Lines changed: 23 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
- :envvar:`OTEL_EXPORTER_JAEGER_AGENT_PORT`
6868
- :envvar:`OTEL_EXPORTER_JAEGER_AGENT_HOST`
6969
- :envvar:`OTEL_EXPORTER_JAEGER_AGENT_SPLIT_OVERSIZED_BATCHES`
70+
- :envvar:`OTEL_EXPORTER_JAEGER_TIMEOUT`
7071
7172
API
7273
---
@@ -94,13 +95,15 @@
9495
OTEL_EXPORTER_JAEGER_AGENT_SPLIT_OVERSIZED_BATCHES,
9596
OTEL_EXPORTER_JAEGER_ENDPOINT,
9697
OTEL_EXPORTER_JAEGER_PASSWORD,
98+
OTEL_EXPORTER_JAEGER_TIMEOUT,
9799
OTEL_EXPORTER_JAEGER_USER,
98100
)
99101
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
100102
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
101103

102104
DEFAULT_AGENT_HOST_NAME = "localhost"
103105
DEFAULT_AGENT_PORT = 6831
106+
DEFAULT_EXPORT_TIMEOUT = 10
104107

105108
logger = logging.getLogger(__name__)
106109

@@ -119,6 +122,7 @@ class JaegerExporter(SpanExporter):
119122
required.
120123
max_tag_value_length: Max length string attribute values can have. Set to None to disable.
121124
udp_split_oversized_batches: Re-emit oversized batches in smaller chunks.
125+
timeout: Maximum time the Jaeger exporter should wait for each batch export.
122126
"""
123127

124128
def __init__(
@@ -130,51 +134,34 @@ def __init__(
130134
password: Optional[str] = None,
131135
max_tag_value_length: Optional[int] = None,
132136
udp_split_oversized_batches: bool = None,
137+
timeout: Optional[int] = None,
133138
):
134139
self._max_tag_value_length = max_tag_value_length
135-
self.agent_host_name = _parameter_setter(
136-
param=agent_host_name,
137-
env_variable=environ.get(OTEL_EXPORTER_JAEGER_AGENT_HOST),
138-
default=DEFAULT_AGENT_HOST_NAME,
140+
self.agent_host_name = agent_host_name or environ.get(
141+
OTEL_EXPORTER_JAEGER_AGENT_HOST, DEFAULT_AGENT_HOST_NAME
139142
)
140143

141-
environ_agent_port = environ.get(OTEL_EXPORTER_JAEGER_AGENT_PORT)
142-
environ_agent_port = (
143-
int(environ_agent_port) if environ_agent_port is not None else None
144+
self.agent_port = agent_port or int(
145+
environ.get(OTEL_EXPORTER_JAEGER_AGENT_PORT, DEFAULT_AGENT_PORT)
144146
)
145147

146-
self.agent_port = _parameter_setter(
147-
param=agent_port,
148-
env_variable=environ_agent_port,
149-
default=DEFAULT_AGENT_PORT,
148+
self._timeout = timeout or int(
149+
environ.get(OTEL_EXPORTER_JAEGER_TIMEOUT, DEFAULT_EXPORT_TIMEOUT)
150150
)
151-
self.udp_split_oversized_batches = _parameter_setter(
152-
param=udp_split_oversized_batches,
153-
env_variable=environ.get(
154-
OTEL_EXPORTER_JAEGER_AGENT_SPLIT_OVERSIZED_BATCHES
155-
),
156-
default=False,
151+
152+
self.udp_split_oversized_batches = udp_split_oversized_batches or bool(
153+
environ.get(OTEL_EXPORTER_JAEGER_AGENT_SPLIT_OVERSIZED_BATCHES)
157154
)
158155
self._agent_client = AgentClientUDP(
159156
host_name=self.agent_host_name,
160157
port=self.agent_port,
161158
split_oversized_batches=self.udp_split_oversized_batches,
162159
)
163-
self.collector_endpoint = _parameter_setter(
164-
param=collector_endpoint,
165-
env_variable=environ.get(OTEL_EXPORTER_JAEGER_ENDPOINT),
166-
default=None,
167-
)
168-
self.username = _parameter_setter(
169-
param=username,
170-
env_variable=environ.get(OTEL_EXPORTER_JAEGER_USER),
171-
default=None,
172-
)
173-
self.password = _parameter_setter(
174-
param=password,
175-
env_variable=environ.get(OTEL_EXPORTER_JAEGER_PASSWORD),
176-
default=None,
160+
self.collector_endpoint = collector_endpoint or environ.get(
161+
OTEL_EXPORTER_JAEGER_ENDPOINT
177162
)
163+
self.username = username or environ.get(OTEL_EXPORTER_JAEGER_USER)
164+
self.password = password or environ.get(OTEL_EXPORTER_JAEGER_PASSWORD)
178165
self._collector = None
179166
tracer_provider = trace.get_tracer_provider()
180167
self.service_name = (
@@ -195,8 +182,12 @@ def _collector_http_client(self) -> Optional[Collector]:
195182
if self.username is not None and self.password is not None:
196183
auth = (self.username, self.password)
197184

185+
# Thrift HTTP Client expects timeout in millis
186+
timeout_in_millis = self._timeout * 1000.0
198187
self._collector = Collector(
199-
thrift_url=self.collector_endpoint, auth=auth
188+
thrift_url=self.collector_endpoint,
189+
auth=auth,
190+
timeout_in_millis=timeout_in_millis,
200191
)
201192
return self._collector
202193

@@ -226,19 +217,3 @@ def export(self, spans) -> SpanExportResult:
226217

227218
def shutdown(self):
228219
pass
229-
230-
231-
def _parameter_setter(param, env_variable, default):
232-
"""Returns value according to the provided data.
233-
234-
Args:
235-
param: Constructor parameter value
236-
env_variable: Environment variable related to the parameter
237-
default: Constructor parameter default value
238-
"""
239-
if param is None:
240-
res = env_variable or default
241-
else:
242-
res = param
243-
244-
return res

exporter/opentelemetry-exporter-jaeger-thrift/src/opentelemetry/exporter/jaeger/thrift/send.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,29 @@ def emit(self, batch: jaeger.Batch):
9696

9797

9898
class Collector:
99-
"""Submits collected spans to Thrift HTTP server.
99+
"""Submits collected spans to Jaeger collector in jaeger.thrift
100+
format over binary thrift protocol. This is recommend option in cases where
101+
it is not feasible to deploy Jaeger Agent next to the application,
102+
for example, when the application code is running as AWS Lambda function.
103+
In these scenarios the Jaeger Clients can be configured to submit spans directly
104+
to the Collectors over HTTP/HTTPS.
100105
101106
Args:
102-
thrift_url: URL of the Jaeger HTTP Thrift.
107+
thrift_url: Endpoint used to send spans
108+
directly to Collector the over HTTP.
103109
auth: Auth tuple that contains username and password for Basic Auth.
110+
timeout_in_millis: timeout for THttpClient.
104111
"""
105112

106-
def __init__(self, thrift_url="", auth=None):
113+
def __init__(self, thrift_url="", auth=None, timeout_in_millis=None):
107114
self.thrift_url = thrift_url
108115
self.auth = auth
109116
self.http_transport = THttpClient.THttpClient(
110117
uri_or_host=self.thrift_url
111118
)
119+
if timeout_in_millis is not None:
120+
self.http_transport.setTimeout(timeout_in_millis)
121+
112122
self.protocol = TBinaryProtocol.TBinaryProtocol(self.http_transport)
113123

114124
# set basic auth header

exporter/opentelemetry-exporter-jaeger-thrift/tests/test_jaeger_exporter_thrift.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
OTEL_EXPORTER_JAEGER_AGENT_PORT,
3333
OTEL_EXPORTER_JAEGER_ENDPOINT,
3434
OTEL_EXPORTER_JAEGER_PASSWORD,
35+
OTEL_EXPORTER_JAEGER_TIMEOUT,
3536
OTEL_EXPORTER_JAEGER_USER,
3637
)
3738
from opentelemetry.sdk.resources import SERVICE_NAME
@@ -148,6 +149,7 @@ def test_constructor_by_environment_variables(self):
148149
OTEL_EXPORTER_JAEGER_ENDPOINT: collector_endpoint,
149150
OTEL_EXPORTER_JAEGER_USER: username,
150151
OTEL_EXPORTER_JAEGER_PASSWORD: password,
152+
OTEL_EXPORTER_JAEGER_TIMEOUT: "20",
151153
},
152154
)
153155

@@ -164,6 +166,7 @@ def test_constructor_by_environment_variables(self):
164166
self.assertEqual(exporter.service_name, service)
165167
self.assertEqual(exporter.agent_host_name, agent_host_name)
166168
self.assertEqual(exporter.agent_port, int(agent_port))
169+
self.assertEqual(exporter._timeout, 20)
167170
self.assertTrue(exporter._collector_http_client is not None)
168171
self.assertEqual(exporter.collector_endpoint, collector_endpoint)
169172
self.assertEqual(exporter._collector_http_client.auth, auth)

opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@
113113
.. envvar:: OTEL_EXPORTER_JAEGER_PASSWORD
114114
"""
115115

116+
OTEL_EXPORTER_JAEGER_TIMEOUT = "OTEL_EXPORTER_JAEGER_TIMEOUT"
117+
"""
118+
.. envvar:: OTEL_EXPORTER_JAEGER_TIMEOUT
119+
120+
Maximum time the Jaeger exporter will wait for each batch export, the default
121+
timeout is 10s.
122+
"""
116123

117124
OTEL_EXPORTER_ZIPKIN_ENDPOINT = "OTEL_EXPORTER_ZIPKIN_ENDPOINT"
118125
"""

0 commit comments

Comments
 (0)