From d5c1da117b2674b82fb9fcb83522c4216098cf10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 22 Nov 2019 13:27:44 +0100 Subject: [PATCH 01/22] Named tracer. --- .../flask_example.py | 4 +- .../ext/http_requests/__init__.py | 7 +- .../tests/test_requests_integration.py | 7 +- .../ext/opentracing_shim/__init__.py | 9 +- .../tests/test_shim.py | 9 +- .../src/opentelemetry/ext/wsgi/__init__.py | 7 +- .../src/opentelemetry/trace/__init__.py | 59 +++++++--- opentelemetry-api/tests/mypysmoke.py | 4 +- opentelemetry-api/tests/test_loader.py | 8 +- .../src/opentelemetry/sdk/trace/__init__.py | 107 +++++++++++++++--- .../tests/trace/export/test_export.py | 4 +- .../export/test_in_memory_span_exporter.py | 6 +- opentelemetry-sdk/tests/trace/test_trace.py | 27 +++-- 13 files changed, 192 insertions(+), 66 deletions(-) diff --git a/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py b/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py index 18dffa30008..5bf0610d04c 100644 --- a/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py +++ b/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py @@ -23,7 +23,7 @@ from opentelemetry import propagators, trace from opentelemetry.ext.wsgi import OpenTelemetryMiddleware from opentelemetry.sdk.context.propagation.b3_format import B3Format -from opentelemetry.sdk.trace import Tracer +from opentelemetry.sdk.trace import TracerSource def configure_opentelemetry(flask_app: flask.Flask): @@ -45,7 +45,7 @@ def configure_opentelemetry(flask_app: flask.Flask): # the preferred implementation of these objects must be set, # as the opentelemetry-api defines the interface with a no-op # implementation. - trace.set_preferred_tracer_implementation(lambda _: Tracer()) + trace.set_preferred_tracer_source_implementation(lambda _: TracerSource()) # Next, we need to configure how the values that are used by # traces and metrics are propagated (such as what specific headers # carry this value). diff --git a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py index f05202c055a..5e7f5221870 100644 --- a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py +++ b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py @@ -24,6 +24,7 @@ from opentelemetry import propagators from opentelemetry.context import Context +from opentelemetry.ext.http_requests.version import __version__ from opentelemetry.trace import SpanKind @@ -32,7 +33,7 @@ # if the SDK/tracer is already using `requests` they may, in theory, bypass our # instrumentation when using `import from`, etc. (currently we only instrument # a instance method so the probability for that is very low). -def enable(tracer): +def enable(tracer_source): """Enables tracing of all requests calls that go through :code:`requests.session.Session.request` (this includes :code:`requests.get`, etc.).""" @@ -47,6 +48,10 @@ def enable(tracer): # Guard against double instrumentation disable() + tracer = tracer_source.get_tracer( + "opentelemetry-ext-http-requests", __version__ + ) + wrapped = Session.request @functools.wraps(wrapped) diff --git a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py index 2a02e1916ab..14696b3020d 100644 --- a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py +++ b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py @@ -28,7 +28,10 @@ class TestRequestsIntegration(unittest.TestCase): # TODO: Copy & paste from test_wsgi_middleware def setUp(self): self.span_attrs = {} - self.tracer = trace.tracer() + self.tracer_source = trace.TracerSource() + self.tracer_source.get_tracer = lambda _name, _version: self.tracer + + self.tracer = trace.Tracer() self.span_context_manager = mock.MagicMock() self.span = mock.create_autospec(trace.Span, spec_set=True) self.span_context_manager.__enter__.return_value = self.span @@ -59,7 +62,7 @@ def setspanattr(key, value): ) self.send = self.send_patcher.start() - opentelemetry.ext.http_requests.enable(self.tracer) + opentelemetry.ext.http_requests.enable(self.tracer_source) def tearDown(self): opentelemetry.ext.http_requests.disable() diff --git a/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py b/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py index eefb85466ae..43f2ad5c8de 100644 --- a/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py +++ b/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py @@ -20,12 +20,17 @@ import opentelemetry.trace as trace_api from opentelemetry import propagators from opentelemetry.ext.opentracing_shim import util +from opentelemetry.ext.opentracing_shim.version import __version__ logger = logging.getLogger(__name__) -def create_tracer(otel_tracer): - return TracerShim(otel_tracer) +def create_tracer(otel_tracer_source): + return TracerShim( + otel_tracer_source.get_tracer( + "opentelemetry-ext-opentracing-shim", __version__ + ) + ) class SpanContextShim(opentracing.SpanContext): diff --git a/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py b/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py index b1cefbcbb4c..6c04bcfac75 100644 --- a/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py +++ b/ext/opentelemetry-ext-opentracing-shim/tests/test_shim.py @@ -21,7 +21,7 @@ from opentelemetry import propagators, trace from opentelemetry.context.propagation.httptextformat import HTTPTextFormat from opentelemetry.ext.opentracing_shim import util -from opentelemetry.sdk.trace import Tracer +from opentelemetry.sdk.trace import TracerSource class TestShim(unittest.TestCase): @@ -30,8 +30,7 @@ class TestShim(unittest.TestCase): def setUp(self): """Create an OpenTelemetry tracer and a shim before every test case.""" - self.tracer = trace.tracer() - self.shim = opentracingshim.create_tracer(self.tracer) + self.shim = opentracingshim.create_tracer(trace.tracer_source()) @classmethod def setUpClass(cls): @@ -39,7 +38,9 @@ def setUpClass(cls): every test method. """ - trace.set_preferred_tracer_implementation(lambda T: Tracer()) + trace.set_preferred_tracer_source_implementation( + lambda T: TracerSource() + ) # Save current propagator to be restored on teardown. cls._previous_propagator = propagators.get_global_httptextformat() diff --git a/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py b/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py index 5e619eb7c6a..1ea204540f3 100644 --- a/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py +++ b/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py @@ -23,7 +23,7 @@ import wsgiref.util as wsgiref_util from opentelemetry import propagators, trace -from opentelemetry.ext.wsgi.version import __version__ # noqa +from opentelemetry.ext.wsgi.version import __version__ class OpenTelemetryMiddleware: @@ -38,6 +38,8 @@ class OpenTelemetryMiddleware: def __init__(self, wsgi): self.wsgi = wsgi + self.tracer = trace.tracer_source().get_tracer("opentelemetry-ext-wsgi", __version__) + @staticmethod def _add_request_attributes(span, environ): @@ -105,11 +107,10 @@ def __call__(self, environ, start_response): start_response: The WSGI start_response callable. """ - tracer = trace.tracer() path_info = environ["PATH_INFO"] or "/" parent_span = propagators.extract(_get_header_from_environ, environ) - span = tracer.create_span( + span = self.tracer.create_span( path_info, parent_span, kind=trace.SpanKind.SERVER ) span.start() diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 4f1dc539a39..d779e1c97cc 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -373,6 +373,35 @@ def is_recording_events(self) -> bool: INVALID_SPAN = DefaultSpan(INVALID_SPAN_CONTEXT) +class TracerSource: + def get_tracer( + self, + instrumenting_library_name: str, + instrumenting_library_version: str = "", + ) -> "Tracer": + """Returns a `Tracer` for use by the given instrumentation library. + + For any two calls it is undefined whether the same or + different `Tracer` instances are returned, even for different library names. + + This function may return different `Tracer` types (e.g. a no-op tracer vs. + a functional tracer). + + Args: + instrumenting_library_name: The name of the instrumenting library. + This should *not* be the name of the library that is + instrumented but the name of the instrumentation library. + E.g., instead of ``"requests"``, `"opentelemetry-ext-http-requests"`. + + This should be the `pip install`-able name of the library rather than the + module name (see also the next argument). + + instrumenting_library_version: Optional. The version string of the instrumenting library. + Usually this should be the same as + ``pkg_resources.get_distribution(instrumenting_library_name).version``. + """ + + class Tracer: """Handles span creation and in-process context propagation. @@ -565,29 +594,31 @@ def use_span( # the following type definition should be replaced with # from opentelemetry.util.loader import ImplementationFactory ImplementationFactory = typing.Callable[ - [typing.Type[Tracer]], typing.Optional[Tracer] + [typing.Type[TracerSource]], typing.Optional[TracerSource] ] -_TRACER = None # type: typing.Optional[Tracer] -_TRACER_FACTORY = None # type: typing.Optional[ImplementationFactory] +_TRACER_SOURCE = None # type: typing.Optional[TracerSource] +_TRACER_SOURCE_FACTORY = None # type: typing.Optional[ImplementationFactory] -def tracer() -> Tracer: +def tracer_source() -> TracerSource: """Gets the current global :class:`~.Tracer` object. If there isn't one set yet, a default will be loaded. """ - global _TRACER, _TRACER_FACTORY # pylint:disable=global-statement + global _TRACER_SOURCE, _TRACER_SOURCE_FACTORY # pylint:disable=global-statement - if _TRACER is None: + if _TRACER_SOURCE is None: # pylint:disable=protected-access - _TRACER = loader._load_impl(Tracer, _TRACER_FACTORY) - del _TRACER_FACTORY + _TRACER_SOURCE = loader._load_impl( + TracerSource, _TRACER_SOURCE_FACTORY + ) + del _TRACER_SOURCE_FACTORY - return _TRACER + return _TRACER_SOURCE -def set_preferred_tracer_implementation( +def set_preferred_tracer_source_implementation( factory: ImplementationFactory, ) -> None: """Set the factory to be used to create the tracer. @@ -599,9 +630,9 @@ def set_preferred_tracer_implementation( Args: factory: Callback that should create a new :class:`Tracer` instance. """ - global _TRACER_FACTORY # pylint:disable=global-statement + global _TRACER_SOURCE_FACTORY # pylint:disable=global-statement - if _TRACER: - raise RuntimeError("Tracer already loaded.") + if _TRACER_SOURCE: + raise RuntimeError("TracerSource already loaded.") - _TRACER_FACTORY = factory + _TRACER_SOURCE_FACTORY = factory diff --git a/opentelemetry-api/tests/mypysmoke.py b/opentelemetry-api/tests/mypysmoke.py index 7badc13b696..3f652adca15 100644 --- a/opentelemetry-api/tests/mypysmoke.py +++ b/opentelemetry-api/tests/mypysmoke.py @@ -15,5 +15,5 @@ import opentelemetry.trace -def dummy_check_mypy_returntype() -> opentelemetry.trace.Tracer: - return opentelemetry.trace.tracer() +def dummy_check_mypy_returntype() -> opentelemetry.trace.TracerSource: + return opentelemetry.trace.tracer_source() diff --git a/opentelemetry-api/tests/test_loader.py b/opentelemetry-api/tests/test_loader.py index 970b6159630..b96b8b90893 100644 --- a/opentelemetry-api/tests/test_loader.py +++ b/opentelemetry-api/tests/test_loader.py @@ -52,7 +52,7 @@ def test_get_default(self): self.assertIs(type(tracer), trace.Tracer) def test_preferred_impl(self): - trace.set_preferred_tracer_implementation( + trace.set_preferred_tracer_source_implementation( get_opentelemetry_implementation ) tracer = trace.tracer() @@ -66,7 +66,9 @@ def do_test_preferred_impl(self, setter: Callable[[Any], Any]) -> None: self.assertIs(tracer, DUMMY_TRACER) def test_preferred_impl_with_tracer(self): - self.do_test_preferred_impl(trace.set_preferred_tracer_implementation) + self.do_test_preferred_impl( + trace.set_preferred_tracer_source_implementation + ) def test_preferred_impl_with_default(self): self.do_test_preferred_impl( @@ -77,7 +79,7 @@ def test_try_set_again(self): self.assertTrue(trace.tracer()) # Try setting after the tracer has already been created: with self.assertRaises(RuntimeError) as einfo: - trace.set_preferred_tracer_implementation( + trace.set_preferred_tracer_source_implementation( get_opentelemetry_implementation ) self.assertIn("already loaded", str(einfo.exception)) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index 9ac9d81bc2c..3f6f922a94f 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -15,7 +15,9 @@ import logging import random +import sys import threading +from collections import namedtuple from contextlib import contextmanager from typing import Iterator, Optional, Sequence, Tuple @@ -133,6 +135,7 @@ def __init__( links: Sequence[trace_api.Link] = (), kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL, span_processor: SpanProcessor = SpanProcessor(), + creator_info: "InstrumentationInfo" = None, ) -> None: self.name = name @@ -166,6 +169,7 @@ def __init__( self.end_time = None # type: Optional[int] self.start_time = None # type: Optional[int] + self.creator_info = creator_info def __repr__(self): return '{}(name="{}", context={})'.format( @@ -291,6 +295,46 @@ def generate_trace_id() -> int: return random.getrandbits(128) +class InstrumentationInfo: + """Immutable information about an instrumentation library. + + See `TracerSource.get_tracer` for the meaning of the properties. + """ + + __slots__ = ("_name", "_version") + + def __init__(self, name: str, version: str): + self._name = name + self._version = version + + def __repr__(self): + return "{}({}, {})".format( + type(self).__name__, self._name, self._version + ) + + def __hash__(self): + return hash((self._name, self._version)) + + def __eq__(self, value): + return type(value) is type(self) and (self._name, self._version) == ( + value._name, + value._version, + ) + + def __lt__(self, value): + if type(value) is not type(self): + return NotImplemented + return (self._name, self._version) < (value._name, value._version) + + @property + def version(self) -> str: + return self._version + + @property + def name(self) -> str: + return self._name + + class Tracer(trace_api.Tracer): """See `opentelemetry.trace.Tracer`. @@ -300,19 +344,15 @@ class Tracer(trace_api.Tracer): def __init__( self, - name: str = "", - sampler: sampling.Sampler = trace_api.sampling.ALWAYS_ON, + source: "TracerSource", + instrumentation_info: InstrumentationInfo, ) -> None: - slot_name = "current_span" - if name: - slot_name = "{}.current_span".format(name) - self._current_span_slot = Context.register_slot(slot_name) - self._active_span_processor = MultiSpanProcessor() - self.sampler = sampler + self.source = source + self.instrumentation_info = instrumentation_info def get_current_span(self): """See `opentelemetry.trace.Tracer.get_current_span`.""" - return self._current_span_slot.get() + return self.source.get_current_span() def start_span( self, @@ -389,7 +429,7 @@ def create_span( # exported. # The sampler may also add attributes to the newly-created span, e.g. # to include information about the sampling decision. - sampling_decision = self.sampler.should_sample( + sampling_decision = self.source.sampler.should_sample( parent_context, context.trace_id, context.span_id, @@ -409,11 +449,12 @@ def create_span( name=name, context=context, parent=parent, - sampler=self.sampler, + sampler=self.source.sampler, attributes=span_attributes, - span_processor=self._active_span_processor, + span_processor=self.source._active_span_processor, # pylint:disable=protected-access kind=kind, links=links, + creator_info=self.instrumentation_info, ) return trace_api.DefaultSpan(context=context) @@ -424,12 +465,16 @@ def use_span( ) -> Iterator[trace_api.Span]: """See `opentelemetry.trace.Tracer.use_span`.""" try: - span_snapshot = self._current_span_slot.get() - self._current_span_slot.set(span) + span_snapshot = self.source.get_current_span() + self.source._current_span_slot.set( # pylint:disable=protected-access + span + ) try: yield span finally: - self._current_span_slot.set(span_snapshot) + self.source._current_span_slot.set( # pylint:disable=protected-access + span_snapshot + ) finally: if end_on_exit: span.end() @@ -442,7 +487,35 @@ def add_span_processor(self, span_processor: SpanProcessor) -> None: # no lock here because MultiSpanProcessor.add_span_processor is # thread safe - self._active_span_processor.add_span_processor(span_processor) + self.source._active_span_processor.add_span_processor( # pylint:disable=protected-access + span_processor + ) + +class TracerSource(trace_api.TracerSource): + def __init__( + self, sampler: sampling.Sampler = trace_api.sampling.ALWAYS_ON, + ): + # TODO: How should multiple TracerSources behave? Should they get their own contexts? + # This could be done by adding `str(id(self))` to the slot name. + self._current_span_slot = Context.register_slot("current_span") + self._active_span_processor = MultiSpanProcessor() + self.sampler = sampler -tracer = Tracer() + def get_tracer( + self, + instrumenting_library_name: str, + instrumenting_library_version: str = "", + ) -> "trace_api.Tracer": + if not instrumenting_library_name: # Reject empty strings too. + instrumenting_library_name = "ERROR:MISSING LIB NAME" + logger.error("get_tracer called with missing library name.") + return Tracer( + self, + InstrumentationInfo( + instrumenting_library_name, instrumenting_library_version + ), + ) + + def get_current_span(self) -> Span: + return self._current_span_slot.get() diff --git a/opentelemetry-sdk/tests/trace/export/test_export.py b/opentelemetry-sdk/tests/trace/export/test_export.py index d45afc299a2..d101473103c 100644 --- a/opentelemetry-sdk/tests/trace/export/test_export.py +++ b/opentelemetry-sdk/tests/trace/export/test_export.py @@ -40,7 +40,7 @@ def export(self, spans: trace.Span) -> export.SpanExportResult: class TestSimpleExportSpanProcessor(unittest.TestCase): def test_simple_span_processor(self): - tracer = trace.Tracer() + tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") spans_names_list = [] @@ -61,7 +61,7 @@ def test_simple_span_processor_no_context(self): SpanProcessors should act on a span's start and end events whether or not it is ever the active span. """ - tracer = trace.Tracer() + tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") spans_names_list = [] diff --git a/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py b/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py index b52d148c1b8..4915f2eaa0f 100644 --- a/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py +++ b/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py @@ -25,7 +25,7 @@ class TestInMemorySpanExporter(unittest.TestCase): def test_get_finished_spans(self): - tracer = trace.Tracer() + tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") memory_exporter = InMemorySpanExporter() span_processor = export.SimpleExportSpanProcessor(memory_exporter) @@ -41,7 +41,7 @@ def test_get_finished_spans(self): self.assertListEqual(["xxx", "bar", "foo"], spans_names_list) def test_clear(self): - tracer = trace.Tracer() + tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") memory_exporter = InMemorySpanExporter() span_processor = export.SimpleExportSpanProcessor(memory_exporter) @@ -57,7 +57,7 @@ def test_clear(self): self.assertEqual(len(span_list), 0) def test_shutdown(self): - tracer = trace.Tracer() + tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") memory_exporter = InMemorySpanExporter() span_processor = export.SimpleExportSpanProcessor(memory_exporter) diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 0d36c003e0f..97df07345cf 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -21,15 +21,20 @@ from opentelemetry.util import time_ns +def new_tracer() -> trace_api.Tracer: + return trace.TracerSource().get_tracer("opentelemetry-sdk") + + class TestTracer(unittest.TestCase): def test_extends_api(self): - tracer = trace.Tracer() + tracer = new_tracer() + self.assertIsInstance(tracer, trace.Tracer) self.assertIsInstance(tracer, trace_api.Tracer) class TestTracerSampling(unittest.TestCase): def test_default_sampler(self): - tracer = trace.Tracer() + tracer = new_tracer() # Check that the default tracer creates real spans via the default # sampler @@ -39,7 +44,7 @@ def test_default_sampler(self): self.assertIsInstance(child_span, trace.Span) def test_sampler_no_sampling(self): - tracer = trace.Tracer() + tracer = new_tracer() tracer.sampler = sampling.ALWAYS_OFF # Check that the default tracer creates no-op spans if the sampler @@ -58,7 +63,7 @@ def test_create_span_invalid_spancontext(self): Invalid span contexts should also not be added as a parent. This eliminates redundant error handling logic in exporters. """ - tracer = trace.Tracer("test_create_span_invalid_spancontext") + tracer = new_tracer() new_span = tracer.create_span( "root", parent=trace_api.INVALID_SPAN_CONTEXT ) @@ -66,7 +71,7 @@ def test_create_span_invalid_spancontext(self): self.assertIsNone(new_span.parent) def test_start_span_implicit(self): - tracer = trace.Tracer("test_start_span_implicit") + tracer = new_tracer() self.assertIsNone(tracer.get_current_span()) @@ -111,7 +116,7 @@ def test_start_span_implicit(self): self.assertIsNotNone(root.end_time) def test_start_span_explicit(self): - tracer = trace.Tracer("test_start_span_explicit") + tracer = new_tracer() other_parent = trace_api.SpanContext( trace_id=0x000000000000000000000000DEADBEEF, @@ -159,7 +164,7 @@ def test_start_span_explicit(self): self.assertIsNotNone(child.end_time) def test_start_as_current_span_implicit(self): - tracer = trace.Tracer("test_start_as_current_span_implicit") + tracer = new_tracer() self.assertIsNone(tracer.get_current_span()) @@ -179,7 +184,7 @@ def test_start_as_current_span_implicit(self): self.assertIsNotNone(root.end_time) def test_start_as_current_span_explicit(self): - tracer = trace.Tracer("test_start_as_current_span_explicit") + tracer = new_tracer() other_parent = trace_api.SpanContext( trace_id=0x000000000000000000000000DEADBEEF, @@ -214,7 +219,7 @@ def test_start_as_current_span_explicit(self): class TestSpan(unittest.TestCase): def setUp(self): - self.tracer = trace.Tracer("test_span") + self.tracer = new_tracer() def test_basic_span(self): span = trace.Span("name", mock.Mock(spec=trace_api.SpanContext)) @@ -473,7 +478,7 @@ def on_end(self, span: "trace.Span") -> None: class TestSpanProcessor(unittest.TestCase): def test_span_processor(self): - tracer = trace.Tracer() + tracer = new_tracer() spans_calls_list = [] # filled by MySpanProcessor expected_list = [] # filled by hand @@ -541,7 +546,7 @@ def test_span_processor(self): self.assertListEqual(spans_calls_list, expected_list) def test_add_span_processor_after_span_creation(self): - tracer = trace.Tracer() + tracer = new_tracer() spans_calls_list = [] # filled by MySpanProcessor expected_list = [] # filled by hand From 94c72f82415193b5243841b41aae4fee25c7e162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 22 Nov 2019 14:19:05 +0100 Subject: [PATCH 02/22] Adapt all the things to named tracers. --- .../flask_example.py | 11 ++++- .../tests/test_requests_integration.py | 11 ++--- .../src/opentelemetry/ext/wsgi/__init__.py | 9 ++-- .../tests/test_wsgi_middleware.py | 12 +++++- .../src/opentelemetry/trace/__init__.py | 2 + opentelemetry-api/tests/test_loader.py | 42 +++++++++---------- opentelemetry-sdk/tests/trace/test_trace.py | 13 ++++-- 7 files changed, 63 insertions(+), 37 deletions(-) diff --git a/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py b/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py index 5bf0610d04c..4e83ef83677 100644 --- a/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py +++ b/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py @@ -17,6 +17,7 @@ the requests library to perform downstream requests """ import flask +import pkg_resources import requests import opentelemetry.ext.http_requests @@ -56,7 +57,7 @@ def configure_opentelemetry(flask_app: flask.Flask): # Integrations are the glue that binds the OpenTelemetry API # and the frameworks and libraries that are used together, automatically # creating Spans and propagating context as appropriate. - opentelemetry.ext.http_requests.enable(trace.tracer()) + opentelemetry.ext.http_requests.enable(trace.tracer_source()) flask_app.wsgi_app = OpenTelemetryMiddleware(flask_app.wsgi_app) @@ -67,7 +68,13 @@ def configure_opentelemetry(flask_app: flask.Flask): def hello(): # emit a trace that measures how long the # sleep takes - with trace.tracer().start_as_current_span("example-request"): + version = pkg_resources.get_distribution( + "opentelemetry-example-app" + ).version + tracer = trace.tracer_source().get_tracer( + "opentelemetry-example-app", version + ) + with tracer.start_as_current_span("example-request"): requests.get("http://www.example.com") return "hello" diff --git a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py index 14696b3020d..5fd733b8a40 100644 --- a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py +++ b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py @@ -73,7 +73,7 @@ def test_basic(self): url = "https://www.example.org/foo/bar?x=y#top" requests.get(url=url) self.assertEqual(1, len(self.send.call_args_list)) - self.tracer.start_as_current_span.assert_called_with( + self.tracer.start_as_current_span.assert_called_with( # pylint:disable=no-member "/foo/bar", kind=trace.SpanKind.CLIENT ) self.span_context_manager.__enter__.assert_called_with() @@ -99,11 +99,12 @@ def test_invalid_url(self): with self.assertRaises(exception_type): requests.post(url=url) + call_args = ( + self.tracer.start_as_current_span.call_args # pylint:disable=no-member + ) self.assertTrue( - self.tracer.start_as_current_span.call_args[0][0].startswith( - " bool: class TracerSource: + # pylint:disable=no-self-use,unused-argument def get_tracer( self, instrumenting_library_name: str, @@ -400,6 +401,7 @@ def get_tracer( Usually this should be the same as ``pkg_resources.get_distribution(instrumenting_library_name).version``. """ + return Tracer() class Tracer: diff --git a/opentelemetry-api/tests/test_loader.py b/opentelemetry-api/tests/test_loader.py index b96b8b90893..92898b6547f 100644 --- a/opentelemetry-api/tests/test_loader.py +++ b/opentelemetry-api/tests/test_loader.py @@ -21,18 +21,18 @@ from opentelemetry import trace from opentelemetry.util import loader -DUMMY_TRACER = None +DUMMY_TRACER_SOURCE = None -class DummyTracer(trace.Tracer): +class DummyTracerSource(trace.TracerSource): pass def get_opentelemetry_implementation(type_): - global DUMMY_TRACER # pylint:disable=global-statement - assert type_ is trace.Tracer - DUMMY_TRACER = DummyTracer() - return DUMMY_TRACER + global DUMMY_TRACER_SOURCE # pylint:disable=global-statement + assert type_ is trace.TracerSource + DUMMY_TRACER_SOURCE = DummyTracerSource() + return DUMMY_TRACER_SOURCE # pylint:disable=redefined-outer-name,protected-access,unidiomatic-typecheck @@ -43,27 +43,27 @@ def setUp(self): reload(loader) reload(trace) - # Need to reload self, otherwise DummyTracer will have the wrong base + # Need to reload self, otherwise DummyTracerSource will have the wrong base # class after reloading `trace`. reload(sys.modules[__name__]) def test_get_default(self): - tracer = trace.tracer() - self.assertIs(type(tracer), trace.Tracer) + tracer_source = trace.tracer_source() + self.assertIs(type(tracer_source), trace.TracerSource) def test_preferred_impl(self): trace.set_preferred_tracer_source_implementation( get_opentelemetry_implementation ) - tracer = trace.tracer() - self.assertIs(tracer, DUMMY_TRACER) + tracer_source = trace.tracer_source() + self.assertIs(tracer_source, DUMMY_TRACER_SOURCE) # NOTE: We use do_* + *_ methods because subtest wouldn't run setUp, # which we require here. def do_test_preferred_impl(self, setter: Callable[[Any], Any]) -> None: setter(get_opentelemetry_implementation) - tracer = trace.tracer() - self.assertIs(tracer, DUMMY_TRACER) + tracer_source = trace.tracer_source() + self.assertIs(tracer_source, DUMMY_TRACER_SOURCE) def test_preferred_impl_with_tracer(self): self.do_test_preferred_impl( @@ -76,8 +76,8 @@ def test_preferred_impl_with_default(self): ) def test_try_set_again(self): - self.assertTrue(trace.tracer()) - # Try setting after the tracer has already been created: + self.assertTrue(trace.tracer_source()) + # Try setting after the tracer_source has already been created: with self.assertRaises(RuntimeError) as einfo: trace.set_preferred_tracer_source_implementation( get_opentelemetry_implementation @@ -85,7 +85,7 @@ def test_try_set_again(self): self.assertIn("already loaded", str(einfo.exception)) def do_test_get_envvar(self, envvar_suffix: str) -> None: - global DUMMY_TRACER # pylint:disable=global-statement + global DUMMY_TRACER_SOURCE # pylint:disable=global-statement # Test is not runnable with this! self.assertFalse(sys.flags.ignore_environment) @@ -93,15 +93,15 @@ def do_test_get_envvar(self, envvar_suffix: str) -> None: envname = "OPENTELEMETRY_PYTHON_IMPLEMENTATION_" + envvar_suffix os.environ[envname] = __name__ try: - tracer = trace.tracer() - self.assertIs(tracer, DUMMY_TRACER) + tracer_source = trace.tracer_source() + self.assertIs(tracer_source, DUMMY_TRACER_SOURCE) finally: - DUMMY_TRACER = None + DUMMY_TRACER_SOURCE = None del os.environ[envname] - self.assertIs(type(tracer), DummyTracer) + self.assertIs(type(tracer_source), DummyTracerSource) def test_get_envvar_tracer(self): - return self.do_test_get_envvar("TRACER") + return self.do_test_get_envvar("TRACERSOURCE") def test_get_envvar_default(self): return self.do_test_get_envvar("DEFAULT") diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 97df07345cf..2e03f04438e 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -44,8 +44,8 @@ def test_default_sampler(self): self.assertIsInstance(child_span, trace.Span) def test_sampler_no_sampling(self): - tracer = new_tracer() - tracer.sampler = sampling.ALWAYS_OFF + tracer_source = trace.TracerSource(sampling.ALWAYS_OFF) + tracer = tracer_source.get_tracer("opentelemetry-sdk") # Check that the default tracer creates no-op spans if the sampler # decides not to sampler @@ -266,14 +266,19 @@ def test_attributes(self): self.assertEqual(root.attributes["attr-key2"], "val2") self.assertEqual(root.attributes["attr-in-both"], "span-attr") + def test_sampling_attributes(self): decision_attributes = { "sampler-attr": "sample-val", "attr-in-both": "decision-attr", } - self.tracer.sampler = sampling.StaticSampler( - sampling.Decision(sampled=True, attributes=decision_attributes) + tracer_source = trace.TracerSource( + sampling.StaticSampler( + sampling.Decision(sampled=True, attributes=decision_attributes) + ) ) + self.tracer = tracer_source.get_tracer("opentelemetry-sdk") + with self.tracer.start_as_current_span("root2") as root: self.assertEqual(len(root.attributes), 2) self.assertEqual(root.attributes["sampler-attr"], "sample-val") From f1a23c12b201d28be640634a62acdb0934b84a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 22 Nov 2019 15:06:38 +0100 Subject: [PATCH 03/22] Fix examples, move add_span_processor to source. --- examples/basic_tracer/tracer.py | 12 +++- examples/http/server.py | 6 +- examples/http/tracer_client.py | 10 +-- .../src/opentelemetry/sdk/trace/__init__.py | 24 +++---- .../tests/trace/export/test_export.py | 10 +-- .../export/test_in_memory_span_exporter.py | 62 ++++++------------- opentelemetry-sdk/tests/trace/test_trace.py | 12 ++-- 7 files changed, 60 insertions(+), 76 deletions(-) diff --git a/examples/basic_tracer/tracer.py b/examples/basic_tracer/tracer.py index c99141f5aac..831da9136e0 100755 --- a/examples/basic_tracer/tracer.py +++ b/examples/basic_tracer/tracer.py @@ -18,7 +18,7 @@ from opentelemetry import trace from opentelemetry.context import Context -from opentelemetry.sdk.trace import Tracer +from opentelemetry.sdk.trace import TracerSource from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, @@ -37,8 +37,14 @@ # The preferred tracer implementation must be set, as the opentelemetry-api # defines the interface with a no-op implementation. -trace.set_preferred_tracer_implementation(lambda T: Tracer()) -tracer = trace.tracer() +trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) + +# We tell OpenTelemetry who it is that is creating spans. In this case, we have +# no real name (no setup.py), so we make one up. If we had a version, we would +# also specify it here. +tracer = trace.tracer_source().get_tracer( + "opentelemetry-examples-basic-tracer" +) # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) diff --git a/examples/http/server.py b/examples/http/server.py index 82cb070c272..b926cdfbe6c 100755 --- a/examples/http/server.py +++ b/examples/http/server.py @@ -22,7 +22,7 @@ from opentelemetry import trace from opentelemetry.ext import http_requests from opentelemetry.ext.wsgi import OpenTelemetryMiddleware -from opentelemetry.sdk.trace import Tracer +from opentelemetry.sdk.trace import TracerSource from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, @@ -41,8 +41,8 @@ # The preferred tracer implementation must be set, as the opentelemetry-api # defines the interface with a no-op implementation. -trace.set_preferred_tracer_implementation(lambda T: Tracer()) -tracer = trace.tracer() +trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) +tracer = trace.tracer_source().get_tracer("opentelemetry-example-http") # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) diff --git a/examples/http/tracer_client.py b/examples/http/tracer_client.py index 671d1d71f91..a71393763ef 100755 --- a/examples/http/tracer_client.py +++ b/examples/http/tracer_client.py @@ -20,7 +20,7 @@ from opentelemetry import trace from opentelemetry.ext import http_requests -from opentelemetry.sdk.trace import Tracer +from opentelemetry.sdk.trace import TracerSource from opentelemetry.sdk.trace.export import ( BatchExportSpanProcessor, ConsoleSpanExporter, @@ -39,16 +39,16 @@ # The preferred tracer implementation must be set, as the opentelemetry-api # defines the interface with a no-op implementation. -trace.set_preferred_tracer_implementation(lambda T: Tracer()) -tracer = trace.tracer() +trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) +tracer_source = trace.tracer_source() # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) -tracer.add_span_processor(span_processor) +tracer_source.add_span_processor(span_processor) # Integrations are the glue that binds the OpenTelemetry API and the # frameworks and libraries that are used together, automatically creating # Spans and propagating context as appropriate. -http_requests.enable(tracer) +http_requests.enable(tracer_source) response = requests.get(url="http://127.0.0.1:5000/") span_processor.shutdown() diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index 3f6f922a94f..aebede9ad74 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -15,9 +15,7 @@ import logging import random -import sys import threading -from collections import namedtuple from contextlib import contextmanager from typing import Iterator, Optional, Sequence, Tuple @@ -479,18 +477,6 @@ def use_span( if end_on_exit: span.end() - def add_span_processor(self, span_processor: SpanProcessor) -> None: - """Registers a new :class:`SpanProcessor` for this `Tracer`. - - The span processors are invoked in the same order they are registered. - """ - - # no lock here because MultiSpanProcessor.add_span_processor is - # thread safe - self.source._active_span_processor.add_span_processor( # pylint:disable=protected-access - span_processor - ) - class TracerSource(trace_api.TracerSource): def __init__( @@ -519,3 +505,13 @@ def get_tracer( def get_current_span(self) -> Span: return self._current_span_slot.get() + + def add_span_processor(self, span_processor: SpanProcessor) -> None: + """Registers a new :class:`SpanProcessor` for this `TracerSource`. + + The span processors are invoked in the same order they are registered. + """ + + # no lock here because MultiSpanProcessor.add_span_processor is + # thread safe + self._active_span_processor.add_span_processor(span_processor) diff --git a/opentelemetry-sdk/tests/trace/export/test_export.py b/opentelemetry-sdk/tests/trace/export/test_export.py index d101473103c..389dba14483 100644 --- a/opentelemetry-sdk/tests/trace/export/test_export.py +++ b/opentelemetry-sdk/tests/trace/export/test_export.py @@ -40,13 +40,14 @@ def export(self, spans: trace.Span) -> export.SpanExportResult: class TestSimpleExportSpanProcessor(unittest.TestCase): def test_simple_span_processor(self): - tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") + tracer_source = trace.TracerSource() + tracer = tracer_source.get_tracer("opentelemetry-sdk") spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list) span_processor = export.SimpleExportSpanProcessor(my_exporter) - tracer.add_span_processor(span_processor) + tracer_source.add_span_processor(span_processor) with tracer.start_as_current_span("foo"): with tracer.start_as_current_span("bar"): @@ -61,13 +62,14 @@ def test_simple_span_processor_no_context(self): SpanProcessors should act on a span's start and end events whether or not it is ever the active span. """ - tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") + tracer_source = trace.TracerSource() + tracer = tracer_source.get_tracer("opentelemetry-sdk") spans_names_list = [] my_exporter = MySpanExporter(destination=spans_names_list) span_processor = export.SimpleExportSpanProcessor(my_exporter) - tracer.add_span_processor(span_processor) + tracer_source.add_span_processor(span_processor) with tracer.start_span("foo"): with tracer.start_span("bar"): diff --git a/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py b/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py index 4915f2eaa0f..cf1db5c830e 100644 --- a/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py +++ b/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py @@ -24,62 +24,40 @@ class TestInMemorySpanExporter(unittest.TestCase): - def test_get_finished_spans(self): - tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") - - memory_exporter = InMemorySpanExporter() - span_processor = export.SimpleExportSpanProcessor(memory_exporter) - tracer.add_span_processor(span_processor) - - with tracer.start_as_current_span("foo"): - with tracer.start_as_current_span("bar"): - with tracer.start_as_current_span("xxx"): + def setUp(self): + self.tracer_source = trace.TracerSource() + self.tracer = self.tracer_source.get_tracer("opentelemetry-sdk") + self.memory_exporter = InMemorySpanExporter() + span_processor = export.SimpleExportSpanProcessor(self.memory_exporter) + self.tracer_source.add_span_processor(span_processor) + self.exec_scenario() + + def exec_scenario(self): + with self.tracer.start_as_current_span("foo"): + with self.tracer.start_as_current_span("bar"): + with self.tracer.start_as_current_span("xxx"): pass - span_list = memory_exporter.get_finished_spans() + def test_get_finished_spans(self): + span_list = self.memory_exporter.get_finished_spans() spans_names_list = [span.name for span in span_list] self.assertListEqual(["xxx", "bar", "foo"], spans_names_list) def test_clear(self): - tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") - - memory_exporter = InMemorySpanExporter() - span_processor = export.SimpleExportSpanProcessor(memory_exporter) - tracer.add_span_processor(span_processor) - - with tracer.start_as_current_span("foo"): - with tracer.start_as_current_span("bar"): - with tracer.start_as_current_span("xxx"): - pass - - memory_exporter.clear() - span_list = memory_exporter.get_finished_spans() + self.memory_exporter.clear() + span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 0) def test_shutdown(self): - tracer = trace.TracerSource().get_tracer("opentelemetry-sdk") - - memory_exporter = InMemorySpanExporter() - span_processor = export.SimpleExportSpanProcessor(memory_exporter) - tracer.add_span_processor(span_processor) - - with tracer.start_as_current_span("foo"): - with tracer.start_as_current_span("bar"): - with tracer.start_as_current_span("xxx"): - pass - - span_list = memory_exporter.get_finished_spans() + span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 3) - memory_exporter.shutdown() + self.memory_exporter.shutdown() # after shutdown no new spans are accepted - with tracer.start_as_current_span("foo"): - with tracer.start_as_current_span("bar"): - with tracer.start_as_current_span("xxx"): - pass + self.exec_scenario() - span_list = memory_exporter.get_finished_spans() + span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 3) def test_return_code(self): diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 2e03f04438e..decf7976eba 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -483,7 +483,8 @@ def on_end(self, span: "trace.Span") -> None: class TestSpanProcessor(unittest.TestCase): def test_span_processor(self): - tracer = new_tracer() + tracer_source = trace.TracerSource() + tracer = tracer_source.get_tracer("opentelemetry-sdk") spans_calls_list = [] # filled by MySpanProcessor expected_list = [] # filled by hand @@ -501,7 +502,7 @@ def test_span_processor(self): self.assertEqual(len(spans_calls_list), 0) # add single span processor - tracer.add_span_processor(sp1) + tracer_source.add_span_processor(sp1) with tracer.start_as_current_span("foo"): expected_list.append(span_event_start_fmt("SP1", "foo")) @@ -524,7 +525,7 @@ def test_span_processor(self): expected_list.clear() # go for multiple span processors - tracer.add_span_processor(sp2) + tracer_source.add_span_processor(sp2) with tracer.start_as_current_span("foo"): expected_list.append(span_event_start_fmt("SP1", "foo")) @@ -551,7 +552,8 @@ def test_span_processor(self): self.assertListEqual(spans_calls_list, expected_list) def test_add_span_processor_after_span_creation(self): - tracer = new_tracer() + tracer_source = trace.TracerSource() + tracer = tracer_source.get_tracer("opentelemetry-sdk") spans_calls_list = [] # filled by MySpanProcessor expected_list = [] # filled by hand @@ -563,7 +565,7 @@ def test_add_span_processor_after_span_creation(self): with tracer.start_as_current_span("bar"): with tracer.start_as_current_span("baz"): # add span processor after spans have been created - tracer.add_span_processor(sp) + tracer_source.add_span_processor(sp) expected_list.append(span_event_end_fmt("SP1", "baz")) From d91e5dd6ad1f3b89b18ee753e4f9864bed9015a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 22 Nov 2019 15:16:35 +0100 Subject: [PATCH 04/22] Fix examples for add_span_processor move. --- examples/basic_tracer/tracer.py | 2 +- examples/http/server.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/basic_tracer/tracer.py b/examples/basic_tracer/tracer.py index 831da9136e0..89eacb39cfe 100755 --- a/examples/basic_tracer/tracer.py +++ b/examples/basic_tracer/tracer.py @@ -49,7 +49,7 @@ # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) -tracer.add_span_processor(span_processor) +trace.tracer_source().add_span_processor(span_processor) with tracer.start_as_current_span("foo"): with tracer.start_as_current_span("bar"): with tracer.start_as_current_span("baz"): diff --git a/examples/http/server.py b/examples/http/server.py index b926cdfbe6c..897628c39a1 100755 --- a/examples/http/server.py +++ b/examples/http/server.py @@ -46,7 +46,7 @@ # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) -tracer.add_span_processor(span_processor) +trace.tracer_source().add_span_processor(span_processor) # Integrations are the glue that binds the OpenTelemetry API and the # frameworks and libraries that are used together, automatically creating From 2f95b61df837d92485c5fdee2eb3bac72845b44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 22 Nov 2019 15:36:34 +0100 Subject: [PATCH 05/22] Fix examples for good. --- examples/http/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/http/server.py b/examples/http/server.py index 897628c39a1..953de27083d 100755 --- a/examples/http/server.py +++ b/examples/http/server.py @@ -51,7 +51,7 @@ # Integrations are the glue that binds the OpenTelemetry API and the # frameworks and libraries that are used together, automatically creating # Spans and propagating context as appropriate. -http_requests.enable(tracer) +http_requests.enable(trace.tracer_source()) app = flask.Flask(__name__) app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app) From 8014e52940e3c153e12a9c65794b48b2ba46dd7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 22 Nov 2019 15:58:00 +0100 Subject: [PATCH 06/22] Add unit tests. --- .../tests/test_requests_integration.py | 14 ++++++++++++-- opentelemetry-sdk/tests/trace/test_trace.py | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py index 5fd733b8a40..97a1970c8d2 100644 --- a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py +++ b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py @@ -16,6 +16,7 @@ import unittest from unittest import mock +import pkg_resources import requests import urllib3 @@ -29,9 +30,15 @@ class TestRequestsIntegration(unittest.TestCase): def setUp(self): self.span_attrs = {} self.tracer_source = trace.TracerSource() - self.tracer_source.get_tracer = lambda _name, _version: self.tracer - self.tracer = trace.Tracer() + self.get_tracer_patcher = mock.patch.object( + self.tracer_source, + "get_tracer", + autospec=True, + spec_set=True, + return_value=self.tracer, + ) + self.get_tracer = self.get_tracer_patcher.start() self.span_context_manager = mock.MagicMock() self.span = mock.create_autospec(trace.Span, spec_set=True) self.span_context_manager.__enter__.return_value = self.span @@ -63,9 +70,12 @@ def setspanattr(key, value): self.send = self.send_patcher.start() opentelemetry.ext.http_requests.enable(self.tracer_source) + distver = pkg_resources.get_distribution("opentelemetry-ext-http-requests").version + self.get_tracer.assert_called_with("opentelemetry-ext-http-requests", distver) def tearDown(self): opentelemetry.ext.http_requests.disable() + self.get_tracer_patcher.stop() self.send_patcher.stop() self.start_span_patcher.stop() diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index decf7976eba..e01961651bb 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -70,6 +70,24 @@ def test_create_span_invalid_spancontext(self): self.assertTrue(new_span.context.is_valid()) self.assertIsNone(new_span.parent) + def test_creator_info(self): + tracer_source = trace.TracerSource() + tracer1 = tracer_source.get_tracer("instr1") + tracer2 = tracer_source.get_tracer("instr2", "1.3b3") + span1 = tracer1.start_span("s1") + span2 = tracer2.start_span("s2") + self.assertEqual(span1.creator_info, trace.InstrumentationInfo("instr1", "")) + self.assertEqual(span2.creator_info, trace.InstrumentationInfo("instr2", "1.3b3")) + + def test_span_processor(self): + tracer_source = trace.TracerSource() + tracer1 = tracer_source.get_tracer("instr1") + tracer2 = tracer_source.get_tracer("instr2", "1.3b3") + span1 = tracer1.start_span("s1") + span2 = tracer2.start_span("s2") + self.assertIs(span1.span_processor, tracer_source._active_span_processor) + self.assertIs(span2.span_processor, tracer_source._active_span_processor) + def test_start_span_implicit(self): tracer = new_tracer() From fbf4a1e66d0c2def12178140747dbbea12e40026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 22 Nov 2019 16:10:48 +0100 Subject: [PATCH 07/22] Fix W3C tests, lint, docs. --- .../tests/test_requests_integration.py | 8 ++++++-- .../src/opentelemetry/trace/__init__.py | 4 ++-- .../src/opentelemetry/util/loader.py | 8 ++++---- opentelemetry-sdk/tests/trace/test_trace.py | 20 ++++++++++++++----- tests/w3c_tracecontext_validation_server.py | 8 ++++---- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py index 97a1970c8d2..f952638bdbe 100644 --- a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py +++ b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py @@ -70,8 +70,12 @@ def setspanattr(key, value): self.send = self.send_patcher.start() opentelemetry.ext.http_requests.enable(self.tracer_source) - distver = pkg_resources.get_distribution("opentelemetry-ext-http-requests").version - self.get_tracer.assert_called_with("opentelemetry-ext-http-requests", distver) + distver = pkg_resources.get_distribution( + "opentelemetry-ext-http-requests" + ).version + self.get_tracer.assert_called_with( + "opentelemetry-ext-http-requests", distver + ) def tearDown(self): opentelemetry.ext.http_requests.disable() diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 5da7ec54ff3..4b38a2a4807 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -392,9 +392,9 @@ def get_tracer( instrumenting_library_name: The name of the instrumenting library. This should *not* be the name of the library that is instrumented but the name of the instrumentation library. - E.g., instead of ``"requests"``, `"opentelemetry-ext-http-requests"`. + E.g., instead of ``"requests"``, ``"opentelemetry-ext-http-requests"``. - This should be the `pip install`-able name of the library rather than the + This should be the ``pip install``-able name of the library rather than the module name (see also the next argument). instrumenting_library_version: Optional. The version string of the instrumenting library. diff --git a/opentelemetry-api/src/opentelemetry/util/loader.py b/opentelemetry-api/src/opentelemetry/util/loader.py index 3ae5a52fc51..c8edf2ad4ae 100644 --- a/opentelemetry-api/src/opentelemetry/util/loader.py +++ b/opentelemetry-api/src/opentelemetry/util/loader.py @@ -15,7 +15,7 @@ """ The OpenTelemetry loader module is mainly used internally to load the -implementation for global objects like :func:`opentelemetry.trace.tracer`. +implementation for global objects like :func:`opentelemetry.trace.tracer_source`. .. _loader-factory: @@ -27,7 +27,7 @@ def my_factory_for_t(api_type: typing.Type[T]) -> typing.Optional[T]: That function is called with e.g., the type of the global object it should create as an argument (e.g. the type object -:class:`opentelemetry.trace.Tracer`) and should return an instance of that type +:class:`opentelemetry.trace.TracerSource`) and should return an instance of that type (such that ``instanceof(my_factory_for_t(T), T)`` is true). Alternatively, it may return ``None`` to indicate that the no-op default should be used. @@ -36,14 +36,14 @@ def my_factory_for_t(api_type: typing.Type[T]) -> typing.Optional[T]: 1. If the environment variable :samp:`OPENTELEMETRY_PYTHON_IMPLEMENTATION_{getter-name}` (e.g., - ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_TRACER``) is set to an nonempty + ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_TRACERSOURCE``) is set to an nonempty value, an attempt is made to import a module with that name and use a factory function named ``get_opentelemetry_implementation`` in it. 2. Otherwise, the same is tried with the environment variable ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_DEFAULT``. 3. Otherwise, if a :samp:`set_preferred_{}_implementation` was called (e.g. - :func:`opentelemetry.trace.set_preferred_tracer_implementation`), the + :func:`opentelemetry.trace.set_preferred_tracer_source_implementation`), the callback set there is used (that is, the environment variables override the callback set in code). 4. Otherwise, if :func:`set_preferred_default_implementation` was called, diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index e01961651bb..fb2ef7fd11d 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -76,17 +76,27 @@ def test_creator_info(self): tracer2 = tracer_source.get_tracer("instr2", "1.3b3") span1 = tracer1.start_span("s1") span2 = tracer2.start_span("s2") - self.assertEqual(span1.creator_info, trace.InstrumentationInfo("instr1", "")) - self.assertEqual(span2.creator_info, trace.InstrumentationInfo("instr2", "1.3b3")) + self.assertEqual( + span1.creator_info, trace.InstrumentationInfo("instr1", "") + ) + self.assertEqual( + span2.creator_info, trace.InstrumentationInfo("instr2", "1.3b3") + ) - def test_span_processor(self): + def test_span_processor_for_source(self): tracer_source = trace.TracerSource() tracer1 = tracer_source.get_tracer("instr1") tracer2 = tracer_source.get_tracer("instr2", "1.3b3") span1 = tracer1.start_span("s1") span2 = tracer2.start_span("s2") - self.assertIs(span1.span_processor, tracer_source._active_span_processor) - self.assertIs(span2.span_processor, tracer_source._active_span_processor) + + # pylint:disable=protected-access + self.assertIs( + span1.span_processor, tracer_source._active_span_processor + ) + self.assertIs( + span2.span_processor, tracer_source._active_span_processor + ) def test_start_span_implicit(self): tracer = new_tracer() diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index a26141f14c8..bea4d4fde55 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -26,7 +26,7 @@ from opentelemetry import trace from opentelemetry.ext import http_requests from opentelemetry.ext.wsgi import OpenTelemetryMiddleware -from opentelemetry.sdk.trace import Tracer +from opentelemetry.sdk.trace import TracerSource from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, SimpleExportSpanProcessor, @@ -34,16 +34,16 @@ # The preferred tracer implementation must be set, as the opentelemetry-api # defines the interface with a no-op implementation. -trace.set_preferred_tracer_implementation(lambda T: Tracer()) +trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) # Integrations are the glue that binds the OpenTelemetry API and the # frameworks and libraries that are used together, automatically creating # Spans and propagating context as appropriate. -http_requests.enable(trace.tracer()) +http_requests.enable(trace.tracer_source()) # SpanExporter receives the spans and send them to the target location. span_processor = SimpleExportSpanProcessor(ConsoleSpanExporter()) -trace.tracer().add_span_processor(span_processor) +trace.tracer_source().add_span_processor(span_processor) app = flask.Flask(__name__) app.wsgi_app = OpenTelemetryMiddleware(app.wsgi_app) From 716ead78ef73ad7d1c61d0bd9b69bb555cc181f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 22 Nov 2019 16:32:56 +0100 Subject: [PATCH 08/22] Increase test coverage. --- opentelemetry-sdk/tests/trace/test_trace.py | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index fb2ef7fd11d..5b7845d6da9 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -83,6 +83,30 @@ def test_creator_info(self): span2.creator_info, trace.InstrumentationInfo("instr2", "1.3b3") ) + self.assertEqual(span2.creator_info.version, "1.3b3") + self.assertEqual(span2.creator_info.name, "instr2") + + self.assertLess( + span1.creator_info, span2.creator_info + ) # Check sortability. + + def test_invalid_creator_info(self): + tracer_source = trace.TracerSource() + tracer1 = tracer_source.get_tracer("") + tracer2 = tracer_source.get_tracer(None) + self.assertEqual( + tracer1.instrumentation_info, tracer2.instrumentation_info + ) + self.assertIsInstance( + tracer1.instrumentation_info, trace.InstrumentationInfo + ) + span1 = tracer1.start_span("foo") + self.assertTrue(span1.is_recording_events()) + self.assertEqual(tracer1.instrumentation_info.version, "") + self.assertEqual( + tracer1.instrumentation_info.name, "ERROR:MISSING LIB NAME" + ) + def test_span_processor_for_source(self): tracer_source = trace.TracerSource() tracer1 = tracer_source.get_tracer("instr1") From 7e9dad71ca7c3ce12919f445a0c478a908c93121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Mon, 25 Nov 2019 10:49:59 +0100 Subject: [PATCH 09/22] Adapt flask extension for named tracers. --- .../src/opentelemetry/ext/flask/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py index eedc8d59988..2ac8573462c 100644 --- a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py +++ b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py @@ -7,6 +7,7 @@ import opentelemetry.ext.wsgi as otel_wsgi from opentelemetry import propagators, trace +from opentelemetry.ext.flask.version import __version__ from opentelemetry.util import time_ns logger = logging.getLogger(__name__) @@ -60,7 +61,9 @@ def _before_flask_request(): otel_wsgi.get_header_from_environ, environ ) - tracer = trace.tracer() + tracer = trace.tracer_source().get_tracer( + "opentelemetry-ext-flask", __version__ + ) span = tracer.create_span( span_name, parent_span, kind=trace.SpanKind.SERVER From 009418a1db7dd0a4b81c70bea0798089ae7da9b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Mon, 25 Nov 2019 11:17:32 +0100 Subject: [PATCH 10/22] Fix mismerge of da8b8d907c29fc358ca635114dac2967b6501563. --- .../src/opentelemetry/ext/testutil/wsgitestutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py b/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py index d3f0957f70b..159faad504d 100644 --- a/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py +++ b/ext/opentelemetry-ext-testutil/src/opentelemetry/ext/testutil/wsgitestutil.py @@ -44,7 +44,7 @@ def tearDown(self): def start_response(self, status, response_headers, exc_info=None): # The span should have started already - self.span.start.assert_called_once_with() + self.assertEqual(self.span.start.call_count, 1) self.status = status self.response_headers = response_headers From 9163c9b921ec5e3951a21736316318adf41f2175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Thu, 5 Dec 2019 16:53:55 +0100 Subject: [PATCH 11/22] Fix tracer -> tracer source in comments/doc. Co-Authored-By: alrex --- opentelemetry-api/src/opentelemetry/trace/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index dd24ec7be46..7025ed921f4 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -567,14 +567,14 @@ def tracer_source() -> TracerSource: def set_preferred_tracer_source_implementation( factory: ImplementationFactory, ) -> None: - """Set the factory to be used to create the tracer. + """Set the factory to be used to create the tracer source. See :mod:`opentelemetry.util.loader` for details. This function may not be called after a tracer is already loaded. Args: - factory: Callback that should create a new :class:`Tracer` instance. + factory: Callback that should create a new :class:`TracerSource` instance. """ global _TRACER_SOURCE_FACTORY # pylint:disable=global-statement From ab805d21e1288a5d5522855cdcb56f39c44c87eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Thu, 5 Dec 2019 16:54:22 +0100 Subject: [PATCH 12/22] Update opentelemetry-api/src/opentelemetry/trace/__init__.py Co-Authored-By: alrex --- opentelemetry-api/src/opentelemetry/trace/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 7025ed921f4..d72c3d79bec 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -548,7 +548,7 @@ def use_span( def tracer_source() -> TracerSource: - """Gets the current global :class:`~.Tracer` object. + """Gets the current global :class:`~.TracerSource` object. If there isn't one set yet, a default will be loaded. """ From 2aa258ae97f34fdf35bdbb82da02bfda9112a7fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Thu, 5 Dec 2019 18:24:17 +0100 Subject: [PATCH 13/22] Adjust new tests to named tracers. --- .../src/opentelemetry/trace/__init__.py | 4 ++-- .../src/opentelemetry/sdk/trace/__init__.py | 7 +++---- opentelemetry-sdk/tests/trace/test_trace.py | 14 +++++++------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index d72c3d79bec..7078ddf1c88 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -548,7 +548,7 @@ def use_span( def tracer_source() -> TracerSource: - """Gets the current global :class:`~.TracerSource` object. + """Gets the current global :class:`~.TracerSource` object. If there isn't one set yet, a default will be loaded. """ @@ -567,7 +567,7 @@ def tracer_source() -> TracerSource: def set_preferred_tracer_source_implementation( factory: ImplementationFactory, ) -> None: - """Set the factory to be used to create the tracer source. + """Set the factory to be used to create the tracer source. See :mod:`opentelemetry.util.loader` for details. diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index 9deafa4bc8c..b0c58d645a4 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -465,7 +465,9 @@ def use_span( class TracerSource(trace_api.TracerSource): def __init__( - self, sampler: sampling.Sampler = trace_api.sampling.ALWAYS_ON, shutdown_on_exit: bool = True + self, + sampler: sampling.Sampler = trace_api.sampling.ALWAYS_ON, + shutdown_on_exit: bool = True, ): # TODO: How should multiple TracerSources behave? Should they get their own contexts? # This could be done by adding `str(id(self))` to the slot name. @@ -510,6 +512,3 @@ def shutdown(self): if self._atexit_handler is not None: atexit.unregister(self._atexit_handler) self._atexit_handler = None - - -tracer = Tracer() diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 239c58d6580..797c82957cf 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -34,15 +34,15 @@ def test_extends_api(self): self.assertIsInstance(tracer, trace_api.Tracer) def test_shutdown(self): - tracer = trace.Tracer() + tracer_source = trace.TracerSource() mock_processor1 = mock.Mock(spec=trace.SpanProcessor) - tracer.add_span_processor(mock_processor1) + tracer_source.add_span_processor(mock_processor1) mock_processor2 = mock.Mock(spec=trace.SpanProcessor) - tracer.add_span_processor(mock_processor2) + tracer_source.add_span_processor(mock_processor2) - tracer.shutdown() + tracer_source.shutdown() self.assertEqual(mock_processor1.shutdown.call_count, 1) self.assertEqual(mock_processor2.shutdown.call_count, 1) @@ -62,8 +62,8 @@ def print_shutdown_count(): # creating the tracer atexit.register(print_shutdown_count) -tracer = trace.Tracer({tracer_parameters}) -tracer.add_span_processor(mock_processor) +tracer_source = trace.TracerSource({tracer_parameters}) +tracer_source.add_span_processor(mock_processor) {tracer_shutdown} """ @@ -76,7 +76,7 @@ def run_general_code(shutdown_on_exit, explicit_shutdown): tracer_parameters = "shutdown_on_exit=False" if explicit_shutdown: - tracer_shutdown = "tracer.shutdown()" + tracer_shutdown = "tracer_source.shutdown()" return subprocess.check_output( [ From f05eaaf875587f75e1332f7427dcbdc2ee0f9bb1 Mon Sep 17 00:00:00 2001 From: Chris Kleinknecht Date: Fri, 6 Dec 2019 13:15:35 -0800 Subject: [PATCH 14/22] Rewrap comments --- .../src/opentelemetry/trace/__init__.py | 22 ++++++++++--------- .../src/opentelemetry/util/loader.py | 21 +++++++++--------- opentelemetry-api/tests/test_loader.py | 4 ++-- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 7078ddf1c88..18268bf0d0c 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -369,23 +369,24 @@ def get_tracer( ) -> "Tracer": """Returns a `Tracer` for use by the given instrumentation library. - For any two calls it is undefined whether the same or - different `Tracer` instances are returned, even for different library names. + For any two calls it is undefined whether the same or different + `Tracer` instances are returned, even for different library names. - This function may return different `Tracer` types (e.g. a no-op tracer vs. - a functional tracer). + This function may return different `Tracer` types (e.g. a no-op tracer + vs. a functional tracer). Args: instrumenting_library_name: The name of the instrumenting library. This should *not* be the name of the library that is instrumented but the name of the instrumentation library. - E.g., instead of ``"requests"``, ``"opentelemetry-ext-http-requests"``. + E.g., instead of ``"requests"``, + ``"opentelemetry-ext-http-requests"``. - This should be the ``pip install``-able name of the library rather than the - module name (see also the next argument). + This should be the ``pip install``-able name of the library + rather than the module name (see also the next argument). - instrumenting_library_version: Optional. The version string of the instrumenting library. - Usually this should be the same as + instrumenting_library_version: Optional. The version string of the + instrumenting library. Usually this should be the same as ``pkg_resources.get_distribution(instrumenting_library_name).version``. """ return Tracer() @@ -574,7 +575,8 @@ def set_preferred_tracer_source_implementation( This function may not be called after a tracer is already loaded. Args: - factory: Callback that should create a new :class:`TracerSource` instance. + factory: Callback that should create a new :class:`TracerSource` + instance. """ global _TRACER_SOURCE_FACTORY # pylint:disable=global-statement diff --git a/opentelemetry-api/src/opentelemetry/util/loader.py b/opentelemetry-api/src/opentelemetry/util/loader.py index c8edf2ad4ae..e95028eec1d 100644 --- a/opentelemetry-api/src/opentelemetry/util/loader.py +++ b/opentelemetry-api/src/opentelemetry/util/loader.py @@ -15,7 +15,8 @@ """ The OpenTelemetry loader module is mainly used internally to load the -implementation for global objects like :func:`opentelemetry.trace.tracer_source`. +implementation for global objects like +:func:`opentelemetry.trace.tracer_source`. .. _loader-factory: @@ -35,17 +36,17 @@ def my_factory_for_t(api_type: typing.Type[T]) -> typing.Optional[T]: factory function or other means to create the global object: 1. If the environment variable - :samp:`OPENTELEMETRY_PYTHON_IMPLEMENTATION_{getter-name}` (e.g., - ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_TRACERSOURCE``) is set to an nonempty - value, an attempt is made to import a module with that name and use a - factory function named ``get_opentelemetry_implementation`` in it. - 2. Otherwise, the same is tried with the environment - variable ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_DEFAULT``. + :samp:`OPENTELEMETRY_PYTHON_IMPLEMENTATION_{getter-name}` (e.g., + ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_TRACERSOURCE``) is set to an + nonempty value, an attempt is made to import a module with that name and + use a factory function named ``get_opentelemetry_implementation`` in it. + 2. Otherwise, the same is tried with the environment variable + ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_DEFAULT``. 3. Otherwise, if a :samp:`set_preferred_{}_implementation` was called (e.g. - :func:`opentelemetry.trace.set_preferred_tracer_source_implementation`), the - callback set there is used (that is, the environment variables override - the callback set in code). + :func:`opentelemetry.trace.set_preferred_tracer_source_implementation`), + the callback set there is used (that is, the environment variables + override the callback set in code). 4. Otherwise, if :func:`set_preferred_default_implementation` was called, the callback set there is used. 5. Otherwise, an attempt is made to import and use the OpenTelemetry SDK. diff --git a/opentelemetry-api/tests/test_loader.py b/opentelemetry-api/tests/test_loader.py index 92898b6547f..8ac397afcb3 100644 --- a/opentelemetry-api/tests/test_loader.py +++ b/opentelemetry-api/tests/test_loader.py @@ -43,8 +43,8 @@ def setUp(self): reload(loader) reload(trace) - # Need to reload self, otherwise DummyTracerSource will have the wrong base - # class after reloading `trace`. + # Need to reload self, otherwise DummyTracerSource will have the wrong + # base class after reloading `trace`. reload(sys.modules[__name__]) def test_get_default(self): From a6a26707ffd0fc2b2bb4b5b37188f443b93911a4 Mon Sep 17 00:00:00 2001 From: Chris Kleinknecht Date: Fri, 6 Dec 2019 13:24:24 -0800 Subject: [PATCH 15/22] Fix stray examples --- README.md | 8 ++++---- ext/opentelemetry-ext-jaeger/README.rst | 6 +++--- .../examples/jaeger_exporter_example.py | 10 +++++----- .../src/opentelemetry/ext/opentracing_shim/__init__.py | 8 +++++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 793d46d5884..50016f49815 100644 --- a/README.md +++ b/README.md @@ -52,15 +52,15 @@ pip install -e ./ext/opentelemetry-ext-{integration} ```python from opentelemetry import trace from opentelemetry.context import Context -from opentelemetry.sdk.trace import Tracer +from opentelemetry.sdk.trace import TracerSource from opentelemetry.sdk.trace.export import ConsoleSpanExporter from opentelemetry.sdk.trace.export import SimpleExportSpanProcessor -trace.set_preferred_tracer_implementation(lambda T: Tracer()) -tracer = trace.tracer() -tracer.add_span_processor( +trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) +trace.tracer_source().add_span_processor( SimpleExportSpanProcessor(ConsoleSpanExporter()) ) +tracer = trace.tracer_source().get_tracer("myapp") with tracer.start_as_current_span('foo'): with tracer.start_as_current_span('bar'): with tracer.start_as_current_span('baz'): diff --git a/ext/opentelemetry-ext-jaeger/README.rst b/ext/opentelemetry-ext-jaeger/README.rst index 742ec6220fe..83bf2eb5d70 100644 --- a/ext/opentelemetry-ext-jaeger/README.rst +++ b/ext/opentelemetry-ext-jaeger/README.rst @@ -32,11 +32,11 @@ gRPC is still not supported by this implementation. from opentelemetry import trace from opentelemetry.ext import jaeger - from opentelemetry.sdk.trace import Tracer + from opentelemetry.sdk.trace import TracerSource from opentelemetry.sdk.trace.export import BatchExportSpanProcessor - trace.set_preferred_tracer_implementation(lambda T: Tracer()) - tracer = trace.tracer() + trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) + tracer = trace.tracer_source().get_tracer("myapp") # create a JaegerSpanExporter jaeger_exporter = jaeger.JaegerSpanExporter( diff --git a/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py b/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py index d459855dcf2..086b3193238 100644 --- a/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py +++ b/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py @@ -2,11 +2,11 @@ from opentelemetry import trace from opentelemetry.ext import jaeger -from opentelemetry.sdk.trace import Tracer +from opentelemetry.sdk.trace import TracerSource from opentelemetry.sdk.trace.export import BatchExportSpanProcessor -trace.set_preferred_tracer_implementation(lambda T: Tracer()) -tracer = trace.tracer() +trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) +tracer = trace.tracer_source().get_tracer("myapp") # create a JaegerSpanExporter jaeger_exporter = jaeger.JaegerSpanExporter( @@ -25,8 +25,8 @@ # create a BatchExportSpanProcessor and add the exporter to it span_processor = BatchExportSpanProcessor(jaeger_exporter) -# add to the tracer -tracer.add_span_processor(span_processor) +# add to the tracer factory +trace.tracer_source().add_span_processor(span_processor) # create some spans for testing with tracer.start_as_current_span("foo") as foo: diff --git a/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py b/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py index 1dfdac145a6..bb207a25f95 100644 --- a/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py +++ b/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py @@ -29,13 +29,15 @@ import time from opentelemetry import trace - from opentelemetry.sdk.trace import Tracer + from opentelemetry.sdk.trace import TracerSource from opentelemetry.ext.opentracing_shim import create_tracer # Tell OpenTelemetry which Tracer implementation to use. - trace.set_preferred_tracer_implementation(lambda T: Tracer()) + trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) + # Create an OpenTelemetry Tracer. - otel_tracer = trace.tracer() + otel_tracer = trace.tracer_source().get_tracer("myapp") + # Create an OpenTracing shim. shim = create_tracer(otel_tracer) From 0cbdccb7108faace34bc1b2b5d115ff2494cf6ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Mon, 9 Dec 2019 11:29:32 +0100 Subject: [PATCH 16/22] Adapt new tests. --- opentelemetry-api/tests/test_implementation.py | 3 ++- opentelemetry-sdk/tests/test_implementation.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/opentelemetry-api/tests/test_implementation.py b/opentelemetry-api/tests/test_implementation.py index 60bf9dd9fad..8ccf98e9e79 100644 --- a/opentelemetry-api/tests/test_implementation.py +++ b/opentelemetry-api/tests/test_implementation.py @@ -26,7 +26,8 @@ class TestAPIOnlyImplementation(unittest.TestCase): """ def test_tracer(self): - tracer = trace.Tracer() + tracer_source = trace.TracerSource() + tracer = tracer_source.get_tracer("opentelemetry-api") with tracer.start_span("test") as span: self.assertEqual(span.get_context(), trace.INVALID_SPAN_CONTEXT) self.assertEqual(span, trace.INVALID_SPAN) diff --git a/opentelemetry-sdk/tests/test_implementation.py b/opentelemetry-sdk/tests/test_implementation.py index 9aaa5fc35a3..9f0ca38326b 100644 --- a/opentelemetry-sdk/tests/test_implementation.py +++ b/opentelemetry-sdk/tests/test_implementation.py @@ -28,7 +28,7 @@ class TestSDKImplementation(unittest.TestCase): """ def test_tracer(self): - tracer = trace.Tracer() + tracer = trace.TracerSource().get_tracer("opentelemetery-sdk") with tracer.start_span("test") as span: self.assertNotEqual(span.get_context(), INVALID_SPAN_CONTEXT) self.assertNotEqual(span, INVALID_SPAN) From 923660611cf5979df9fe89aec01c1c3e92777e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Mon, 9 Dec 2019 12:29:03 +0100 Subject: [PATCH 17/22] Fix docstrings. --- .../src/opentelemetry/trace/__init__.py | 17 ++++++++++++----- .../src/opentelemetry/util/loader.py | 8 ++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 514e5e6f914..637926a6619 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -25,6 +25,10 @@ tracing, and a concrete no-op :class:`.DefaultSpan` that allows applications to use the API package alone without a supporting implementation. +To get a tracer, you need to provide the package name from which you are +calling the tracer APIs to OpenTelemetry by calling `TracerSource.get_tracer` +with the name and version of your package. + The tracer supports creating spans that are "attached" or "detached" from the context. New spans are "attached" to the context in that they are created as children of the currently active span, and the newly-created span @@ -32,8 +36,10 @@ from opentelemetry import trace + tracer = trace.tracer_source().get_tracer("my-instrumentation-library") + # Create a new root span, set it as the current span in context - with trace.tracer().start_as_current_span("parent"): + with tracer.start_as_current_span("parent"): # Attach a new child and update the current span with tracer.start_as_current_span("child"): do_work(): @@ -43,20 +49,21 @@ When creating a span that's "detached" from the context the active span doesn't change, and the caller is responsible for managing the span's lifetime:: - from opentelemetry import trace - # Explicit parent span assignment - child = trace.tracer().start_span("child", parent=parent) + child = tracer.start_span("child", parent=parent) try: do_work(span=child) finally: child.end() -Applications should generally use a single global tracer, and use either +Applications should generally use a single global tracer source, and use either implicit or explicit context propagation consistently throughout. .. versionadded:: 0.1.0 +.. versionchanged:: 0.3.0 + `TracerSource` was introduced and the global ``tracer`` getter was replaced + by `tracer_source`. """ import enum diff --git a/opentelemetry-api/src/opentelemetry/util/loader.py b/opentelemetry-api/src/opentelemetry/util/loader.py index e95028eec1d..b65c822ab9f 100644 --- a/opentelemetry-api/src/opentelemetry/util/loader.py +++ b/opentelemetry-api/src/opentelemetry/util/loader.py @@ -36,10 +36,10 @@ def my_factory_for_t(api_type: typing.Type[T]) -> typing.Optional[T]: factory function or other means to create the global object: 1. If the environment variable - :samp:`OPENTELEMETRY_PYTHON_IMPLEMENTATION_{getter-name}` (e.g., - ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_TRACERSOURCE``) is set to an - nonempty value, an attempt is made to import a module with that name and - use a factory function named ``get_opentelemetry_implementation`` in it. + :samp:`OPENTELEMETRY_PYTHON_IMPLEMENTATION_{getter-name}` (e.g., + ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_TRACERSOURCE``) is set to an + nonempty value, an attempt is made to import a module with that name and + use a factory function named ``get_opentelemetry_implementation`` in it. 2. Otherwise, the same is tried with the environment variable ``OPENTELEMETRY_PYTHON_IMPLEMENTATION_DEFAULT``. 3. Otherwise, if a :samp:`set_preferred_{}_implementation` was From 725bb161f9c22285893b6756230e7bad2fdbc6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Mon, 9 Dec 2019 12:39:54 +0100 Subject: [PATCH 18/22] Rename creator_info to instrumentation_info. In-reply-to: https://github.com/open-telemetry/opentelemetry-python/pull/301/files#r351007226 --- .../src/opentelemetry/sdk/trace/__init__.py | 6 +++--- opentelemetry-sdk/tests/trace/test_trace.py | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index 4da5be07436..5771eadac21 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -134,7 +134,7 @@ def __init__( links: Sequence[trace_api.Link] = (), kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL, span_processor: SpanProcessor = SpanProcessor(), - creator_info: "InstrumentationInfo" = None, + instrumentation_info: "InstrumentationInfo" = None, ) -> None: self.name = name @@ -168,7 +168,7 @@ def __init__( self.end_time = None # type: Optional[int] self.start_time = None # type: Optional[int] - self.creator_info = creator_info + self.instrumentation_info = instrumentation_info def __repr__(self): return '{}(name="{}", context={})'.format( @@ -435,7 +435,7 @@ def start_span( span_processor=self.source._active_span_processor, # pylint:disable=protected-access kind=kind, links=links, - creator_info=self.instrumentation_info, + instrumentation_info=self.instrumentation_info, ) span.start(start_time=start_time) else: diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 797c82957cf..b3fdfb4a47e 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -143,27 +143,28 @@ def test_start_span_invalid_spancontext(self): self.assertTrue(new_span.context.is_valid()) self.assertIsNone(new_span.parent) - def test_creator_info(self): + def test_instrumentation_info(self): tracer_source = trace.TracerSource() tracer1 = tracer_source.get_tracer("instr1") tracer2 = tracer_source.get_tracer("instr2", "1.3b3") span1 = tracer1.start_span("s1") span2 = tracer2.start_span("s2") self.assertEqual( - span1.creator_info, trace.InstrumentationInfo("instr1", "") + span1.instrumentation_info, trace.InstrumentationInfo("instr1", "") ) self.assertEqual( - span2.creator_info, trace.InstrumentationInfo("instr2", "1.3b3") + span2.instrumentation_info, + trace.InstrumentationInfo("instr2", "1.3b3"), ) - self.assertEqual(span2.creator_info.version, "1.3b3") - self.assertEqual(span2.creator_info.name, "instr2") + self.assertEqual(span2.instrumentation_info.version, "1.3b3") + self.assertEqual(span2.instrumentation_info.name, "instr2") self.assertLess( - span1.creator_info, span2.creator_info + span1.instrumentation_info, span2.instrumentation_info ) # Check sortability. - def test_invalid_creator_info(self): + def test_invalid_instrumentation_info(self): tracer_source = trace.TracerSource() tracer1 = tracer_source.get_tracer("") tracer2 = tracer_source.get_tracer(None) From b7c688c91abccef77818ccb14c3df6e0f7038ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 13 Dec 2019 14:02:18 +0100 Subject: [PATCH 19/22] Fix tests. --- opentelemetry-sdk/tests/trace/test_trace.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 991477ab2a4..951bceca97e 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -578,7 +578,9 @@ def test_ended_span(self): def test_error_status(self): try: - with trace.Tracer("test_error_status").start_span("root") as root: + with trace.TracerSource().get_tracer( + "opentelemetry-sdk" + ).start_span("root") as root: raise Exception("unknown") except Exception: # pylint: disable=broad-except pass From e4db2174fcd04d53efd449f13e149059f5215e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 13 Dec 2019 14:55:46 +0100 Subject: [PATCH 20/22] libname -> module name --- README.md | 2 +- examples/basic_tracer/tracer.py | 4 +--- examples/http/server.py | 2 +- .../flask_example.py | 4 +--- .../src/opentelemetry/ext/flask/__init__.py | 4 +--- .../ext/http_requests/__init__.py | 4 +--- .../tests/test_requests_integration.py | 6 +++--- ext/opentelemetry-ext-jaeger/README.rst | 2 +- .../examples/jaeger_exporter_example.py | 2 +- .../ext/opentracing_shim/__init__.py | 8 ++----- .../src/opentelemetry/ext/wsgi/__init__.py | 4 +--- .../src/opentelemetry/trace/__init__.py | 21 +++++++++---------- .../tests/test_implementation.py | 2 +- .../src/opentelemetry/sdk/trace/__init__.py | 12 +++++------ .../tests/test_implementation.py | 2 +- .../tests/trace/export/test_export.py | 4 ++-- .../export/test_in_memory_span_exporter.py | 2 +- opentelemetry-sdk/tests/trace/test_trace.py | 18 ++++++++-------- 18 files changed, 44 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 149fec0ee81..fcedf05e025 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) trace.tracer_source().add_span_processor( SimpleExportSpanProcessor(ConsoleSpanExporter()) ) -tracer = trace.tracer_source().get_tracer("myapp") +tracer = trace.tracer_source().get_tracer(__name__) with tracer.start_as_current_span('foo'): with tracer.start_as_current_span('bar'): with tracer.start_as_current_span('baz'): diff --git a/examples/basic_tracer/tracer.py b/examples/basic_tracer/tracer.py index 61b468ebfcd..4b392fd1eab 100755 --- a/examples/basic_tracer/tracer.py +++ b/examples/basic_tracer/tracer.py @@ -42,9 +42,7 @@ # We tell OpenTelemetry who it is that is creating spans. In this case, we have # no real name (no setup.py), so we make one up. If we had a version, we would # also specify it here. -tracer = trace.tracer_source().get_tracer( - "opentelemetry-examples-basic-tracer" -) +tracer = trace.tracer_source().get_tracer(__name__) # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) diff --git a/examples/http/server.py b/examples/http/server.py index 27c93ebdaf4..68e3d952b0d 100755 --- a/examples/http/server.py +++ b/examples/http/server.py @@ -42,7 +42,7 @@ # The preferred tracer implementation must be set, as the opentelemetry-api # defines the interface with a no-op implementation. trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) -tracer = trace.tracer_source().get_tracer("opentelemetry-example-http") +tracer = trace.tracer_source().get_tracer(__name__) # SpanExporter receives the spans and send them to the target location. span_processor = BatchExportSpanProcessor(exporter) diff --git a/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py b/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py index 93b1c7496eb..ae484dd30e2 100644 --- a/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py +++ b/examples/opentelemetry-example-app/src/opentelemetry_example_app/flask_example.py @@ -71,9 +71,7 @@ def hello(): version = pkg_resources.get_distribution( "opentelemetry-example-app" ).version - tracer = trace.tracer_source().get_tracer( - "opentelemetry-example-app", version - ) + tracer = trace.tracer_source().get_tracer(__name__, version) with tracer.start_as_current_span("example-request"): requests.get("http://www.example.com") return "hello" diff --git a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py index 49763daf536..ce11b18d635 100644 --- a/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py +++ b/ext/opentelemetry-ext-flask/src/opentelemetry/ext/flask/__init__.py @@ -61,9 +61,7 @@ def _before_flask_request(): otel_wsgi.get_header_from_environ, environ ) - tracer = trace.tracer_source().get_tracer( - "opentelemetry-ext-flask", __version__ - ) + tracer = trace.tracer_source().get_tracer(__name__, __version__) attributes = otel_wsgi.collect_request_attributes(environ) if flask_request.url_rule: diff --git a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py index 5e7f5221870..4f5a18cf9ea 100644 --- a/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py +++ b/ext/opentelemetry-ext-http-requests/src/opentelemetry/ext/http_requests/__init__.py @@ -48,9 +48,7 @@ def enable(tracer_source): # Guard against double instrumentation disable() - tracer = tracer_source.get_tracer( - "opentelemetry-ext-http-requests", __version__ - ) + tracer = tracer_source.get_tracer(__name__, __version__) wrapped = Session.request diff --git a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py index f952638bdbe..3560aacde9a 100644 --- a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py +++ b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py @@ -55,7 +55,6 @@ def setspanattr(key, value): spec_set=True, return_value=self.span_context_manager, ) - self.start_as_current_span = self.start_span_patcher.start() mocked_response = requests.models.Response() mocked_response.status_code = 200 @@ -67,6 +66,8 @@ def setspanattr(key, value): spec_set=True, return_value=mocked_response, ) + + self.start_as_current_span = self.start_span_patcher.start() self.send = self.send_patcher.start() opentelemetry.ext.http_requests.enable(self.tracer_source) @@ -74,8 +75,7 @@ def setspanattr(key, value): "opentelemetry-ext-http-requests" ).version self.get_tracer.assert_called_with( - "opentelemetry-ext-http-requests", distver - ) + opentelemetry.ext.http_requests.__name__, distver) def tearDown(self): opentelemetry.ext.http_requests.disable() diff --git a/ext/opentelemetry-ext-jaeger/README.rst b/ext/opentelemetry-ext-jaeger/README.rst index 83bf2eb5d70..80306aa59bf 100644 --- a/ext/opentelemetry-ext-jaeger/README.rst +++ b/ext/opentelemetry-ext-jaeger/README.rst @@ -36,7 +36,7 @@ gRPC is still not supported by this implementation. from opentelemetry.sdk.trace.export import BatchExportSpanProcessor trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) - tracer = trace.tracer_source().get_tracer("myapp") + tracer = trace.tracer_source().get_tracer(__name__) # create a JaegerSpanExporter jaeger_exporter = jaeger.JaegerSpanExporter( diff --git a/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py b/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py index 086b3193238..9eec28dc75e 100644 --- a/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py +++ b/ext/opentelemetry-ext-jaeger/examples/jaeger_exporter_example.py @@ -6,7 +6,7 @@ from opentelemetry.sdk.trace.export import BatchExportSpanProcessor trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) -tracer = trace.tracer_source().get_tracer("myapp") +tracer = trace.tracer_source().get_tracer(__name__) # create a JaegerSpanExporter jaeger_exporter = jaeger.JaegerSpanExporter( diff --git a/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py b/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py index 5ff39f76dbf..7c7640017bf 100644 --- a/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py +++ b/ext/opentelemetry-ext-opentracing-shim/src/opentelemetry/ext/opentracing_shim/__init__.py @@ -36,7 +36,7 @@ trace.set_preferred_tracer_source_implementation(lambda T: TracerSource()) # Create an OpenTelemetry Tracer. - otel_tracer = trace.tracer_source().get_tracer("myapp") + otel_tracer = trace.tracer_source().get_tracer(__name__) # Create an OpenTracing shim. shim = create_tracer(otel_tracer) @@ -110,11 +110,7 @@ def create_tracer(otel_tracer_source): The created :class:`TracerShim`. """ - return TracerShim( - otel_tracer_source.get_tracer( - "opentelemetry-ext-opentracing-shim", __version__ - ) - ) + return TracerShim(otel_tracer_source.get_tracer(__name__, __version__)) class SpanContextShim(opentracing.SpanContext): diff --git a/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py b/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py index bef2cc2fe93..6581662d598 100644 --- a/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py +++ b/ext/opentelemetry-ext-wsgi/src/opentelemetry/ext/wsgi/__init__.py @@ -164,9 +164,7 @@ class OpenTelemetryMiddleware: def __init__(self, wsgi): self.wsgi = wsgi - self.tracer = trace.tracer_source().get_tracer( - "opentelemetry-ext-wsgi", __version__ - ) + self.tracer = trace.tracer_source().get_tracer(__name__, __version__) @staticmethod def _create_start_response(span, start_response): diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index c3f57b8c7b6..e426d11a1a7 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -27,7 +27,7 @@ To get a tracer, you need to provide the package name from which you are calling the tracer APIs to OpenTelemetry by calling `TracerSource.get_tracer` -with the name and version of your package. +with the calling module name and the version of your package. The tracer supports creating spans that are "attached" or "detached" from the context. New spans are "attached" to the context in that they are @@ -36,7 +36,7 @@ from opentelemetry import trace - tracer = trace.tracer_source().get_tracer("my-instrumentation-library") + tracer = trace.tracer_source().get_tracer(__name__) # Create a new root span, set it as the current span in context with tracer.start_as_current_span("parent"): @@ -378,7 +378,7 @@ class TracerSource: # pylint:disable=no-self-use,unused-argument def get_tracer( self, - instrumenting_library_name: str, + instrumenting_module_name: str, instrumenting_library_version: str = "", ) -> "Tracer": """Returns a `Tracer` for use by the given instrumentation library. @@ -390,14 +390,13 @@ def get_tracer( vs. a functional tracer). Args: - instrumenting_library_name: The name of the instrumenting library. - This should *not* be the name of the library that is - instrumented but the name of the instrumentation library. - E.g., instead of ``"requests"``, - ``"opentelemetry-ext-http-requests"``. - - This should be the ``pip install``-able name of the library - rather than the module name (see also the next argument). + instrumenting_module_name: The name of the instrumenting module + (usually just ``__name__``). + + This should *not* be the name of the module that is + instrumented but the name of the module doing the instrumentation. + E.g., instead of ``"requests"``, use + ``"opentelemetry.ext.http_requests"``. instrumenting_library_version: Optional. The version string of the instrumenting library. Usually this should be the same as diff --git a/opentelemetry-api/tests/test_implementation.py b/opentelemetry-api/tests/test_implementation.py index 8ccf98e9e79..cd126229f9a 100644 --- a/opentelemetry-api/tests/test_implementation.py +++ b/opentelemetry-api/tests/test_implementation.py @@ -27,7 +27,7 @@ class TestAPIOnlyImplementation(unittest.TestCase): def test_tracer(self): tracer_source = trace.TracerSource() - tracer = tracer_source.get_tracer("opentelemetry-api") + tracer = tracer_source.get_tracer(__name__) with tracer.start_span("test") as span: self.assertEqual(span.get_context(), trace.INVALID_SPAN_CONTEXT) self.assertEqual(span, trace.INVALID_SPAN) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index 501309155ff..82fca41f4cc 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -329,7 +329,7 @@ def generate_trace_id() -> int: class InstrumentationInfo: - """Immutable information about an instrumentation library. + """Immutable information about an instrumentation library module. See `TracerSource.get_tracer` for the meaning of the properties. """ @@ -516,16 +516,16 @@ def __init__( def get_tracer( self, - instrumenting_library_name: str, + instrumenting_module_name: str, instrumenting_library_version: str = "", ) -> "trace_api.Tracer": - if not instrumenting_library_name: # Reject empty strings too. - instrumenting_library_name = "ERROR:MISSING LIB NAME" - logger.error("get_tracer called with missing library name.") + if not instrumenting_module_name: # Reject empty strings too. + instrumenting_module_name = "ERROR:MISSING MODULE NAME" + logger.error("get_tracer called with missing module name.") return Tracer( self, InstrumentationInfo( - instrumenting_library_name, instrumenting_library_version + instrumenting_module_name, instrumenting_library_version ), ) diff --git a/opentelemetry-sdk/tests/test_implementation.py b/opentelemetry-sdk/tests/test_implementation.py index 9f0ca38326b..d8d6bae1393 100644 --- a/opentelemetry-sdk/tests/test_implementation.py +++ b/opentelemetry-sdk/tests/test_implementation.py @@ -28,7 +28,7 @@ class TestSDKImplementation(unittest.TestCase): """ def test_tracer(self): - tracer = trace.TracerSource().get_tracer("opentelemetery-sdk") + tracer = trace.TracerSource().get_tracer(__name__) with tracer.start_span("test") as span: self.assertNotEqual(span.get_context(), INVALID_SPAN_CONTEXT) self.assertNotEqual(span, INVALID_SPAN) diff --git a/opentelemetry-sdk/tests/trace/export/test_export.py b/opentelemetry-sdk/tests/trace/export/test_export.py index 0c10c5d55e9..54fdee2629b 100644 --- a/opentelemetry-sdk/tests/trace/export/test_export.py +++ b/opentelemetry-sdk/tests/trace/export/test_export.py @@ -45,7 +45,7 @@ def shutdown(self): class TestSimpleExportSpanProcessor(unittest.TestCase): def test_simple_span_processor(self): tracer_source = trace.TracerSource() - tracer = tracer_source.get_tracer("opentelemetry-sdk") + tracer = tracer_source.get_tracer(__name__) spans_names_list = [] @@ -70,7 +70,7 @@ def test_simple_span_processor_no_context(self): not it is ever the active span. """ tracer_source = trace.TracerSource() - tracer = tracer_source.get_tracer("opentelemetry-sdk") + tracer = tracer_source.get_tracer(__name__) spans_names_list = [] diff --git a/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py b/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py index cf1db5c830e..5c5194053bb 100644 --- a/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py +++ b/opentelemetry-sdk/tests/trace/export/test_in_memory_span_exporter.py @@ -26,7 +26,7 @@ class TestInMemorySpanExporter(unittest.TestCase): def setUp(self): self.tracer_source = trace.TracerSource() - self.tracer = self.tracer_source.get_tracer("opentelemetry-sdk") + self.tracer = self.tracer_source.get_tracer(__name__) self.memory_exporter = InMemorySpanExporter() span_processor = export.SimpleExportSpanProcessor(self.memory_exporter) self.tracer_source.add_span_processor(span_processor) diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 951bceca97e..98a7bb100e7 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -25,7 +25,7 @@ def new_tracer() -> trace_api.Tracer: - return trace.TracerSource().get_tracer("opentelemetry-sdk") + return trace.TracerSource().get_tracer(__name__) class TestTracer(unittest.TestCase): @@ -119,7 +119,7 @@ def test_default_sampler(self): def test_sampler_no_sampling(self): tracer_source = trace.TracerSource(sampling.ALWAYS_OFF) - tracer = tracer_source.get_tracer("opentelemetry-sdk") + tracer = tracer_source.get_tracer(__name__) # Check that the default tracer creates no-op spans if the sampler # decides not to sampler @@ -179,7 +179,7 @@ def test_invalid_instrumentation_info(self): self.assertTrue(span1.is_recording_events()) self.assertEqual(tracer1.instrumentation_info.version, "") self.assertEqual( - tracer1.instrumentation_info.name, "ERROR:MISSING LIB NAME" + tracer1.instrumentation_info.name, "ERROR:MISSING MODULE NAME" ) def test_span_processor_for_source(self): @@ -404,7 +404,7 @@ def test_sampling_attributes(self): ) ) - self.tracer = tracer_source.get_tracer("opentelemetry-sdk") + self.tracer = tracer_source.get_tracer(__name__) with self.tracer.start_as_current_span("root2") as root: self.assertEqual(len(root.attributes), 2) @@ -578,9 +578,9 @@ def test_ended_span(self): def test_error_status(self): try: - with trace.TracerSource().get_tracer( - "opentelemetry-sdk" - ).start_span("root") as root: + with trace.TracerSource().get_tracer(__name__).start_span( + "root" + ) as root: raise Exception("unknown") except Exception: # pylint: disable=broad-except pass @@ -612,7 +612,7 @@ def on_end(self, span: "trace.Span") -> None: class TestSpanProcessor(unittest.TestCase): def test_span_processor(self): tracer_source = trace.TracerSource() - tracer = tracer_source.get_tracer("opentelemetry-sdk") + tracer = tracer_source.get_tracer(__name__) spans_calls_list = [] # filled by MySpanProcessor expected_list = [] # filled by hand @@ -681,7 +681,7 @@ def test_span_processor(self): def test_add_span_processor_after_span_creation(self): tracer_source = trace.TracerSource() - tracer = tracer_source.get_tracer("opentelemetry-sdk") + tracer = tracer_source.get_tracer(__name__) spans_calls_list = [] # filled by MySpanProcessor expected_list = [] # filled by hand From 239a18dfd1cf4f40d7ecb8235b617ab66df611af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 13 Dec 2019 15:22:06 +0100 Subject: [PATCH 21/22] Lint. --- .../tests/test_requests_integration.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py index 3560aacde9a..35cf3110f3e 100644 --- a/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py +++ b/ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py @@ -75,7 +75,8 @@ def setspanattr(key, value): "opentelemetry-ext-http-requests" ).version self.get_tracer.assert_called_with( - opentelemetry.ext.http_requests.__name__, distver) + opentelemetry.ext.http_requests.__name__, distver + ) def tearDown(self): opentelemetry.ext.http_requests.disable() From b48e7083cd4a1c1680092238e90387afa3a988e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Neum=C3=BCller?= Date: Fri, 13 Dec 2019 15:25:19 +0100 Subject: [PATCH 22/22] Fix docs build. --- opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index 82fca41f4cc..3035ae7ef9f 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -41,8 +41,8 @@ class SpanProcessor: invocations. Span processors can be registered directly using - :func:`Tracer.add_span_processor` and they are invoked in the same order - as they were registered. + :func:`TracerSource.add_span_processor` and they are invoked + in the same order as they were registered. """ def on_start(self, span: "Span") -> None: