o
    ib                     @   s  d dl mZ d dlZd dl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 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 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& 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l0m1Z1 d dl0m2Z2 d dl3m4Z4 e"e5Z6e7d dure68d! e9d"e:ej;d"d#d$d%e(d&e(d d%e/d'e/d'e/e(d(d%d#oe/e(d)d%d#e/e(d)d%d#e/e(d*d+d#d, d-Z<d.Z=d/e>fd0d1Z?d2e	e>e@f d/e>fd3d4ZAd5ee>ef d6ee>ef d/ee>e>f fd7d8ZBd5ee>ef d/ee>ef fd9d:ZCd;d< ZDd5ee>ef d/ee1 fd=d>ZEd5ee>ef d?ed@efdAdBZFdCee>e>f d/ee>ef fdDdEZGd5ee>ef fdFdGZHG dHdI dIZIdS )J    )wrapsN)Any)Callable)Mapping)Optional)Union)parse)config)	SPAN_KIND)trace_utils)guarantee_single_callable)SpanKind)	SpanTypes)http)core)BlockingException)find_exception)is_valid_ip)	COMPONENT)
get_logger)schematize_url_operation)SpanDirection)_get_config)get_blocked)set_blocked)DDTraceDeprecationWarning)asbool)Span)tracer)	deprecateDD_ASGI_TRACE_WEBSOCKETzDD_ASGI_TRACE_WEBSOCKET is deprecated and will be removed in a future version. Use DD_TRACE_WEBSOCKET_MESSAGES_ENABLED instead.asgi)defaultasgi.requestT#DD_TRACE_WEBSOCKET_MESSAGES_ENABLED)r"   modifier,DD_TRACE_WEBSOCKET_MESSAGES_INHERIT_SAMPLING+DD_TRACE_WEBSOCKET_MESSAGES_SEPARATE_TRACESDD_ASGI_OBFUSCATE_404_RESOURCEF)service_namerequest_span_namedistributed_tracingtrace_asgi_websocket_messages(asgi_websocket_messages_inherit_sampling"websocket_messages_separate_tracesobfuscate_404_resourcezasgi.versionzasgi.spec_versionreturnc                   C   s   dS )N  r2   r2   r2   \/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/contrib/internal/asgi/middleware.pyget_versionF   s   r4   str_or_bytesc                 C   s   t | tr| jddS | S )Nignoreerrors)
isinstancebytesdecode)r5   r2   r2   r3   bytes_to_strJ      r<   scopeintegration_configc                 C   sZ   i }|  d}|r||tj< |  d}|rd|v r|d |t< |r+d|v r+|d |t< |S )z?
    Extract HTTP and ASGI version information from scope.
    http_versionr!   versionspec_version)getr   VERSIONASGI_VERSIONASGI_SPEC_VERSION)r>   r?   tagsr@   
scope_asgir2   r2   r3   _extract_versions_from_scopeN   s   


rI   c                 C   s$   |  d}|rtdd |D S i S )z
    Extract and decode headers from ASGI scope.

    ASGI headers are stored as byte strings; this method decodes them
    to UTF-8 strings for easier processing.
    headersc                 s   s$    | ]\}}t |t |fV  qd S )N)r<   ).0kvr2   r2   r3   	<genexpr>m   s   " z#_extract_headers.<locals>.<genexpr>)rC   dict)r>   rJ   r2   r2   r3   _extract_headersc   s   
rP   c                 C   s   | tjd dS )z&Default handler for exception for span500N)_set_tag_strr   STATUS_CODE)excspanr2   r2   r3   _default_handle_exception_spanq   s   rV   c                 C   s   |  di  dd gd S )Ndatadogrequest_spansr   )rC   )r>   r2   r2   r3   span_from_scopev   r=   rY   receivesendc                    s0   |ddg dI d H  |dddI d H  d S )Nhttp.response.start  )typestatusrJ   http.response.body    )r^   bodyr2   )r>   rZ   r[   r2   r2   r3   _blocked_asgi_appz   s   rc   response_headersc                 C   sf   i }z|  ddjddd}t|dkr|\}}|||< W |S W |S  ty2   tjddd	 Y |S w )
Nz
set-cookier1   =   )maxsplit   z"failed to extract response cookiesTexc_info)rC   splitlen	Exceptionlogdebug)rd   cookiesresult
cookie_keycookie_valuer2   r2   r3   _parse_response_cookies   s   
rt   c                 C   s6   |  di  d}|r|  | d dd  d S d S )NrW   current_receive_span)rC   finishpop)r>   ru   r2   r2   r3   _cleanup_previous_receive   s
   rx   c                   @   s,  e Zd ZdZdddddZdejedfddZde	e
