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)
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)
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)