
    gAI                    T   d Z ddlmZ ddlZddlmZmZ ddlZddlm	Z	 ddl
mZmZmZmZ ddlmZ ddlmZmZmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlm Z  ddl!m"Z"m#Z#m$Z$  e"d      Z% ejL                  e'      Z( G d de      Z) G d dejT                        Z+d Z,d Z-y)a  
Usage
-----

.. code-block:: python

    import fastapi
    from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor

    app = fastapi.FastAPI()

    @app.get("/foobar")
    async def foobar():
        return {"message": "hello world"}

    FastAPIInstrumentor.instrument_app(app)

Configuration
-------------

Exclude lists
*************
To exclude certain URLs from tracking, set the environment variable ``OTEL_PYTHON_FASTAPI_EXCLUDED_URLS``
(or ``OTEL_PYTHON_EXCLUDED_URLS`` to cover all instrumentations) to a string of comma delimited regexes that match the
URLs.

For example,

::

    export OTEL_PYTHON_FASTAPI_EXCLUDED_URLS="client/.*/info,healthcheck"

will exclude requests such as ``https://site/client/123/info`` and ``https://site/xyz/healthcheck``.

You can also pass comma delimited regexes directly to the ``instrument_app`` method:

.. code-block:: python

    FastAPIInstrumentor.instrument_app(app, excluded_urls="client/.*/info,healthcheck")

Request/Response hooks
**********************

This instrumentation supports request and response hooks. These are functions that get called
right after a span is created for a request and right before the span is finished for the response.

- The server request hook is passed a server span and ASGI scope object for every incoming request.
- The client request hook is called with the internal span, and ASGI scope and event when the method ``receive`` is called.
- The client response hook is called with the internal span, and ASGI scope and event when the method ``send`` is called.

.. code-block:: python

    def server_request_hook(span: Span, scope: dict[str, Any]):
        if span and span.is_recording():
            span.set_attribute("custom_user_attribute_from_request_hook", "some-value")

    def client_request_hook(span: Span, scope: dict[str, Any], message: dict[str, Any]):
        if span and span.is_recording():
            span.set_attribute("custom_user_attribute_from_client_request_hook", "some-value")

    def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, Any]):
        if span and span.is_recording():
            span.set_attribute("custom_user_attribute_from_response_hook", "some-value")

   FastAPIInstrumentor().instrument(server_request_hook=server_request_hook, client_request_hook=client_request_hook, client_response_hook=client_response_hook)

Capture HTTP request and response headers
*****************************************
You can configure the agent to capture specified HTTP headers as span attributes, according to the
`semantic convention <https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-request-and-response-headers>`_.

Request headers
***************
To capture HTTP request headers as span attributes, set the environment variable
``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST`` to a comma delimited list of HTTP header names,
or pass the ``http_capture_headers_server_request`` keyword argument to the ``instrument_app`` method.

For example using the environment variable,
::

    export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST="content-type,custom_request_header"

will extract ``content-type`` and ``custom_request_header`` from the request headers and add them as span attributes.

Request header names in FastAPI are case-insensitive. So, giving the header name as ``CUStom-Header`` in the environment
variable will capture the header named ``custom-header``.

Regular expressions may also be used to match multiple headers that correspond to the given pattern.  For example:
::

    export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST="Accept.*,X-.*"

Would match all request headers that start with ``Accept`` and ``X-``.

To capture all request headers, set ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST`` to ``".*"``.
::

    export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=".*"

The name of the added span attribute will follow the format ``http.request.header.<header_name>`` where ``<header_name>``
is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
single item list containing all the header values.

For example:
``http.request.header.custom_request_header = ["<value1>", "<value2>"]``

Response headers
****************
To capture HTTP response headers as span attributes, set the environment variable
``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`` to a comma delimited list of HTTP header names,
or pass the ``http_capture_headers_server_response`` keyword argument to the ``instrument_app`` method.

For example using the environment variable,
::

    export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE="content-type,custom_response_header"

will extract ``content-type`` and ``custom_response_header`` from the response headers and add them as span attributes.

Response header names in FastAPI are case-insensitive. So, giving the header name as ``CUStom-Header`` in the environment
variable will capture the header named ``custom-header``.

Regular expressions may also be used to match multiple headers that correspond to the given pattern.  For example:
::

    export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE="Content.*,X-.*"

Would match all response headers that start with ``Content`` and ``X-``.

To capture all response headers, set ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`` to ``".*"``.
::

    export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=".*"

The name of the added span attribute will follow the format ``http.response.header.<header_name>`` where ``<header_name>``
is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
list containing the header values.

For example:
``http.response.header.custom_response_header = ["<value1>", "<value2>"]``

Sanitizing headers
******************
In order to prevent storing sensitive data such as personally identifiable information (PII), session keys, passwords,
etc, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS``
to a comma delimited list of HTTP header names to be sanitized, or pass the ``http_capture_headers_sanitize_fields``
keyword argument to the ``instrument_app`` method.

