o
    g9I                     @  s  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&e'Z(G dd deZ)G dd dej*Z+dd Z,dd Z-dS )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)_OpenTelemetrySemanticConventionStability!_OpenTelemetryStabilitySignalType_StabilityMode)OpenTelemetryMiddleware)ClientRequestHookClientResponseHookServerRequestHook_instruments)__version__)BaseInstrumentor)	get_meter)SpanAttributes)
get_tracer)get_excluded_urlsparse_excluded_urlssanitize_methodFASTAPIc                   @  s`   e Zd ZdZdZe										ddddZedddZd ddZdd Z	dd Z
dS )!FastAPIInstrumentorz<An instrumentor for FastAPI

    See `BaseInstrumentor`
    Nserver_request_hookr   client_request_hookr   client_response_hookr   #http_capture_headers_server_requestlist[str] | None$http_capture_headers_server_response$http_capture_headers_sanitize_fieldsexclude_spans'list[Literal['receive', 'send']] | Nonec                 C  s   t | dsd| _t| ddsZt  ttj}|du rt}nt	|}t
tt|t|d}ttt|t|d}| jt|t||||||||	|
d d| _| tjvrXtj|  dS dS td dS )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_detailsr   r   r   tracermeterr   r   r    r!   Tz?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*    r=   e/var/www/visachat/venv/lib/python3.10/site-packages/opentelemetry/instrumentation/fastapi/__init__.pyinstrument_app   sV   
"
z"FastAPIInstrumentor.instrument_appr9   fastapi.FastAPIc                 C  s&   dd | j D | _ |  | _d| _d S )Nc                 S  s   g | ]	}|j tur|qS r=   )clsr
   ).0xr=   r=   r>   
<listcomp>4  s
    
z8FastAPIInstrumentor.uninstrument_app.<locals>.<listcomp>F)user_middlewarebuild_middleware_stackmiddleware_stackr#   )r9   r=   r=   r>   uninstrument_app2  s
   

z$FastAPIInstrumentor.uninstrument_appreturnCollection[str]c                 C  s   t S Nr   selfr=   r=   r>   instrumentation_dependencies<  s   z0FastAPIInstrumentor.instrumentation_dependenciesc                 K  s   t j| _|dt_|dt_|dt_|dt_|dt_	|dt_
|dt_|d}|d u r9tnt|t_|d	t_|d
t_tt _d S )Nr:   r   r   r   r   r   r    r'   r;   r!   )fastapiFastAPI_original_fastapigetr4   _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_fieldsr0   r   _excluded_urls_meter_provider_exclude_spans)rM   kwargsrZ   r=   r=   r>   _instrument?  s4   

zFastAPIInstrumentor._instrumentc                 K  s,   t jD ]}| | qt j  | jt_d S rK   )r4   r5   rH   clearrQ   rO   rP   )rM   r]   instancer=   r=   r>   _uninstrument^  s   

z!FastAPIInstrumentor._uninstrument)
NNNNNNNNNN)r   r   r   r   r   r   r   r   r   r   r    r   r!   r"   )r9   r@   )rI   rJ   )r1   
__module____qualname____doc__rQ   staticmethodr?   rH   rN   r^   ra   r=   r=   r=   r>   r      s(    R
	r   c                      sb   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d	Zd
d Z  ZS )r4   Nr   rT   r   rU   r   rV   c                   s   t  j|i | ttttjttjd}t	tttj
ttjd}| jttjttjtjtj||tjtjtjtjd d| _tj|  d S )Nr$   r&   T)super__init__r   r1   r   r4   rS   r   _sem_conv_opt_in_moder   r[   r2   r
   rZ   r3   rT   rU   rV   rW   rX   rY   r\   r#   r5   r6   )rM   argsr]   r)   r*   	__class__r=   r>   rg   o  sB   z_InstrumentedFastAPI.__init__c                 C  s   | t jv rt j|  d S d S rK   )r4   r5   removerL   r=   r=   r>   __del__  s   
z_InstrumentedFastAPI.__del__)r1   rb   rc   rS   r[   rZ   rT   __annotations__rU   rV   setr5   r	   DEFAULTrh   rg   rm   __classcell__r=   r=   rj   r>   r4   e  s   
 $r4   c                 C  sP   | d }d}|j D ]}|| \}}|tjkr|j} |S |tjkr%|j}q	|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
    r9   N)routesmatchesr   FULLpathPARTIAL)scoper9   routestarlette_routematch_r=   r=   r>   _get_route_details  s   


r|   c                 C  st   t | }t| dd }i }|dkrd}|r||tj< |r,|r,| d| }||fS |r4|}||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 _OTHERr/    )r|   r   rR   stripr   
HTTP_ROUTE)rw   rx   r}   
attributes	span_namer=   r=   r>   r3     s   	
r3   ).rd   
__future__r   loggingtypingr   r   rO   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   r0   	getLoggerr1   r7   r   rP   r4   r|   r3   r=   r=   r=   r>   <module>   s0    %
 3