Beispiel #1
0
 def test_log_unfinished_spans_disabled(self, log):
     # the trace finished status logging is disabled
     tracer = get_dummy_tracer()
     ctx = Context()
     # manually create a root-child trace
     root = Span(tracer=tracer, name='root')
     child_1 = Span(tracer=tracer,
                    name='child_1',
                    trace_id=root.trace_id,
                    parent_id=root.span_id)
     child_2 = Span(tracer=tracer,
                    name='child_2',
                    trace_id=root.trace_id,
                    parent_id=root.span_id)
     child_1._parent = root
     child_2._parent = root
     ctx.add_span(root)
     ctx.add_span(child_1)
     ctx.add_span(child_2)
     # close only the parent
     root.finish()
     # the logger has never been invoked to print unfinished spans
     for call, _ in log.call_args_list:
         msg = call[0]
         assert 'the trace has %d unfinished spans' not in msg
Beispiel #2
0
    def test_partial_flush_too_few(self):
        """
        When calling `Context.get`
            When partial flushing is enabled
            When we do not have enough finished spans to flush
                We return no spans
        """
        tracer = get_dummy_tracer()
        ctx = Context()

        # Create a root span with 5 children, all of the children are finished, the root is not
        root = Span(tracer=tracer, name='root')
        ctx.add_span(root)
        for i in range(5):
            child = Span(tracer=tracer,
                         name='child_{}'.format(i),
                         trace_id=root.trace_id,
                         parent_id=root.span_id)
            child._parent = root
            child.finished = True
            ctx.add_span(child)
            ctx.close_span(child)

        # Test with having 1 too few spans for partial flush
        with self.override_partial_flush(ctx, enabled=True, min_spans=6):
            trace, sampled = ctx.get()

        self.assertIsNone(trace)
        self.assertIsNone(sampled)

        self.assertEqual(len(ctx._trace), 6)
        self.assertEqual(
            set([
                'root', 'child_0', 'child_1', 'child_2', 'child_3', 'child_4'
            ]), set([span.name for span in ctx._trace]))
Beispiel #3
0
def test_log_unfinished_spans(log, tracer_with_debug_logging):
    # when the root parent is finished, notify if there are spans still pending
    tracer = tracer_with_debug_logging
    ctx = Context()
    # manually create a root-child trace
    root = Span(tracer=tracer, name='root')
    child_1 = Span(tracer=tracer,
                   name='child_1',
                   trace_id=root.trace_id,
                   parent_id=root.span_id)
    child_2 = Span(tracer=tracer,
                   name='child_2',
                   trace_id=root.trace_id,
                   parent_id=root.span_id)
    child_1._parent = root
    child_2._parent = root
    ctx.add_span(root)
    ctx.add_span(child_1)
    ctx.add_span(child_2)
    # close only the parent
    root.finish()
    unfinished_spans_log = log.call_args_list[-3][0][2]
    child_1_log = log.call_args_list[-2][0][1]
    child_2_log = log.call_args_list[-1][0][1]
    assert 2 == unfinished_spans_log
    assert 'name child_1' in child_1_log
    assert 'name child_2' in child_2_log
    assert 'duration 0.000000s' in child_1_log
    assert 'duration 0.000000s' in child_2_log
Beispiel #4
0
 def test_get_trace_empty(self):
     # it should return None if the Context is not finished
     ctx = Context()
     span = Span(tracer=None, name='fake_span')
     ctx.add_span(span)
     trace, sampled = ctx.get()
     assert trace is None
     assert sampled is None
Beispiel #5
0
 def test_close_span(self):
     # it should keep track of closed spans, moving
     # the current active to it's parent
     ctx = Context()
     span = Span(tracer=None, name='fake_span')
     ctx.add_span(span)
     ctx.close_span(span)
     assert ctx.get_current_span() is None
 def test_finish_called_multiple_times(self):
     # we should only record a span the first time finish is called on it
     ctx = Context()
     s = Span(self.tracer, 'bar', context=ctx)
     ctx.add_span(s)
     s.finish()
     s.finish()
     self.assert_span_count(1)
