o
    ic                  .   @   s  d Z 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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.Z0 ddl1Z2dd l3m4Z4 erdd!l5m6Z6 ddl7mZ dd"l7m8Z8 e,e9Z:ej;Z<e2j=j>j?j@Z@e2j=j>j?jAZAd#ZBd$ZCeDd%ZEd&ZFd'eGeHeHf d(ed)d*d+eHd,df
d-d.ZIdzd'eeHeHf d0eJd,eHfd1d2ZKd3eHd,eHfd4d5ZL	/d{d'eeeHeHf  d6eeH d0eJd,eHfd7d8ZMd'eGeHeHf d(ed)d*d,dfd9d:ZNd'eGeHeHf d(ed)d*d,dfd;d<ZOd=eHd,eHfd>d?ZPd@dA ZQdzdBd*dCeJd,eJfdDdEZRd|dFee dBd*dCeeH d,eeH fdGdHZSd|dFee dBd*dCeeH d,eeH fdIdJZT																	/		d}d(ed)d*dKeeH d=eeH dLeeH dMeeH dNeeeUeHf  dOeeH dPeeH dQeeeHeHf  dReeeHeHf  dSeeeHeHf  dTeeeUeHf  dUeeH dVeeGeHeHf  dWeeGeHeHf  dXeeeHeGeHeVeH f f  d6eeH d0eJdYeeH dZeeGeHeHf  d,df,d[d\ZW			d~d]d^dBed* dReeGeHeHf  d_eeJ d,df
d`daZXdbedcefdddeZY	f	g	ddhedieHdjeHdkeeeHgeJf  d,e	eZeHef ddf f
dldmZ[	f		dd(edne
eZeHef  dieHdkeeeHgeJf  doeeegef  d,dfdpdqZ\d=eHd,eZeHeHf fdrdsZ]G dtdu due^Z_dvdw Z`dxdy ZadS )zJ
This module contains utility functions for writing ddtrace integrations.
    )dequeN)TYPE_CHECKING)Any)Callable)	Generator)Iterator)Mapping)Optional)Union)cast)parse)Pin)Span)_ORIGIN_KEY)USER_AGENT_PATTERNS)"_get_header_value_case_insensitive)_get_request_header_user_agent)_normalize_tag_name)_set_url_tag)set_user)http)net)core)ensure_text)ip_is_global)SAMPLING_DECISION_TRACE_TAG_KEY)dispatch)
get_logger)config)HTTPPropagator)IntegrationConfig)Tracerrequestresponsez([^a-z0-9_\-:/]){1})
zx-forwarded-forz	x-real-ipztrue-client-ipzx-client-ip	forwardedzforwarded-forzx-cluster-client-ipzfastly-client-ipzcf-connecting-ipzcf-connecting-ipv6headersspanintegration_configr    request_or_responsereturnc                 C   s   t | tszt| } W n
 ty   Y dS w |du r!td dS |  D ]\}}||}|du r3q%||p;t||| q%dS )aP  
    :param headers: A dict of http headers to be stored in the span
    :type headers: dict or list
    :param span: The Span instance where tags will be stored
    :type span: ddtrace.trace.Span
    :param integration_config: An integration specific config object.
    :type integration_config: ddtrace.settings.IntegrationConfig
    Nz>Skipping headers tracing as no integration config was provided)	
isinstancedict	Exceptionlogdebugitems_header_tag_name_set_tag_strr   )r%   r&   r'   r(   header_nameheader_valuetag_name r5   X/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/contrib/internal/trace_utils.py_store_headersO   s   


r7   Fheaders_are_case_sensitivec              	   C   s^   |r	t | tj}n| tj}|r-zt|}|jr|jW S W dS  ttfy,   Y dS w dS )aX  Get referrer host from request headers
    :param headers: A dict of http headers to be stored in the span
    :type headers: dict or list
    :param headers_are_case_sensitive: Whether the headers are case sensitive
    :type headers_are_case_sensitive: bool
    :return: The referrer host if found, empty string otherwise
    :rtype: str
     )	r   r   REFERER_HEADERgetr   urlparsehostname
