o
    ٰi3                     @   sf  d dl m Z mZ d dlmZ d dlmZmZ d dlmZmZ d dl	m
Z
mZ d dlmZ d dlmZmZ d dlmZ d d	lmZmZ d d
lmZ z*d dlmZ d dlmZmZ d dl m!Z! d dl"m#Z#m$Z$m%Z%m&Z& d dl'm(Z(m)Z) W n e*y}   edw erd dlm+Z+m,Z,m-Z- d dl.m/Z0 d dl1m2Z2m3Z3 dZ4dZ5dZ6						d!ddZ7G dd deZ8d S )"    )datetimetimezone)time)TYPE_CHECKINGcast)
get_clientstart_transaction)INSTRUMENTER
SPANSTATUS)DidNotEnable)SENTRY_BAGGAGE_KEYSENTRY_TRACE_KEYadd_global_event_processor)TransactionSpan)	parse_url)	get_value)SpanProcessorReadableSpan)SpanAttributes)format_span_idformat_trace_idget_current_spanSpanKind)INVALID_SPAN_IDINVALID_TRACE_IDzopentelemetry not installed)AnyOptionalUnion)context)EventHintotel
   z	auto.oteleventr!   otel_span_map)dict[str, Union[Transaction, SentrySpan]]returnc                 C   s   t  }|jd tjkr| S t| dr| d dkr| S t }|s!| S | }|jtks/|j	t
kr1| S |t|j	d }|s>| S | di }|di |  | S )Ninstrumentertypetransactioncontextstrace)r   optionsr	   OTELhasattrr   get_span_contexttrace_idr   span_idr   getr   
setdefaultupdateget_trace_context)r%   r&   client	otel_spanctxsentry_spanr,    r<   h/home/ubuntu/.local/lib/python3.10/site-packages/sentry_sdk/integrations/opentelemetry/span_processor.py!link_trace_context_to_error_event,   s"   r>   c                       s   e Zd ZU dZi Zded< i Zded< d& fddZd'd
dZd(ddZ			d)						d*ddZ
d+ddZdddefddZd,ddZ						d-ddZ							d.d d!Z							d.d"d#Z							d.d$d%Z  ZS )/SentrySpanProcessorzZ
    Converts OTel spans into Sentry spans so they can be sent to the Sentry backend.
    r'   r&   zdict[int, set[str]]
open_spansr(   c                    s   t | dst | | _| jS )Ninstance)r0   super__new__rA   )cls	__class__r<   r=   rC   U   s   
zSentrySpanProcessor.__new__Nc                    s   t d fdd}d S )	Nr%   r!   hintr"   r(   c                    s   t |  jS N)r>   r&   )r%   rG   selfr<   r=   global_event_processor\   s   z<SentrySpanProcessor.__init__.<locals>.global_event_processor)r%   r!   rG   r"   r(   r!   r   )rJ   rK   r<   rI   r=   __init__[   s   zSentrySpanProcessor.__init__rJ   c                 C   sp   t t d }t| j D ]'}| j| t kr| j| q|| tkr5| j|D ]	}| j|d q+qdS )z?
        Prune spans that have been open for too long.
        <   N)	intr   listr@   keyssetpopSPAN_MAX_TIME_OPEN_MINUTESr&   )rJ   current_time_minutesspan_start_minutesr3   r<   r<   r=   _prune_old_spans`   s   z$SentrySpanProcessor._prune_old_spansr9   OTelSpanparent_contextOptional[context_api.Context]c           
   
   C   s(  t  }|jsd S |jd tjkrd S | jsd S | |r d S | ||}|d }|r2| j	
|nd }d }|jd urEt|jd tj}d }|rX|j|d |j|tjtd}nt|j|d ||d |d |tjtd}|| j	|d < |jd urt|jd d	 }	| j|	t |d  |   d S )
Nr)   parent_span_id    eAr3   )r3   namestart_timestampr)   originr2   baggage)r\   r3   rZ   r2   r_   r]   r)   r^   rM   )r   
parsed_dsnr.   r	   r/   r1   is_valid_is_sentry_span_get_trace_datar&   r4   
start_timer   fromtimestampr   utcstart_childr\   SPAN_ORIGINr   rN   r@   r5   rQ   addrV   )
rJ   r9   rX   r8   
trace_datarZ   sentry_parent_spanr]   r;   span_start_in_minutesr<   r<   r=   on_startq   s\   



zSentrySpanProcessor.on_startc                 C   s
  t  }|jd tjkrd S | }|jsd S t|j}| j	|d }|s&d S |j
|_| || t|trI|j
|_
|t| | | || n| || d }|jd ur`t|jd tj}|j|d |jd urt|jd d }| j|t | |    d S )Nr)   r[   )end_timestamprM   )!r   r.   r	   r/   r1   ra   r   r3   r&   rR   r\   op_update_span_with_otel_status
isinstancer   set_contextOPEN_TELEMETRY_CONTEXT_get_otel_context"_update_transaction_with_otel_data_update_span_with_otel_dataend_timer   re   r   rf   finishrd   rN   r@   r5   rQ   discardrV   )rJ   r9   r8   span_contextr3   r;   rn   rl   r<   r<   r=   on_end   s>   