Beispiel #7
0
 def test_add_span(self):
     # it should add multiple spans
     ctx = Context()
     span = Span(tracer=None, name='fake_span')
     ctx.add_span(span)
     assert 1 == len(ctx._trace)
     assert 'fake_span' == ctx._trace[0].name
     assert ctx == span.context
Beispiel #8
0
 def test_context_sampled(self):
     # a context is sampled if the spans are sampled
     ctx = Context()
     span = Span(tracer=None, name='fake_span')
     ctx.add_span(span)
     span.finish()
     trace, sampled = ctx.get()
     assert sampled is True
     assert ctx.sampling_priority is None
Beispiel #9
0
 def test_get_trace(self):
     # it should return the internal trace structure
     # if the context is finished
     ctx = Context()
     span = Span(tracer=None, name='fake_span')
     ctx.add_span(span)
     span.finish()
     trace, sampled = ctx.get()
     assert [span] == trace
     assert sampled is True
     # the context should be empty
     assert 0 == len(ctx._trace)
     assert ctx._current_span is None
    def test_finish(self):
        # ensure finish will record a span
        ctx = Context()
        s = Span(self.tracer, 'test.span', context=ctx)
        ctx.add_span(s)
        assert s.duration is None

        sleep = 0.05
        with s as s1:
            assert s is s1
            time.sleep(sleep)
        assert s.duration >= sleep, '%s < %s' % (s.duration, sleep)
        self.assert_span_count(1)
Beispiel #11
0
    def test_get_report_hostname_default(self, get_hostname):
        get_hostname.return_value = 'test-hostname'

        # Create a context and add a span and finish it
        ctx = Context()
        span = Span(tracer=None, name='fake_span')
        ctx.add_span(span)
        span.finish()

        # Assert that we have not added the tag to the span yet
        assert span.get_tag(HOSTNAME_KEY) is None

        # Assert that retrieving the trace does not set the tag
        trace, _ = ctx.get()
        assert trace[0].get_tag(HOSTNAME_KEY) is None
        assert span.get_tag(HOSTNAME_KEY) is None
Beispiel #12
0
 def test_context_priority(self):
     # a context is sampled if the spans are sampled
     ctx = Context()
     for priority in [
             USER_REJECT, AUTO_REJECT, AUTO_KEEP, USER_KEEP, None, 999
     ]:
         ctx.sampling_priority = priority
         span = Span(tracer=None, name=('fake_span_%s' % repr(priority)))
         ctx.add_span(span)
         span.finish()
         # It's "normal" to have sampled be true even when priority sampling is
         # set to 0 or -1. It would stay false even even with priority set to 2.
         # The only criteria to send (or not) the spans to the agent should be
         # this "sampled" attribute, as it's tightly related to the trace weight.
         assert priority == ctx.sampling_priority
         trace, sampled = ctx.get()
         assert sampled is True, 'priority has no impact on sampled status'
Beispiel #13
0
    def test_get_report_hostname_disabled(self, get_hostname):
        get_hostname.return_value = 'test-hostname'

        with self.override_global_config(dict(report_hostname=False)):
            # Create a context and add a span and finish it
            ctx = Context()
            span = Span(tracer=None, name='fake_span')
            ctx.add_span(span)
            span.finish()

            # Assert that we have not added the tag to the span yet
            assert span.get_tag(HOSTNAME_KEY) is None

            # Assert that retrieving the trace does not set the tag
            trace, _ = ctx.get()
            assert trace[0].get_tag(HOSTNAME_KEY) is None
            assert span.get_tag(HOSTNAME_KEY) is None
