Source code for fastapi_contrib.tracing.middlewares

import contextvars
import warnings

from typing import Any

from opentracing import tags
from opentracing.propagation import Format

from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response


request_span = contextvars.ContextVar('request_span')


[docs]class OpentracingMiddleware(BaseHTTPMiddleware):
[docs] @staticmethod def before_request(request: Request, tracer): """ Gather various info about the request and start new span with the data. """ span_context = tracer.extract( format=Format.HTTP_HEADERS, carrier=request.headers ) span = tracer.start_span( operation_name=f"{request.method} {request.url.path}", child_of=span_context, ) span.set_tag("http.url", str(request.url)) remote_ip = request.client.host span.set_tag(tags.PEER_HOST_IPV4, remote_ip or "") remote_port = request.client.port span.set_tag(tags.PEER_PORT, remote_port or "") return span
[docs] async def dispatch(self, request: Request, call_next: Any) -> Response: """ Store span in some request.state storage using Tracer.scope_manager, using the returned `Scope` as Context Manager to ensure `Span` will be cleared and (in this case) `Span.finish()` be called. :param request: Starlette's Request object :param call_next: Next callable Middleware in chain or final view :return: Starlette's Response object """ tracer = request.app.state.tracer span = self.before_request(request, tracer) with tracer.scope_manager.activate(span, True) as scope: request_span.set(span) warnings.warn( """ opentracing objects request.state will be removed in favor of saving them in request's scope in the next minor version 0.3.0 """, FutureWarning ) request.state.opentracing_span = span request.scope["opentracing_span"] = span request.state.opentracing_scope = scope request.scope["opentracing_scope"] = scope request.state.opentracing_tracer = tracer request.scope["opentracing_tracer"] = tracer response = await call_next(request) return response