def test_detach_out_of_order(self):
     t1 = context.attach(context.set_value("c", 1))
     self.assertEqual(context.get_current(), {"c": 1})
     t2 = context.attach(context.set_value("c", 2))
     self.assertEqual(context.get_current(), {"c": 2})
     context.detach(t1)
     self.assertEqual(context.get_current(), {})
     context.detach(t2)
     self.assertEqual(context.get_current(), {"c": 1})
    def test_context(self):
        self.assertIsNone(context.get_value("say"))
        empty = context.get_current()
        second = context.set_value("say", "foo")
        self.assertEqual(context.get_value("say", context=second), "foo")

        do_work()
        self.assertEqual(context.get_value("say"), "bar")
        third = context.get_current()

        self.assertIsNone(context.get_value("say", context=empty))
        self.assertEqual(context.get_value("say", context=second), "foo")
        self.assertEqual(context.get_value("say", context=third), "bar")
    def test_context(self):
        key1 = context.create_key("say")
        self.assertIsNone(context.get_value(key1))
        empty = context.get_current()
        second = context.set_value(key1, "foo")
        self.assertEqual(context.get_value(key1, context=second), "foo")

        key2 = _do_work()
        self.assertEqual(context.get_value(key2), "bar")
        third = context.get_current()

        self.assertIsNone(context.get_value(key1, context=empty))
        self.assertEqual(context.get_value(key1, context=second), "foo")
        self.assertEqual(context.get_value(key2, context=third), "bar")
 def decorated_function(
     exchange: str,
     routing_key: str,
     body: bytes,
     properties: BasicProperties = None,
     mandatory: bool = False,
 ) -> Any:
     if not properties:
         properties = BasicProperties(headers={})
     ctx = context.get_current()
     span = _get_span(
         tracer,
         channel,
         properties,
         span_kind=SpanKind.PRODUCER,
         task_name="(temporary)",
         ctx=ctx,
         operation=None,
     )
     if not span:
         return original_function(
             exchange, routing_key, body, properties, mandatory
         )
     with trace.use_span(span, end_on_exit=True):
         if span.is_recording():
             propagate.inject(properties.headers)
         retval = original_function(
             exchange, routing_key, body, properties, mandatory
         )
     return retval
Example #5
0
    def extract(
        self,
        getter: Getter[TextMapPropagatorT],
        carrier: TextMapPropagatorT,
        context: typing.Optional[Context] = None,
    ) -> Context:

        if context is None:
            context = get_current()
        header = getter.get(carrier, self.TRACE_ID_KEY)
        if not header:
            return trace.set_span_in_context(trace.INVALID_SPAN, context)
        fields = _extract_first_element(header).split(":")

        context = self._extract_baggage(getter, carrier, context)
        if len(fields) != 4:
            return trace.set_span_in_context(trace.INVALID_SPAN, context)

        trace_id, span_id, _parent_id, flags = fields
        if (trace_id == trace.INVALID_TRACE_ID
                or span_id == trace.INVALID_SPAN_ID):
            return trace.set_span_in_context(trace.INVALID_SPAN, context)

        span = trace.DefaultSpan(
            trace.SpanContext(
                trace_id=int(trace_id, 16),
                span_id=int(span_id, 16),
                is_remote=True,
                trace_flags=trace.TraceFlags(
                    int(flags, 16) & trace.TraceFlags.SAMPLED),
            ))
        return trace.set_span_in_context(span, context)
 def decorated_callback(
     channel: Channel,
     method: Basic.Deliver,
     properties: BasicProperties,
     body: bytes,
 ) -> Any:
     if not properties:
         properties = BasicProperties(headers={})
     if properties.headers is None:
         properties.headers = {}
     ctx = propagate.extract(properties.headers, getter=_pika_getter)
     if not ctx:
         ctx = context.get_current()
     token = context.attach(ctx)
     span = _get_span(
         tracer,
         channel,
         properties,
         destination=method.exchange
         if method.exchange else method.routing_key,
         span_kind=SpanKind.CONSUMER,
         task_name=task_name,
         operation=MessagingOperationValues.RECEIVE,
     )
     try:
         with trace.use_span(span, end_on_exit=True):
             try:
                 consume_hook(span, body, properties)
             except Exception as hook_exception:  # pylint: disable=W0703
                 _LOG.exception(hook_exception)
             retval = callback(channel, method, properties, body)
     finally:
         context.detach(token)
     return retval
 def extract(
     self,
     get_from_carrier: Getter[HTTPTextFormatT],
     carrier: HTTPTextFormatT,
     context: typing.Optional[Context] = None,
 ) -> Context:
     return get_current()