ValueErrorAttributeError)r%   r8   referrer
parsed_urlr5   r5   r6   !_get_request_header_referrer_hostn   s   	
rB   ip_header_valuec                 C   s8   g d}|D ]}t || t j }r|d  S qdS )zParse the ip header, either in Forwarded-For format or Forwarded format.

    references: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Forwarded
    )z+^\s*(?P<ip>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$z6(?:^|;)\s*for="?(?P<ip>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)z^\s*(?P<ip>[0-9a-fA-F:]+)$z((?:^|;)\s*for="\[(?P<ip>[0-9a-fA-F:]+)\]ipr9   )research
IGNORECASEgroup)rC   IP_EXTRACTIONSpatternmr5   r5   r6   _parse_ip_header   s   rL   peer_ipc              	      s  dt dtt  f fdd} s%z
tt |}W |S  ty$   Y dS w d}tj}|r_|r7| ddn|}|sDt	
d| dS z	tt |}W n; ty^   t	
d	|| Y dS w rzd
d   D }tD ]}||v rx|| } nqlntD ]}| v r | } nq|d}	|r|d}
|
D ]!}t|}|sqzt|r|W   S |	s|}	W q ty   Y qw zt|s|	s|W S W |	S  ty   Y |	S w )Nkeyr)   c                    s   s  | S t | S N)r;   r   )rN   r%   r8   r5   r6   get_header_value   s   

z7_get_request_header_client_ip.<locals>.get_header_valuer9   _-z<DD_TRACE_CLIENT_IP_HEADER configured but '%s' header missingz0Invalid IP address from configured %s header: %sc                 S   s"   i | ]\}}|  d d|qS )rR   rS   )lowerreplace.0kvr5   r5   r6   
<dictcomp>   s   " z1_get_request_header_client_ip.<locals>.<dictcomp>,)strr	   	ipaddress
ip_addressr>   r   _client_ip_headerrT   rU   r-   r.   r/   IP_PATTERNSsplitrL   r   )r%   rM   r8   rQ   rR   rC   user_configured_ip_headernew_headers	ip_headerprivate_ip_from_headersip_listrD   r5   rP   r6   _get_request_header_client_ip   s~   

rg   c                 C      t | ||t dS )a  
    Store request headers as a span's tags
    :param headers: All the request's http headers, will be filtered through the whitelist
    :type headers: dict or list
    :param span: The Span instance where tags will be stored
    :type span: ddtrace.trace.Span
    :param integration_config: An integration specific config object.
    :type integration_config: ddtrace.settings.IntegrationConfig
    N)r7   REQUESTr%   r&   r'   r5   r5   r6   _store_request_headers      
rk   c                 C   rh   )a  
    Store response headers as a span's tags
    :param headers: All the response's http headers, will be filtered through the whitelist
    :type headers: dict or list
    :param span: The Span instance where tags will be stored
    :type span: ddtrace.trace.Span
    :param integration_config: An integration specific config object.
    :type integration_config: ddtrace.settings.IntegrationConfig
    N)r7   RESPONSErj   r5   r5   r6   _store_response_headers   rl   rn   urlc                 C   sZ   d| v r+t | }|j}d|vr| S ||dd d }t |j||jd|jdfS | S )zA
    Sanitize url by removing parts with potential auth info
    @   Nr9   )r   r<   netlocindex
urlunparseschemepathquery)ro   parsedrr   r5   r5   r6   _sanitized_url   s    
ry   c                    s    fdd}|S )a  Helper for providing tracing essentials (module and pin) for tracing
    wrappers.

    This helper enables tracing wrappers to dynamically be disabled when the
    corresponding pin is disabled.

    Usage::

        @with_traced_module
        def my_traced_wrapper(django, pin, func, instance, args, kwargs):
            # Do tracing stuff
            pass

        def patch():
            import django
            wrap(django.somefunc, my_traced_wrapper(django))
    c                    s    fdd}|S )Nc                    sV   t |}|r| s| |i |S |s"td|  | |i |S  || |||S )Nz"Pin not found for traced method %r)r   _findenabledr-   r.   )wrappedinstanceargskwargspin)funcmodr5   r6   wrapper.  s   z5with_traced_module.<locals>.with_mod.<locals>.wrapperr5   )r   r   r   )r   r6   with_mod-  s   	z$with_traced_module.<locals>.with_modr5   )r   r   r5   r   r6   with_traced_module  s   r   
