Attempts to extract a tracing span from incoming request.
    If no tracing context is passed in the headers, or the data
    cannot be parsed, a new root span is started.

    :param request: HTTP request with `.headers` property exposed
        that satisfies a regular dictionary interface
    :param tracer: optional tracer instance to use. If not specified
        the global opentracing.tracer will be used.
    :return: returns a new, already started span.

def before_request(request, tracer=None):
    """
    Attempts to extract a tracing span from incoming request.
    If no tracing context is passed in the headers, or the data
    cannot be parsed, a new root span is started.

    :param request: HTTP request with `.headers` property exposed
        that satisfies a regular dictionary interface
    :param tracer: optional tracer instance to use. If not specified
        the global opentracing.tracer will be used.
    :return: returns a new, already started span.
    """
    if tracer is None:  # pragma: no cover
        tracer = opentracing.tracer

    # we need to prepare tags upfront, mainly because RPC_SERVER tag must be
    # set when starting the span, to support Zipkin's one-span-per-RPC model
    tags_dict = {
        tags.SPAN_KIND: tags.SPAN_KIND_RPC_SERVER,
        tags.HTTP_URL: request.full_url,
    }

    remote_ip = request.remote_ip
    if remote_ip:
        tags_dict[tags.PEER_HOST_IPV4] = remote_ip

    caller_name = request.caller_name
    if caller_name:
        tags_dict[tags.PEER_SERVICE] = caller_name

    remote_port = request.remote_port
    if remote_port:
        tags_dict[tags.PEER_PORT] = remote_port

    operation = request.operation
    try:
        carrier = {}
        for key, value in six.iteritems(request.headers):
            carrier[key] = value
        parent_ctx = tracer.extract(
            format=Format.HTTP_HEADERS, carrier=carrier
        )
    except Exception as e:
        logging.exception('trace extract failed: %s' % e)
        parent_ctx = None

    span = tracer.start_span(
        operation_name=operation,
        child_of=parent_ctx,
        tags=tags_dict)

    return span