Example #8
0
def _start_internal_or_server_span(
    tracer, span_name, start_time, context_carrier, context_getter
):
    """Returns internal or server span along with the token which can be used by caller to reset context


    Args:
        tracer : tracer in use by given instrumentation library
        name (string): name of the span
        start_time : start time of the span
        context_carrier : object which contains values that are
            used to construct a Context. This object
            must be paired with an appropriate getter
            which understands how to extract a value from it.
        context_getter : an object which contains a get function that can retrieve zero
            or more values from the carrier and a keys function that can get all the keys
            from carrier.
    """

    token = ctx = span_kind = None
    if trace.get_current_span() is trace.INVALID_SPAN:
        ctx = extract(context_carrier, getter=context_getter)
        token = context.attach(ctx)
        span_kind = trace.SpanKind.SERVER
    else:
        ctx = context.get_current()
        span_kind = trace.SpanKind.INTERNAL
    span = tracer.start_span(
        name=span_name,
        context=ctx,
        kind=span_kind,
        start_time=start_time,
    )
    return span, token
 def extract(
     self,
     carrier: CarrierT,
     context: typing.Optional[Context] = None,
     getter: Getter = default_getter,
 ) -> Context:
     return get_current()
Example #10
0
 def extract(
     self,
     getter: Getter[TextMapPropagatorT],
     carrier: TextMapPropagatorT,
     context: typing.Optional[Context] = None,
 ) -> Context:
     return get_current()
Example #11
0
 def _inject(self, values):
     """Test helper"""
     ctx = get_current()
     for k, v in values.items():
         ctx = baggage.set_baggage(k, v, context=ctx)
     output = {}
     self.propagator.inject(output, context=ctx)
     return output.get("baggage")
 def _inject(self, span=None):
     """Test helper"""
     ctx = get_current()
     if span is not None:
         ctx = trace.set_span_in_context(span, ctx)
     output = {}
     self.propagator.inject(dict.__setitem__, output, context=ctx)
     return output.get(_TRACE_CONTEXT_HEADER_NAME)
 def _inject(self, values):
     """Test helper"""
     ctx = get_current()
     for k, v in values.items():
         ctx = baggage.set_baggage(k, v, context=ctx)
     output = {}
     self.propagator.inject(dict.__setitem__, output, context=ctx)
     return output.get("otcorrelations")
    async def __call__(self, scope, receive, send):
        """The ASGI application

        Args:
            scope: A ASGI environment.
            receive: An awaitable callable yielding dictionaries
            send: An awaitable callable taking a single dictionary as argument.
        """
        if scope["type"] not in ("http", "websocket"):
            return await self.app(scope, receive, send)

        _, _, url = get_host_port_url_tuple(scope)
        if self.excluded_urls and self.excluded_urls.url_disabled(url):
            return await self.app(scope, receive, send)

        token = ctx = span_kind = None

        if trace.get_current_span() is INVALID_SPAN:
            ctx = extract(scope, getter=asgi_getter)
            token = context.attach(ctx)
            span_kind = SpanKind.SERVER
        else:
            ctx = context.get_current()
            span_kind = SpanKind.INTERNAL

        span_name, additional_attributes = self.default_span_details(scope)

        try:
            with self.tracer.start_as_current_span(
                    span_name,
                    context=ctx,
                    kind=span_kind,
            ) as current_span:
                if current_span.is_recording():
                    attributes = collect_request_attributes(scope)
                    attributes.update(additional_attributes)
                    for key, value in attributes.items():
                        current_span.set_attribute(key, value)

                if callable(self.server_request_hook):
                    self.server_request_hook(current_span, scope)

                otel_receive = self._get_otel_receive(span_name, scope,
                                                      receive)

                otel_send = self._get_otel_send(
                    current_span,
                    span_name,
                    scope,
                    send,
                )

                await self.app(scope, otel_receive, otel_send)
        finally:
            if token:
                context.detach(token)
