Esempio n. 1
0
def test_follows_from(tracer):
    span = tracer.start_span('test')
    span1 = tracer.start_span('test2')
    follow_span = tracer.start_span('follow-span', references=[follows_from(span.context),
                                                               follows_from(span1.context),
                                                               follows_from(None)])
    span.finish()
    span1.finish()
    follow_span.finish()
    tracer.reporter.report_span.assert_called()
    assert len(follow_span.references) == 2
    assert follow_span.context.parent_id == span.context.span_id
    for reference in follow_span.references:
        assert reference.referenced_context is not None

    tracer.reporter = mock.MagicMock()
    span = tracer.start_span('test')
    follow_span = tracer.start_span(references=follows_from(span.context))
    span.finish()
    follow_span.finish()
    tracer.reporter.report_span.assert_called()
    assert isinstance(follow_span.references, list)

    tracer.reporter = mock.MagicMock()
    span = tracer.start_span('test')
    parent_span = tracer.start_span('test-parent')
    child_span = tracer.start_span('test-child', child_of=parent_span,
                                   references=follows_from(span.context))
    span.finish()
    parent_span.finish()
    child_span.finish()
    tracer.reporter.report_span.assert_called()
    assert child_span.context.parent_id == parent_span.context.span_id
    assert len(child_span.references) == 1
    tracer.close()
    def produce(self, topic, value=None, *args, **kwargs):
        """
        overridden method

        :param topic:
        :param value:
        :param args:
        :param kwargs:
        :return:
        """
        msg_header_dict = dict() if kwargs.get('headers') is None else dict(
            kwargs.get('headers'))

        parent_context = self.tracer.extract(Format.TEXT_MAP, msg_header_dict)

        user_tags = {}
        for span_tag_provider in self.span_tags_providers:
            user_tags = merge_two_dicts(
                user_tags, span_tag_provider(topic, kwargs.get('key'), value))

        span = self.tracer.start_span(
            self.span_name_provider(topic, kwargs.get('key'), value),
            references=[follows_from(parent_context)],
            tags=merge_two_dicts(producer_span_tags_provider(topic),
                                 user_tags))

        # Inject created span context into message header for sending to kafka queue
        self.tracer.inject(span.context, Format.TEXT_MAP, msg_header_dict)
        kwargs['headers'] = list(msg_header_dict.items())

        kwargs['on_delivery'] = create_tracing_delivery_callback(
            kwargs['on_delivery'], span)

        Producer.produce(self, topic, value, *args, **kwargs)
Esempio n. 3
0
def get_new_span(f,
                 func_args,
                 func_kwargs,
                 operation_name=None,
                 inspect_stack=True,
                 ignore_parent_span=False,
                 span_extractor=None,
                 use_follows_from=False):
    parent_span = None
    span_arg_name = DEFAULT_SPAN_ARG_NAME

    if not ignore_parent_span:
        if callable(span_extractor):
            try:
                parent_span = span_extractor(*func_args, **func_kwargs)
            except Exception:
                logger.exception('Failed to extract span from: {}'.format(
                    span_extractor.__name__))

        if not parent_span:
            span_arg_name, parent_span = get_parent_span(
                inspect_stack=inspect_stack, **func_kwargs)

    op_name = f.__name__ if not operation_name else operation_name

    references = None
    if parent_span:
        references = [
            follows_from(parent_span.context)
        ] if use_follows_from else [child_of(parent_span.context)]

    return span_arg_name, opentracing.tracer.start_span(operation_name=op_name,
                                                        references=references)
Esempio n. 4
0
def start_active_span_follows_from(operation_name, contexts):
    if opentracing is None:
        return noop_context_manager()

    references = [opentracing.follows_from(context) for context in contexts]
    scope = start_active_span(operation_name, references=references)
    return scope