zSentrySpanProcessor.on_endc                 C   sT   d}|j dur|j tj}td|}t j}|r|jnd}|r(|r(||v r(dS dS )zs
        Break infinite loop:
        HTTP requests to Sentry are caught by OTel and send again to Sentry.
        NOptional[str]TF)
attributesr4   r   HTTP_URLr   r   r`   netloc)rJ   r9   otel_span_urlr`   dsn_urlr<   r<   r=   rb      s   

z#SentrySpanProcessor._is_sentry_spandict[str, Any]c                 C   s4   i }|j rt|j |d< |jj rt|jj |d< |S )z
        Returns the OTel context for Sentry.
        See: https://develop.sentry.dev/sdk/performance/opentelemetry/#step-5-add-opentelemetry-context
        r}   resource)r}   dictr   )rJ   r9   r:   r<   r<   r=   rt      s   z%SentrySpanProcessor._get_otel_contextc           
      C   s   i }|  }t|j}||d< t|j}||d< |jr!t|jjnd}||d< tt|}td|}|r7|d nd|d< tt	|}	|	|d< |S )z^
        Extracts tracing information from one OTel span and its parent OTel context.
        r3   r2   NrZ   z!dict[str, Union[str, bool, None]]parent_sampledr_   )
r1   r   r3   r   r2   parentr   r   r   r   )
rJ   r9   rX   rj   rz   r3   r2   rZ   sentry_trace_datar_   r<   r<   r=   rc      s    




z#SentrySpanProcessor._get_trace_datar;   
SentrySpanc                 C   s4   |j jrdS |j jr|tj dS |tj dS )z?
        Set the Sentry span status from the OTel span
        N)statusis_unsetis_ok
set_statusr
   OKINTERNAL_ERROR)rJ   r;   r9   r<   r<   r=   rp     s   z1SentrySpanProcessor._update_span_with_otel_statusc                 C   s  | d|j |j}|j}|jdur|j D ]
\}}| || q|jtj}td|}|jtj	}|rd}|jt
jkrD|d7 }n
|jt
jkrN|d7 }|}|jtjd}	|	ra|d|	7 }|jtjd}
|
rr|d|
7 }|	s|
s|jtjd}td|}|rt|}d|j|j|j}|d|7 }|jtjd}td	|}|r|| n|rd
}|jtjd}td|}|r|}||_||_dS )z
        Convert OTel span data and update the Sentry span with it.
        This should eventually happen on the server when ingesting the spans.
        z	otel.kindNr|   http.server.clientz {}z	{}://{}{}Optional[int]db)set_datakindr\   r}   itemsr4   r   HTTP_METHODr   	DB_SYSTEMr   SERVERCLIENTNET_PEER_NAMEformatHTTP_TARGETr~   urlparseschemer   pathHTTP_STATUS_CODEset_http_statusDB_STATEMENTro   description)rJ   r;   r9   ro   r   keyvalhttp_methoddb_query	peer_nametargeturl
parsed_urlstatus_code	statementr<   r<   r=   rv   .  s\   







z/SentrySpanProcessor._update_span_with_otel_datac                 C   s   |j d u rd S |j tj}|r?|j tj}td|}|r#|| d}|jtj	kr0|d7 }n
|jtj
kr:|d7 }||_d S d S )Nr   r   r   r   )r}   r4   r   r   r   r   r   r   r   r   r   ro   )rJ   r;   r9   r   r   ro   r<   r<   r=   ru   p  s   




z6SentrySpanProcessor._update_transaction_with_otel_data)r(   r?   )r(   N)rJ   r?   r(   NrH   )r9   rW   rX   rY   r(   N)r9   rW   r(   N)r9   rW   r(   r   )r9   rW   rX   rY   r(   r   )r;   r   r9   rW   r(   N)__name__
__module____qualname____doc__r&   __annotations__r@   rC   rL   rV   rm   r{   boolrb   rt   rc   rp   rv   ru   __classcell__r<   r<   rE   r=   r?   J   s\   
 



A-



Br?   N)r%   r!   r&   r'   r(   r!   )9r   r   r   typingr   r   
sentry_sdkr   r   sentry_sdk.constsr	   r
   sentry_sdk.integrationsr   ,sentry_sdk.integrations.opentelemetry.constsr   r   sentry_sdk.scoper   sentry_sdk.tracingr   r   r   urllib3.utilr   r   opentelemetry.contextr   opentelemetry.sdk.tracer   r   rW   opentelemetry.semconv.tracer   opentelemetry.tracer   r   r   r   opentelemetry.trace.spanr   r   ImportErrorr   r   r   opentelemetryr    context_apisentry_sdk._typesr!   r"   rs   rS   rh   r>   r?   r<   r<   r<   r=   <module>   sD    