ef d	ed
efddZde	e
ef de	e
ef defddZde	e
ef de	e
ef defddZde	e
ef de	e
ef dede
dee	e
ef  f
ddZdejde	e
ef de	e
ef dedef
ddZde	e
ef de	e
ef defddZdS )TraceMiddlewarea  
    ASGI application middleware that traces HTTP and websocket requests.

    Provides distributed tracing for ASGI applications, including
    support for websocket connections with configurable message-level tracing.

    When websocket instrumentation is enabled, the middleware creates spans for:
    - websocket handshake (HTTP upgrade)
    - Individual message receive/send operations
    - Connection close events
    P   i  )r   httpswswssNc                 C   s8   t || _|d urtddtdd || _|| _|| _d S )Nz"The tracer parameter is deprecatedz'The global tracer will be used instead.z5.0.0)messagecategoryremoval_version)r   appr   r   r?   handle_exception_spanspan_modifier)selfr   r   r?   r   r   r2   r2   r3   __init__   s   

zTraceMiddleware.__init__r>   rZ   r[   c           #         s  d dkrd nd dkrj jrdn
I dH S zt}W n ty;   tjddd i }Y n
w tjt	j |d	 d

d g}j dd}d dkrct|tjdd}tjdd|d||tjtdj |dj dǉ  jjr d}t D ]!\}}	| dkrz|	}W n ty   tjddd Y nw  nqdd}
dd}ttdd}dd}|rd|||n5|
rt|
dkr|
d }j|d}|
d |dur||krdt| nd }d|||ndd}|r0t|}r0 d| j j s7d}d}t!d|fj"}|rM|j#I dH \}d}t$|t%rit|rit&|d ri|d }nd}tj'j |||||dd  t(j }| D ]\}}	)||	 qt*fd!d"}t*d#t+tt,f ffd$d%}d#t+tt,f f fd&d'}d dkr|n}z5zMt-d(d) ||I dH W W t-d*f d+i d,}|r|v r|. d dkrd+v rt/ W  d   W  d   S  t0y~ } zRt1|j2d  t3|I dH W  Y d}~W t-d*f d+i d,}|r[|v r[|. d dkrkd+v rkt/ W  d   W  d   S d}~w ty } zt45 \}} }!6|| |! 7|  d}~w t8y }" z[t9|"t0 }rt1|j2d  t3|I dH W  Y d}"~"W t-d*f d+i d,}|r|v r|. d dkrd+v rt/ W  d   W  d   S  d}"~"ww t-d*f d+i d,}|r$|v r$|. d dkr5d+v r6t/ w w w 1 s;w   Y  W d   dS 1 sLw   Y  dS )-aJ  
        Handle ASGI application calls with tracing.

        Processes ASGI requests and responses, creating spans for:
        - HTTP requests and responses
        - websocket handshakes and message exchanges
        - Error handling and exception tracking

        Raises:
            BlockingException: When request is blocked
            Exception: Re-raises any exceptions from the wrapped application

        Span Types Created:
            - HTTP: asgi.request spans with HTTP metadata
            - websocket: websocket.receive, websocket.send, websocket.close spans
        r^   r   method	websocketNz0failed to decode headers for distributed tracingTri   )
