Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
foo.set_attribute("my_atribbute", True)
foo.add_event("event in foo", {"name": "foo1"})
with tracer.start_as_current_span(
"bar", links=[trace.Link(foo.get_context())]
"bar", links=[trace.Link(foo)]
) as bar:
time.sleep(0.2)
bar.set_attribute("speed", 100.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,8 @@ def _translate_to_jaeger(spans: Span):
jaeger_spans = []

for span in spans:
ctx = span.get_context()
trace_id = ctx.trace_id
span_id = ctx.span_id
trace_id = span.trace_id
span_id = span.span_id

start_time_us = _nsec_to_usec_round(span.start_time)
duration_us = _nsec_to_usec_round(span.end_time - span.start_time)
Expand Down Expand Up @@ -235,7 +234,7 @@ def _translate_to_jaeger(spans: Span):
refs = _extract_refs_from_span(span)
logs = _extract_logs_from_span(span)

flags = int(ctx.trace_flags)
flags = int(span.trace_flags)

jaeger_span = jaeger.Span(
traceIdHigh=_get_trace_id_high(trace_id),
Expand Down Expand Up @@ -263,8 +262,8 @@ def _extract_refs_from_span(span):

refs = []
for link in span.links:
trace_id = link.context.trace_id
span_id = link.context.span_id
trace_id = link.span.trace_id
span_id = link.span.span_id
refs.append(
jaeger.SpanRef(
refType=jaeger.SpanRefType.FOLLOWS_FROM,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,12 @@
class TestJaegerSpanExporter(unittest.TestCase):
def setUp(self):
# create and save span to be used in tests
context = trace_api.SpanContext(
self._test_span = trace.Span(
"test_span",
trace_id=0x000000000000000000000000DEADBEEF,
span_id=0x00000000DEADBEF0,
is_remote=False,
)

self._test_span = trace.Span("test_span", context=context)
self._test_span.start()
self._test_span.end()

Expand Down Expand Up @@ -141,13 +140,10 @@ def test_translate_to_jaeger(self):
start_times[2] + durations[2],
)

span_context = trace_api.SpanContext(
trace_id, span_id, is_remote=False
)
parent_context = trace_api.SpanContext(
parent_span = trace_api.DefaultSpan(
trace_id, parent_id, is_remote=False
)
other_context = trace_api.SpanContext(
other_span = trace_api.DefaultSpan(
trace_id, other_id, is_remote=False
)

Expand All @@ -167,7 +163,7 @@ def test_translate_to_jaeger(self):
link_attributes = {"key_bool": True}

link = trace_api.Link(
context=other_context, attributes=link_attributes
span=other_span, attributes=link_attributes
)

default_tags = [
Expand All @@ -189,16 +185,27 @@ def test_translate_to_jaeger(self):
otel_spans = [
trace.Span(
name=span_names[0],
context=span_context,
parent=parent_context,
trace_id=trace_id,
span_id=span_id,
is_remote=False,
parent=parent_span,
events=(event,),
links=(link,),
kind=trace_api.SpanKind.CLIENT,
),
trace.Span(
name=span_names[1], context=parent_context, parent=None
name=span_names[1],
trace_id=parent_span.trace_id,
span_id=parent_span.span_id,
is_remote=parent_span.is_remote,
parent=None
),
trace.Span(name=span_names[2], context=other_context, parent=None),
trace.Span(
name=span_names[2],
trace_id=other_span.trace_id,
span_id=other_span.span_id,
is_remote=other_span.is_remote,
parent=None),
]

otel_spans[0].start(start_time=start_times[0])
Expand Down
18 changes: 8 additions & 10 deletions opentelemetry-api/src/opentelemetry/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,10 @@
DEFAULT_TRACE_OPTIONS,
DEFAULT_TRACE_STATE,
INVALID_SPAN,
INVALID_SPAN_CONTEXT,
INVALID_SPAN_ID,
INVALID_TRACE_ID,
DefaultSpan,
Span,
SpanContext,
TraceFlags,
TraceState,
format_span_id,
Expand All @@ -102,16 +100,16 @@
logger = getLogger(__name__)

# TODO: quarantine
ParentSpan = typing.Optional[typing.Union["Span", "SpanContext"]]
ParentSpan = typing.Optional["Span"]


class LinkBase(abc.ABC):
def __init__(self, context: "SpanContext") -> None:
self._context = context
def __init__(self, span: "Span") -> None:
self._span = span

@property
def context(self) -> "SpanContext":
return self._context
def span(self) -> "Span":
return self._span

@property
@abc.abstractmethod
Expand All @@ -128,9 +126,9 @@ class Link(LinkBase):
"""

def __init__(
self, context: "SpanContext", attributes: types.Attributes = None,
self, span: "Span", attributes: types.Attributes = None,
) -> None:
super().__init__(context)
super().__init__(span)
self._attributes = attributes

@property
Expand Down Expand Up @@ -221,7 +219,7 @@ class Tracer(abc.ABC):

# Constant used to represent the current span being used as a parent.
# This is the default behavior when creating spans.
CURRENT_SPAN = DefaultSpan(INVALID_SPAN_CONTEXT)
CURRENT_SPAN = INVALID_SPAN

@abc.abstractmethod
def start_span(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,15 @@ def extract(
)
tracestate = _parse_tracestate(tracestate_headers)

span_context = trace.SpanContext(
extracted_span = trace.DefaultSpan(
trace_id=int(trace_id, 16),
span_id=int(span_id, 16),
is_remote=True,
trace_flags=trace.TraceFlags(trace_flags),
trace_state=tracestate,
)
return trace.set_span_in_context(
trace.DefaultSpan(span_context), context
extracted_span, context
)

def inject(
Expand All @@ -118,19 +118,18 @@ def inject(
See `opentelemetry.trace.propagation.textmap.TextMapPropagator.inject`
"""
span = trace.get_current_span(context)
span_context = span.get_context()
if span_context == trace.INVALID_SPAN_CONTEXT:
if span == trace.INVALID_SPAN:
return
traceparent_string = "00-{:032x}-{:016x}-{:02x}".format(
span_context.trace_id,
span_context.span_id,
span_context.trace_flags,
span.trace_id,
span.span_id,
span.trace_flags,
)
set_in_carrier(
carrier, self._TRACEPARENT_HEADER_NAME, traceparent_string
)
if span_context.trace_state:
tracestate_string = _format_tracestate(span_context.trace_state)
if span.trace_state:
tracestate_string = _format_tracestate(span.trace_state)
set_in_carrier(
carrier, self._TRACESTATE_HEADER_NAME, tracestate_string
)
Expand Down
94 changes: 32 additions & 62 deletions opentelemetry-api/src/opentelemetry/trace/span.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@
class Span(abc.ABC):
"""A span represents a single operation within a trace."""

def __init__(
self,
trace_id: int,
span_id: int,
is_remote: bool,
trace_flags: "TraceFlags",
trace_state: "TraceState"
) -> None:
if trace_flags is None:
trace_flags = DEFAULT_TRACE_OPTIONS
if trace_state is None:
trace_state = DEFAULT_TRACE_STATE
self.trace_id = trace_id
self.span_id = span_id
self.trace_flags = trace_flags
self.trace_state = trace_state
self.is_remote = is_remote
self.is_valid = (
self.trace_id != INVALID_TRACE_ID
and self.span_id != INVALID_SPAN_ID
)

@abc.abstractmethod
def end(self, end_time: typing.Optional[int] = None) -> None:
"""Sets the current time as the span's end time.
Expand All @@ -19,17 +41,6 @@ def end(self, end_time: typing.Optional[int] = None) -> None:
implementations are free to ignore or raise on further calls.
"""

@abc.abstractmethod
def get_context(self) -> "SpanContext":
"""Gets the span's SpanContext.

Get an immutable, serializable identifier for this span that can be
used to create new child spans.

Returns:
A :class:`opentelemetry.trace.SpanContext` with a copy of this span's immutable state.
"""

@abc.abstractmethod
def set_attribute(self, key: str, value: types.AttributeValue) -> None:
"""Sets an Attribute.
Expand Down Expand Up @@ -143,20 +154,11 @@ def get_default(cls) -> "TraceState":
DEFAULT_TRACE_STATE = TraceState.get_default()


class SpanContext:
"""The state of a Span to propagate between processes.

This class includes the immutable attributes of a :class:`.Span` that must
be propagated to a span's children and across process boundaries.
class DefaultSpan(Span):
"""The default Span that is used when no Span implementation is available.

Args:
trace_id: The ID of the trace that this span belongs to.
span_id: This span's ID.
trace_flags: Trace options to propagate.
trace_state: Tracing-system-specific info to propagate.
is_remote: True if propagated from a remote parent.
All operations are no-op except context propagation.
"""

def __init__(
self,
trace_id: int,
Expand All @@ -165,44 +167,14 @@ def __init__(
trace_flags: "TraceFlags" = DEFAULT_TRACE_OPTIONS,
trace_state: "TraceState" = DEFAULT_TRACE_STATE,
) -> None:
if trace_flags is None:
trace_flags = DEFAULT_TRACE_OPTIONS
if trace_state is None:
trace_state = DEFAULT_TRACE_STATE
self.trace_id = trace_id
self.span_id = span_id
self.trace_flags = trace_flags
self.trace_state = trace_state
self.is_remote = is_remote
self.is_valid = (
self.trace_id != INVALID_TRACE_ID
and self.span_id != INVALID_SPAN_ID
)

def __repr__(self) -> str:
return (
"{}(trace_id={}, span_id={}, trace_state={!r}, is_remote={})"
).format(
type(self).__name__,
format_trace_id(self.trace_id),
format_span_id(self.span_id),
self.trace_state,
self.is_remote,
super().__init__(
trace_id,
span_id,
is_remote,
trace_flags,
trace_state
)


class DefaultSpan(Span):
"""The default Span that is used when no Span implementation is available.

All operations are no-op except context propagation.
"""

def __init__(self, context: "SpanContext") -> None:
self._context = context

def get_context(self) -> "SpanContext":
return self._context

def is_recording(self) -> bool:
return False

Expand Down Expand Up @@ -232,15 +204,13 @@ def record_exception(self, exception: Exception) -> None:

INVALID_SPAN_ID = 0x0000000000000000
INVALID_TRACE_ID = 0x00000000000000000000000000000000
INVALID_SPAN_CONTEXT = SpanContext(
INVALID_SPAN = DefaultSpan(
trace_id=INVALID_TRACE_ID,
span_id=INVALID_SPAN_ID,
is_remote=False,
trace_flags=DEFAULT_TRACE_OPTIONS,
trace_state=DEFAULT_TRACE_STATE,
)
INVALID_SPAN = DefaultSpan(INVALID_SPAN_CONTEXT)


def format_trace_id(trace_id: int) -> str:
return "0x{:032x}".format(trace_id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,11 @@ def test_propagation(self):
baggage_entries = baggage.get_all(context=ctx)
expected = {"key1": "val1", "key2": "val2"}
self.assertEqual(baggage_entries, expected)
span_context = get_current_span(context=ctx).get_context()
span = get_current_span(context=ctx)

self.assertEqual(span_context.trace_id, self.TRACE_ID)
self.assertEqual(span_context.span_id, self.SPAN_ID)
self.assertEqual(span.trace_id, self.TRACE_ID)
self.assertEqual(span.span_id, self.SPAN_ID)

span = trace.DefaultSpan(span_context)
ctx = baggage.set_baggage("key3", "val3")
ctx = baggage.set_baggage("key4", "val4", context=ctx)
ctx = set_span_in_context(span, context=ctx)
Expand Down
8 changes: 2 additions & 6 deletions opentelemetry-api/tests/test_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,9 @@ def test_default_tracer(self):
tracer_provider = trace.DefaultTracerProvider()
tracer = tracer_provider.get_tracer(__name__)
with tracer.start_span("test") as span:
self.assertEqual(span.get_context(), trace.INVALID_SPAN_CONTEXT)
self.assertEqual(span, trace.INVALID_SPAN)
self.assertIs(span.is_recording(), False)
with tracer.start_span("test2") as span2:
self.assertEqual(
span2.get_context(), trace.INVALID_SPAN_CONTEXT
)
self.assertEqual(span2, trace.INVALID_SPAN)
self.assertIs(span2.is_recording(), False)

Expand All @@ -53,8 +49,8 @@ def test_span(self):
trace.Span() # type:ignore

def test_default_span(self):
span = trace.DefaultSpan(trace.INVALID_SPAN_CONTEXT)
self.assertEqual(span.get_context(), trace.INVALID_SPAN_CONTEXT)
span = trace.INVALID_SPAN
self.assertEqual(False, span.is_valid)
self.assertIs(span.is_recording(), False)

# METER
Expand Down
Loading