예제 #1
0
파일: web.py 프로젝트: vmagamedov/harness
async def _opentracing_middleware(
    request: Request,
    handler: Callable[[Request], Awaitable[StreamResponse]],
) -> StreamResponse:
    tracer = get_tracer(__name__)
    attach(extract(_headers_getter, request))
    with tracer.start_as_current_span(
            request.path,
            kind=SpanKind.SERVER,
            attributes={
                "component": "http",
                "http.method": request.method,
                "http.scheme": request.scheme,
                "http.host": request.host,
            },
    ) as span:
        try:
            response = await handler(request)
        except HTTPException as e:
            code = _utils.status_to_canonical_code(e.status)
            span.set_status(Status(code))
            span.set_attribute("http.status_text", e.reason)
            raise
        else:
            code = _utils.status_to_canonical_code(response.status)
            span.set_status(Status(code))
            span.set_attribute("http.status_text", response.reason)
            return response
    def test_set_current(self):
        context.attach(context.set_value("a", "yyy"))

        token = context.attach(context.set_value("a", "zzz"))
        self.assertEqual("zzz", context.get_value("a"))

        context.detach(token)
        self.assertEqual("yyy", context.get_value("a"))
 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_attach(self):
            context.attach(context.set_value("a", "yyy"))

            token = context.attach(context.set_value("a", "zzz"))
            self.assertEqual("zzz", context.get_value("a"))

            context.detach(token)
            self.assertEqual("yyy", context.get_value("a"))

            with self.assertLogs(level=ERROR):
                context.detach("some garbage")
예제 #5
0
async def _recv_request(event: RecvRequest) -> None:
    tracer = get_tracer(__name__)
    attach(extract(_metadata_getter, event.metadata))
    span_ctx = tracer.start_as_current_span(
        event.method_name,
        kind=SpanKind.SERVER,
        attributes={
            "component": "grpc",
            "grpc.method": event.method_name
        },
    )
    span_ctx.__enter__()
    _server_span_ctx.set(span_ctx)
예제 #6
0
    def process_view(self, request, view_func, view_args, view_kwargs):  # pylint: disable=unused-argument
        # request.META is a dictionary containing all available HTTP headers
        # Read more about request.META here:
        # https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.META

        # environ = {
        #     key.lower().replace('_', '-').replace("http-", "", 1): value
        #     for key, value in request.META.items()
        # }

        environ = request.META

        token = attach(extract(get_header_from_environ, environ))

        tracer = get_tracer(__name__, __version__)

        attributes = collect_request_attributes(environ)

        span = tracer.start_span(
            view_func.__name__,
            kind=SpanKind.SERVER,
            attributes=attributes,
            start_time=environ.get(
                "opentelemetry-instrumentor-django.starttime_key"),
        )

        activation = tracer.use_span(span, end_on_exit=True)
        activation.__enter__()

        request.META[self._environ_activation_key] = activation
        request.META[self._environ_span_key] = span
        request.META[self._environ_token] = token
예제 #7
0
    def __call__(self, environ, start_response):
        """The WSGI application

        Args:
            environ: A WSGI environment.
            start_response: The WSGI start_response callable.
        """

        token = context.attach(
            propagators.extract(get_header_from_environ, environ)
        )
        span_name = self.name_callback(environ)

        span = self.tracer.start_span(
            span_name,
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(environ),
        )

        try:
            with self.tracer.use_span(span):
                start_response = self._create_start_response(
                    span, start_response
                )
                iterable = self.wsgi(environ, start_response)
                return _end_span_after_iterating(
                    iterable, span, self.tracer, token
                )
        except:  # noqa
            # TODO Set span status (cf. https://github.com/open-telemetry/opentelemetry-python/issues/292)
            span.end()
            context.detach(token)
            raise
예제 #8
0
def _suppress_further_instrumentation():
    token = context.attach(
        context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True))
    try:
        yield
    finally:
        context.detach(token)
