Skip to content

add schema_url to TracerProvider.get_tracer #2154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#2147](https://github.com/open-telemetry/opentelemetry-python/pull/2147))
- Fix validity calculation for trace and span IDs
([#2145](https://github.com/open-telemetry/opentelemetry-python/pull/2145))
- Add `schema_url` to `TracerProvider.get_tracer`
([#2154](https://github.com/open-telemetry/opentelemetry-python/pull/2154))

## [1.5.0-0.24b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.5.0-0.24b0) - 2021-08-26

Expand Down
30 changes: 22 additions & 8 deletions opentelemetry-api/src/opentelemetry/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@


import os
import typing
from abc import ABC, abstractmethod
from contextlib import contextmanager
from enum import Enum
Expand Down Expand Up @@ -186,7 +187,8 @@ class TracerProvider(ABC):
def get_tracer(
self,
instrumenting_module_name: str,
instrumenting_library_version: str = "",
instrumenting_library_version: typing.Optional[str] = None,
schema_url: typing.Optional[str] = None,
) -> "Tracer":
"""Returns a `Tracer` for use by the given instrumentation library.

Expand All @@ -208,6 +210,8 @@ def get_tracer(
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``.

schema_url: Optional. Specifies the Schema URL of the emitted telemetry.
"""


Expand All @@ -220,7 +224,8 @@ class _DefaultTracerProvider(TracerProvider):
def get_tracer(
self,
instrumenting_module_name: str,
instrumenting_library_version: str = "",
instrumenting_library_version: typing.Optional[str] = None,
schema_url: typing.Optional[str] = None,
) -> "Tracer":
# pylint:disable=no-self-use,unused-argument
return _DefaultTracer()
Expand All @@ -230,14 +235,19 @@ class ProxyTracerProvider(TracerProvider):
def get_tracer(
self,
instrumenting_module_name: str,
instrumenting_library_version: str = "",
instrumenting_library_version: typing.Optional[str] = None,
schema_url: typing.Optional[str] = None,
) -> "Tracer":
if _TRACER_PROVIDER:
return _TRACER_PROVIDER.get_tracer(
instrumenting_module_name, instrumenting_library_version
instrumenting_module_name,
instrumenting_library_version,
schema_url,
)
return ProxyTracer(
instrumenting_module_name, instrumenting_library_version
instrumenting_module_name,
instrumenting_library_version,
schema_url,
)


Expand Down Expand Up @@ -375,10 +385,12 @@ class ProxyTracer(Tracer):
def __init__(
self,
instrumenting_module_name: str,
instrumenting_library_version: str,
instrumenting_library_version: typing.Optional[str] = None,
schema_url: typing.Optional[str] = None,
):
self._instrumenting_module_name = instrumenting_module_name
self._instrumenting_library_version = instrumenting_library_version
self._schema_url = schema_url
self._real_tracer: Optional[Tracer] = None
self._noop_tracer = _DefaultTracer()

Expand All @@ -391,6 +403,7 @@ def _tracer(self) -> Tracer:
self._real_tracer = _TRACER_PROVIDER.get_tracer(
self._instrumenting_module_name,
self._instrumenting_library_version,
self._schema_url,
)
return self._real_tracer
return self._noop_tracer
Expand Down Expand Up @@ -445,8 +458,9 @@ def start_as_current_span(

def get_tracer(
instrumenting_module_name: str,
instrumenting_library_version: str = "",
instrumenting_library_version: typing.Optional[str] = None,
tracer_provider: Optional[TracerProvider] = None,
schema_url: typing.Optional[str] = None,
) -> "Tracer":
"""Returns a `Tracer` for use by the given instrumentation library.

Expand All @@ -458,7 +472,7 @@ def get_tracer(
if tracer_provider is None:
tracer_provider = get_tracer_provider()
return tracer_provider.get_tracer(
instrumenting_module_name, instrumenting_library_version
instrumenting_module_name, instrumenting_library_version, schema_url
)


Expand Down
6 changes: 4 additions & 2 deletions opentelemetry-api/tests/trace/test_globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ def tearDown(self) -> None:
def test_get_tracer(self):
"""trace.get_tracer should proxy to the global tracer provider."""
trace.get_tracer("foo", "var")
self._mock_tracer_provider.get_tracer.assert_called_with("foo", "var")
self._mock_tracer_provider.get_tracer.assert_called_with(
"foo", "var", None
)
mock_provider = unittest.mock.Mock()
trace.get_tracer("foo", "var", mock_provider)
mock_provider.get_tracer.assert_called_with("foo", "var")
mock_provider.get_tracer.assert_called_with("foo", "var", None)


class TestTracer(unittest.TestCase):
Expand Down
5 changes: 3 additions & 2 deletions opentelemetry-api/tests/trace/test_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

# pylint: disable=W0212,W0222,W0221

import typing
import unittest

from opentelemetry import trace
Expand All @@ -24,7 +24,8 @@ class TestProvider(trace._DefaultTracerProvider):
def get_tracer(
self,
instrumenting_module_name: str,
instrumenting_library_version: str = "",
instrumenting_library_version: typing.Optional[str] = None,
schema_url: typing.Optional[str] = None,
) -> trace.Tracer:
return TestTracer()

Expand Down
10 changes: 8 additions & 2 deletions opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import logging
import threading
import traceback
import typing
from collections import OrderedDict
from contextlib import contextmanager
from os import environ
Expand Down Expand Up @@ -1099,18 +1100,23 @@ def resource(self) -> Resource:
def get_tracer(
self,
instrumenting_module_name: str,
instrumenting_library_version: str = "",
instrumenting_library_version: typing.Optional[str] = None,
schema_url: typing.Optional[str] = None,
) -> "trace_api.Tracer":
if not instrumenting_module_name: # Reject empty strings too.
instrumenting_module_name = ""
logger.error("get_tracer called with missing module name.")
if instrumenting_library_version is None:
instrumenting_library_version = ""
return Tracer(
self.sampler,
self.resource,
self._active_span_processor,
self.id_generator,
InstrumentationInfo(
instrumenting_module_name, instrumenting_library_version
instrumenting_module_name,
instrumenting_library_version,
schema_url,
),
self._span_limits,
)
Expand Down
38 changes: 29 additions & 9 deletions opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import typing


class InstrumentationInfo:
Expand All @@ -20,31 +21,50 @@ class InstrumentationInfo:
properties.
"""

__slots__ = ("_name", "_version")
__slots__ = ("_name", "_version", "_schema_url")

def __init__(self, name: str, version: str):
def __init__(
self,
name: str,
version: typing.Optional[str] = None,
schema_url: typing.Optional[str] = None,
):
self._name = name
self._version = version
self._schema_url = schema_url

def __repr__(self):
return f"{type(self).__name__}({self._name}, {self._version})"
return f"{type(self).__name__}({self._name}, {self._version}, {self._schema_url})"

def __hash__(self):
return hash((self._name, self._version))
return hash((self._name, self._version, self._schema_url))

def __eq__(self, value):
return type(value) is type(self) and (self._name, self._version) == (
value._name,
value._version,
return (
type(value) is type(self)
and (
self._name,
self._version,
self._schema_url,
)
== (value._name, value._version, value._schema_url)
)

def __lt__(self, value):
if type(value) is not type(self):
return NotImplemented
return (self._name, self._version) < (value._name, value._version)
return (self._name, self._version, self._schema_url) < (
value._name,
value._version,
value._schema_url,
)

@property
def schema_url(self) -> typing.Optional[str]:
return self._schema_url

@property
def version(self) -> str:
def version(self) -> typing.Optional[str]:
return self._version

@property
Expand Down
9 changes: 7 additions & 2 deletions opentelemetry-sdk/tests/trace/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,17 +237,20 @@ def test_start_span_invalid_spancontext(self):

def test_instrumentation_info(self):
tracer_provider = trace.TracerProvider()
schema_url = "https://opentelemetry.io/schemas/1.3.0"
tracer1 = tracer_provider.get_tracer("instr1")
tracer2 = tracer_provider.get_tracer("instr2", "1.3b3")
tracer2 = tracer_provider.get_tracer("instr2", "1.3b3", schema_url)
span1 = tracer1.start_span("s1")
span2 = tracer2.start_span("s2")
self.assertEqual(
span1.instrumentation_info, InstrumentationInfo("instr1", "")
)
self.assertEqual(
span2.instrumentation_info, InstrumentationInfo("instr2", "1.3b3")
span2.instrumentation_info,
InstrumentationInfo("instr2", "1.3b3", schema_url),
)

self.assertEqual(span2.instrumentation_info.schema_url, schema_url)
self.assertEqual(span2.instrumentation_info.version, "1.3b3")
self.assertEqual(span2.instrumentation_info.name, "instr2")

Expand All @@ -267,6 +270,7 @@ def test_invalid_instrumentation_info(self):
)
span1 = tracer1.start_span("foo")
self.assertTrue(span1.is_recording())
self.assertEqual(tracer1.instrumentation_info.schema_url, None)
self.assertEqual(tracer1.instrumentation_info.version, "")
self.assertEqual(tracer1.instrumentation_info.name, "")

Expand All @@ -275,6 +279,7 @@ def test_invalid_instrumentation_info(self):
)
span2 = tracer2.start_span("bar")
self.assertTrue(span2.is_recording())
self.assertEqual(tracer2.instrumentation_info.schema_url, None)
self.assertEqual(tracer2.instrumentation_info.version, "")
self.assertEqual(tracer2.instrumentation_info.name, "")

Expand Down