Esempio n. 5
0
    def decorator(*args, **kwargs):
        parent_span = get_current_span() if not ignore_active_span else None
        if parent_span is None and require_active_trace:
            return func(*args, **kwargs)

        tracer = global_tracer()
        if async_result:
            reference_span = follows_from(
                parent_span.context) if parent_span is not None else None
            parent_span = None
        else:
            reference_span = None

        with tracer.start_active_span(
                operation_name,
                child_of=parent_span,
                references=reference_span,
                ignore_active_span=ignore_active_span,
                tags=tags,
                finish_on_close=finish_on_close) as scope:
            span = scope.span

            if callable(on_start):
                on_start(span, *args, **kwargs)

            # We explicitly invoke deactivation callback for the StackContext,
            # because there are scenarios when it gets retained forever, for
            # example when a Periodic Callback is scheduled lazily while in the
            # scope of a tracing StackContext.
            try:
                d = func(*args, **kwargs)

                # Twisted routines and inlineCallbacks generate defers
                if isinstance(d, defer.Deferred):

                    def done(results):
                        span.finish()
                        return results

                    def failed(reason):
                        # Set error in span
                        span.log(event='exception', payload=reason)
                        span.set_tag('error', 'true')
                        span.finish()
                        return reason

                    if d.called:
                        span.finish()
                    else:
                        d.addCallbacks(done, failed)
                else:
                    span.finish()
                return d

            except Exception as e:
                span.set_tag(tags.ERROR, 'true')
                span.log(event='exception', payload=e)
                span.finish()
                raise
Esempio n. 6
0
def extract_tracing_span(carrier, use_follows_from=False):
    try:
        span_context = opentracing.tracer.extract(opentracing.Format.TEXT_MAP, carrier)

        references = [follows_from(span_context)] if use_follows_from else [child_of(span_context)]

        return opentracing.tracer.start_span(references=references)
    except Exception:
        return opentracing.tracer.start_span()
Esempio n. 7
0
def test_parse_span_references(tracer):
    span = tracer.start_span('test')
    span2 = tracer.start_span('test2')
    follow_span = tracer.start_span(
        'test-follow',
        references=[follows_from(span.context),
                    child_of(span2.context)])
    span.finish()
    span2.finish()
    follow_span.finish()
    _marshall_span(follow_span)
Esempio n. 8
0
def extract_tracing_span(carrier, use_follows_from=False):
    try:
        span_context = opentracing.tracer.extract(opentracing.Format.TEXT_MAP,
                                                  carrier)

        references = [follows_from(span_context)
                      ] if use_follows_from else [child_of(span_context)]

        return opentracing.tracer.start_span(references=references)
    except Exception:
        return opentracing.tracer.start_span()
Esempio n. 9
0
 def test_start_span_with_parent(self):
     tracer = self.tracer()
     parent_span = tracer.start_span(operation_name='parent')
     assert parent_span is not None
     span = tracer.start_span(operation_name='Leela', child_of=parent_span)
     span.finish()
     span = tracer.start_span(
         operation_name='Leela',
         references=[opentracing.follows_from(parent_span.context)],
         tags={'birthplace': 'sewers'})
     span.finish()
     parent_span.finish()
Esempio n. 10
0
 def test_start_span_with_parent(self):
     tracer = self.tracer()
     parent_span = tracer.start_span(operation_name='parent')
     assert parent_span is not None
     span = tracer.start_span(
         operation_name='Leela',
         child_of=parent_span)
     span.finish()
     span = tracer.start_span(
         operation_name='Leela',
         references=[opentracing.follows_from(parent_span.context)],
         tags={'birthplace': 'sewers'})
     span.finish()
     parent_span.finish()