int_configrequest_headers pathr*   r#   )	directionprotocolREMOTE_ADDR)remote_addrrJ   headers_case_sensitiveenviron
middleware	span_nameresource	span_typeservicedistributed_headersactivate_distributed_headersr>   r?   s   hostzKfailed to decode host header, host from http headers will not be consideredserverschemequery_stringra   r1   z	{}://{}{}rh   rf   r   :?zasgi.request.parse.bodyclient)	r   urlqueryr   raw_uriparsed_queryrequest_bodypeer_ipheaders_are_case_sensitivec                     sj  j js  I dH S di d} tjdj djddd tjj js,ndd	d
d	y}| rA| 	  d 
dd |j}zVzB  I dH }d dkrb|d dkrb||| n|d dkro| |W W dvs|dd vr|	  W  d   S  ty   |jt   |	   w dvsdd vr|	  w w 1 sw   Y  dS )a  
                Wrapped receive function that instruments websocket message reception.

                Intercepts websocket receive operations to create ExecutionContexts for:
                - Message receive timing and metadata
                - Message type (text/binary)
                - Message length measurement
                - Connection close events

                When websocket instrumentation is enabled, creates ExecutionContexts for:
                - websocket.receive: For incoming messages
                - websocket.close: For peer disconnect events

                Note:
                    - Spans are linked to the handshake span
                    - Receive spans are finished exactly when the next receive operation starts
                NrW   ru   asgi.websocket.receive.messagezwebsocket.receive
websocket r   r1   FT)r?   r   r   r   r   child_of
call_traceactivater^   r   zwebsocket.disconnect)r?   r,   rC   r   context_with_datar   r   	WEBSOCKETr.   rv   rw   rU   !_handle_websocket_receive_message$_handle_websocket_disconnect_messagerm   set_exc_infosysrj   )ru   ctx	recv_spanr~   )rZ   r>   r   rU   r2   r3   wrapped_receive/  sN   

z1TraceMiddleware.__call__.<locals>.wrapped_receiver~   c              
      s  zcd dkr&j jr&| ddkr&rjdkr  | I dH W S d dkr?j jr?| ddkr?|  n d dkr_j jr_| ddkr_|  | I dH W S t| }W n tyv   t	j
dd	d
 d}Y nw |  | td| d|f t }|rt|z!| I dH W | ddkr| ddsjdkr  S S S S | ddkr| ddsΈjdkrψ  w w w w )a  
                Wrapped ASGI send function that traces websocket message transmission.

                Intercepts websocket send operations to create spans for:
                - Message transmission timing and metadata
                - Message type (text/binary)
                - Message length measurement
                - Connection close operations

                When websocket instrumentation is enabled, creates ExecutionContexts for:
                - websocket.send: For outgoing messages
                - websocket.close: For application-initiated close events

                Note:
                    - Spans are linked to the handshake span
                    - Context (baggage, sampling) is propagated from handshake span
                    - Each sent message is attached to the current context
                    - Close spans include additional metadata like close codes and reasons
                r^   r   zwebsocket.acceptr   Nwebsocket.sendwebsocket.closez"failed to extract response headersTri   asgi.finalize_responserb   r`   	more_bodyF)r?   r,   rC   errorrv   _handle_websocket_send_message_handle_websocket_close_messagerP   rm   rn   warning_handle_http_responser   dispatchr   r   )r~   rd   blocked)r   r>   r   r[   rU   r2   r3   wrapped_sendl  s\   





