Skip to content

Commit f669b67

Browse files
authored
Support Environment Variables for JaegerSpanExporter configuration (open-telemetry#1114)
1 parent 535c2e6 commit f669b67

File tree

4 files changed

+117
-54
lines changed

4 files changed

+117
-54
lines changed

exporter/opentelemetry-exporter-jaeger/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Changelog
22

33
## Unreleased
4+
- Add support for Jaeger Span Exporter configuration by environment variables and<br/>
5+
change JaegerSpanExporter constructor parameters
6+
([#1114](https://github.com/open-telemetry/opentelemetry-python/pull/1114))
47

58
## Version 0.13b0
69

exporter/opentelemetry-exporter-jaeger/README.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ Installation
1919
.. _Jaeger: https://www.jaegertracing.io/
2020
.. _OpenTelemetry: https://github.com/open-telemetry/opentelemetry-python/
2121

22+
Configuration
23+
-------------
24+
25+
OpenTelemetry Jaeger Exporter can be configured by setting `JaegerSpanExporter parameters
26+
<https://github.com/open-telemetry/opentelemetry-python/blob/master/exporter/opentelemetry-exporter-jaeger
27+
/src/opentelemetry/exporter/jaeger/__init__.py#L88>`_ or by setting
28+
`environment variables <https://github.com/open-telemetry/opentelemetry-specification/blob/master/
29+
specification/sdk-environment-variables.md#jaeger-exporter>`_
2230

2331
References
2432
----------

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

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@
3939
agent_host_name='localhost',
4040
agent_port=6831,
4141
# optional: configure also collector
42-
# collector_host_name='localhost',
43-
# collector_port=14268,
44-
# collector_endpoint='/api/traces?format=jaeger.thrift',
45-
# collector_protocol='http',
42+
# collector_endpoint='http://localhost:14268/api/traces?format=jaeger.thrift',
4643
# username=xxxx, # optional
4744
# password=xxxx, # optional
4845
)
@@ -69,16 +66,14 @@
6966
from thrift.protocol import TBinaryProtocol, TCompactProtocol
7067
from thrift.transport import THttpClient, TTransport
7168

72-
import opentelemetry.trace as trace_api
69+
from opentelemetry.configuration import Configuration
7370
from opentelemetry.exporter.jaeger.gen.agent import Agent as agent
7471
from opentelemetry.exporter.jaeger.gen.jaeger import Collector as jaeger
7572
from opentelemetry.sdk.trace.export import Span, SpanExporter, SpanExportResult
7673
from opentelemetry.trace.status import StatusCanonicalCode
7774

7875
DEFAULT_AGENT_HOST_NAME = "localhost"
7976
DEFAULT_AGENT_PORT = 6831
80-
DEFAULT_COLLECTOR_ENDPOINT = "/api/traces?format=jaeger.thrift"
81-
DEFAULT_COLLECTOR_PROTOCOL = "http"
8277

8378
UDP_PACKET_MAX_LENGTH = 65000
8479

@@ -93,11 +88,7 @@ class JaegerSpanExporter(SpanExporter):
9388
when query for spans.
9489
agent_host_name: The host name of the Jaeger-Agent.
9590
agent_port: The port of the Jaeger-Agent.
96-
collector_host_name: The host name of the Jaeger-Collector HTTP/HTTPS
97-
Thrift.
98-
collector_port: The port of the Jaeger-Collector HTTP/HTTPS Thrift.
9991
collector_endpoint: The endpoint of the Jaeger-Collector HTTP/HTTPS Thrift.
100-
collector_protocol: The transfer protocol for the Jaeger-Collector(HTTP or HTTPS).
10192
username: The user name of the Basic Auth if authentication is
10293
required.
10394
password: The password of the Basic Auth if authentication is
@@ -107,25 +98,39 @@ class JaegerSpanExporter(SpanExporter):
10798
def __init__(
10899
self,
109100
service_name,
110-
agent_host_name=DEFAULT_AGENT_HOST_NAME,
111-
agent_port=DEFAULT_AGENT_PORT,
112-
collector_host_name=None,
113-
collector_port=None,
114-
collector_endpoint=DEFAULT_COLLECTOR_ENDPOINT,
115-
collector_protocol=DEFAULT_COLLECTOR_PROTOCOL,
101+
agent_host_name=None,
102+
agent_port=None,
103+
collector_endpoint=None,
116104
username=None,
117105
password=None,
118106
):
119107
self.service_name = service_name
120-
self.agent_host_name = agent_host_name
121-
self.agent_port = agent_port
108+
self.agent_host_name = _parameter_setter(
109+
param=agent_host_name,
110+
env_variable=Configuration().EXPORTER_JAEGER_AGENT_HOST,
111+
default=DEFAULT_AGENT_HOST_NAME,
112+
)
113+
self.agent_port = _parameter_setter(
114+
param=agent_port,
115+
env_variable=Configuration().EXPORTER_JAEGER_AGENT_PORT,
116+
default=DEFAULT_AGENT_PORT,
117+
)
122118
self._agent_client = None
123-
self.collector_host_name = collector_host_name
124-
self.collector_port = collector_port
125-
self.collector_endpoint = collector_endpoint
126-
self.collector_protocol = collector_protocol
127-
self.username = username
128-
self.password = password
119+
self.collector_endpoint = _parameter_setter(
120+
param=collector_endpoint,
121+
env_variable=Configuration().EXPORTER_JAEGER_ENDPOINT,
122+
default=None,
123+
)
124+
self.username = _parameter_setter(
125+
param=username,
126+
env_variable=Configuration().EXPORTER_JAEGER_USER,
127+
default=None,
128+
)
129+
self.password = _parameter_setter(
130+
param=password,
131+
env_variable=Configuration().EXPORTER_JAEGER_PASSWORD,
132+
default=None,
133+
)
129134
self._collector = None
130135

131136
@property
@@ -141,21 +146,16 @@ def collector(self):
141146
if self._collector is not None:
142147
return self._collector
143148

144-
if self.collector_host_name is None or self.collector_port is None:
149+
if self.collector_endpoint is None:
145150
return None
146151

147-
thrift_url = "{}://{}:{}{}".format(
148-
self.collector_protocol,
149-
self.collector_host_name,
150-
self.collector_port,
151-
self.collector_endpoint,
152-
)
153-
154152
auth = None
155153
if self.username is not None and self.password is not None:
156154
auth = (self.username, self.password)
157155

158-
self._collector = Collector(thrift_url=thrift_url, auth=auth)
156+
self._collector = Collector(
157+
thrift_url=self.collector_endpoint, auth=auth
158+
)
159159
return self._collector
160160

161161
def export(self, spans):
@@ -177,6 +177,22 @@ def shutdown(self):
177177
pass
178178

179179

180+
def _parameter_setter(param, env_variable, default):
181+
"""Returns value according to the provided data.
182+
183+
Args:
184+
param: Constructor parameter value
185+
env_variable: Environment variable related to the parameter
186+
default: Constructor parameter default value
187+
"""
188+
if param is None:
189+
res = env_variable or default
190+
else:
191+
res = param
192+
193+
return res
194+
195+
180196
def _nsec_to_usec_round(nsec):
181197
"""Round nanoseconds to microseconds"""
182198
return (nsec + 500) // 10 ** 3

exporter/opentelemetry-exporter-jaeger/tests/test_jaeger_exporter.py

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# pylint:disable=import-error
2121
import opentelemetry.exporter.jaeger as jaeger_exporter
2222
from opentelemetry import trace as trace_api
23+
from opentelemetry.configuration import Configuration
2324
from opentelemetry.exporter.jaeger.gen.jaeger import ttypes as jaeger
2425
from opentelemetry.sdk import trace
2526
from opentelemetry.sdk.trace import Resource
@@ -43,20 +44,14 @@ def setUp(self):
4344
def test_constructor_default(self):
4445
"""Test the default values assigned by constructor."""
4546
service_name = "my-service-name"
46-
host_name = "localhost"
47-
thrift_port = None
47+
agent_host_name = "localhost"
4848
agent_port = 6831
49-
collector_endpoint = "/api/traces?format=jaeger.thrift"
50-
collector_protocol = "http"
5149
exporter = jaeger_exporter.JaegerSpanExporter(service_name)
5250

5351
self.assertEqual(exporter.service_name, service_name)
54-
self.assertEqual(exporter.collector_host_name, None)
55-
self.assertEqual(exporter.agent_host_name, host_name)
52+
self.assertEqual(exporter.agent_host_name, agent_host_name)
5653
self.assertEqual(exporter.agent_port, agent_port)
57-
self.assertEqual(exporter.collector_port, thrift_port)
58-
self.assertEqual(exporter.collector_protocol, collector_protocol)
59-
self.assertEqual(exporter.collector_endpoint, collector_endpoint)
54+
self.assertEqual(exporter.collector_endpoint, None)
6055
self.assertEqual(exporter.username, None)
6156
self.assertEqual(exporter.password, None)
6257
self.assertTrue(exporter.collector is None)
@@ -65,10 +60,7 @@ def test_constructor_default(self):
6560
def test_constructor_explicit(self):
6661
"""Test the constructor passing all the options."""
6762
service = "my-opentelemetry-jaeger"
68-
collector_host_name = "opentelemetry.io"
69-
collector_port = 15875
70-
collector_endpoint = "/myapi/traces?format=jaeger.thrift"
71-
collector_protocol = "https"
63+
collector_endpoint = "https://opentelemetry.io:15875"
7264

7365
agent_port = 14268
7466
agent_host_name = "opentelemetry.io"
@@ -79,21 +71,16 @@ def test_constructor_explicit(self):
7971

8072
exporter = jaeger_exporter.JaegerSpanExporter(
8173
service_name=service,
82-
collector_host_name=collector_host_name,
83-
collector_port=collector_port,
84-
collector_endpoint=collector_endpoint,
85-
collector_protocol="https",
8674
agent_host_name=agent_host_name,
8775
agent_port=agent_port,
76+
collector_endpoint=collector_endpoint,
8877
username=username,
8978
password=password,
9079
)
80+
9181
self.assertEqual(exporter.service_name, service)
9282
self.assertEqual(exporter.agent_host_name, agent_host_name)
9383
self.assertEqual(exporter.agent_port, agent_port)
94-
self.assertEqual(exporter.collector_host_name, collector_host_name)
95-
self.assertEqual(exporter.collector_port, collector_port)
96-
self.assertEqual(exporter.collector_protocol, collector_protocol)
9784
self.assertTrue(exporter.collector is not None)
9885
self.assertEqual(exporter.collector.auth, auth)
9986
# property should not construct new object
@@ -107,6 +94,55 @@ def test_constructor_explicit(self):
10794
self.assertNotEqual(exporter.collector, collector)
10895
self.assertTrue(exporter.collector.auth is None)
10996

97+
def test_constructor_by_environment_variables(self):
98+
"""Test the constructor using Environment Variables."""
99+
service = "my-opentelemetry-jaeger"
100+
101+
agent_host_name = "opentelemetry.io"
102+
agent_port = "6831"
103+
104+
collector_endpoint = "https://opentelemetry.io:15875"
105+
106+
username = "username"
107+
password = "password"
108+
auth = (username, password)
109+
110+
environ_patcher = mock.patch.dict(
111+
"os.environ",
112+
{
113+
"OTEL_EXPORTER_JAEGER_AGENT_HOST": agent_host_name,
114+
"OTEL_EXPORTER_JAEGER_AGENT_PORT": agent_port,
115+
"OTEL_EXPORTER_JAEGER_ENDPOINT": collector_endpoint,
116+
"OTEL_EXPORTER_JAEGER_USER": username,
117+
"OTEL_EXPORTER_JAEGER_PASSWORD": password,
118+
},
119+
)
120+
121+
environ_patcher.start()
122+
123+
exporter = jaeger_exporter.JaegerSpanExporter(service_name=service)
124+
125+
self.assertEqual(exporter.service_name, service)
126+
self.assertEqual(exporter.agent_host_name, agent_host_name)
127+
self.assertEqual(exporter.agent_port, int(agent_port))
128+
self.assertTrue(exporter.collector is not None)
129+
self.assertEqual(exporter.collector_endpoint, collector_endpoint)
130+
self.assertEqual(exporter.collector.auth, auth)
131+
# property should not construct new object
132+
collector = exporter.collector
133+
self.assertEqual(exporter.collector, collector)
134+
# property should construct new object
135+
# pylint: disable=protected-access
136+
exporter._collector = None
137+
exporter.username = None
138+
exporter.password = None
139+
self.assertNotEqual(exporter.collector, collector)
140+
self.assertTrue(exporter.collector.auth is None)
141+
142+
environ_patcher.stop()
143+
144+
Configuration._reset()
145+
110146
def test_nsec_to_usec_round(self):
111147
# pylint: disable=protected-access
112148
nsec_to_usec_round = jaeger_exporter._nsec_to_usec_round

0 commit comments

Comments
 (0)