From 2ebc31ed309fcf3c98e7d98626f2d5d5fd05e090 Mon Sep 17 00:00:00 2001 From: Diego Hurtado Date: Tue, 30 Jan 2024 21:43:31 -0600 Subject: [PATCH] Add __repr__ to all classes Fixes #3651 --- .../src/opentelemetry/attributes/__init__.py | 12 +- .../metrics/_internal/observation.py | 6 +- .../src/opentelemetry/opentelemetry.py | 67 +++ .../src/opentelemetry/trace/span.py | 33 +- opentelemetry-api/tests/test_opentelemetry.py | 533 ++++++++++++++++++ .../sdk/_logs/_internal/__init__.py | 13 +- .../src/opentelemetry/sdk/trace/__init__.py | 11 +- .../src/opentelemetry/sdk/trace/sampling.py | 6 +- .../src/opentelemetry/sdk/util/__init__.py | 14 +- .../opentelemetry/sdk/util/instrumentation.py | 12 +- .../tests/logs/test_log_limits.py | 5 +- opentelemetry-sdk/tests/trace/test_trace.py | 6 +- 12 files changed, 650 insertions(+), 68 deletions(-) create mode 100644 opentelemetry-api/src/opentelemetry/opentelemetry.py create mode 100644 opentelemetry-api/tests/test_opentelemetry.py 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..7b714b07710 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. @@ -47,6 +48,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..800999a269c --- /dev/null +++ b/opentelemetry-api/src/opentelemetry/opentelemetry.py @@ -0,0 +1,67 @@ +# 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 inspect import signature + + +class OpenTelemetry: + def __init__(self, *args, **kwargs) -> None: + + args = list(args) + + object.__setattr__(self, "_repr", []) + + parameters = signature(self.__init__).parameters.values() + + for index, parameter in enumerate(parameters): + if ( + parameter.kind is parameter.POSITIONAL_ONLY + or parameter.kind is parameter.POSITIONAL_OR_KEYWORD + ): + if args: + self._repr.append(repr(args.pop(0))) + else: + break + elif parameter.kind is parameter.VAR_POSITIONAL: + for _ in range(len(args)): + self._repr.append(repr(args.pop(0))) + + for index, parameter in enumerate(parameters): + if parameter.kind is parameter.KEYWORD_ONLY: + if args: + value = args.pop(0) + + if parameter.default != value: + self._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 kwargs.keys(): + value = kwargs.pop(parameter.name) + + if parameter.default != value: + self._repr.append(f"{parameter.name}={repr(value)}") + + elif parameter.kind is parameter.VAR_KEYWORD: + for key, value in kwargs.items(): + self._repr.append(f"{key}={repr(value)}") + + self._repr = f"{self.__class__.__name__}({', '.join(self._repr)})" + + def __repr__(self) -> str: + return self._repr diff --git a/opentelemetry-api/src/opentelemetry/trace/span.py b/opentelemetry-api/src/opentelemetry/trace/span.py index 4afc4d520a2..b6efa606acc 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. @@ -571,9 +573,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..b3b1a6f8033 --- /dev/null +++ b/opentelemetry-api/tests/test_opentelemetry.py @@ -0,0 +1,533 @@ +# 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): + 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): + 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..bc83daa7bf3 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, @@ -682,9 +683,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 +733,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 +816,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..0c073cfc130 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,9 +178,6 @@ 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, diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/util/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/util/__init__.py index 68f10ddc9e9..6a670c19fbb 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 @@ -55,9 +57,6 @@ def __init__(self, maxlen: Optional[int]): 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 +93,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 @@ -112,11 +111,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..9bad9a93aea 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/util/instrumentation.py @@ -19,8 +19,10 @@ from opentelemetry.attributes import BoundedAttributes from opentelemetry.util.types import Attributes +from opentelemetry.opentelemetry import OpenTelemetry -class InstrumentationInfo: + +class InstrumentationInfo(OpenTelemetry): """Immutable information about an instrumentation library module. See `opentelemetry.trace.TracerProvider.get_tracer` for the meaning of these @@ -42,9 +44,6 @@ def __init__( 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. @@ -101,9 +100,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": ""}}', )