Example #15
0
    def with_current_context(cls, func):
        # type: (Callable) -> Callable
        """Passes the current spans to the new context the function will be run in.

        :param func: The function that will be run in the new context
        :return: The target the pass in instead of the function
        """
        # returns the current Context object
        context = get_current()

        def call_with_current_context(*args, **kwargs):
            try:
                token = attach(context)
                return func(*args, **kwargs)
            finally:
                detach(token)

        return call_with_current_context
Example #16
0
    def _before_request():
        if excluded_urls and excluded_urls.url_disabled(flask.request.url):
            return
        flask_request_environ = flask.request.environ
        span_name = get_default_span_name()

        token = ctx = span_kind = None

        if trace.get_current_span() is trace.INVALID_SPAN:
            ctx = extract(flask_request_environ, getter=otel_wsgi.wsgi_getter)
            token = context.attach(ctx)
            span_kind = trace.SpanKind.SERVER
        else:
            ctx = context.get_current()
            span_kind = trace.SpanKind.INTERNAL

        span = tracer.start_span(
            span_name,
            ctx,
            kind=span_kind,
            start_time=flask_request_environ.get(_ENVIRON_STARTTIME_KEY),
        )

        if request_hook:
            request_hook(span, flask_request_environ)

        if span.is_recording():
            attributes = otel_wsgi.collect_request_attributes(
                flask_request_environ)
            if flask.request.url_rule:
                # For 404 that result from no route found, etc, we
                # don't have a url_rule.
                attributes[
                    SpanAttributes.HTTP_ROUTE] = flask.request.url_rule.rule
            for key, value in attributes.items():
                span.set_attribute(key, value)

        activation = trace.use_span(span, end_on_exit=True)
        activation.__enter__()  # pylint: disable=E1101
        flask_request_environ[_ENVIRON_ACTIVATION_KEY] = activation
        flask_request_environ[_ENVIRON_SPAN_KEY] = span
        flask_request_environ[_ENVIRON_TOKEN] = token
Example #17
0
    def extract(
        self,
        get_from_carrier: httptextformat.Getter[
            httptextformat.HTTPTextFormatT],
        carrier: httptextformat.HTTPTextFormatT,
        context: typing.Optional[Context] = None,
    ) -> Context:
        """Extract CorrelationContext from the carrier.

        See
        `opentelemetry.trace.propagation.httptextformat.HTTPTextFormat.extract`
        """

        if context is None:
            context = get_current()

        header = _extract_first_element(
            get_from_carrier(carrier, self._CORRELATION_CONTEXT_HEADER_NAME))

        if not header or len(header) > self.MAX_HEADER_LENGTH:
            return context

        correlations = header.split(",")
        total_correlations = self.MAX_PAIRS
        for correlation in correlations:
            if total_correlations <= 0:
                return context
            total_correlations -= 1
            if len(correlation) > self.MAX_PAIR_LENGTH:
                continue
            try:
                name, value = correlation.split("=", 1)
            except Exception:  # pylint: disable=broad-except
                continue
            context = correlationcontext.set_correlation(
                urllib.parse.unquote(name).strip(),
                urllib.parse.unquote(value).strip(),
                context=context,
            )

        return context