Regexes may be used, and all header names will be matched in a case-insensitive manner.

For example using the environment variable,
::

    export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS=".*session.*,set-cookie"

will replace the value of headers such as ``session-id`` and ``set-cookie`` with ``[REDACTED]`` in the span.

Note:
    The environment variable names used to capture HTTP headers are still experimental, and thus are subject to change.

API
---
    )annotationsN)
CollectionLiteral)Match)_get_schema_url_HTTPStabilityMode)_OpenTelemetrySemanticConventionStability!_OpenTelemetryStabilitySignalType)OpenTelemetryMiddleware)ClientRequestHookClientResponseHookServerRequestHook_instruments)__version__)BaseInstrumentor)	get_meter)SpanAttributes)
get_tracer)get_excluded_urlsparse_excluded_urlssanitize_methodFASTAPIc                  |    e Zd ZdZdZe	 	 	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 d	d       Zed
d       ZddZd Z	d Z
y)FastAPIInstrumentorz<An instrumentor for FastAPI

    See `BaseInstrumentor`
    Nc                B   t        | d      sd| _        t        | dd      st        j                          t        j
                  t        j                        }|t        }nt        |      }t        t        t        |t        |            }t        t        t        |t        |            }| j                  t         |t"        ||||||||	|
       d| _        | t$        j&                  vr t$        j&                  j)                  |        yyt*        j-                  d       y)a  Instrument an uninstrumented FastAPI application.

        Args:
            app: The fastapi ASGI application callable to forward requests to.
            server_request_hook: Optional callback which is called with the server span and ASGI
                          scope object for every incoming request.
            client_request_hook: Optional callback which is called with the internal span, and ASGI
                          scope and event which are sent as dictionaries for when the method receive is called.
            client_response_hook: Optional callback which is called with the internal span, and ASGI
                          scope and event which are sent as dictionaries for when the method send is called.
            tracer_provider: The optional tracer provider to use. If omitted
                the current globally configured one is used.
            meter_provider: The optional meter provider to use. If omitted
                the current globally configured one is used.
            excluded_urls: Optional comma delimited string of regexes to match URLs that should not be traced.
            http_capture_headers_server_request: Optional list of HTTP headers to capture from the request.
            http_capture_headers_server_response: Optional list of HTTP headers to capture from the response.
            http_capture_headers_sanitize_fields: Optional list of HTTP headers to sanitize.
            exclude_spans: Optionally exclude HTTP `send` and/or `receive` spans from the trace.
        !_is_instrumented_by_opentelemetryFN
schema_urlexcluded_urlsdefault_span_detailsserver_request_hookclient_request_hookclient_response_hooktracermeter#http_capture_headers_server_request$http_capture_headers_server_response$http_capture_headers_sanitize_fieldsexclude_spansTz?Attempting to instrument FastAPI app while already instrumented)hasattrr   getattrr	   _initialize(_get_opentelemetry_stability_opt_in_moder
   HTTP_excluded_urls_from_envr   r   __name__r   r   r   add_middlewarer   _get_default_span_details_InstrumentedFastAPI_instrumented_fastapi_appsadd_loggerwarning)appr#   r$   r%   tracer_providermeter_providerr!   r(   r)   r*   r+   sem_conv_opt_in_moder&   r'   s                 c/var/www/openai/venv/lib/python3.12/site-packages/opentelemetry/instrumentation/fastapi/__init__.pyinstrument_appz"FastAPIInstrumentor.instrument_app   s   D s?@49C1s?G5AAC#L#u#u166$  $ 7 3M B*+?@	F *+?@	E '+%>$7$7%94W5Y5Y+   59C1.III$??CCCH J OOQ    c                    | j                   D cg c]  }|j                  t        ur| c}| _         | j                         | _        d| _        y c c}w )NF)user_middlewareclsr   build_middleware_stackmiddleware_stackr   )r:   xs     r>   uninstrument_appz$FastAPIInstrumentor.uninstrument_app2  sW     ((
(uu33 (

  #99;05-
s   Ac                    t         S Nr   selfs    r>   instrumentation_dependenciesz0FastAPIInstrumentor.instrumentation_dependencies<  s    r@   c                z   t         j                  | _        |j                  d      t        _        |j                  d      t        _        |j                  d      t        _        |j                  d      t        _        |j                  d      t        _	        |j                  d      t        _
        |j                  d      t        _        |j                  d      }|t        n
t        |      t        _        |j                  d	      t        _        |j                  d
      t        _        t        t         _        y )Nr;   r#   r$   r%   r(   r)   r*   r!   r<   r+   )fastapiFastAPI_original_fastapigetr5   _tracer_provider_server_request_hook_client_request_hook_client_response_hook$_http_capture_headers_server_request%_http_capture_headers_server_response%_http_capture_headers_sanitize_fieldsr1   r   _excluded_urls_meter_provider_exclude_spans)rK   kwargsrY   s      r>   _instrumentzFastAPIInstrumentor._instrument?  s   !(06