예제 #9
0
def _start_span(tracer, handler, start_time) -> _TraceContext:
    token = context.attach(extract(handler.request.headers))

    span = tracer.start_span(
        _get_operation_name(handler, handler.request),
        kind=trace.SpanKind.SERVER,
        start_time=start_time,
    )
    if span.is_recording():
        attributes = _get_attributes_from_request(handler.request)
        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
    ctx = _TraceContext(activation, span, token)
    setattr(handler, _HANDLER_CONTEXT_KEY, ctx)

    # finish handler is called after the response is sent back to
    # the client so it is too late to inject trace response headers
    # there.
    propagator = get_global_response_propagator()
    if propagator:
        propagator.inject(handler, setter=response_propagation_setter)

    return ctx
 async def suppressed_request(server: aiohttp.test_utils.TestServer):
     async with aiohttp.test_utils.TestClient(server) as client:
         token = context.attach(
             context.set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)
         )
         await client.get(TestAioHttpClientInstrumentor.URL)
         context.detach(token)
예제 #11
0
    def __call__(self, environ, start_response):
        """The WSGI application

        Args:
            environ: A WSGI environment.
            start_response: The WSGI start_response callable.
        """

        token = context.attach(extract(environ, getter=wsgi_getter))
        span_name = self.name_callback(environ)

        span = self.tracer.start_span(
            span_name,
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(environ),
        )

        try:
            with trace.use_span(span):
                start_response = self._create_start_response(
                    span, start_response)
                iterable = self.wsgi(environ, start_response)
                return _end_span_after_iterating(iterable, span, self.tracer,
                                                 token)
        except Exception as ex:
            if span.is_recording():
                span.set_status(Status(StatusCode.ERROR, str(ex)))
            span.end()
            context.detach(token)
            raise
예제 #12
0
파일: __init__.py 프로젝트: wangzlei/action
    def export(self, spans) -> SpanExportResult:
        logger.info("--- XraySpanExporter emitter ---")

        # TODO: merge segments to one request, else batch processor does not make sense
        for span in spans:
            segment = self._translate_to_segment(span)
            if segment == "":
                continue
            entity = json.dumps(segment)

            # emit segment to daemon or xray ...
            # self._emitter.send_entity(entity)
            logger.info(entity)

            # suppress boto3 instumentation
            token = attach(set_value("suppress_instrumentation", True))
            response = self._xray_client.put_trace_segments(
                TraceSegmentDocuments=[
                    entity,
                ]
            )
            detach(token)
            logger.info(response)

        return SpanExportResult.SUCCESS
예제 #13
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
    async def on_request_start(
        unused_session: aiohttp.ClientSession,
        trace_config_ctx: types.SimpleNamespace,
        params: aiohttp.TraceRequestStartParams,
    ):
        if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
            trace_config_ctx.span = None
            return

        http_method = params.method.upper()
        request_span_name = f"HTTP {http_method}"
        request_url = (remove_url_credentials(
            trace_config_ctx.url_filter(params.url)) if callable(
                trace_config_ctx.url_filter) else remove_url_credentials(
                    str(params.url)))

        span_attributes = {
            SpanAttributes.HTTP_METHOD: http_method,
            SpanAttributes.HTTP_URL: request_url,
        }

        trace_config_ctx.span = trace_config_ctx.tracer.start_span(
            request_span_name,
            kind=SpanKind.CLIENT,
            attributes=span_attributes)

        if callable(request_hook):
            request_hook(trace_config_ctx.span, params)

        trace_config_ctx.token = context_api.attach(
            trace.set_span_in_context(trace_config_ctx.span))

        inject(params.headers)
예제 #15
0
        def _before_flask_request():
            environ = flask.request.environ
            span_name = (flask.request.endpoint
                         or otel_wsgi.get_default_span_name(environ))
            token = context.attach(
                propagators.extract(otel_wsgi.get_header_from_environ,
                                    environ))

            tracer = trace.get_tracer(__name__, __version__)

            attributes = otel_wsgi.collect_request_attributes(environ)
            if flask.request.url_rule:
                # For 404 that result from no route found, etc, we
                # don't have a url_rule.
                attributes["http.route"] = flask.request.url_rule.rule
            span = tracer.start_span(
                span_name,
                kind=trace.SpanKind.SERVER,
                attributes=attributes,
                start_time=environ.get(_ENVIRON_STARTTIME_KEY),
            )
            activation = tracer.use_span(span, end_on_exit=True)
            activation.__enter__()
            environ[_ENVIRON_ACTIVATION_KEY] = activation
            environ[_ENVIRON_SPAN_KEY] = span
            environ[_ENVIRON_TOKEN] = token
