From 985b62caff468c7386f2f33e4184b57263e9eb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Fri, 6 Sep 2019 19:41:17 -0500 Subject: [PATCH 1/4] remove annotation for self --- opentelemetry-api/src/opentelemetry/trace/__init__.py | 8 +++----- .../src/opentelemetry/sdk/trace/__init__.py | 10 ++++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index dc57358183d..a67a99ae24a 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -102,16 +102,14 @@ def get_context(self) -> "SpanContext": A :class:`.SpanContext` with a copy of this span's immutable state. """ - def set_attribute( - self: "Span", key: str, value: types.AttributeValue - ) -> None: + def set_attribute(self, key: str, value: types.AttributeValue) -> None: """Sets an Attribute. Sets a single Attribute with the key and value passed as arguments. """ def add_event( - self: "Span", name: str, attributes: types.Attributes = None + self, name: str, attributes: types.Attributes = None ) -> None: """Adds an Event. @@ -120,7 +118,7 @@ def add_event( """ def add_link( - self: "Span", + self, link_target_context: "SpanContext", attributes: types.Attributes = None, ) -> None: diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index 21acb394945..f20ea91321c 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -233,7 +233,7 @@ class Span(trace_api.Span): empty_links = BoundedList(MAX_NUM_LINKS) def __init__( - self: "Span", + self, name: str, context: "trace_api.SpanContext", parent: trace_api.ParentSpan = None, @@ -283,15 +283,13 @@ def __repr__(self): def get_context(self): return self.context - def set_attribute( - self: "Span", key: str, value: types.AttributeValue - ) -> None: + def set_attribute(self, key: str, value: types.AttributeValue) -> None: if self.attributes is Span.empty_attributes: self.attributes = BoundedDict(MAX_NUM_ATTRIBUTES) self.attributes[key] = value def add_event( - self: "Span", name: str, attributes: types.Attributes = None + self, name: str, attributes: types.Attributes = None ) -> None: if self.events is Span.empty_events: self.events = BoundedList(MAX_NUM_EVENTS) @@ -300,7 +298,7 @@ def add_event( self.events.append(Event(name, attributes)) def add_link( - self: "Span", + self, link_target_context: "trace_api.SpanContext", attributes: types.Attributes = None, ) -> None: From 8a369fda600a2864061e7bba41f626d96f739838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Fri, 6 Sep 2019 09:22:52 -0500 Subject: [PATCH 2/4] sdk/tests/trace/span: reorganize by member Put all actions of the same member together so it is easier to update the tests. --- opentelemetry-sdk/tests/trace/test_trace.py | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index c0a0e65008d..aa9185a4c5f 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -130,6 +130,7 @@ def test_span_members(self): self.assertIsNone(tracer.get_current_span()) with tracer.start_span("root") as root: + # attributes root.set_attribute("component", "http") root.set_attribute("http.method", "GET") root.set_attribute( @@ -144,18 +145,6 @@ def test_span_members(self): root.set_attribute("attr-key", "attr-value1") root.set_attribute("attr-key", "attr-value2") - root.add_event("event0") - root.add_event("event1", {"name": "birthday"}) - - root.add_link(other_context1) - root.add_link(other_context2, {"name": "neighbor"}) - - root.update_name("toor") - self.assertEqual(root.name, "toor") - - # The public API does not expose getters. - # Checks by accessing the span members directly - self.assertEqual(len(root.attributes), 7) self.assertEqual(root.attributes["component"], "http") self.assertEqual(root.attributes["http.method"], "GET") @@ -168,6 +157,10 @@ def test_span_members(self): self.assertEqual(root.attributes["misc.pi"], 3.14) self.assertEqual(root.attributes["attr-key"], "attr-value2") + # events + root.add_event("event0") + root.add_event("event1", {"name": "birthday"}) + self.assertEqual(len(root.events), 2) self.assertEqual( root.events[0], trace.Event(name="event0", attributes={}) @@ -177,6 +170,10 @@ def test_span_members(self): trace.Event(name="event1", attributes={"name": "birthday"}), ) + # links + root.add_link(other_context1) + root.add_link(other_context2, {"name": "neighbor"}) + self.assertEqual(len(root.links), 2) self.assertEqual( root.links[0].context.trace_id, other_context1.trace_id @@ -193,6 +190,9 @@ def test_span_members(self): ) self.assertEqual(root.links[1].attributes, {"name": "neighbor"}) + # name + root.update_name("toor") + self.assertEqual(root.name, "toor") class TestSpan(unittest.TestCase): def test_basic_span(self): From 96b75677911a212fde76c38f3900f0bfd3125086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Fri, 6 Sep 2019 09:29:15 -0500 Subject: [PATCH 3/4] add Link class Make Link a class, also implement addLazyLink --- .../src/opentelemetry/trace/__init__.py | 28 +++++++++++++++++-- opentelemetry-api/src/opentelemetry/types.py | 2 +- .../src/opentelemetry/sdk/trace/__init__.py | 13 +++++---- opentelemetry-sdk/tests/trace/test_trace.py | 14 +++++++++- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index a67a99ae24a..3a417c6b136 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -70,6 +70,24 @@ ParentSpan = typing.Optional[typing.Union["Span", "SpanContext"]] +class Link: + """A link to a `Span`.""" + + def __init__( + self, context: "SpanContext", attributes: types.Attributes = None + ) -> None: + self._context = context + self._attributes = attributes + + @property + def context(self) -> "SpanContext": + return self._context + + @property + def attributes(self) -> types.Attributes: + return self._attributes + + class Span: """A span represents a single operation within a trace.""" @@ -122,12 +140,18 @@ def add_link( link_target_context: "SpanContext", attributes: types.Attributes = None, ) -> None: - """Adds a Link to another span. + """Adds a `Link` to another span. - Adds a single Link from this Span to another Span identified by the + Adds a single `Link` from this Span to another Span identified by the `SpanContext` passed as argument. """ + def add_lazy_link(self, link: "Link") -> None: + """Adds a `Link` to another span. + + Adds a `Link` that has previously been created. + """ + def update_name(self, name: str) -> None: """Updates the `Span` name. diff --git a/opentelemetry-api/src/opentelemetry/types.py b/opentelemetry-api/src/opentelemetry/types.py index ce5682ee0af..28fab893890 100644 --- a/opentelemetry-api/src/opentelemetry/types.py +++ b/opentelemetry-api/src/opentelemetry/types.py @@ -16,4 +16,4 @@ import typing AttributeValue = typing.Union[str, bool, float] -Attributes = typing.Dict[str, AttributeValue] +Attributes = typing.Optional[typing.Dict[str, AttributeValue]] diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index f20ea91321c..a8d654a5b9e 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -142,8 +142,6 @@ def from_map(cls, maxlen, mapping): Event = namedtuple("Event", ("name", "attributes")) -Link = namedtuple("Link", ("context", "attributes")) - class SpanProcessor: """Interface which allows hooks for SDK's `Span`s start and end method @@ -242,7 +240,7 @@ def __init__( resource=None, # TODO attributes: types.Attributes = None, # TODO events: typing.Sequence[Event] = None, # TODO - links: typing.Sequence[Link] = None, # TODO + links: typing.Sequence[trace_api.Link] = None, # TODO span_processor: SpanProcessor = SpanProcessor(), ) -> None: @@ -302,11 +300,14 @@ def add_link( link_target_context: "trace_api.SpanContext", attributes: types.Attributes = None, ) -> None: - if self.links is Span.empty_links: - self.links = BoundedList(MAX_NUM_LINKS) if attributes is None: attributes = Span.empty_attributes - self.links.append(Link(link_target_context, attributes)) + self.add_lazy_link(trace_api.Link(link_target_context, attributes)) + + def add_lazy_link(self, link: "trace_api.Link") -> None: + if self.links is Span.empty_links: + self.links = BoundedList(MAX_NUM_LINKS) + self.links.append(link) def start(self): if self.start_time is None: diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index aa9185a4c5f..1a837135134 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -126,6 +126,10 @@ def test_span_members(self): trace_id=trace.generate_trace_id(), span_id=trace.generate_span_id(), ) + other_context3 = trace_api.SpanContext( + trace_id=trace.generate_trace_id(), + span_id=trace.generate_span_id(), + ) self.assertIsNone(tracer.get_current_span()) @@ -173,8 +177,11 @@ def test_span_members(self): # links root.add_link(other_context1) root.add_link(other_context2, {"name": "neighbor"}) + root.add_lazy_link( + trace_api.Link(other_context3, {"component": "http"}) + ) - self.assertEqual(len(root.links), 2) + self.assertEqual(len(root.links), 3) self.assertEqual( root.links[0].context.trace_id, other_context1.trace_id ) @@ -189,11 +196,16 @@ def test_span_members(self): 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"}) # name root.update_name("toor") self.assertEqual(root.name, "toor") + class TestSpan(unittest.TestCase): def test_basic_span(self): span = trace.Span("name", mock.Mock(spec=trace_api.SpanContext)) From a339e7d3863242732683c7decb91027a7e36ef7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20V=C3=A1squez?= Date: Fri, 6 Sep 2019 16:01:08 -0500 Subject: [PATCH 4/4] add Event class Make Event a class and implement add_lazy_event --- .../src/opentelemetry/trace/__init__.py | 33 +++++++++++++++++-- .../src/opentelemetry/sdk/trace/__init__.py | 16 ++++----- opentelemetry-sdk/tests/trace/test_trace.py | 24 +++++++++----- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/opentelemetry-api/src/opentelemetry/trace/__init__.py b/opentelemetry-api/src/opentelemetry/trace/__init__.py index 3a417c6b136..e6a7a55649d 100644 --- a/opentelemetry-api/src/opentelemetry/trace/__init__.py +++ b/opentelemetry-api/src/opentelemetry/trace/__init__.py @@ -88,6 +88,29 @@ def attributes(self) -> types.Attributes: return self._attributes +class Event: + """A text annotation with a set of attributes.""" + + def __init__( + self, name: str, timestamp: int, attributes: types.Attributes = None + ) -> None: + self._name = name + self._attributes = attributes + self._timestamp = timestamp + + @property + def name(self) -> str: + return self._name + + @property + def attributes(self) -> types.Attributes: + return self._attributes + + @property + def timestamp(self) -> int: + return self._timestamp + + class Span: """A span represents a single operation within a trace.""" @@ -129,12 +152,18 @@ def set_attribute(self, key: str, value: types.AttributeValue) -> None: def add_event( self, name: str, attributes: types.Attributes = None ) -> None: - """Adds an Event. + """Adds an `Event`. - Adds a single Event with the name and, optionally, attributes passed + Adds a single `Event` with the name and, optionally, attributes passed as arguments. """ + def add_lazy_event(self, event: Event) -> None: + """Adds an `Event`. + + Adds an `Event` that has previously been created. + """ + def add_link( self, link_target_context: "SpanContext", diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index a8d654a5b9e..a6f70589b3f 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -16,7 +16,7 @@ import random import threading import typing -from collections import OrderedDict, deque, namedtuple +from collections import OrderedDict, deque from contextlib import contextmanager from opentelemetry import trace as trace_api @@ -140,9 +140,6 @@ def from_map(cls, maxlen, mapping): return bounded_dict -Event = namedtuple("Event", ("name", "attributes")) - - class SpanProcessor: """Interface which allows hooks for SDK's `Span`s start and end method invocations. @@ -239,7 +236,7 @@ def __init__( trace_config=None, # TODO resource=None, # TODO attributes: types.Attributes = None, # TODO - events: typing.Sequence[Event] = None, # TODO + events: typing.Sequence[trace_api.Event] = None, # TODO links: typing.Sequence[trace_api.Link] = None, # TODO span_processor: SpanProcessor = SpanProcessor(), ) -> None: @@ -289,11 +286,14 @@ def set_attribute(self, key: str, value: types.AttributeValue) -> None: def add_event( self, name: str, attributes: types.Attributes = None ) -> None: - if self.events is Span.empty_events: - self.events = BoundedList(MAX_NUM_EVENTS) if attributes is None: attributes = Span.empty_attributes - self.events.append(Event(name, attributes)) + self.add_lazy_event(trace_api.Event(name, util.time_ns(), attributes)) + + def add_lazy_event(self, event: trace_api.Event) -> None: + if self.events is Span.empty_events: + self.events = BoundedList(MAX_NUM_EVENTS) + self.events.append(event) def add_link( self, diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index 1a837135134..a1182823b59 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -17,6 +17,7 @@ from opentelemetry import trace as trace_api from opentelemetry.sdk import trace +from opentelemetry.sdk import util class TestTracer(unittest.TestCase): @@ -164,16 +165,23 @@ def test_span_members(self): # events root.add_event("event0") root.add_event("event1", {"name": "birthday"}) - - self.assertEqual(len(root.events), 2) - self.assertEqual( - root.events[0], trace.Event(name="event0", attributes={}) - ) - self.assertEqual( - root.events[1], - trace.Event(name="event1", attributes={"name": "birthday"}), + now = util.time_ns() + root.add_lazy_event( + trace_api.Event("event2", now, {"name": "hello"}) ) + self.assertEqual(len(root.events), 3) + + self.assertEqual(root.events[0].name, "event0") + self.assertEqual(root.events[0].attributes, {}) + + self.assertEqual(root.events[1].name, "event1") + self.assertEqual(root.events[1].attributes, {"name": "birthday"}) + + self.assertEqual(root.events[2].name, "event2") + self.assertEqual(root.events[2].attributes, {"name": "hello"}) + self.assertEqual(root.events[2].timestamp, now) + # links root.add_link(other_context1) root.add_link(other_context2, {"name": "neighbor"})