Esempio n. 11
0
 def _span(self,
           record: aiokafka.ConsumerRecord) -> opentracing.SpanContext:
     tracer = opentracing.tracer
     headers = {x[0]: x[1].decode() for x in record.headers or []}
     parent = tracer.extract(opentracing.Format.TEXT_MAP, headers)
     context = tracer.start_active_span(
         record.topic,
         tags={
             "message_bus.destination": record.topic,
             "message_bus.partition": record.partition,
             "message_bus.group_id": self.group_id,
         },
         references=[opentracing.follows_from(parent)],
     )
     return context.span
Esempio n. 12
0
    def test_follows_from_references(self):
        """Test span creation using the `references` argument with a follows from relationship."""

        with self.shim.start_span("ParentSpan") as parent:
            ref = opentracing.follows_from(parent.context)

        with self.shim.start_active_span(
            "FollowingSpan", references=[ref]
        ) as child:
            self.assertEqual(
                child.span.unwrap().links[0].context,
                parent.context.unwrap(),
            )
            self.assertEqual(
                child.span.unwrap().parent,
                parent.context.unwrap(),
            )
Esempio n. 13
0
def get_new_span(
        f, func_args, func_kwargs, operation_name=None, inspect_stack=True, ignore_parent_span=False,
        span_extractor=None, use_follows_from=False):
    parent_span = None
    using_scope_manager = False
    span_arg_name = None

    if not ignore_parent_span:
        if callable(span_extractor):
            try:
                parent_span = span_extractor(*func_args, **func_kwargs)
            except Exception:
                logger.exception('Failed to extract span from: {}'.format(span_extractor.__name__))

        if not parent_span:
            span_arg_name, parent_span = get_span_from_kwargs(**func_kwargs)

        if not parent_span:
            try:
                # We try inspecting ``active_span`` managed by ``tracer.scope_manager``.
                parent_span = opentracing.tracer.active_span
                using_scope_manager = True if parent_span else False
            except AttributeError:
                # Old opentracing lib!
                pass

        # Finally, try to inspect call stack frames.
        if not parent_span:
            span_arg_name, parent_span = get_parent_span(
                inspect_stack=inspect_stack, inspect_kwargs=False, **func_kwargs)

    op_name = f.__name__ if not operation_name else operation_name

    references = None
    if parent_span:
        references = [follows_from(parent_span.context)] if use_follows_from else [child_of(parent_span.context)]

    span_arg_name = span_arg_name or DEFAULT_SPAN_ARG_NAME

    return (
        span_arg_name,
        using_scope_manager,
        opentracing.tracer.start_span(operation_name=op_name, references=references)
    )
Esempio n. 14
0
def start_active_span_follows_from(
    operation_name: str,
    contexts: Collection,
    child_of=None,
    start_time: Optional[float] = None,
    *,
    inherit_force_tracing=False,
    tracer=None,
):
    """Starts an active opentracing span, with additional references to previous spans

    Args:
        operation_name: name of the operation represented by the new span
        contexts: the previous spans to inherit from

        child_of: optionally override the parent span. If unset, the currently active
           span will be the parent. (If there is no currently active span, the first
           span in `contexts` will be the parent.)

        start_time: optional override for the start time of the created span. Seconds
            since the epoch.

        inherit_force_tracing: if set, and any of the previous contexts have had tracing
           forced, the new span will also have tracing forced.
        tracer: override the opentracing tracer. By default the global tracer is used.
    """
    if opentracing is None:
        return contextlib.nullcontext()  # type: ignore[unreachable]

    references = [opentracing.follows_from(context) for context in contexts]
    scope = start_active_span(
        operation_name,
        child_of=child_of,
        references=references,
        start_time=start_time,
        tracer=tracer,
    )

    if inherit_force_tracing and any(
            is_context_forced_tracing(ctx) for ctx in contexts):
        force_tracing(scope.span)

    return scope