예제 #16
0
 async def suppressed_request(server: aiohttp.test_utils.TestServer):
     async with aiohttp.test_utils.TestClient(server) as client:
         token = context.attach(
             context.set_value("suppress_instrumentation", True)
         )
         await client.get(TestAioHttpClientInstrumentor.URL)
         context.detach(token)
예제 #17
0
    async def on_request_start(
        unused_session: aiohttp.ClientSession,
        trace_config_ctx: types.SimpleNamespace,
        params: aiohttp.TraceRequestStartParams,
    ):
        http_method = params.method.upper()
        if trace_config_ctx.span_name is None:
            request_span_name = http_method
        elif callable(trace_config_ctx.span_name):
            request_span_name = str(trace_config_ctx.span_name(params))
        else:
            request_span_name = str(trace_config_ctx.span_name)

        trace_config_ctx.span = trace_config_ctx.tracer.start_span(
            request_span_name,
            kind=SpanKind.CLIENT,
            attributes={
                "component": "http",
                "http.method": http_method,
                "http.url": trace_config_ctx.url_filter(params.url)
                if callable(trace_config_ctx.url_filter)
                else str(params.url),
            },
        )

        trace_config_ctx.token = context_api.attach(
            trace.propagation.set_span_in_context(trace_config_ctx.span)
        )

        propagators.inject(
            tracer, type(params.headers).__setitem__, params.headers
        )
예제 #18
0
    def use_span(
        self,
        span: trace_api.Span,
        end_on_exit: bool = False,
        record_exception: bool = True,
    ) -> Iterator[trace_api.Span]:
        try:
            token = context_api.attach(context_api.set_value(SPAN_KEY, span))
            try:
                yield span
            finally:
                context_api.detach(token)

        except Exception as error:  # pylint: disable=broad-except
            # pylint:disable=protected-access
            if isinstance(span, Span):
                if record_exception:
                    span.record_exception(error)

                if span.status is None and span._set_status_on_exception:
                    span.set_status(
                        Status(
                            canonical_code=getattr(
                                error,
                                EXCEPTION_STATUS_FIELD,
                                StatusCanonicalCode.UNKNOWN,
                            ),
                            description="{}: {}".format(
                                type(error).__name__, error),
                        ))
            raise

        finally:
            if end_on_exit:
                span.end()
예제 #19
0
    def export(self) -> None:
        """Exports at most max_export_batch_size spans."""
        idx = 0
        notify_flush = False
        # currently only a single thread acts as consumer, so queue.pop() will
        # not raise an exception
        while idx < self.max_export_batch_size and self.queue:
            span = self.queue.pop()
            if span is self._FLUSH_TOKEN_SPAN:
                notify_flush = True
            else:
                self.spans_list[idx] = span
                idx += 1
        token = attach(set_value("suppress_instrumentation", True))
        try:
            # Ignore type b/c the Optional[None]+slicing is too "clever"
            # for mypy
            self.span_exporter.export(self.spans_list[:idx])  # type: ignore
        # pylint: disable=broad-except
        except Exception:
            logger.exception("Exception while exporting Span batch.")
        detach(token)

        if notify_flush:
            with self.flush_condition:
                self.flush_condition.notify()

        # clean up list
        for index in range(idx):
            self.spans_list[index] = None
예제 #20
0
 def __init__(self,
              manager: "ScopeManagerShim",
              span: SpanShim,
              span_cm=None):
     super().__init__(manager, span)
     self._span_cm = span_cm
     self._token = attach(set_value("scope_shim", self))
예제 #21
0
    def _instrumented_open_call(_, request, call_wrapped,
                                get_or_create_headers):  # pylint: disable=too-many-locals
        if context.get_value(
                _SUPPRESS_INSTRUMENTATION_KEY) or context.get_value(
                    _SUPPRESS_HTTP_INSTRUMENTATION_KEY):
            return call_wrapped()

        method = request.get_method().upper()
        url = request.full_url

        span_name = f"HTTP {method}".strip()

        url = remove_url_credentials(url)

        labels = {
            SpanAttributes.HTTP_METHOD: method,
            SpanAttributes.HTTP_URL: url,
        }

        with tracer.start_as_current_span(span_name,
                                          kind=SpanKind.CLIENT,
                                          attributes=labels) as span:
            exception = None
            if callable(request_hook):
                request_hook(span, request)

            headers = get_or_create_headers()
            inject(headers)

            token = context.attach(
                context.set_value(_SUPPRESS_HTTP_INSTRUMENTATION_KEY, True))
            try:
                result = call_wrapped()  # *** PROCEED
            except Exception as exc:  # pylint: disable=W0703
                exception = exc
                result = getattr(exc, "file", None)
            finally:
                context.detach(token)

            if result is not None:

                code_ = result.getcode()
                labels[SpanAttributes.HTTP_STATUS_CODE] = str(code_)

                if span.is_recording():
                    span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, code_)
                    span.set_status(Status(http_status_to_status_code(code_)))

                ver_ = str(getattr(result, "version", ""))
                if ver_:
                    labels[
                        SpanAttributes.HTTP_FLAVOR] = f"{ver_[:1]}.{ver_[:-1]}"

            if callable(response_hook):
                response_hook(span, request, result)

            if exception is not None:
                raise exception.with_traceback(exception.__traceback__)

        return result
예제 #22
0
    def use_span(self,
                 span: trace_api.Span,
                 end_on_exit: bool = False) -> Iterator[trace_api.Span]:
        try:
            token = context_api.attach(context_api.set_value(SPAN_KEY, span))
            try:
                yield span
            finally:
                context_api.detach(token)

        except Exception as error:  # pylint: disable=broad-except
            if (isinstance(span, Span) and span.status is None
                    and span._set_status_on_exception  # pylint:disable=protected-access  # noqa
                ):
                span.set_status(
                    Status(
                        canonical_code=StatusCanonicalCode.UNKNOWN,
                        description="{}: {}".format(
                            type(error).__name__, error),
                    ))

            raise

        finally:
            if end_on_exit:
                span.end()
예제 #23
0
    def __call__(self, environ, start_response):
        """The WSGI application

        Args:
            environ: A WSGI environment.
            start_response: The WSGI start_response callable.
        """

        token = context.attach(
            propagators.extract(get_header_from_environ, environ))
        span_name = self.name_callback(environ)

        span = self.tracer.start_span(
            span_name,
            kind=trace.SpanKind.SERVER,
            attributes=collect_request_attributes(environ),
        )

        try:
            with self.tracer.use_span(span):
                start_response = self._create_start_response(
                    span, start_response)
                iterable = self.wsgi(environ, start_response)
                return _end_span_after_iterating(iterable, span, self.tracer,
                                                 token)
        except Exception as ex:
            span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex)))
            span.end()
            context.detach(token)
            raise
