Skip to content

Commit 731ed02

Browse files
mauriciovasquezbernalOberon00
authored andcommitted
Add Link and Event classes (#130)
* remove annotation for self * sdk/tests/trace/span: reorganize by member Put all actions of the same member together so it is easier to update the tests. * add Link class Make Link a class, also implement addLazyLink * add Event class Make Event a class and implement add_lazy_event
1 parent fb11568 commit 731ed02

File tree

4 files changed

+119
-49
lines changed

4 files changed

+119
-49
lines changed

opentelemetry-api/src/opentelemetry/trace/__init__.py

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,47 @@
7070
ParentSpan = typing.Optional[typing.Union["Span", "SpanContext"]]
7171

7272

73+
class Link:
74+
"""A link to a `Span`."""
75+
76+
def __init__(
77+
self, context: "SpanContext", attributes: types.Attributes = None
78+
) -> None:
79+
self._context = context
80+
self._attributes = attributes
81+
82+
@property
83+
def context(self) -> "SpanContext":
84+
return self._context
85+
86+
@property
87+
def attributes(self) -> types.Attributes:
88+
return self._attributes
89+
90+
91+
class Event:
92+
"""A text annotation with a set of attributes."""
93+
94+
def __init__(
95+
self, name: str, timestamp: int, attributes: types.Attributes = None
96+
) -> None:
97+
self._name = name
98+
self._attributes = attributes
99+
self._timestamp = timestamp
100+
101+
@property
102+
def name(self) -> str:
103+
return self._name
104+
105+
@property
106+
def attributes(self) -> types.Attributes:
107+
return self._attributes
108+
109+
@property
110+
def timestamp(self) -> int:
111+
return self._timestamp
112+
113+
73114
class Span:
74115
"""A span represents a single operation within a trace."""
75116

@@ -102,34 +143,44 @@ def get_context(self) -> "SpanContext":
102143
A :class:`.SpanContext` with a copy of this span's immutable state.
103144
"""
104145

105-
def set_attribute(
106-
self: "Span", key: str, value: types.AttributeValue
107-
) -> None:
146+
def set_attribute(self, key: str, value: types.AttributeValue) -> None:
108147
"""Sets an Attribute.
109148
110149
Sets a single Attribute with the key and value passed as arguments.
111150
"""
112151

113152
def add_event(
114-
self: "Span", name: str, attributes: types.Attributes = None
153+
self, name: str, attributes: types.Attributes = None
115154
) -> None:
116-
"""Adds an Event.
155+
"""Adds an `Event`.
117156
118-
Adds a single Event with the name and, optionally, attributes passed
157+
Adds a single `Event` with the name and, optionally, attributes passed
119158
as arguments.
120159
"""
121160

161+
def add_lazy_event(self, event: Event) -> None:
162+
"""Adds an `Event`.
163+
164+
Adds an `Event` that has previously been created.
165+
"""
166+
122167
def add_link(
123-
self: "Span",
168+
self,
124169
link_target_context: "SpanContext",
125170
attributes: types.Attributes = None,
126171
) -> None:
127-
"""Adds a Link to another span.
172+
"""Adds a `Link` to another span.
128173
129-
Adds a single Link from this Span to another Span identified by the
174+
Adds a single `Link` from this Span to another Span identified by the
130175
`SpanContext` passed as argument.
131176
"""
132177

178+
def add_lazy_link(self, link: "Link") -> None:
179+
"""Adds a `Link` to another span.
180+
181+
Adds a `Link` that has previously been created.
182+
"""
183+
133184
def update_name(self, name: str) -> None:
134185
"""Updates the `Span` name.
135186

opentelemetry-api/src/opentelemetry/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
import typing
1717

1818
AttributeValue = typing.Union[str, bool, float]
19-
Attributes = typing.Dict[str, AttributeValue]
19+
Attributes = typing.Optional[typing.Dict[str, AttributeValue]]

opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import random
1717
import threading
1818
import typing
19-
from collections import OrderedDict, deque, namedtuple
19+
from collections import OrderedDict, deque
2020
from contextlib import contextmanager
2121

2222
from opentelemetry import trace as trace_api
@@ -140,11 +140,6 @@ def from_map(cls, maxlen, mapping):
140140
return bounded_dict
141141

142142

143-
Event = namedtuple("Event", ("name", "attributes"))
144-
145-
Link = namedtuple("Link", ("context", "attributes"))
146-
147-
148143
class SpanProcessor:
149144
"""Interface which allows hooks for SDK's `Span`s start and end method
150145
invocations.
@@ -233,16 +228,16 @@ class Span(trace_api.Span):
233228
empty_links = BoundedList(MAX_NUM_LINKS)
234229

235230
def __init__(
236-
self: "Span",
231+
self,
237232
name: str,
238233
context: "trace_api.SpanContext",
239234
parent: trace_api.ParentSpan = None,
240235
sampler=None, # TODO
241236
trace_config=None, # TODO
242237
resource=None, # TODO
243238
attributes: types.Attributes = None, # TODO
244-
events: typing.Sequence[Event] = None, # TODO
245-
links: typing.Sequence[Link] = None, # TODO
239+
events: typing.Sequence[trace_api.Event] = None, # TODO
240+
links: typing.Sequence[trace_api.Link] = None, # TODO
246241
span_processor: SpanProcessor = SpanProcessor(),
247242
) -> None:
248243

@@ -283,32 +278,36 @@ def __repr__(self):
283278
def get_context(self):
284279
return self.context
285280

286-
def set_attribute(
287-
self: "Span", key: str, value: types.AttributeValue
288-
) -> None:
281+
def set_attribute(self, key: str, value: types.AttributeValue) -> None:
289282
if self.attributes is Span.empty_attributes:
290283
self.attributes = BoundedDict(MAX_NUM_ATTRIBUTES)
291284
self.attributes[key] = value
292285

293286
def add_event(
294-
self: "Span", name: str, attributes: types.Attributes = None
287+
self, name: str, attributes: types.Attributes = None
295288
) -> None:
296-
if self.events is Span.empty_events:
297-
self.events = BoundedList(MAX_NUM_EVENTS)
298289
if attributes is None:
299290
attributes = Span.empty_attributes
300-
self.events.append(Event(name, attributes))
291+
self.add_lazy_event(trace_api.Event(name, util.time_ns(), attributes))
292+
293+
def add_lazy_event(self, event: trace_api.Event) -> None:
294+
if self.events is Span.empty_events:
295+
self.events = BoundedList(MAX_NUM_EVENTS)
296+
self.events.append(event)
301297

302298
def add_link(
303-
self: "Span",
299+
self,
304300
link_target_context: "trace_api.SpanContext",
305301
attributes: types.Attributes = None,
306302
) -> None:
307-
if self.links is Span.empty_links:
308-
self.links = BoundedList(MAX_NUM_LINKS)
309303
if attributes is None:
310304
attributes = Span.empty_attributes
311-
self.links.append(Link(link_target_context, attributes))
305+
self.add_lazy_link(trace_api.Link(link_target_context, attributes))
306+
307+
def add_lazy_link(self, link: "trace_api.Link") -> None:
308+
if self.links is Span.empty_links:
309+
self.links = BoundedList(MAX_NUM_LINKS)
310+
self.links.append(link)
312311

313312
def start(self):
314313
if self.start_time is None:

opentelemetry-sdk/tests/trace/test_trace.py

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from opentelemetry import trace as trace_api
1919
from opentelemetry.sdk import trace
20+
from opentelemetry.sdk import util
2021

2122

2223
class TestTracer(unittest.TestCase):
@@ -126,10 +127,15 @@ def test_span_members(self):
126127
trace_id=trace.generate_trace_id(),
127128
span_id=trace.generate_span_id(),
128129
)
130+
other_context3 = trace_api.SpanContext(
131+
trace_id=trace.generate_trace_id(),
132+
span_id=trace.generate_span_id(),
133+
)
129134

130135
self.assertIsNone(tracer.get_current_span())
131136

132137
with tracer.start_span("root") as root:
138+
# attributes
133139
root.set_attribute("component", "http")
134140
root.set_attribute("http.method", "GET")
135141
root.set_attribute(
@@ -144,18 +150,6 @@ def test_span_members(self):
144150
root.set_attribute("attr-key", "attr-value1")
145151
root.set_attribute("attr-key", "attr-value2")
146152

147-
root.add_event("event0")
148-
root.add_event("event1", {"name": "birthday"})
149-
150-
root.add_link(other_context1)
151-
root.add_link(other_context2, {"name": "neighbor"})
152-
153-
root.update_name("toor")
154-
self.assertEqual(root.name, "toor")
155-
156-
# The public API does not expose getters.
157-
# Checks by accessing the span members directly
158-
159153
self.assertEqual(len(root.attributes), 7)
160154
self.assertEqual(root.attributes["component"], "http")
161155
self.assertEqual(root.attributes["http.method"], "GET")
@@ -168,16 +162,34 @@ def test_span_members(self):
168162
self.assertEqual(root.attributes["misc.pi"], 3.14)
169163
self.assertEqual(root.attributes["attr-key"], "attr-value2")
170164

171-
self.assertEqual(len(root.events), 2)
172-
self.assertEqual(
173-
root.events[0], trace.Event(name="event0", attributes={})
165+
# events
166+
root.add_event("event0")
167+
root.add_event("event1", {"name": "birthday"})
168+
now = util.time_ns()
169+
root.add_lazy_event(
170+
trace_api.Event("event2", now, {"name": "hello"})
174171
)
175-
self.assertEqual(
176-
root.events[1],
177-
trace.Event(name="event1", attributes={"name": "birthday"}),
172+
173+
self.assertEqual(len(root.events), 3)
174+
175+
self.assertEqual(root.events[0].name, "event0")
176+
self.assertEqual(root.events[0].attributes, {})
177+
178+
self.assertEqual(root.events[1].name, "event1")
179+
self.assertEqual(root.events[1].attributes, {"name": "birthday"})
180+
181+
self.assertEqual(root.events[2].name, "event2")
182+
self.assertEqual(root.events[2].attributes, {"name": "hello"})
183+
self.assertEqual(root.events[2].timestamp, now)
184+
185+
# links
186+
root.add_link(other_context1)
187+
root.add_link(other_context2, {"name": "neighbor"})
188+
root.add_lazy_link(
189+
trace_api.Link(other_context3, {"component": "http"})
178190
)
179191

180-
self.assertEqual(len(root.links), 2)
192+
self.assertEqual(len(root.links), 3)
181193
self.assertEqual(
182194
root.links[0].context.trace_id, other_context1.trace_id
183195
)
@@ -192,6 +204,14 @@ def test_span_members(self):
192204
root.links[1].context.span_id, other_context2.span_id
193205
)
194206
self.assertEqual(root.links[1].attributes, {"name": "neighbor"})
207+
self.assertEqual(
208+
root.links[2].context.span_id, other_context3.span_id
209+
)
210+
self.assertEqual(root.links[2].attributes, {"component": "http"})
211+
212+
# name
213+
root.update_name("toor")
214+
self.assertEqual(root.name, "toor")
195215

196216

197217
class TestSpan(unittest.TestCase):

0 commit comments

Comments
 (0)