int_configdefaultc                 C   s4   d| v r| j dur| j S d| v r| jdur| jS |S )zJReturns whether distributed tracing is enabled for this integration configdistributed_tracing_enabledNdistributed_tracing)r   r   )r   r   r5   r5   r6   r   <  s
   r   r   c                 C   s   | dur
| j r
| j S d|v r|j durtt|j S d|v r(|jdur(tt|jS |j }|r:||jjkr:tt|S d|v rI|jdurItt|jS |du rT|rTtt|S |S )aQ  Returns the service name for an integration which is internal
    to the application. Internal meaning that the work belongs to the
    user's application. Eg. Web framework, sqlalchemy, web servers.

    For internal integrations we prioritize overrides, then global defaults and
    lastly the default provided by the integration.
    Nserviceservice_name_default_service)r   r   r\   r   global_config_get_service_inferred_base_servicer   )r   r   r   global_servicer5   r5   r6   int_serviceE  s   	


r   c                 C   sr   | dur
| j r
| j S d|v r|j durtt|j S d|v r(|jdur(tt|jS d|v r7|jdur7tt|jS |S )zReturns the service name for an integration which is external
    to the application. External meaning that the integration generates
    spans wrapping code that is outside the scope of the user's application. Eg. A database, RPC, cache, etc.
    Nr   r   r   )r   r   r\   r   r   )r   r   r   r5   r5   r6   ext_servicej  s   r   methodtarget_hostserver_addressstatus_code
status_msgrw   parsed_queryrequest_headersresponse_headersretries_remainraw_urirequest_cookiesrequest_path_paramsrequest_bodyrouteresponse_cookiesc                 C   s  |dur|  tj| |durt|}t|| || |dur%|  tj| |dur0|  tj| |dur^zt|}W n t	t
fyK   td| Y nw |  tjt| tj|r^d| _|duri|  tj| |durw|jrw|  tj| |}|
rt|
|}|r|  tj| t|
|}|r|  tj| tjstjrtd}|st|
||p|}|r|  tj | |  d| |j!r	 t"t#|
| | |dur|j!rt$t#|| | |dur|  tj%t| t&d| |||||
||	|||||g |dur|  tj'| dS dS )a  
    Set HTTP metas on the span

    :param method: the HTTP method
    :param url: the HTTP URL
    :param status_code: the HTTP status code
    :param status_msg: the HTTP status message
    :param query: the HTTP query part of the URI as a string
    :param parsed_query: the HTTP query part of the URI as parsed by the framework and forwarded to the user code
    :param request_headers: the HTTP request headers
    :param response_headers: the HTTP response headers
    :param raw_uri: the full raw HTTP URI (including ports and query)
    :param request_cookies: the HTTP request cookies as a dict
    :param request_path_params: the parameters of the HTTP URL as set by the framework: /posts/<id:int> would give us
         { "id": <int_value> }
    Nz,failed to convert http status code %r to intrq   zhttp.request.remote_ipznetwork.client.ipset_http_meta_for_asm)(r1   r   METHODry   r   r   TARGET_HOSTSERVER_ADDRESSint	TypeErrorr>   r-   r.   STATUS_CODEr\   r   _http_serveris_error_codeerror
STATUS_MSGtrace_query_stringQUERY_STRINGr   
USER_AGENTrB   REFERRER_HOSTNAME
asm_config_asm_enabled_retrieve_client_ipr   	find_itemrg   	CLIENT_IPis_header_tracing_configuredrk   r+   rn   RETRIES_REMAINr   ROUTE)r&   r'   r   ro   r   r   r   r   rw   r   r   r   r   r   r   r   r   rM   r8   r   r   int_status_code
request_ip
user_agentreferrer_hostr5   r5   r6   set_http_meta~  s   '



