Repository: open-telemetry/opentelemetry-python

Issue:
Remove lazy Event and Link API from Span interface 
As per spec https://github.com/open-telemetry/opentelemetry-specification/pull/840


Discussion:

Resolving patch:
diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py
--- a/opentelemetry-api/src/opentelemetry/trace/__init__.py
+++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py
@@ -138,28 +138,6 @@ def attributes(self) -> types.Attributes:
         return self._attributes
 
 
-class LazyLink(LinkBase):
-    """A lazy link to a `Span`.
-
-    Args:
-        context: `SpanContext` of the `Span` to link to.
-        link_formatter: Callable object that returns the attributes of the
-            Link.
-    """
-
-    def __init__(
-        self,
-        context: "SpanContext",
-        link_formatter: types.AttributesFormatter,
-    ) -> None:
-        super().__init__(context)
-        self._link_formatter = link_formatter
-
-    @property
-    def attributes(self) -> types.Attributes:
-        return self._link_formatter()
-
-
 class SpanKind(enum.Enum):
     """Specifies additional details on how this span relates to its parent span.
 
@@ -464,7 +442,6 @@ def get_tracer_provider() -> TracerProvider:
     "DefaultSpan",
     "DefaultTracer",
     "DefaultTracerProvider",
-    "LazyLink",
     "Link",
     "LinkBase",
     "ParentSpan",
diff --git a/opentelemetry-api/src/opentelemetry/trace/span.py b/opentelemetry-api/src/opentelemetry/trace/span.py
--- a/opentelemetry-api/src/opentelemetry/trace/span.py
+++ b/opentelemetry-api/src/opentelemetry/trace/span.py
@@ -51,19 +51,6 @@ def add_event(
         timestamp if the `timestamp` argument is omitted.
         """
 
-    @abc.abstractmethod
-    def add_lazy_event(
-        self,
-        name: str,
-        event_formatter: types.AttributesFormatter,
-        timestamp: typing.Optional[int] = None,
-    ) -> None:
-        """Adds an `Event`.
-        Adds a single `Event` with the name, an event formatter that calculates
-        the attributes lazily and, optionally, a timestamp. Implementations
-        should generate a timestamp if the `timestamp` argument is omitted.
-        """
-
     @abc.abstractmethod
     def update_name(self, name: str) -> None:
         """Updates the `Span` name.
@@ -233,14 +220,6 @@ def add_event(
     ) -> None:
         pass
 
-    def add_lazy_event(
-        self,
-        name: str,
-        event_formatter: types.AttributesFormatter,
-        timestamp: typing.Optional[int] = None,
-    ) -> None:
-        pass
-
     def update_name(self, name: str) -> None:
         pass
 
diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
--- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
+++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
@@ -284,35 +284,6 @@ def attributes(self) -> types.Attributes:
         return self._attributes
 
 
-class LazyEvent(EventBase):
-    """A text annotation with a set of attributes.
-
-    Args:
-        name: Name of the event.
-        event_formatter: Callable object that returns the attributes of the
-            event.
-        timestamp: Timestamp of the event. If `None` it will filled
-            automatically.
-    """
-
-    def __init__(
-        self,
-        name: str,
-        event_formatter: types.AttributesFormatter,
-        timestamp: Optional[int] = None,
-    ) -> None:
-        super().__init__(name, timestamp)
-        self._event_formatter = event_formatter
-
-    @property
-    def attributes(self) -> types.Attributes:
-        attributes = self._event_formatter()
-        _filter_attribute_values(attributes)
-        if not attributes:
-            attributes = Span._new_attributes()
-        return attributes
-
-
 def _is_valid_attribute_value(value: types.AttributeValue) -> bool:
     """Checks if attribute value is valid.
 
@@ -596,20 +567,6 @@ def add_event(
             )
         )
 
-    def add_lazy_event(
-        self,
-        name: str,
-        event_formatter: types.AttributesFormatter,
-        timestamp: Optional[int] = None,
-    ) -> None:
-        self._add_event(
-            LazyEvent(
-                name=name,
-                event_formatter=event_formatter,
-                timestamp=time_ns() if timestamp is None else timestamp,
-            )
-        )
-
     def start(self, start_time: Optional[int] = None) -> None:
         with self._lock:
             if not self.is_recording_events():


Test patch:
diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py
--- a/opentelemetry-sdk/tests/trace/test_trace.py
+++ b/opentelemetry-sdk/tests/trace/test_trace.py
@@ -572,13 +572,7 @@ def test_events(self):
             mutable_list = ["original_contents"]
             root.add_event("event3", {"name": mutable_list})
 
-            def event_formatter():
-                return {"name": "hello"}
-
-            # lazy event
-            root.add_lazy_event("event4", event_formatter, now)
-
-            self.assertEqual(len(root.events), 5)
+            self.assertEqual(len(root.events), 4)
 
             self.assertEqual(root.events[0].name, "event0")
             self.assertEqual(root.events[0].attributes, {})
@@ -604,13 +598,8 @@ def event_formatter():
                 root.events[3].attributes, {"name": ("original_contents",)}
             )
 
-            self.assertEqual(root.events[4].name, "event4")
-            self.assertEqual(root.events[4].attributes, {"name": "hello"})
-            self.assertEqual(root.events[4].timestamp, now)
-
     def test_invalid_event_attributes(self):
         self.assertEqual(trace_api.get_current_span(), trace_api.INVALID_SPAN)
-        now = time_ns()
 
         with self.tracer.start_as_current_span("root") as root:
             root.add_event("event0", {"attr1": True, "attr2": ["hi", False]})
@@ -624,19 +613,6 @@ def test_invalid_event_attributes(self):
             self.assertEqual(root.events[2].attributes, {})
             self.assertEqual(root.events[3].attributes, {"attr2": (1, 2)})
 
-            def event_formatter():
-                properties = {}
-                properties["attr1"] = dict()
-                properties["attr2"] = "hello"
-                return properties
-
-            root.add_lazy_event("event4", event_formatter, now)
-
-            self.assertEqual(len(root.events), 5)
-            self.assertEqual(root.events[4].name, "event4")
-            self.assertEqual(root.events[4].attributes, {"attr2": "hello"})
-            self.assertEqual(root.events[4].timestamp, now)
-
     def test_links(self):
         other_context1 = trace_api.SpanContext(
             trace_id=trace.generate_trace_id(),
@@ -648,23 +624,14 @@ def test_links(self):
             span_id=trace.generate_span_id(),
             is_remote=False,
         )
-        other_context3 = trace_api.SpanContext(
-            trace_id=trace.generate_trace_id(),
-            span_id=trace.generate_span_id(),
-            is_remote=False,
-        )
-
-        def get_link_attributes():
-            return {"component": "http"}
 
         links = (
             trace_api.Link(other_context1),
             trace_api.Link(other_context2, {"name": "neighbor"}),
-            trace_api.LazyLink(other_context3, get_link_attributes),
         )
         with self.tracer.start_as_current_span("root", links=links) as root:
 
-            self.assertEqual(len(root.links), 3)
+            self.assertEqual(len(root.links), 2)
             self.assertEqual(
                 root.links[0].context.trace_id, other_context1.trace_id
             )
@@ -679,10 +646,6 @@ def get_link_attributes():
                 root.links[1].context.span_id, other_context2.span_id
             )
             self.assertEqual(root.links[1].attributes, {"name": "neighbor"})
-            self.assertEqual(
-                root.links[2].context.span_id, other_context3.span_id
-            )
-            self.assertEqual(root.links[2].attributes, {"component": "http"})
 
     def test_update_name(self):
         with self.tracer.start_as_current_span("root") as root: