Esempio n. 1
0
def _wrap_request(func, instance, args, kwargs):
    # Use any attached tracer if available, otherwise use the global tracer
    pin = Pin.get_from(instance)
    if should_skip_request(pin, instance):
        return func(*args, **kwargs)

    cfg = config.get_from(instance)

    try:
        # Create a new span and attach to this instance (so we can retrieve/update/close later on the response)
        span = pin.tracer.trace(span_name, span_type=SpanTypes.HTTP)
        setattr(instance, "_datadog_span", span)

        # propagate distributed tracing headers
        if cfg.get("distributed_tracing"):
            if len(args) > 3:
                headers = args[3]
            else:
                headers = kwargs.setdefault("headers", {})
            HTTPPropagator.inject(span.context, headers)
    except Exception:
        log.debug("error configuring request", exc_info=True)
        span = getattr(instance, "_datadog_span", None)
        if span:
            span.finish()

    try:
        return func(*args, **kwargs)
    except Exception:
        span = getattr(instance, "_datadog_span", None)
        exc_info = sys.exc_info()
        if span:
            span.set_exc_info(*exc_info)
            span.finish()
        six.reraise(*exc_info)
Esempio n. 2
0
    def __call__(self, environ, start_response):
        def intercept_start_response(status, response_headers, exc_info=None):
            span = self.tracer.current_root_span()
            status_code, status_msg = status.split(" ", 1)
            span.set_tag("http.status_msg", status_msg)
            trace_utils.set_http_meta(span, config.wsgi, status_code=status_code, response_headers=response_headers)
            with self.tracer.trace(
                "wsgi.start_response",
                service=trace_utils.int_service(None, config.wsgi),
                span_type=SpanTypes.WEB,
            ):
                write = start_response(status, response_headers, exc_info)
            return write

        if config.wsgi.distributed_tracing:
            ctx = propagator.extract(environ)
            if ctx.trace_id:
                self.tracer.context_provider.activate(ctx)

        with self.tracer.trace(
            "wsgi.request",
            service=trace_utils.int_service(None, config.wsgi),
            span_type=SpanTypes.WEB,
        ) as span:
            # This prevents GeneratorExit exceptions from being propagated to the top-level span.
            # This can occur if a streaming response exits abruptly leading to a broken pipe.
            # Note: The wsgi.response span will still have the error information included.
            span._ignore_exception(generatorExit)
            with self.tracer.trace("wsgi.application"):
                result = self.app(environ, intercept_start_response)

            with self.tracer.trace("wsgi.response") as resp_span:
                if hasattr(result, "__class__"):
                    resp_class = getattr(getattr(result, "__class__"), "__name__", None)
                    if resp_class:
                        resp_span.meta["result_class"] = resp_class

                for chunk in result:
                    yield chunk

            url = construct_url(environ)
            method = environ.get("REQUEST_METHOD")
            query_string = environ.get("QUERY_STRING")
            request_headers = get_request_headers(environ)
            trace_utils.set_http_meta(
                span, config.wsgi, method=method, url=url, query=query_string, request_headers=request_headers
            )

            if self.span_modifier:
                self.span_modifier(span, environ)

            if hasattr(result, "close"):
                try:
                    result.close()
                except Exception:
                    typ, val, tb = sys.exc_info()
                    span.set_exc_info(typ, val, tb)
                    six.reraise(typ, val, tb=tb)
Esempio n. 3
0
def _wrap_putrequest(func, instance, args, kwargs):
    # Use any attached tracer if available, otherwise use the global tracer
    pin = Pin.get_from(instance)
    if should_skip_request(pin, instance):
        return func(*args, **kwargs)

    try:
        if hasattr(instance, "_datadog_span"):
            # Reuse an existing span set in _wrap_request
            span = instance._datadog_span
        else:
            # Create a new span and attach to this instance (so we can retrieve/update/close later on the response)
            span = pin.tracer.trace(span_name, span_type=SpanTypes.HTTP)
            setattr(instance, "_datadog_span", span)

        method, path = args[:2]
        scheme = "https" if isinstance(instance, httplib.HTTPSConnection) else "http"
        port = ":{port}".format(port=instance.port)

        if (scheme == "http" and instance.port == 80) or (scheme == "https" and instance.port == 443):
            port = ""
        url = "{scheme}://{host}{port}{path}".format(scheme=scheme, host=instance.host, port=port, path=path)

        # sanitize url
        parsed = parse.urlparse(url)
        sanitized_url = parse.urlunparse(
            (parsed.scheme, parsed.netloc, parsed.path, parsed.params, None, parsed.fragment)  # drop query
        )
        trace_utils.set_http_meta(span, config.httplib, method=method, url=sanitized_url, query=parsed.query)

        # set analytics sample rate
        span.set_tag(ANALYTICS_SAMPLE_RATE_KEY, config.httplib.get_analytics_sample_rate())
    except Exception:
        log.debug("error applying request tags", exc_info=True)

        # Close the span to prevent memory leaks.
        span = getattr(instance, "_datadog_span", None)
        if span:
            span.finish()

    try:
        return func(*args, **kwargs)
    except Exception:
        span = getattr(instance, "_datadog_span", None)
        exc_info = sys.exc_info()
        if span:
            span.set_exc_info(*exc_info)
            span.finish()
        six.reraise(*exc_info)