Beispiel #14
0
    def test_partial_flush_remaining(self):
        """
        When calling `Context.get`
            When partial flushing is enabled
            When we have some unfinished spans
                We keep the unfinished spans around
        """
        tracer = get_dummy_tracer()
        ctx = Context()

        # Create a root span with 5 children, all of the children are finished, the root is not
        root = Span(tracer=tracer, name='root')
        ctx.add_span(root)
        for i in range(10):
            child = Span(tracer=tracer,
                         name='child_{}'.format(i),
                         trace_id=root.trace_id,
                         parent_id=root.span_id)
            child._parent = root
            ctx.add_span(child)

            # CLose the first 5 only
            if i < 5:
                child.finished = True
                ctx.close_span(child)

        with self.override_partial_flush(ctx, enabled=True, min_spans=5):
            trace, sampled = ctx.get()

        # Assert partially flushed spans
        self.assertTrue(len(trace), 5)
        self.assertIsNotNone(sampled)
        self.assertEqual(
            set(['child_0', 'child_1', 'child_2', 'child_3', 'child_4']),
            set([span.name for span in trace]))

        # Assert remaining unclosed spans
        self.assertEqual(len(ctx._trace), 6)
        self.assertEqual(
            set([
                'root', 'child_5', 'child_6', 'child_7', 'child_8', 'child_9'
            ]),
            set([span.name for span in ctx._trace]),
        )
Beispiel #15
0
 def test_clone(self):
     ctx = Context()
     ctx.sampling_priority = 2
     # manually create a root-child trace
     root = Span(tracer=None, name='root')
     child = Span(tracer=None,
                  name='child_1',
                  trace_id=root.trace_id,
                  parent_id=root.span_id)
     child._parent = root
     ctx.add_span(root)
     ctx.add_span(child)
     cloned_ctx = ctx.clone()
     assert cloned_ctx._parent_trace_id == ctx._parent_trace_id
     assert cloned_ctx._parent_span_id == ctx._parent_span_id
     assert cloned_ctx._sampling_priority == ctx._sampling_priority
     assert cloned_ctx._otel_origin == ctx._otel_origin
     assert cloned_ctx._current_span == ctx._current_span
     assert cloned_ctx._trace == []
Beispiel #16
0
 def test_log_unfinished_spans_when_ok(self, log):
     # if the unfinished spans logging is enabled but the trace is finished, don't log anything
     tracer = get_dummy_tracer()
     ctx = Context()
     # manually create a root-child trace
     root = Span(tracer=tracer, name='root')
     child = Span(tracer=tracer,
                  name='child_1',
                  trace_id=root.trace_id,
                  parent_id=root.span_id)
     child._parent = root
     ctx.add_span(root)
     ctx.add_span(child)
     # close the trace
     child.finish()
     root.finish()
     # the logger has never been invoked to print unfinished spans
     for call, _ in log.call_args_list:
         msg = call[0]
         assert 'the trace has %d unfinished spans' not in msg
Beispiel #17
0
    def test_partial_flush_too_many(self):
        """
        When calling `Context.get`
            When partial flushing is enabled
            When we have more than the minimum number of spans needed to flush
                We return the finished spans
        """
        tracer = get_dummy_tracer()
        ctx = Context()

        # Create a root span with 5 children, all of the children are finished, the root is not
        root = Span(tracer=tracer, name='root')
        ctx.add_span(root)
        for i in range(5):
            child = Span(tracer=tracer,
                         name='child_{}'.format(i),
                         trace_id=root.trace_id,
                         parent_id=root.span_id)
            child._parent = root
            child.finished = True
            ctx.add_span(child)
            ctx.close_span(child)

        with self.override_partial_flush(ctx, enabled=True, min_spans=1):
            trace, sampled = ctx.get()

        self.assertIsNotNone(trace)
        self.assertIsNotNone(sampled)

        self.assertEqual(len(trace), 5)
        self.assertEqual(
            set(['child_0', 'child_1', 'child_2', 'child_3', 'child_4']),
            set([span.name for span in trace]))

        # Ensure we clear/reset internal stats as expected
        self.assertEqual(ctx._trace, [root])
        with self.override_partial_flush(ctx, enabled=True, min_spans=5):
            trace, sampled = ctx.get()
            self.assertIsNone(trace)
            self.assertIsNone(sampled)
Beispiel #18
0
 def test_current_root_span(self):
     # it should return the current active root span
     ctx = Context()
     span = Span(tracer=None, name='fake_span')
     ctx.add_span(span)
     assert span == ctx.get_current_root_span()
Beispiel #19
0
 def test_finished(self):
     # a Context is finished if all spans inside are finished
     ctx = Context()
     span = Span(tracer=None, name='fake_span')
     ctx.add_span(span)
     ctx.close_span(span)