r   tracerr!   overridec                 C   s   |du rdS |s|rWt |rYt|}|du rdS |js$|js$|js$dS |  }|rA|jr6|jrA|j|jkrAtd|j|j	 dS | j
| td||f td|f dS dS dS )a+  
    Helper for activating a distributed trace headers' context if enabled in integration config.
    int_config will be used to check if distributed trace headers context will be activated, but
    override will override whatever value is set in int_config if passed any value other than None.
    FNzlwill not activate extracted Context(trace_id=%r, span_id=%r), a context with that trace id is already activez!http.activate_distributed_headerszdistributed_context.activated)r   r   extracttrace_id_baggage_span_linkscurrent_trace_contextr-   r.   span_idcontext_provideractivater   r   )r   r   r   r   contextcurrent_contextr5   r5   r6   activate_distributed_headers   s2   
	r   target_spanparentc                 C   s   |j j D ]\}}| j || | d| | q|j jdur'|j j| j _|j jtr8| t|j jt  |j jt	rK| t	|j jt	  dS dS )zZ
    Copies baggage, tags, origin, sampling decision from parent span to target span.
    zbaggage.N)
r   r   r/   set_baggage_itemr1   sampling_priority_metar;   r   r   )r   r   rN   valuer5   r5   r6   _copy_trace_level_tags7  s   r   .r9   objsepprefixexclude_policyc                 #   sx    t  }||| f |r:| \ }|d ur| rqt|tr1| fdd| D  n |fV  |sd S d S )Nc                 3   s.    | ]\}} r  |fn||fV  qd S rO   )joinrV   pr   r5   r6   	<genexpr>V  s   , z_flatten.<locals>.<genexpr>)r   appendpopr*   r+   extendr/   )r   r   r   r   srY   r5   r   r6   _flattenI  s   
 
r   r/   	processorc           	      C   sF   |D ]\}}t ||||D ]\}}| ||d ur||n| qqd S rO   )r   set_tag)	r&   r/   r   r   r   r   r   tagrY   r5   r5   r6   set_flattened_tags[  s
   r   c                 C   sR   t | }|j}|jst dj| d}|jddd }|ddd }||fS )Nz//{url})ro   rp   rq   :r   )r   r<   rw   rr   formatra   )ro   parse_resultrw   rr   r5   r5   r6   &extract_netloc_and_query_info_from_urlg  s   
r   c                   @   s   e Zd ZdS )InterruptExceptionN)__name__
__module____qualname__r5   r5   r5   r6   r   t  s    r   c                 C   s,   | rt | tst | trt| S t| S | S rO   )r*   r   floatr\   r   )attrr5   r5   r6   _convert_to_stringx  s
   r   c              	   C   sX   | sdS z| }| dD ]}t||s W dS t||}qW dS  ttfy+   Y dS w )a  
    Helper function to safely check if a nested attribute path exists on a module.

    Args:
        module: The root module object
        attr_path: Dot-separated path to the attribute (e.g., "flows.llm_flows.functions")

    Returns:
        bool: True if the full path exists, False otherwise

    Example:
        check_module_path(adk, "flows.llm_flows.functions.__call_tool_async")
        check_module_path(adk, "agents.llm_agent.LlmAgent")
    Fr   T)ra   hasattrgetattrImportErrorr?   )module	attr_pathcurrentr   r5   r5   r6   check_module_path  s   
r   )F)NFrO   )NNNNNNNNNNNNNNNNFNN)NNN)r   r9   N)r   NN)b__doc__collectionsr   r]   rE   typingr   r   r   r   r   r   r	   r
   r   urllibr   wraptddtrace._trace.pinr   ddtrace._trace.spanr   ddtrace.constantsr   )ddtrace.contrib.internal.trace_utils_baser   r   r   r   r   r   ddtrace.extr   r   ddtrace.internalr   ddtrace.internal.compatr   r   ddtrace.internal.constantsr   ddtrace.internal.core.event_hubr   ddtrace.internal.loggerr   !ddtrace.internal.settings._configr   ddtrace.internal.settings.asmr   ddtrace.internal.utils.wrappersddtraceddtrace.propagation.httpr   %ddtrace.internal.settings.integrationr    ddtrace.tracer!   r   r-   wrap_function_wrapperwrapinternalutilswrappersunwrap	iswrappedri   rm   compileNORMALIZE_PATTERNr`   r+   r\   r7   boolrB   rL   rg   rk   rn   ry   r   r   r   r   r   listr   r   r   tupler   r   r   r,   r   r   r   r5   r5   r5   r6   <module>   s   


 
"O""(	(%	

 
7