예제 #24
0
    def _before_request():
        if _excluded_urls.url_disabled(flask.request.url):
            return

        flask_request_environ = flask.request.environ
        span_name = name_callback()
        token = context.attach(
            extract(flask_request_environ, getter=otel_wsgi.wsgi_getter))

        tracer = trace.get_tracer(__name__, __version__)

        span = tracer.start_span(
            span_name,
            kind=trace.SpanKind.SERVER,
            start_time=flask_request_environ.get(_ENVIRON_STARTTIME_KEY),
        )
        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["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
예제 #25
0
    def process_request(self, request):
        # request.META is a dictionary containing all available HTTP headers
        # Read more about request.META here:
        # https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpRequest.META

        if self._excluded_urls.url_disabled(request.build_absolute_uri("?")):
            return

        environ = request.META

        token = attach(extract(get_header_from_environ, environ))

        tracer = get_tracer(__name__, __version__)

        attributes = collect_request_attributes(environ)
        for attr in self._traced_request_attrs:
            value = getattr(request, attr, None)
            if value is not None:
                attributes[attr] = str(value)

        span = tracer.start_span(
            self._get_span_name(request),
            kind=SpanKind.SERVER,
            attributes=attributes,
            start_time=environ.get(
                "opentelemetry-instrumentor-django.starttime_key"),
        )

        activation = tracer.use_span(span, end_on_exit=True)
        activation.__enter__()

        request.META[self._environ_activation_key] = activation
        request.META[self._environ_span_key] = span
        request.META[self._environ_token] = token
예제 #26
0
    def use_span(
        self,
        span: trace_api.Span,
        end_on_exit: bool = False,
    ) -> Iterator[trace_api.Span]:
        try:
            token = context_api.attach(context_api.set_value(SPAN_KEY, span))
            try:
                yield span
            finally:
                context_api.detach(token)

        except Exception as exc:  # pylint: disable=broad-except
            # Record the exception as an event
            if isinstance(span, Span) and span.is_recording():
                # pylint:disable=protected-access
                if span._record_exception:
                    span.record_exception(exc)

                # Records status if use_span is used
                # i.e. with tracer.start_as_current_span() as span:
                if (span.status.status_code is StatusCode.UNSET
                        and span._set_status_on_exception):
                    span.set_status(
                        Status(
                            status_code=StatusCode.ERROR,
                            description="{}: {}".format(
                                type(exc).__name__, exc),
                        ))
            raise

        finally:
            if end_on_exit:
                span.end()
예제 #27
0
 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 _instrumented_requests_call(method: str, url: str, call_wrapped,
                                    get_or_create_headers):
        if context.get_value("suppress_instrumentation") or context.get_value(
                _SUPPRESS_REQUESTS_INSTRUMENTATION_KEY):
            return call_wrapped()

        # See
        # https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-client
        method = method.upper()
        span_name = ""
        if name_callback is not None:
            span_name = name_callback(method, url)
        if not span_name or not isinstance(span_name, str):
            span_name = get_default_span_name(method)

        labels = {}
        labels["http.method"] = method
        labels["http.url"] = url

        with get_tracer(__name__, __version__,
                        tracer_provider).start_as_current_span(
                            span_name, kind=SpanKind.CLIENT) as span:
            exception = None
            if span.is_recording():
                span.set_attribute("http.method", method)
                span.set_attribute("http.url", url)

            headers = get_or_create_headers()
            inject(type(headers).__setitem__, headers)

            token = context.attach(
                context.set_value(_SUPPRESS_REQUESTS_INSTRUMENTATION_KEY,
                                  True))
            try:
                result = call_wrapped()  # *** PROCEED
            except Exception as exc:  # pylint: disable=W0703
                exception = exc
                result = getattr(exc, "response", None)
            finally:
                context.detach(token)

            if isinstance(result, Response):
                if span.is_recording():
                    span.set_attribute("http.status_code", result.status_code)
                    span.set_attribute("http.status_text", result.reason)
                    span.set_status(
                        Status(http_status_to_status_code(result.status_code)))
                labels["http.status_code"] = str(result.status_code)
                if result.raw and result.raw.version:
                    labels["http.flavor"] = (str(result.raw.version)[:1] +
                                             "." +
                                             str(result.raw.version)[:-1])
            if span_callback is not None:
                span_callback(span, result)

            if exception is not None:
                raise exception.with_traceback(exception.__traceback__)

        return result
 def setUp(self):
     self.token = context.attach(context.Context())
     self.tracer_provider = trace.TracerProvider()
     self.tracer = self.tracer_provider.get_tracer(__name__)
     self.memory_exporter = InMemorySpanExporter()
     span_processor = export.SimpleExportSpanProcessor(self.memory_exporter)
     self.tracer_provider.add_span_processor(span_processor)
     self.loop = asyncio.get_event_loop()
예제 #30
0
def use_context(parent_context: "Context") -> Generator[None, None, None]:
    """Uses the Ray trace context for the span."""
    new_context = parent_context if parent_context is not None else Context()
    token = context.attach(new_context)
    try:
        yield
    finally:
        context.detach(token)