Example #18
0
    def extract(
        self,
        getter: textmap.Getter[textmap.TextMapPropagatorT],
        carrier: textmap.TextMapPropagatorT,
        context: typing.Optional[Context] = None,
    ) -> Context:
        """Extract Baggage from the carrier.

        See
        `opentelemetry.propagators.textmap.TextMapPropagator.extract`
        """

        if context is None:
            context = get_current()

        header = _extract_first_element(
            getter.get(carrier, self._BAGGAGE_HEADER_NAME)
        )

        if not header or len(header) > self.MAX_HEADER_LENGTH:
            return context

        baggage_entries = header.split(",")
        total_baggage_entries = self.MAX_PAIRS
        for entry in baggage_entries:
            if total_baggage_entries <= 0:
                return context
            total_baggage_entries -= 1
            if len(entry) > self.MAX_PAIR_LENGTH:
                continue
            try:
                name, value = entry.split("=", 1)
            except Exception:  # pylint: disable=broad-except
                continue
            context = baggage.set_baggage(
                urllib.parse.unquote(name).strip(),
                urllib.parse.unquote(value).strip(),
                context=context,
            )

        return context
 def decorated_callback(
     channel: Channel,
     method: Basic.Deliver,
     properties: BasicProperties,
     body: bytes,
 ) -> Any:
     if not properties:
         properties = BasicProperties(headers={})
     ctx = propagate.extract(properties.headers, getter=_pika_getter)
     if not ctx:
         ctx = context.get_current()
     span = _get_span(
         tracer,
         channel,
         properties,
         span_kind=SpanKind.CONSUMER,
         task_name=task_name,
         ctx=ctx,
         operation=MessagingOperationValues.RECEIVE,
     )
     with trace.use_span(span, end_on_exit=True):
         retval = callback(channel, method, properties, body)
     return retval
    def on_start(self,
                 span: "Span",
                 parent_context: Optional[context_api.Context] = None) -> None:
        """
        Span listener that will:

        1. copy attributes from parent span to
        :param span:
        :param parent_context:
        :return:
        """
        current_span = trace_api.get_current_span(context_api.get_current())

        wrapped_span = telemetry.Span(span)

        if current_span and not isinstance(current_span,
                                           trace_api.DefaultSpan):
            # copy parent span's attributes into this span
            for key, value in current_span.attributes.items():
                if Attributes.propagte(key):
                    span.set_attribute(key, value)

        # set/overwrite any span-specific attributes/labels
        wrapped_span.set(Attributes.TRACE_ID, str(span.context.trace_id))
        wrapped_span.set(Attributes.TRACE_SPAN_ID, str(span.context.span_id))
        wrapped_span.set(Attributes.TRACE_IS_REMOTE, span.context.is_remote)
        wrapped_span.set(Attributes.TRACE_CATEGORY, wrapped_span.category)
        wrapped_span.set(Attributes.TRACE_NAME, wrapped_span.qname)

        for key, value in Environment.attributes.items():
            wrapped_span.set_attribute(key, value)

        for key, value in Environment.labels.items():
            wrapped_span.set_label(key, value)

        super().on_start(span, parent_context)
 def test_inject_empty_context(self):
     """If the current context has no span, don't add headers"""
     new_carrier = {}
     self.get_propagator().inject(new_carrier, get_current())
     assert len(new_carrier) == 0
 def test_inject_empty_context():
     """If the current context has no span, don't add headers"""
     new_carrier = {}
     FORMAT.inject(dict.__setitem__, new_carrier, get_current())
     assert len(new_carrier) == 0
 def setUp(self) -> None:
     self.previous_context = context.get_current()
    def extract(
        self,
        carrier: textmap.CarrierT,
        context: Optional[Context] = None,
        getter: textmap.Getter = textmap.default_getter,
    ) -> Context:
        """Extract Baggage from the carrier.

        See
        `opentelemetry.propagators.textmap.TextMapPropagator.extract`
        """

        if context is None:
            context = get_current()

        header = _extract_first_element(
            getter.get(carrier, self._BAGGAGE_HEADER_NAME)
        )

        if not header:
            return context

        if len(header) > self._MAX_HEADER_LENGTH:
            _logger.warning(
                "Baggage header `%s` exceeded the maximum number of bytes per baggage-string",
                header,
            )
            return context

        baggage_entries = split(_DELIMITER_PATTERN, header)
        total_baggage_entries = self._MAX_PAIRS

        if len(baggage_entries) > self._MAX_PAIRS:
            _logger.warning(
                "Baggage header `%s` exceeded the maximum number of list-members",
                header,
            )

        for entry in baggage_entries:
            if len(entry) > self._MAX_PAIR_LENGTH:
                _logger.warning(
                    "Baggage entry `%s` exceeded the maximum number of bytes per list-member",
                    entry,
                )
                continue
            if not entry:  # empty string
                continue
            try:
                name, value = entry.split("=", 1)
            except Exception:  # pylint: disable=broad-except
                _logger.warning(
                    "Baggage list-member `%s` doesn't match the format", entry
                )
                continue
            name = unquote_plus(name).strip().lower()
            value = unquote_plus(value).strip()
            if not _is_valid_pair(name, value):
                _logger.warning("Invalid baggage entry: `%s`", entry)
                continue

            context = set_baggage(
                name,
                value,
                context=context,
            )
            total_baggage_entries -= 1
            if total_baggage_entries == 0:
                break

        return context
 def test_context_is_immutable(self):
     with self.assertRaises(ValueError):
         # ensure a context
         context.get_current()["test"] = "cant-change-immutable"