Esempio n. 15
0
    def build_and_finish_child_span(self, msg):
        msg_header_text_dict = dict((key, binary_value.decode("utf-8"))
                                    for key, binary_value in msg.headers())

        parent_context = self.tracer.extract(Format.TEXT_MAP,
                                             msg_header_text_dict)

        user_tags = {}
        for span_tag_provider in self.span_tags_providers:
            user_tags = merge_two_dicts(user_tags, span_tag_provider(msg))

        span = self.tracer.start_span(
            self.span_name_provider(msg),
            references=[follows_from(parent_context)],
            tags=merge_two_dicts(consumer_span_tags_provider(msg), user_tags))
        span.finish()

        # Inject created span context into message header for extraction by client to continue span chain
        self.tracer.inject(span.context, Format.TEXT_MAP, msg_header_text_dict)
        msg.set_headers(list(msg_header_text_dict.items()))
Esempio n. 16
0
def start_active_span_follows_from(operation_name: str,
                                   contexts: Collection,
                                   inherit_force_tracing=False):
    """Starts an active opentracing span, with additional references to previous spans

    Args:
        operation_name: name of the operation represented by the new span
        contexts: the previous spans to inherit from
        inherit_force_tracing: if set, and any of the previous contexts have had tracing
           forced, the new span will also have tracing forced.
    """
    if opentracing is None:
        return noop_context_manager()

    references = [opentracing.follows_from(context) for context in contexts]
    scope = start_active_span(operation_name, references=references)

    if inherit_force_tracing and any(
            is_context_forced_tracing(ctx) for ctx in contexts):
        force_tracing(scope.span)

    return scope
Esempio n. 17
0
 def _deliver_to(self, consumers):
     try:
         result = False
         for c in consumers:
             if c.credit:
                 msg = self.queue.popleft()
                 with tracer.start_active_span('dequeue-message', ignore_active_span=True, references=follows_from(msg.qspan.context)):
                     c.send(msg)
                     result = True
         return result
     except IndexError:  # no more messages
         return False
    # for _ in range(100000):
    # tr = tracker.SummaryTracker()

    # tr = tracker.SummaryTracker()

    while True:
        with tracer.start_span("TestSpan") as span:

            span.set_tag("test_int", 25)
            span.set_tag("test_str", "foobar")
            span.set_tag("test_double", 1.25)
            span.set_tag("test_bool", True)

            with tracer.start_span(
                    "ChildSpan",
                    references=opentracing.follows_from(span.context),
            ) as span2:
                pass

        i += 1
        if i % 10000 == 0:
            # print(reporter.get_stats())
            gc.collect()
            # print(len(objgraph.get_leaking_objects()))

            # all_objects = muppy.get_objects()
            # print("objects", len(all_objects))
            # tr.print_diff()

            # roots = objgraph.get_leaking_objects()
            # print("Roots", len(roots))
Esempio n. 19
0
    def _pub(self,
             message,
             exchange_name,
             routing_key,
             parent_span=None,
             span_enqueued=None,
             dont_close_span=False):
        """
        Just send the message. Sends BasicDeliver + header + body.

        BECAUSE OF publish THIS CAN GET CALLED BY FOREIGN THREAD.

        :param message: Message instance
        :param exchange_name: exchange to use
        :param routing_key: routing key to use
        :type exchange_name: bytes
        :param routing_key: bytes
        """
        span = None
        if parent_span is not None:
            import opentracing
            span_enqueued.finish()
            span = self.cluster.tracer.start_span(
                'Sending',
                child_of=parent_span,
                references=opentracing.follows_from(span_enqueued))
        # Break down large bodies
        bodies = []

        body = memoryview(message.body)
        max_body_size = self.connection.frame_max - AMQPBodyFrame.FRAME_SIZE_WITHOUT_PAYLOAD - 16
        while len(body) > 0:
            bodies.append(body[:max_body_size])
            body = body[max_body_size:]

        frames_to_send = [
            AMQPMethodFrame(
                self.channel_id,
                BasicPublish(exchange_name, routing_key, False, False)),
            AMQPHeaderFrame(self.channel_id, Basic.INDEX, 0, len(message.body),
                            message.properties)
        ]

        if len(bodies) == 1:
            frames_to_send.append(AMQPBodyFrame(self.channel_id, bodies[0]))

        if self.content_flow and not self.blocked:
            self.connection.send(frames_to_send)

            if len(bodies) > 1:
                while self.content_flow and not self.blocked and len(
                        bodies) > 0:
                    self.connection.send(
                        [AMQPBodyFrame(self.channel_id, bodies[0])])
                    del bodies[0]

                if not self.content_flow and not self.blocked and len(
                        bodies) > 0:
                    for body in bodies:
                        self.frames_to_send.append(
                            AMQPBodyFrame(self.channel_id, body))
        else:
            self.frames_to_send.extend(frames_to_send)
            if len(bodies) > 1:
                for body in bodies:
                    self.frames_to_send.append(
                        AMQPBodyFrame(self.channel_id, body))

        if span is not None:
            span.finish()

        if parent_span is not None and not dont_close_span:
            parent_span.finish()
