diff --git a/docs/api/index.rst b/docs/api/index.rst index c1dffd6e75d..391dd52ae70 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -14,3 +14,4 @@ OpenTelemetry Python API trace metrics environment_variables + opentelemetry diff --git a/docs/api/opentelemetry.rst b/docs/api/opentelemetry.rst new file mode 100644 index 00000000000..9f7957af9e0 --- /dev/null +++ b/docs/api/opentelemetry.rst @@ -0,0 +1,7 @@ +opentelemetry.opentelemetry package +=================================== + +Module contents +--------------- + +.. automodule:: opentelemetry.opentelemetry diff --git a/opentelemetry-api/src/opentelemetry/attributes/__init__.py b/opentelemetry-api/src/opentelemetry/attributes/__init__.py index 497952984db..b930db2146d 100644 --- a/opentelemetry-api/src/opentelemetry/attributes/__init__.py +++ b/opentelemetry-api/src/opentelemetry/attributes/__init__.py @@ -18,6 +18,7 @@ from collections.abc import MutableMapping from typing import Optional, Sequence, Tuple, Union +from opentelemetry.opentelemetry import OpenTelemetry from opentelemetry.util import types # bytes are accepted as a user supplied value for attributes but @@ -125,7 +126,7 @@ def _clean_attribute_value( return value -class BoundedAttributes(MutableMapping): # type: ignore +class BoundedAttributes(OpenTelemetry, MutableMapping): # type: ignore """An ordered dict with a fixed max capacity. Oldest elements are dropped when the dict is full and a new element is @@ -139,6 +140,12 @@ def __init__( immutable: bool = True, max_value_len: Optional[int] = None, ): + super().__init__( + maxlen=maxlen, + attributes=attributes, + immutable=immutable, + max_value_len=max_value_len, + ) if maxlen is not None: if not isinstance(maxlen, int) or maxlen < 0: raise ValueError( @@ -159,9 +166,6 @@ def __init__( self[key] = value self._immutable = immutable - def __repr__(self) -> str: - return f"{dict(self._dict)}" - def __getitem__(self, key: str) -> types.AttributeValue: return self._dict[key] diff --git a/opentelemetry-api/src/opentelemetry/metrics/_internal/observation.py b/opentelemetry-api/src/opentelemetry/metrics/_internal/observation.py index 7aa24e3342d..35b00702766 100644 --- a/opentelemetry-api/src/opentelemetry/metrics/_internal/observation.py +++ b/opentelemetry-api/src/opentelemetry/metrics/_internal/observation.py @@ -14,10 +14,11 @@ from typing import Union +from opentelemetry.opentelemetry import OpenTelemetry from opentelemetry.util.types import Attributes -class Observation: +class Observation(OpenTelemetry): """A measurement observed in an asynchronous instrument Return/yield instances of this class from asynchronous instrument callbacks. @@ -30,6 +31,7 @@ class Observation: def __init__( self, value: Union[int, float], attributes: Attributes = None ) -> None: + super().__init__(value, attributes=attributes) self._value = value self._attributes = attributes @@ -47,6 +49,3 @@ def __eq__(self, other: object) -> bool: and self.value == other.value and self.attributes == other.attributes ) - - def __repr__(self) -> str: - return f"Observation(value={self.value}, attributes={self.attributes})" diff --git a/opentelemetry-api/src/opentelemetry/opentelemetry.py b/opentelemetry-api/src/opentelemetry/opentelemetry.py new file mode 100644 index 00000000000..9b057e82c8d --- /dev/null +++ b/opentelemetry-api/src/opentelemetry/opentelemetry.py @@ -0,0 +1,79 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +# type: ignore + +from inspect import signature + + +class OpenTelemetry: + # pylint: disable=no-member + def __init__(self, *args, **kwargs) -> None: + + object.__setattr__(self, "_args", list(args)) + object.__setattr__(self, "_kwargs", kwargs) + object.__setattr__(self, "_repr", None) + + def __repr__(self) -> str: + # pylint: disable=too-many-branches + + if self._repr is not None: + return self._repr + + repr_ = [] + + parameters = signature(self.__init__).parameters.values() + + for parameter in parameters: + if ( + parameter.kind is parameter.POSITIONAL_ONLY + or parameter.kind is parameter.POSITIONAL_OR_KEYWORD + ): + if self._args: + repr_.append(repr(self._args.pop(0))) + else: + break + elif parameter.kind is parameter.VAR_POSITIONAL: + for _ in range(len(self._args)): + repr_.append(repr(self._args.pop(0))) + + for parameter in parameters: + if parameter.kind is parameter.KEYWORD_ONLY: + if self._args: + value = self._args.pop(0) + + if parameter.default != value: + repr_.append(f"{parameter.name}={repr(value)}") + else: + break + + for parameter in parameters: + if ( + parameter.kind is parameter.KEYWORD_ONLY + or parameter.kind is parameter.POSITIONAL_OR_KEYWORD + ) and parameter.name in self._kwargs.keys(): + value = self._kwargs.pop(parameter.name) + + if parameter.default != value: + repr_.append(f"{parameter.name}={repr(value)}") + + elif parameter.kind is parameter.VAR_KEYWORD: + for key, value in self._kwargs.items(): + repr_.append(f"{key}={repr(value)}") + + object.__setattr__( + self, "_repr", f"{self.__class__.__name__}({', '.join(repr_)})" + ) + + return self._repr diff --git a/opentelemetry-api/src/opentelemetry/propagators/composite.py b/opentelemetry-api/src/opentelemetry/propagators/composite.py index 77330d94103..0c1d25a76ba 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/composite.py +++ b/opentelemetry-api/src/opentelemetry/propagators/composite.py @@ -33,6 +33,7 @@ class CompositePropagator(textmap.TextMapPropagator): def __init__( self, propagators: typing.Sequence[textmap.TextMapPropagator] ) -> None: + super().__init__(propagators) self._propagators = propagators def extract( diff --git a/opentelemetry-api/src/opentelemetry/propagators/textmap.py b/opentelemetry-api/src/opentelemetry/propagators/textmap.py index 42f1124f36d..80eb8ce418f 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/textmap.py +++ b/opentelemetry-api/src/opentelemetry/propagators/textmap.py @@ -16,6 +16,7 @@ import typing from opentelemetry.context.context import Context +from opentelemetry.opentelemetry import OpenTelemetry CarrierT = typing.TypeVar("CarrierT") # pylint: disable=invalid-name @@ -121,7 +122,7 @@ def set( default_setter: Setter[CarrierT] = DefaultSetter() # type: ignore -class TextMapPropagator(abc.ABC): +class TextMapPropagator(OpenTelemetry, abc.ABC): """This class provides an interface that enables extracting and injecting context into headers of HTTP requests. HTTP frameworks and clients can integrate with TextMapPropagator by providing the object containing the diff --git a/opentelemetry-api/src/opentelemetry/trace/span.py b/opentelemetry-api/src/opentelemetry/trace/span.py index 4afc4d520a2..5ac5f52faa1 100644 --- a/opentelemetry-api/src/opentelemetry/trace/span.py +++ b/opentelemetry-api/src/opentelemetry/trace/span.py @@ -5,6 +5,7 @@ import typing import warnings +from opentelemetry.opentelemetry import OpenTelemetry from opentelemetry.trace.status import Status, StatusCode from opentelemetry.util import types @@ -54,7 +55,7 @@ def _is_valid_pair(key: str, value: str) -> bool: ) -class Span(abc.ABC): +class Span(OpenTelemetry, abc.ABC): """A span represents a single operation within a trace.""" @abc.abstractmethod @@ -222,7 +223,7 @@ def sampled(self) -> bool: DEFAULT_TRACE_OPTIONS = TraceFlags.get_default() -class TraceState(typing.Mapping[str, str]): +class TraceState(OpenTelemetry, typing.Mapping[str, str]): """A list of key-value pairs representing vendor-specific trace info. Keys and values are strings of up to 256 printable US-ASCII characters. @@ -239,6 +240,7 @@ def __init__( typing.Sequence[typing.Tuple[str, str]] ] = None, ) -> None: + super().__init__(entries=entries) self._dict = {} # type: dict[str, str] if entries is None: return @@ -272,13 +274,6 @@ def __iter__(self) -> typing.Iterator[str]: def __len__(self) -> int: return len(self._dict) - def __repr__(self) -> str: - pairs = [ - f"{{key={key}, value={value}}}" - for key, value in self._dict.items() - ] - return str(pairs) - def add(self, key: str, value: str) -> "TraceState": """Adds a key-value pair to tracestate. The provided pair should adhere to w3c tracestate identifiers format. @@ -424,7 +419,8 @@ def values(self) -> typing.ValuesView[str]: class SpanContext( - typing.Tuple[int, int, bool, "TraceFlags", "TraceState", bool] + OpenTelemetry, + typing.Tuple[int, int, bool, "TraceFlags", "TraceState", bool], ): """The state of a Span to propagate between processes. @@ -457,10 +453,19 @@ def __new__( and INVALID_SPAN_ID < span_id <= _SPAN_ID_MAX_VALUE ) - return tuple.__new__( + span_context = tuple.__new__( cls, (trace_id, span_id, is_remote, trace_flags, trace_state, is_valid), ) + cls.__init__( + span_context, + trace_id, + span_id, + is_remote, + trace_flags=trace_flags, + trace_state=trace_state, + ) + return span_context def __getnewargs__( self, @@ -507,9 +512,6 @@ def __delattr__(self, *args: str) -> None: "Immutable type, ignoring call to set attribute", stack_info=True ) - def __repr__(self) -> str: - return f"{type(self).__name__}(trace_id=0x{format_trace_id(self.trace_id)}, span_id=0x{format_span_id(self.span_id)}, trace_flags=0x{self.trace_flags:02x}, trace_state={self.trace_state!r}, is_remote={self.is_remote})" - class NonRecordingSpan(Span): """The Span that is used when no Span implementation is available. @@ -518,6 +520,7 @@ class NonRecordingSpan(Span): """ def __init__(self, context: "SpanContext") -> None: + super().__init__(context) self._context = context def get_span_context(self) -> "SpanContext": @@ -571,9 +574,6 @@ def record_exception( ) -> None: pass - def __repr__(self) -> str: - return f"NonRecordingSpan({self._context!r})" - INVALID_SPAN_ID = 0x0000000000000000 INVALID_TRACE_ID = 0x00000000000000000000000000000000 diff --git a/opentelemetry-api/tests/test_opentelemetry.py b/opentelemetry-api/tests/test_opentelemetry.py new file mode 100644 index 00000000000..9fbaec75f42 --- /dev/null +++ b/opentelemetry-api/tests/test_opentelemetry.py @@ -0,0 +1,537 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +from unittest import TestCase + +from opentelemetry.opentelemetry import OpenTelemetry + + +class TestOpenTelemetry(TestCase): + # pylint: disable=useless-parent-delegation + # pylint: disable=too-many-public-methods + def test_opentelemetry(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self): + super().__init__() + + self.assertEqual(repr(OpenTelemetryChild()), "OpenTelemetryChild()") + + def test_opentelemetry_slash(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, /): + super().__init__() + + self.assertEqual(repr(OpenTelemetryChild()), "OpenTelemetryChild()") + + def test_opentelemetry_args(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, *args): + super().__init__(*args) + + self.assertEqual(repr(OpenTelemetryChild()), "OpenTelemetryChild()") + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + + def test_opentelemetry_slash_args(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, /, *args): + super().__init__(*args) + + self.assertEqual(repr(OpenTelemetryChild()), "OpenTelemetryChild()") + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + + def test_opentelemetry_a_b(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b): + super().__init__(a, b) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", b="b")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild('a', 'b')", + ) + + def test_opentelemetry_a_b_slash(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, /): + super().__init__(a, b) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + + def test_opentelemetry_a_b_args(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, *args): + super().__init__(a, b, *args) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", b="b")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + + def test_opentelemetry_a_b_slash_args(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, /, *args): + super().__init__(a, b, *args) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + + def test_opentelemetry_a_b_c_d(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, c="c", d="d"): + super().__init__(a, b, c=c, d=d) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="d")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="dd")), + "OpenTelemetryChild('a', 'b', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="dd")), + "OpenTelemetryChild('a', 'b', c='cc', d='dd')", + ) + + def test_opentelemetry_a_b_slash_c_d(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, /, c="c", d="d"): + super().__init__(a, b, c=c, d=d) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="d")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="dd")), + "OpenTelemetryChild('a', 'b', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="dd")), + "OpenTelemetryChild('a', 'b', c='cc', d='dd')", + ) + + def test_opentelemetry_a_b_args_c_d(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, *args, c="c", d="d"): + super().__init__(a, b, *args, c=c, d=d) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="d")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="dd")), + "OpenTelemetryChild('a', 'b', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="dd")), + "OpenTelemetryChild('a', 'b', c='cc', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="c")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="cc")), + "OpenTelemetryChild('a', 'b', 'c', 'd', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="c", d="d")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="cc", d="d")), + "OpenTelemetryChild('a', 'b', 'c', 'd', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="c", d="dd")), + "OpenTelemetryChild('a', 'b', 'c', 'd', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="cc", d="dd")), + "OpenTelemetryChild('a', 'b', 'c', 'd', c='cc', d='dd')", + ) + + def test_opentelemetry_a_b_slash_args_c_d(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, /, *args, c="c", d="d"): + super().__init__(a, b, *args, c=c, d=d) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="d")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="dd")), + "OpenTelemetryChild('a', 'b', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="dd")), + "OpenTelemetryChild('a', 'b', c='cc', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="c")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="cc")), + "OpenTelemetryChild('a', 'b', 'c', 'd', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="c", d="d")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="cc", d="d")), + "OpenTelemetryChild('a', 'b', 'c', 'd', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="c", d="dd")), + "OpenTelemetryChild('a', 'b', 'c', 'd', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", c="cc", d="dd")), + "OpenTelemetryChild('a', 'b', 'c', 'd', c='cc', d='dd')", + ) + + def test_opentelemetry_asterisk_a_b(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, *, a, b): + super().__init__(a, b) + + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild(a='a', b='b')", + ) + + def test_opentelemetry_slash_asterisk_a_b(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, /, *, a, b): + super().__init__(a, b) + + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild(a='a', b='b')", + ) + + def test_x_opentelemetry_a_b_asterisk_c_d(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, *, c, d): + super().__init__(a, b, c=c, d=d) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b', c='c', d='d')", + ) + + class OpenTelemetryChild( + OpenTelemetry + ): # pylint: disable=function-redefined + def __init__(self, a, b, *, c="c", d="d"): + super().__init__(a, b, c=c, d=d) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", d="d")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="d")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="dd")), + "OpenTelemetryChild('a', 'b', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="dd")), + "OpenTelemetryChild('a', 'b', c='cc', d='dd')", + ) + + def test_x_opentelemetry_a_b_slash_asterisk_c_d(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, /, *, c, d): + super().__init__(a, b, c=c, d=d) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b', c='c', d='d')", + ) + + def test_opentelemetry_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + self.assertEqual(repr(OpenTelemetryChild()), "OpenTelemetryChild()") + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild(a='a', b='b')", + ) + + def test_opentelemetry_slash_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, /, **kwargs): + super().__init__(**kwargs) + + self.assertEqual(repr(OpenTelemetryChild()), "OpenTelemetryChild()") + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild(a='a', b='b')", + ) + + def test_opentelemetry_args_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.assertEqual(repr(OpenTelemetryChild()), "OpenTelemetryChild()") + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild(a='a', b='b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b', c='c', d='d')", + ) + + def test_opentelemetry_slash_args_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, /, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.assertEqual(repr(OpenTelemetryChild()), "OpenTelemetryChild()") + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild(a='a', b='b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b', c='c', d='d')", + ) + + def test_opentelemetry_a_b_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, **kwargs): + super().__init__(a, b, **kwargs) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", b="b")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b', c='c', d='d')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", b="b", c="c", d="d")), + "OpenTelemetryChild('a', 'b', c='c', d='d')", + ) + self.assertEqual( + repr(OpenTelemetryChild(a="a", b="b", c="c", d="d")), + "OpenTelemetryChild('a', 'b', c='c', d='d')", + ) + + def test_opentelemetry_a_b_slash_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, /, **kwargs): + super().__init__(a, b, **kwargs) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c", d="d")), + "OpenTelemetryChild('a', 'b', c='c', d='d')", + ) + + def test_opentelemetry_a_b_args_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, *args, **kwargs): + super().__init__(a, b, *args, **kwargs) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + + def test_opentelemetry_a_b_slash_args_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, /, *args, **kwargs): + super().__init__(a, b, *args, **kwargs) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d")), + "OpenTelemetryChild('a', 'b', 'c', 'd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", "c", "d", e="e", f="f")), + "OpenTelemetryChild('a', 'b', 'c', 'd', e='e', f='f')", + ) + + def test_opentelemetry_a_b_c_d_kwargs(self): + class OpenTelemetryChild(OpenTelemetry): + def __init__(self, a, b, c="c", d="d", **kwargs): + super().__init__(a, b, c=c, d=d, **kwargs) + + self.assertEqual( + repr(OpenTelemetryChild("a", "b")), "OpenTelemetryChild('a', 'b')" + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="c")), + "OpenTelemetryChild('a', 'b')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="d")), + "OpenTelemetryChild('a', 'b', c='cc')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="dd")), + "OpenTelemetryChild('a', 'b', c='cc', d='dd')", + ) + self.assertEqual( + repr(OpenTelemetryChild("a", "b", c="cc", d="dd", e="e", f="f")), + "OpenTelemetryChild('a', 'b', c='cc', d='dd', e='e', f='f')", + ) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py index 56d78ce653a..73e49bd5869 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/__init__.py @@ -35,6 +35,7 @@ std_to_otel, ) from opentelemetry.attributes import BoundedAttributes +from opentelemetry.opentelemetry import OpenTelemetry from opentelemetry.sdk.environment_variables import ( OTEL_ATTRIBUTE_COUNT_LIMIT, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT, @@ -70,7 +71,7 @@ class LogDroppedAttributesWarning(UserWarning): warnings.simplefilter("once", LogDroppedAttributesWarning) -class LogLimits: +class LogLimits(OpenTelemetry): """This class is based on a SpanLimits class in the Tracing module. This class represents the limits that should be enforced on recorded data such as events, links, attributes etc. @@ -104,10 +105,13 @@ class LogLimits: def __init__( self, - max_attributes: Optional[int] = None, + max_attributes: Optional[int] = _DEFAULT_OTEL_ATTRIBUTE_COUNT_LIMIT, max_attribute_length: Optional[int] = None, ): - + super().__init__( + max_attributes=max_attributes, + max_attribute_length=max_attribute_length, + ) # attribute count global_max_attributes = self._from_env_if_absent( max_attributes, OTEL_ATTRIBUTE_COUNT_LIMIT @@ -124,9 +128,6 @@ def __init__( OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT, ) - def __repr__(self): - return f"{type(self).__name__}(max_attributes={self.max_attributes}, max_attribute_length={self.max_attribute_length})" - @classmethod def _from_env_if_absent( cls, value: Optional[int], env_var: str, default: Optional[int] = None diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index 58cbf01e08b..15096ceebdd 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -44,6 +44,7 @@ from opentelemetry import context as context_api from opentelemetry import trace as trace_api from opentelemetry.attributes import BoundedAttributes +from opentelemetry.opentelemetry import OpenTelemetry from opentelemetry.sdk import util from opentelemetry.sdk.environment_variables import ( OTEL_ATTRIBUTE_COUNT_LIMIT, @@ -563,7 +564,7 @@ def _format_links(links: Sequence[trace_api.Link]) -> List[Dict[str, Any]]: ] -class SpanLimits: +class SpanLimits(OpenTelemetry): """The limits that should be enforce on recorded data such as events, links, attributes etc. This class does not enforce any limits itself. It only provides an a way read limits from env, @@ -620,6 +621,16 @@ def __init__( max_span_attribute_length: Optional[int] = None, ): + super().__init__( + max_attributes=max_attributes, + max_events=max_events, + max_links=max_links, + max_span_attributes=max_span_attributes, + max_event_attributes=max_event_attributes, + max_link_attributes=max_link_attributes, + max_attribute_length=max_attribute_length, + max_span_attribute_length=max_span_attribute_length, + ) # span events and links count self.max_events = self._from_env_if_absent( max_events, @@ -682,9 +693,6 @@ def __init__( self.max_attribute_length, ) - def __repr__(self): - return f"{type(self).__name__}(max_span_attributes={self.max_span_attributes}, max_events_attributes={self.max_event_attributes}, max_link_attributes={self.max_link_attributes}, max_attributes={self.max_attributes}, max_events={self.max_events}, max_links={self.max_links}, max_attribute_length={self.max_attribute_length})" - @classmethod def _from_env_if_absent( cls, value: Optional[int], env_var: str, default: Optional[int] = None @@ -735,7 +743,7 @@ def _from_env_if_absent( ) -class Span(trace_api.Span, ReadableSpan): +class Span(trace_api.Span, ReadableSpan, OpenTelemetry): """See `opentelemetry.trace.Span`. Users should create `Span` objects via the `Tracer` instead of this @@ -818,9 +826,6 @@ def __init__( self._links = self._new_links(links) - def __repr__(self): - return f'{type(self).__name__}(name="{self._name}", context={self._context})' - def _new_events(self): return BoundedList(self._limits.max_events) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py index 40e142ea1a9..ac00f8e4ea3 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py @@ -140,6 +140,7 @@ class CustomSamplerFactory: # pylint: disable=unused-import from opentelemetry.context import Context +from opentelemetry.opentelemetry import OpenTelemetry from opentelemetry.sdk.environment_variables import ( OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG, @@ -166,7 +167,7 @@ def is_sampled(self): return self is Decision.RECORD_AND_SAMPLE -class SamplingResult: +class SamplingResult(OpenTelemetry): """A sampling result as applied to a newly-created Span. Args: @@ -177,15 +178,15 @@ class SamplingResult: Could possibly have been modified by the sampler. """ - def __repr__(self) -> str: - return f"{type(self).__name__}({str(self.decision)}, attributes={str(self.attributes)})" - def __init__( self, decision: Decision, attributes: "Attributes" = None, trace_state: Optional["TraceState"] = None, ) -> None: + super().__init__( + decision, attributes=attributes, trace_state=trace_state + ) self.decision = decision if attributes is None: self.attributes = MappingProxyType({}) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/util/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/util/__init__.py index 68f10ddc9e9..547a8e79999 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/util/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/util/__init__.py @@ -20,6 +20,8 @@ from deprecated import deprecated +from opentelemetry.opentelemetry import OpenTelemetry + def ns_to_iso_str(nanoseconds): """Get an ISO 8601 string from time_ns value.""" @@ -43,7 +45,7 @@ def get_dict_as_key(labels): ) -class BoundedList(Sequence): +class BoundedList(OpenTelemetry, Sequence): """An append only list with a fixed max size. Calls to `append` and `extend` will drop the oldest elements if there is @@ -51,13 +53,11 @@ class BoundedList(Sequence): """ def __init__(self, maxlen: Optional[int]): + super().__init__(maxlen) self.dropped = 0 self._dq = deque(maxlen=maxlen) # type: deque self._lock = threading.Lock() - def __repr__(self): - return f"{type(self).__name__}({list(self._dq)}, maxlen={self._dq.maxlen})" - def __getitem__(self, index): return self._dq[index] @@ -94,7 +94,7 @@ def from_seq(cls, maxlen, seq): @deprecated(version="1.4.0") # type: ignore -class BoundedDict(MutableMapping): +class BoundedDict(OpenTelemetry, MutableMapping): """An ordered dict with a fixed max capacity. Oldest elements are dropped when the dict is full and a new element is @@ -102,6 +102,7 @@ class BoundedDict(MutableMapping): """ def __init__(self, maxlen: Optional[int]): + super().__init__(maxlen) if maxlen is not None: if not isinstance(maxlen, int): raise ValueError @@ -112,11 +113,6 @@ def __init__(self, maxlen: Optional[int]): self._dict = {} # type: dict self._lock = threading.Lock() # type: threading.Lock - def __repr__(self): - return ( - f"{type(self).__name__}({dict(self._dict)}, maxlen={self.maxlen})" - ) - def __getitem__(self, key): return self._dict[key] diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py b/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py index a6fd7d7f66b..9f74eaa88d6 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py @@ -17,10 +17,11 @@ from deprecated import deprecated from opentelemetry.attributes import BoundedAttributes +from opentelemetry.opentelemetry import OpenTelemetry from opentelemetry.util.types import Attributes -class InstrumentationInfo: +class InstrumentationInfo(OpenTelemetry): """Immutable information about an instrumentation library module. See `opentelemetry.trace.TracerProvider.get_tracer` for the meaning of these @@ -36,15 +37,13 @@ def __init__( version: Optional[str] = None, schema_url: Optional[str] = None, ): + super().__init__(name, version=version, schema_url=schema_url) self._name = name self._version = version if schema_url is None: schema_url = "" self._schema_url = schema_url - def __repr__(self): - return f"{type(self).__name__}({self._name}, {self._version}, {self._schema_url})" - def __hash__(self): return hash((self._name, self._version, self._schema_url)) @@ -77,7 +76,7 @@ def name(self) -> str: return self._name -class InstrumentationScope: +class InstrumentationScope(OpenTelemetry): """A logical unit of the application code with which the emitted telemetry can be associated. @@ -94,6 +93,9 @@ def __init__( schema_url: Optional[str] = None, attributes: Optional[Attributes] = None, ) -> None: + super().__init__( + name, version=version, schema_url=schema_url, attributes=attributes + ) self._name = name self._version = version if schema_url is None: @@ -101,9 +103,6 @@ def __init__( self._schema_url = schema_url self._attributes = BoundedAttributes(attributes=attributes) - def __repr__(self) -> str: - return f"{type(self).__name__}({self._name}, {self._version}, {self._schema_url}, {self._attributes})" - def __hash__(self) -> int: return hash((self._name, self._version, self._schema_url)) diff --git a/opentelemetry-sdk/tests/logs/test_log_limits.py b/opentelemetry-sdk/tests/logs/test_log_limits.py index c2135b65694..1eafea86345 100644 --- a/opentelemetry-sdk/tests/logs/test_log_limits.py +++ b/opentelemetry-sdk/tests/logs/test_log_limits.py @@ -15,14 +15,11 @@ import unittest from opentelemetry.sdk._logs import LogLimits -from opentelemetry.sdk._logs._internal import ( - _DEFAULT_OTEL_ATTRIBUTE_COUNT_LIMIT, -) class TestLogLimits(unittest.TestCase): def test_log_limits_repr_unset(self): - expected = f"LogLimits(max_attributes={_DEFAULT_OTEL_ATTRIBUTE_COUNT_LIMIT}, max_attribute_length=None)" + expected = "LogLimits()" limits = str(LogLimits()) self.assertEqual(expected, limits) diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 779093f736f..b98a88e607a 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -1561,7 +1561,7 @@ def test_to_json(self): "context": { "trace_id": "0x000000000000000000000000deadbeef", "span_id": "0x00000000deadbef0", - "trace_state": "[]" + "trace_state": "TraceState()" }, "kind": "SpanKind.INTERNAL", "parent_id": "0x00000000deadbef0", @@ -1581,7 +1581,7 @@ def test_to_json(self): ) self.assertEqual( span.to_json(indent=None), - '{"name": "span-name", "context": {"trace_id": "0x000000000000000000000000deadbeef", "span_id": "0x00000000deadbef0", "trace_state": "[]"}, "kind": "SpanKind.INTERNAL", "parent_id": "0x00000000deadbef0", "start_time": null, "end_time": null, "status": {"status_code": "UNSET"}, "attributes": {}, "events": [], "links": [], "resource": {"attributes": {}, "schema_url": ""}}', + '{"name": "span-name", "context": {"trace_id": "0x000000000000000000000000deadbeef", "span_id": "0x00000000deadbef0", "trace_state": "TraceState()"}, "kind": "SpanKind.INTERNAL", "parent_id": "0x00000000deadbef0", "start_time": null, "end_time": null, "status": {"status_code": "UNSET"}, "attributes": {}, "events": [], "links": [], "resource": {"attributes": {}, "schema_url": ""}}', ) def test_attributes_to_json(self): @@ -1597,7 +1597,7 @@ def test_attributes_to_json(self): date_str = ns_to_iso_str(123) self.assertEqual( span.to_json(indent=None), - '{"name": "span-name", "context": {"trace_id": "0x000000000000000000000000deadbeef", "span_id": "0x00000000deadbef0", "trace_state": "[]"}, "kind": "SpanKind.INTERNAL", "parent_id": null, "start_time": null, "end_time": null, "status": {"status_code": "UNSET"}, "attributes": {"key": "value"}, "events": [{"name": "event", "timestamp": "' + '{"name": "span-name", "context": {"trace_id": "0x000000000000000000000000deadbeef", "span_id": "0x00000000deadbef0", "trace_state": "TraceState()"}, "kind": "SpanKind.INTERNAL", "parent_id": null, "start_time": null, "end_time": null, "status": {"status_code": "UNSET"}, "attributes": {"key": "value"}, "events": [{"name": "event", "timestamp": "' + date_str + '", "attributes": {"key2": "value2"}}], "links": [], "resource": {"attributes": {}, "schema_url": ""}}', )