text: from flask import g
  from flask import request
  from flask import signals
  import flask.templating
  
  from ddtrace import config
  
  from .. import trace_utils
  from ... import compat
  from ...ext import SpanTypes
  from ...ext import errors
  from ...ext import http
  from ...internal.logger import get_logger
  from ...propagation.http import HTTPPropagator
  from ...utils.deprecation import deprecated
  
  
  log = get_logger(__name__)
  
  
  SPAN_NAME = "flask.request"
  
  
  class TraceMiddleware(object):
      @deprecated(message="Use patching instead (see the docs).", version="1.0.0")
      def __init__(self, app, tracer, service="flask", use_signals=True, distributed_tracing=False):
          self.app = app
          log.debug("flask: initializing trace middleware")
  
          # Attach settings to the inner application middleware. This is required if double
          # instrumentation happens (i.e. `ddtrace-run` with `TraceMiddleware`). In that
          # case, `ddtrace-run` instruments the application, but then users code is unable
          # to update settings such as `distributed_tracing` flag. This step can be removed
          # when the `Config` object is used
          self.app._tracer = tracer
          self.app._service = service
          self.app._use_distributed_tracing = distributed_tracing
          self.use_signals = use_signals
  
          # safe-guard to avoid double instrumentation
          if getattr(app, "__dd_instrumentation", False):
              return
          setattr(app, "__dd_instrumentation", True)
  
          # Install hooks which time requests.
          self.app.before_request(self._before_request)
          self.app.after_request(self._after_request)
          self.app.teardown_request(self._teardown_request)
  
          # Add exception handling signals. This will annotate exceptions that
          # are caught and handled in custom user code.
          # See https://github.com/DataDog/dd-trace-py/issues/390
          if use_signals and not signals.signals_available:
              log.debug(_blinker_not_installed_msg)
          self.use_signals = use_signals and signals.signals_available
          timing_signals = {
              "got_request_exception": self._request_exception,
          }
          self._receivers = []
          if self.use_signals and _signals_exist(timing_signals):
              self._connect(timing_signals)
  
          _patch_render(tracer)
  
      def _connect(self, signal_to_handler):
          connected = True
          for name, handler in signal_to_handler.items():
              s = getattr(signals, name, None)
              if not s:
                  connected = False
                  log.warning("trying to instrument missing signal %s", name)
                  continue
              # we should connect to the signal without using weak references
              # otherwise they will be garbage collected and our handlers
              # will be disconnected after the first call; for more details check:
              # https://github.com/jek/blinker/blob/207446f2d97/blinker/base.py#L106-L108
              s.connect(handler, sender=self.app, weak=False)
              self._receivers.append(handler)
          return connected
  
      def _before_request(self):
          """Starts tracing the current request and stores it in the global
          request object.
          """
          self._start_span()
  
      def _after_request(self, response):
          """ Runs after the server can process a response. """
          try:
              self._process_response(response)
          except Exception:
              log.debug("flask: error tracing response", exc_info=True)
          return response
  
      def _teardown_request(self, exception):
          """Runs at the end of a request. If there's an unhandled exception, it
          will be passed in.
          """
          # when we teardown the span, ensure we have a clean slate.
          span = getattr(g, "flask_datadog_span", None)
          setattr(g, "flask_datadog_span", None)
          if not span:
              return
  
          try:
              self._finish_span(span, exception=exception)
          except Exception:
              log.debug("flask: error finishing span", exc_info=True)
  
      def _start_span(self):
          if self.app._use_distributed_tracing:
              context = HTTPPropagator.extract(request.headers)
              # Only need to active the new context if something was propagated
              if context.trace_id:
                  self.app._tracer.context_provider.activate(context)
          try:
              g.flask_datadog_span = self.app._tracer.trace(
                  SPAN_NAME,
                  service=self.app._service,
                  span_type=SpanTypes.WEB,
              )
          except Exception:
              log.debug("flask: error tracing request", exc_info=True)
  
      def _process_response(self, response):
          span = getattr(g, "flask_datadog_span", None)
          if not span:
              return
  
          code = response.status_code if response else ""
          trace_utils.set_http_meta(span, config.flask, status_code=code, response_headers=response.headers)
  
      def _request_exception(self, *args, **kwargs):
          exception = kwargs.get("exception", None)
          span = getattr(g, "flask_datadog_span", None)
          if span and exception:
              _set_error_on_span(span, exception)
  
      def _finish_span(self, span, exception=None):
          if not span:
              return
  
          code = span.get_tag(http.STATUS_CODE) or 0
          try:
              code = int(code)
          except Exception:
              code = 0
  
          if exception:
              # if the request has already had a code set, don't override it.
              code = code or 500
              _set_error_on_span(span, exception)
  
          # the endpoint that matched the request is None if an exception
          # happened so we fallback to a common resource
          span.error = 0 if code < 500 else 1
  
          # the request isn't guaranteed to exist here, so only use it carefully.
          method = ""
          endpoint = ""
          url = ""
          query = ""
          request_headers = ""
  
          if request:
              method = request.method
              endpoint = request.endpoint or code
              url = request.base_url or ""
              query = request.query_string.decode() if hasattr(request.query_string, "decode") else request.query_string
              request_headers = request.headers
  
          # Let users specify their own resource in middleware if they so desire.
          # See case https://github.com/DataDog/dd-trace-py/issues/353
          if span.resource == SPAN_NAME:
              resource = endpoint or code
              span.resource = compat.to_unicode(resource).lower()
  
          trace_utils.set_http_meta(
              span,
              config.flask,
              method=method,
              url=compat.to_unicode(url),
              status_code=code,
              query=query,
              request_headers=request_headers,
          )
          span.finish()
  
  
  def _set_error_on_span(span, exception):
      # The 3 next lines might not be strictly required, since `set_traceback`
      # also get the exception from the sys.exc_info (and fill the error meta).
      # Since we aren't sure it always work/for insuring no BC break, keep
      # these lines which get overridden anyway.
      span.set_tag(errors.ERROR_TYPE, type(exception))
      span.set_tag(errors.ERROR_MSG, exception)
      # The provided `exception` object doesn't have a stack trace attached,
      # so attach the stack trace with `set_traceback`.
      span.set_traceback()
  
  
  def _patch_render(tracer):
      """ patch flask's render template methods with the given tracer. """
      # fall back to patching  global method
      _render = flask.templating._render
  
      # If the method has already been patched and we're patching again then
      # we have to patch again with the new tracer reference.
      if hasattr(_render, "__dd_orig"):
          _render = getattr(_render, "__dd_orig")
  
      def _traced_render(template, context, app):
          with tracer.trace("flask.template", span_type=SpanTypes.TEMPLATE) as span:
              span.set_tag("flask.template", template.name or "string")
              return _render(template, context, app)
  
      setattr(_traced_render, "__dd_orig", _render)
      flask.templating._render = _traced_render
  
  
  def _signals_exist(names):
      """Return true if all of the given signals exist in this version of flask."""
      return all(getattr(signals, n, False) for n in names)
  
  
  _blinker_not_installed_msg = "please install blinker to use flask signals. " "http://flask.pocoo.org/docs/0.11/signals/"
  