;L0M-4:JJ!5
1 5;JJ!5
1 6<ZZ"6
2 EKJJ1E
A JJ=> 	B JJ=> 	B  O4 % $$^4 	+
 06zz:J/K,.4jj.I+.r@   c                    t         j                  D ]  }| j                  |        t         j                  j                          | j                  t
        _        y rI   )r5   r6   rG   clearrP   rN   rO   )rK   r\   instances      r>   _uninstrumentz!FastAPIInstrumentor._uninstrument^  s@    ,GGH!!(+ H77==?00r@   )
NNNNNNNNNN)r#   r   r$   r   r%   r   r(   list[str] | Noner)   rb   r*   rb   r+   z'list[Literal['receive', 'send']] | None)r:   zfastapi.FastAPI)returnzCollection[str])r2   
__module____qualname____doc__rP   staticmethodr?   rG   rL   r]   ra    r@   r>   r   r      s    
  261537@DAEAEAEP.P /P 1	P .>P /?P /?P ?P Pd 6 6/>1r@   r   c                       e Zd ZU dZdZdZdZded<   dZded<   dZ	ded<    e
       Zej                  Z fdZd	 Z xZS )
r5   Nr   rS   r   rT   r   rU   c                   t        |   |i | t        t        t        t
        j                  t        t
        j                              }t        t        t        t
        j                  t        t
        j                              }| j                  t        t
        j                  t        t
        j                  t
        j                   t
        j"                  ||t
        j$                  t
        j&                  t
        j(                  t
        j*                         d| _        t
        j.                  j1                  |        y )Nr   r    T)super__init__r   r2   r   r5   rR   r   _sem_conv_opt_in_moder   rZ   r3   r   rY   r4   rS   rT   rU   rV   rW   rX   r[   r   r6   r7   )rK   argsr\   r&   r'   	__class__s        r>   rl   z_InstrumentedFastAPI.__init__o  s    $)&) 11&$::	
  00&$::	
 	#.==!: 4 I I 4 I I!5!K!K0D0i0i1E1k1k1E1k1k.== 	 	
 26.77;;DAr@   c                h    | t         j                  v r t         j                  j                  |        y y rI   )r5   r6   removerJ   s    r>   __del__z_InstrumentedFastAPI.__del__  s+    'BBB ;;BB4H Cr@   )r2   rd   re   rR   rZ   rY   rS   __annotations__rT   rU   setr6   r   DEFAULTrm   rl   rr   __classcell__)ro   s   @r>   r5   r5   e  sX    ON.2+2.2+204-4!$.66"BHIr@   r5   c                    | d   }d}|j                   D ]X  }|j                  |       \  }}|t        j                  k(  r|j                  } |S |t        j
                  k(  sM|j                  }Z |S )a@  
    Function to retrieve Starlette route from scope.

    TODO: there is currently no way to retrieve http.route from
    a starlette application from scope.
    See: https://github.com/encode/starlette/pull/804

    Args:
        scope: A Starlette scope
    Returns:
        A string containing the route or None
    r:   N)routesmatchesr   FULLpathPARTIAL)scoper:   routestarlette_routematch_s         r>   _get_route_detailsr     su     ,CE::"**51qEJJ#((E L EMM!#((E & Lr@   c                    t        |       }t        | j                  dd      j                               }i }|dk(  rd}|r||t        j
                  <   |r|r| d| }||fS |r|}||fS |}||fS )z
    Callback to retrieve span name and attributes from scope.

    Args:
        scope: A Starlette scope
    Returns:
        A tuple of span name and attributes
    method _OTHERr0    )r   r   rQ   stripr   
HTTP_ROUTE)r}   r~   r   
attributes	span_names        r>   r4   r4     s     u%EUYYx4::<=FJ05
>,,-%haw'	
 j  	 
	 j   	j  r@   ).rf   
__future__r   loggingtypingr   r   rN   starlette.routingr   &opentelemetry.instrumentation._semconvr   r   r	   r
   "opentelemetry.instrumentation.asgir   (opentelemetry.instrumentation.asgi.typesr   r   r   -opentelemetry.instrumentation.fastapi.packager   -opentelemetry.instrumentation.fastapi.versionr   *opentelemetry.instrumentation.instrumentorr   opentelemetry.metricsr   opentelemetry.semconv.tracer   opentelemetry.tracer   opentelemetry.util.httpr   r   r   r1   	getLoggerr2   r8   r   rO   r5   r   r4   rh   r@   r>   <module>r      s   bH #  &  #  G 
 G E G + 6 *  ,I6 
'

H
%K1* K1\0I7?? 0If4!r@   