z.TraceMiddleware.__call__.<locals>.wrapped_sendc                    s8  t d fj}|r|j\}}}ndg d}}}r7| ddkr7|| d< t|| d< t dd |f n#| dd	krZt|trE|n|j	d
dd| d< d| d< t d|d f z$| I d H W t
jj||d | dd	kr}jdkr~  S S S t
jj||d | dd	krjdkr  w w w )Nzasgi.block.startedr]   ra   r^   r\   rJ   r_   r   r`   zutf-8r6   r7   rb   Fr   )status_coderd   r   )r   dispatch_with_resultsstatus_headers_contentvaluerC   intr   r9   r:   encoder   set_http_metar?   r   rv   )r~   rq   r_   rJ   content)r   r   r[   rU   r   r2   r3   wrapped_blocked_send  s@   



z6TraceMiddleware.__call__.<locals>.wrapped_blocked_sendzasgi.start_requestr!   zweb.request.final_tagsrW   rX   ):r?   r,   r   rP   rm   rn   r   r   r   r   joinrC   r   r   INBOUNDr   r   r   WEBint_servicerU   r   itemsr   UnicodeDecodeErrorr   parse_qsr<   formatrl   default_portsstrtrace_query_stringr   await_receive_and_bodyr   r9   listr   r   rI   rR   r   r   r   r   removerx   r   r   argsrc   r   rj   r   r   BaseExceptionr   )#r   r>   rZ   r[   rJ   r   operation_namehost_headerkeyr   r   r   r   	full_pathportdefault_portserver_hostr   rb   rq   r   r   rG   namer   r   r   wrapped_recvrX   erT   exc_typeexc_valexc_tb	exceptionr2   )r   r   rZ   r>   r   r[   rU   r   r3   __call__   sR  



,


$
<$"F
   x
   {
    

  8zTraceMiddleware.__call__r~   request_spanc                 C   s   | di  d}| jjr|r|}n|}tjd| jd|jd| dd tj|dd	t| jj	t
tjid

}td|||f W d    d S 1 sIw   Y  d S )NrW   ru   zasgi.websocket.send.messager   r   r   r1   FT	r?   r   r   r   r   r   r   r   rG   )rC   r?   r.   r   r   r   r   r   r   integration_namer
   r   PRODUCERr   r   r>   r~   r   ru   parent_spanr   r2   r2   r3   r     s&   "z.TraceMiddleware._handle_websocket_send_messagec                 C   s   | di  d}| jjr|r|}n|}tjd| jdd| dd tj|dd	t| jjt	t
jid
	}td|||f W d    n1 sFw   Y  t| d S )NrW   ru   zasgi.websocket.close.messager   r   r   r1   FT)r?   r   r   r   r   r   r   rG   )rC   r?   r.   r   r   r   r   r   r   r
   r   r   r   rx   r   r2   r2   r3   r     s&   
z/TraceMiddleware._handle_websocket_close_messagerU   r   rd   c                 C   s|   |r8| ddkr:d|v r<t|}|d }| jjr%|dkr%d|df|_tj|| j|||d t	dd	 d S d S d S d S )
Nr^   r\   r_   i  r   404)r   rd   response_cookieszasgi.start_responser   )
rC   rt   r?   r/   r   r   r   r   r   r   )r   r>   r~   rU   r   rd   rp   r   r2   r2   r3   r     s   z%TraceMiddleware._handle_http_responser   r   c                 C   s*   t | td|||f ||d d< d S )Nr   rW   ru   )rx   r   r   )r   r   r>   r~   r   r   r2   r2   r3   r   1  s   z1TraceMiddleware._handle_websocket_receive_messagec                 C   s   t | tjd| jd|jd|dd tj| jjs|nd ddt	| jj
ttjid
}td|||f W d    d S 1 s?w   Y  d S )	Nz!asgi.websocket.disconnect.messager   r   r   r1   FTr   )rx   r   r   r?   r   rC   r   r   r.   r   r   r
   r   CONSUMERr   )r   r>   r~   r   r   r2   r2   r3   r   >  s    "z4TraceMiddleware._handle_websocket_disconnect_message)__name__
__module____qualname____doc__r   r	   r!   rV   r   r   r   r   r   r   r   r   r   r   r   r   ExecutionContextr   r   r2   r2   r2   r3   ry      sT    
  &9&







ry   )J	functoolsr   osr   typingr   r   r   r   r   urllibr   ddtracer	   ddtrace.constantsr
   ddtrace.contribr   #ddtrace.contrib.internal.asgi.utilsr   ddtrace.extr   r   r   ddtrace.internalr   ddtrace.internal._exceptionsr   r   ddtrace.internal.compatr   ddtrace.internal.constantsr   ddtrace.internal.loggerr   ddtrace.internal.schemar   -ddtrace.internal.schema.span_attribute_schemar   !ddtrace.internal.settings._configr   ddtrace.internal.utilsr   r   #ddtrace.internal.utils.deprecationsr   ddtrace.internal.utils.formatsr   ddtrace.tracer   r   ddtrace.vendor.debtcollectorr   r   rn   getenvr   _addrO   _get_servicerE   rF   r   r4   r:   r<   rI   rP   rV   rY   rc   rt   rx   ry   r2   r2   r2   r3   <module>   s    


.""