Skip to content

Commit baab508

Browse files
Oberon00c24t
authored andcommitted
Named tracers (open-telemetry#301)
Implements the "Tracers" part of open-telemetry#203.
1 parent d74c39c commit baab508

File tree

25 files changed

+427
-220
lines changed

25 files changed

+427
-220
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ pip install -e ./ext/opentelemetry-ext-{integration}
5252
```python
5353
from opentelemetry import trace
5454
from opentelemetry.context import Context
55-
from opentelemetry.sdk.trace import Tracer
55+
from opentelemetry.sdk.trace import TracerSource
5656
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
5757
from opentelemetry.sdk.trace.export import SimpleExportSpanProcessor
5858

59-
trace.set_preferred_tracer_implementation(lambda T: Tracer())
60-
tracer = trace.tracer()
61-
tracer.add_span_processor(
59+
trace.set_preferred_tracer_source_implementation(lambda T: TracerSource())
60+
trace.tracer_source().add_span_processor(
6261
SimpleExportSpanProcessor(ConsoleSpanExporter())
6362
)
63+
tracer = trace.tracer_source().get_tracer(__name__)
6464
with tracer.start_as_current_span('foo'):
6565
with tracer.start_as_current_span('bar'):
6666
with tracer.start_as_current_span('baz'):

examples/basic_tracer/tracer.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
from opentelemetry import trace
2020
from opentelemetry.context import Context
21-
from opentelemetry.sdk.trace import Tracer
21+
from opentelemetry.sdk.trace import TracerSource
2222
from opentelemetry.sdk.trace.export import (
2323
BatchExportSpanProcessor,
2424
ConsoleSpanExporter,
@@ -37,13 +37,17 @@
3737

3838
# The preferred tracer implementation must be set, as the opentelemetry-api
3939
# defines the interface with a no-op implementation.
40-
trace.set_preferred_tracer_implementation(lambda T: Tracer())
41-
tracer = trace.tracer()
40+
trace.set_preferred_tracer_source_implementation(lambda T: TracerSource())
41+
42+
# We tell OpenTelemetry who it is that is creating spans. In this case, we have
43+
# no real name (no setup.py), so we make one up. If we had a version, we would
44+
# also specify it here.
45+
tracer = trace.tracer_source().get_tracer(__name__)
4246

4347
# SpanExporter receives the spans and send them to the target location.
4448
span_processor = BatchExportSpanProcessor(exporter)
4549

46-
tracer.add_span_processor(span_processor)
50+
trace.tracer_source().add_span_processor(span_processor)
4751
with tracer.start_as_current_span("foo"):
4852
with tracer.start_as_current_span("bar"):
4953
with tracer.start_as_current_span("baz"):

examples/http/server.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from opentelemetry import trace
2323
from opentelemetry.ext import http_requests
2424
from opentelemetry.ext.wsgi import OpenTelemetryMiddleware
25-
from opentelemetry.sdk.trace import Tracer
25+
from opentelemetry.sdk.trace import TracerSource
2626
from opentelemetry.sdk.trace.export import (
2727
BatchExportSpanProcessor,
2828
ConsoleSpanExporter,
@@ -41,17 +41,17 @@
4141

4242
# The preferred tracer implementation must be set, as the opentelemetry-api
4343
# defines the interface with a no-op implementation.
44-
trace.set_preferred_tracer_implementation(lambda T: Tracer())
45-
tracer = trace.tracer()
44+
trace.set_preferred_tracer_source_implementation(lambda T: TracerSource())
45+
tracer = trace.tracer_source().get_tracer(__name__)
4646

4747
# SpanExporter receives the spans and send them to the target location.
4848
span_processor = BatchExportSpanProcessor(exporter)
49-
tracer.add_span_processor(span_processor)
49+
trace.tracer_source().add_span_processor(span_processor)
5050

5151
# Integrations are the glue that binds the OpenTelemetry API and the
5252
# frameworks and libraries that are used together, automatically creating
5353
# Spans and propagating context as appropriate.
54-
http_requests.enable(tracer)
54+
http_requests.enable(trace.tracer_source())
5555
app = flask.Flask(__name__)
5656
app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app)
5757

examples/http/tracer_client.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from opentelemetry import trace
2222
from opentelemetry.ext import http_requests
23-
from opentelemetry.sdk.trace import Tracer
23+
from opentelemetry.sdk.trace import TracerSource
2424
from opentelemetry.sdk.trace.export import (
2525
BatchExportSpanProcessor,
2626
ConsoleSpanExporter,
@@ -39,15 +39,15 @@
3939

4040
# The preferred tracer implementation must be set, as the opentelemetry-api
4141
# defines the interface with a no-op implementation.
42-
trace.set_preferred_tracer_implementation(lambda T: Tracer())
43-
tracer = trace.tracer()
42+
trace.set_preferred_tracer_source_implementation(lambda T: TracerSource())
43+
tracer_source = trace.tracer_source()
4444

4545
# SpanExporter receives the spans and send them to the target location.
4646
span_processor = BatchExportSpanProcessor(exporter)
47-
tracer.add_span_processor(span_processor)
47+
tracer_source.add_span_processor(span_processor)
4848

4949
# Integrations are the glue that binds the OpenTelemetry API and the
5050
# frameworks and libraries that are used together, automatically creating
5151
# Spans and propagating context as appropriate.
52-
http_requests.enable(tracer)
52+
http_requests.enable(tracer_source)
5353
response = requests.get(url="http://127.0.0.1:5000/")

examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
the requests library to perform downstream requests
1818
"""
1919
import flask
20+
import pkg_resources
2021
import requests
2122

2223
import opentelemetry.ext.http_requests
2324
from opentelemetry import propagators, trace
2425
from opentelemetry.ext.flask import instrument_app
2526
from opentelemetry.sdk.context.propagation.b3_format import B3Format
26-
from opentelemetry.sdk.trace import Tracer
27+
from opentelemetry.sdk.trace import TracerSource
2728

2829

2930
def configure_opentelemetry(flask_app: flask.Flask):
@@ -45,7 +46,7 @@ def configure_opentelemetry(flask_app: flask.Flask):
4546
# the preferred implementation of these objects must be set,
4647
# as the opentelemetry-api defines the interface with a no-op
4748
# implementation.
48-
trace.set_preferred_tracer_implementation(lambda _: Tracer())
49+
trace.set_preferred_tracer_source_implementation(lambda _: TracerSource())
4950
# Next, we need to configure how the values that are used by
5051
# traces and metrics are propagated (such as what specific headers
5152
# carry this value).
@@ -56,7 +57,7 @@ def configure_opentelemetry(flask_app: flask.Flask):
5657
# Integrations are the glue that binds the OpenTelemetry API
5758
# and the frameworks and libraries that are used together, automatically
5859
# creating Spans and propagating context as appropriate.
59-
opentelemetry.ext.http_requests.enable(trace.tracer())
60+
opentelemetry.ext.http_requests.enable(trace.tracer_source())
6061
instrument_app(flask_app)
6162

6263

@@ -67,7 +68,11 @@ def configure_opentelemetry(flask_app: flask.Flask):
6768
def hello():
6869
# emit a trace that measures how long the
6970
# sleep takes
70-
with trace.tracer().start_as_current_span("example-request"):
71+
version = pkg_resources.get_distribution(
72+
"opentelemetry-example-app"
73+
).version
74+
tracer = trace.tracer_source().get_tracer(__name__, version)
75+
with tracer.start_as_current_span("example-request"):
7176
requests.get("http://www.example.com")
7277
return "hello"
7378

ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import opentelemetry.ext.wsgi as otel_wsgi
99
from opentelemetry import propagators, trace
10+
from opentelemetry.ext.flask.version import __version__
1011
from opentelemetry.util import time_ns
1112

1213
logger = logging.getLogger(__name__)
@@ -60,7 +61,7 @@ def _before_flask_request():
6061
otel_wsgi.get_header_from_environ, environ
6162
)
6263

63-
tracer = trace.tracer()
64+
tracer = trace.tracer_source().get_tracer(__name__, __version__)
6465

6566
attributes = otel_wsgi.collect_request_attributes(environ)
6667
if flask_request.url_rule:

ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
from opentelemetry import propagators
2626
from opentelemetry.context import Context
27+
from opentelemetry.ext.http_requests.version import __version__
2728
from opentelemetry.trace import SpanKind
2829

2930

@@ -32,7 +33,7 @@
3233
# if the SDK/tracer is already using `requests` they may, in theory, bypass our
3334
# instrumentation when using `import from`, etc. (currently we only instrument
3435
# a instance method so the probability for that is very low).
35-
def enable(tracer):
36+
def enable(tracer_source):
3637
"""Enables tracing of all requests calls that go through
3738
:code:`requests.session.Session.request` (this includes
3839
:code:`requests.get`, etc.)."""
@@ -47,6 +48,8 @@ def enable(tracer):
4748
# Guard against double instrumentation
4849
disable()
4950

51+
tracer = tracer_source.get_tracer(__name__, __version__)
52+
5053
wrapped = Session.request
5154

5255
@functools.wraps(wrapped)

ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py

+27-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import unittest
1717
from unittest import mock
1818

19+
import pkg_resources
1920
import requests
2021
import urllib3
2122

@@ -28,7 +29,16 @@ class TestRequestsIntegration(unittest.TestCase):
2829
# TODO: Copy & paste from test_wsgi_middleware
2930
def setUp(self):
3031
self.span_attrs = {}
31-
self.tracer = trace.tracer()
32+
self.tracer_source = trace.TracerSource()
33+
self.tracer = trace.Tracer()
34+
self.get_tracer_patcher = mock.patch.object(
35+
self.tracer_source,
36+
"get_tracer",
37+
autospec=True,
38+
spec_set=True,
39+
return_value=self.tracer,
40+
)
41+
self.get_tracer = self.get_tracer_patcher.start()
3242
self.span_context_manager = mock.MagicMock()
3343
self.span = mock.create_autospec(trace.Span, spec_set=True)
3444
self.span_context_manager.__enter__.return_value = self.span
@@ -45,7 +55,6 @@ def setspanattr(key, value):
4555
spec_set=True,
4656
return_value=self.span_context_manager,
4757
)
48-
self.start_as_current_span = self.start_span_patcher.start()
4958

5059
mocked_response = requests.models.Response()
5160
mocked_response.status_code = 200
@@ -57,20 +66,29 @@ def setspanattr(key, value):
5766
spec_set=True,
5867
return_value=mocked_response,
5968
)
69+
70+
self.start_as_current_span = self.start_span_patcher.start()
6071
self.send = self.send_patcher.start()
6172

62-
opentelemetry.ext.http_requests.enable(self.tracer)
73+
opentelemetry.ext.http_requests.enable(self.tracer_source)
74+
distver = pkg_resources.get_distribution(
75+
"opentelemetry-ext-http-requests"
76+
).version
77+
self.get_tracer.assert_called_with(
78+
opentelemetry.ext.http_requests.__name__, distver
79+
)
6380

6481
def tearDown(self):
6582
opentelemetry.ext.http_requests.disable()
83+
self.get_tracer_patcher.stop()
6684
self.send_patcher.stop()
6785
self.start_span_patcher.stop()
6886

6987
def test_basic(self):
7088
url = "https://www.example.org/foo/bar?x=y#top"
7189
requests.get(url=url)
7290
self.assertEqual(1, len(self.send.call_args_list))
73-
self.tracer.start_as_current_span.assert_called_with(
91+
self.tracer.start_as_current_span.assert_called_with( # pylint:disable=no-member
7492
"/foo/bar", kind=trace.SpanKind.CLIENT
7593
)
7694
self.span_context_manager.__enter__.assert_called_with()
@@ -96,11 +114,12 @@ def test_invalid_url(self):
96114

97115
with self.assertRaises(exception_type):
98116
requests.post(url=url)
117+
call_args = (
118+
self.tracer.start_as_current_span.call_args # pylint:disable=no-member
119+
)
99120
self.assertTrue(
100-
self.tracer.start_as_current_span.call_args[0][0].startswith(
101-
"<Unparsable URL"
102-
),
103-
msg=self.tracer.start_as_current_span.call_args,
121+
call_args[0][0].startswith("<Unparsable URL"),
122+
msg=self.tracer.start_as_current_span.call_args, # pylint:disable=no-member
104123
)
105124
self.span_context_manager.__enter__.assert_called_with()
106125
exitspan = self.span_context_manager.__exit__

ext/opentelemetry-ext-jaeger/README.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ gRPC is still not supported by this implementation.
3232
3333
from opentelemetry import trace
3434
from opentelemetry.ext import jaeger
35-
from opentelemetry.sdk.trace import Tracer
35+
from opentelemetry.sdk.trace import TracerSource
3636
from opentelemetry.sdk.trace.export import BatchExportSpanProcessor
3737
38-
trace.set_preferred_tracer_implementation(lambda T: Tracer())
39-
tracer = trace.tracer()
38+
trace.set_preferred_tracer_source_implementation(lambda T: TracerSource())
39+
tracer = trace.tracer_source().get_tracer(__name__)
4040
4141
# create a JaegerSpanExporter
4242
jaeger_exporter = jaeger.JaegerSpanExporter(

ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
from opentelemetry import trace
44
from opentelemetry.ext import jaeger
5-
from opentelemetry.sdk.trace import Tracer
5+
from opentelemetry.sdk.trace import TracerSource
66
from opentelemetry.sdk.trace.export import BatchExportSpanProcessor
77

8-
trace.set_preferred_tracer_implementation(lambda T: Tracer())
9-
tracer = trace.tracer()
8+
trace.set_preferred_tracer_source_implementation(lambda T: TracerSource())
9+
tracer = trace.tracer_source().get_tracer(__name__)
1010

1111
# create a JaegerSpanExporter
1212
jaeger_exporter = jaeger.JaegerSpanExporter(
@@ -25,8 +25,8 @@
2525
# create a BatchExportSpanProcessor and add the exporter to it
2626
span_processor = BatchExportSpanProcessor(jaeger_exporter)
2727

28-
# add to the tracer
29-
tracer.add_span_processor(span_processor)
28+
# add to the tracer factory
29+
trace.tracer_source().add_span_processor(span_processor)
3030

3131
# create some spans for testing
3232
with tracer.start_as_current_span("foo") as foo:

ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@
2929
import time
3030
3131
from opentelemetry import trace
32-
from opentelemetry.sdk.trace import Tracer
32+
from opentelemetry.sdk.trace import TracerSource
3333
from opentelemetry.ext.opentracing_shim import create_tracer
3434
3535
# Tell OpenTelemetry which Tracer implementation to use.
36-
trace.set_preferred_tracer_implementation(lambda T: Tracer())
36+
trace.set_preferred_tracer_source_implementation(lambda T: TracerSource())
37+
3738
# Create an OpenTelemetry Tracer.
38-
otel_tracer = trace.tracer()
39+
otel_tracer = trace.tracer_source().get_tracer(__name__)
40+
3941
# Create an OpenTracing shim.
4042
shim = create_tracer(otel_tracer)
4143
@@ -86,28 +88,29 @@
8688
import opentelemetry.trace as trace_api
8789
from opentelemetry import propagators
8890
from opentelemetry.ext.opentracing_shim import util
91+
from opentelemetry.ext.opentracing_shim.version import __version__
8992

9093
logger = logging.getLogger(__name__)
9194

9295

93-
def create_tracer(otel_tracer):
96+
def create_tracer(otel_tracer_source):
9497
"""Creates a :class:`TracerShim` object from the provided OpenTelemetry
95-
:class:`opentelemetry.trace.Tracer`.
98+
:class:`opentelemetry.trace.TracerSource`.
9699
97100
The returned :class:`TracerShim` is an implementation of
98101
:class:`opentracing.Tracer` using OpenTelemetry under the hood.
99102
100103
Args:
101-
otel_tracer: A :class:`opentelemetry.trace.Tracer` to be used for
102-
constructing the :class:`TracerShim`. This tracer will be used
104+
otel_tracer_source: A :class:`opentelemetry.trace.TracerSource` to be used for
105+
constructing the :class:`TracerShim`. A tracer from this source will be used
103106
to perform the actual tracing when user code is instrumented using
104107
the OpenTracing API.
105108
106109
Returns:
107110
The created :class:`TracerShim`.
108111
"""
109112

110-
return TracerShim(otel_tracer)
113+
return TracerShim(otel_tracer_source.get_tracer(__name__, __version__))
111114

112115

113116
class SpanContextShim(opentracing.SpanContext):

0 commit comments

Comments
 (0)