Esempio n. 20
0
    # Create span2, span3 child of span1.
    span2 = tracer.start_span(operation_name="span2",
                              references=child_of(span1.context),
                              tags=[("span2_key", "span2_val")])
    span3 = tracer.start_span(operation_name="span3",
                              child_of=span1,
                              tags=[("span3_key", "span3_val")])
    time.sleep(2)
    span2.finish()
    time.sleep(1)
    span3.finish()

    # Create span4 follows from span3.
    span4 = tracer.start_span(operation_name="span4",
                              references=follows_from(span3.context),
                              tags=[("span4_key", "span4_val")])
    time.sleep(2)
    span4.finish()

    span5 = tracer.start_span(operation_name="span5")
    time.sleep(1)
    span5.finish()

    time.sleep(1)

    # Close the scope
    scope.close()

    # Close the tracer
    tracer.close()
Esempio n. 21
0
    async def _handle_message(self,
                              record: aiokafka.structs.ConsumerRecord) -> None:
        tracer = opentracing.tracer
        headers = {x[0]: x[1].decode() for x in record.headers or []}
        parent = tracer.extract(opentracing.Format.TEXT_MAP, headers)
        context = tracer.start_active_span(
            record.topic,
            tags={
                "message_bus.destination": record.topic,
                "message_bus.partition": record.partition,
                "message_bus.group_id": self._subscription.group,
            },
            references=[opentracing.follows_from(parent)],
        )
        CONSUMER_TOPIC_OFFSET.labels(
            group_id=self._subscription.group,
            stream_id=record.topic,
            partition=record.partition,
        ).set(record.offset)
        # Calculate the time since the message is send until is successfully consumed
        lead_time = time.time() - record.timestamp / 1000  # type: ignore
        MESSAGE_LEAD_TIME.labels(
            stream_id=record.topic,
            partition=record.partition,
            group_id=self._subscription.group,
        ).observe(lead_time)

        try:
            logger.debug(f"Handling msg: {record}")

            with CONSUMED_MESSAGE_TIME.labels(
                    stream_id=record.topic,
                    partition=record.partition,
                    group_id=self._subscription.group,
            ).time():
                await self._handler.handle(record, context)

            # No error metric
            CONSUMED_MESSAGES.labels(
                stream_id=record.topic,
                error=NOERROR,
                partition=record.partition,
                group_id=self._subscription.group,
            ).inc()
            self._last_error = False
            await self._maybe_commit()
        except Exception as err:
            self._last_error = True
            CONSUMED_MESSAGES.labels(
                stream_id=record.topic,
                partition=record.partition,
                error=err.__class__.__name__,
                group_id=self._subscription.group,
            ).inc()
            await self.retry_policy(record=record, exception=err)
            # we didn't bubble, so no error here
            self._last_error = False
            await self._maybe_commit()
        finally:
            context.close()
            await self.emit("message", record=record)