o
    ưiD                     @   s   d dl Z d dl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 d dlmZ d dlmZmZ d dlmZ d d	lmZ erSd d
lmZ eeef ZneZdZdZG dd deZdS )    N)datetime)TYPE_CHECKINGAnyOptionalUnion)verbose_logger)_utils)LangfuseLLMObsOTELAttributes)OpenTelemetryOpenTelemetryConfig)LangfuseSpanAttributes)StandardCallbackDynamicParams)Spanz*https://cloud.langfuse.com/api/public/otelz-https://us.cloud.langfuse.com/api/public/otelc                       s  e Zd Zd( fdd	ZedefddZededefd	d
ZededefddZ	edefddZ
edefddZedee fddZdefddZed)ddZedededefddZdedee fddZd ed!edee fd"d#Zd$d% Zd&d' Z  ZS )*LangfuseOtelLoggerNc                    s*   |d u r|   }t j|d|i| d S )Nconfig)/_create_open_telemetry_config_from_langfuse_envsuper__init__)selfr   argskwargs	__class__ b/home/app/Keep/.python/lib/python3.10/site-packages/litellm/integrations/langfuse/langfuse_otel.pyr      s   zLangfuseOtelLogger.__init__spanc                 C   s$   t | ||t tj| ||d dS )z
        Sets OpenTelemetry span attributes for Langfuse observability.
        Uses the same attribute setting logic as Arize Phoenix for consistency.
        r   r   response_objN)r   Zset_attributesr	   r   !_set_langfuse_specific_attributesr   r   r   r   set_langfuse_otel_attributes&   s
   z/LangfuseOtelLogger.set_langfuse_otel_attributesr   returnc                 C   sh   |  di pi }| dpi }|du st|tsi }zddlm} |||}W |S  ty3   Y |S w )a  
        Extracts Langfuse metadata from the standard LiteLLM kwargs structure.

        1. Reads kwargs["litellm_params"]["metadata"] if present and is a dict.
        2. Enriches it with any `langfuse_*` request-header params via the
           existing LangFuseLogger.add_metadata_from_header helper so that proxy
           users get identical behaviour across vanilla and OTEL integrations.
        litellm_paramsmetadataNr   )LangFuseLogger)get
isinstancedictZ&litellm.integrations.langfuse.langfuser#   Zadd_metadata_from_header	Exception)r   r!   r"   Z	_LFLoggerr   r   r   _extract_langfuse_metadata7   s   
z-LangfuseOtelLogger._extract_langfuse_metadatar"   c              	   C   s.  ddl m} i dtjdtjdtjdtjdtjdtjd	tj	d
tj
dtjdtjdtjdtjdtjdtjdtjdtjdtj}| D ]D\}}||v r|| dur|| }|dkrqt|trq|dd}t|ttfrzt|}W n ty   t|}Y nw || |j| qPdS )z/Helper to set metadata attributes from mapping.r   safe_set_attributeZgeneration_nameZgeneration_idZparent_observation_idversionZ
mask_inputZmask_outputZtrace_user_idZ
session_idtagsZ
trace_nameZtrace_idZtrace_metadataZtrace_versionZtrace_releaseZexisting_trace_idZupdate_trace_keysZdebug_langfuseN- )!litellm.integrations.arize._utilsr*   r   ZGENERATION_NAMEZGENERATION_IDZPARENT_OBSERVATION_IDZGENERATION_VERSIONZ
MASK_INPUTZMASK_OUTPUTZTRACE_USER_IDZ
SESSION_IDZTAGSZ
TRACE_NAMEZTRACE_IDZTRACE_METADATAZTRACE_VERSIONZTRACE_RELEASEZEXISTING_TRACE_IDZUPDATE_TRACE_KEYSZDEBUG_LANGFUSEitemsr%   strreplacelistr&   jsondumpsr'   value)r   r"   r*   mappingkeyZ	enum_attrr6   r   r   r   _set_metadata_attributesT   sd   	
z+LangfuseOtelLogger._set_metadata_attributesc              	   C   s~  ddl m} ddlm} |rt|dsdS |dg }|r|d }|di }|d}|rg }|D ]B}	|	d	i }
|
d
d}zt|trKt	|n|}W n tj
yZ   i }Y nw |dd|
dd|	ddd|d}|| q2|| tjj|| n(i }|dr|d|d< |ddur|d|d< |r|| tjj|| |dg }|r;g }|D ]v}t|dr+|j}|dkrt|dr|jD ]}t|dr|d|jd qq|dkr|t|ddtt|di gd ddd q|dkr+t|d
d}t|trt	|n|}t|ddt|ddt|ddd|d}|| q|r=|| tjj|| dS dS dS )z,Helper to set observation output attributes.r   r)   
safe_dumpsr$   Nchoicesmessage
tool_callsfunction	argumentsz{}idr.   nameZfunction_call)rA   rB   call_idtyper@   rolecontentoutputrD   Z	reasoningsummarytextZreasoning_summary)rE   rF   Z	assistantrC   )r/   r*   *litellm.litellm_core_utils.safe_json_dumpsr;   hasattrr$   r%   r1   r4   loadsJSONDecodeErrorappendr   ZOBSERVATION_OUTPUTr6   rD   rH   rI   getattr)r   r   r*   r;   r<   Zfirst_choicer=   r>   Ztransformed_tool_callsZ	tool_callr?   Zarguments_strZarguments_objZlangfuse_tool_callZoutput_datarG   Zoutput_items_dataitemZ	item_typerH   r   r   r   _set_observation_output{   s   












&z*LangfuseOtelLogger._set_observation_outputc                 C   s   ddl m} ddlm} tjd}|r|| tjj	| t
|}t
j| |d |d}|r9|| tjj	|| t
j| |d dS )	aH  
        Sets Langfuse specific metadata attributes onto the OTEL span.

        All keys supported by the vanilla Langfuse integration are mapped to
        OTEL-safe attribute names defined in LangfuseSpanAttributes.  Complex
        values (lists/dicts) are serialised to JSON strings for OTEL
        compatibility.
        r   r)   r:   ZLANGFUSE_TRACING_ENVIRONMENT)r   r"   messages)r   r   N)r/   r*   rJ   r;   osenvironr$   r   ZLANGFUSE_ENVIRONMENTr6   r   r(   r9   ZOBSERVATION_INPUTrQ   )r   r   r   r*   r;   Zlangfuse_environmentr"   rR   r   r   r   r      s&   


z4LangfuseOtelLogger._set_langfuse_specific_attributesc                   C   s   t jdpt jdS )z
        Returns the Langfuse OTEL host based on environment variables.

        Returned in the following order of precedence:
        1. LANGFUSE_OTEL_HOST
        2. LANGFUSE_HOST
        ZLANGFUSE_OTEL_HOSTZLANGFUSE_HOST)rS   rT   r$   r   r   r   r   _get_langfuse_otel_host   s   	z*LangfuseOtelLogger._get_langfuse_otel_hostc                 C   s   ddl m} tjdd}tjdd}|r|s| S t }|r<|ds+d| }|	d d	}t
d
|  n
t}t
d|  tj||d}d| }|d||dS )z
        Creates OpenTelemetryConfig from Langfuse environment variables.
        Does NOT modify global environment variables.
        r   )r   LANGFUSE_PUBLIC_KEYNLANGFUSE_SECRET_KEYhttphttps:////api/public/otel(Using Langfuse OTEL endpoint from host: "Using Langfuse US cloud endpoint: 
public_key
secret_keyAuthorization=	otlp_httpZexporterendpointheaders)"litellm.integrations.opentelemetryr   rS   rT   r$   Zfrom_envr   rU   
startswithrstripr   debugLANGFUSE_CLOUD_US_ENDPOINT"_get_langfuse_authorization_header)r   r   r_   r`   langfuse_hostrd   auth_headerotlp_auth_headersr   r   r   r     s,   

zBLangfuseOtelLogger._create_open_telemetry_config_from_langfuse_envr   c                  C   s   t jdd} t jdd}| r|stdt }|r6|ds%d| }|d d}t	d	|  n
t
}t	d
|  tj| |d}d| }td||dS )a2  
        Retrieves the Langfuse OpenTelemetry configuration based on environment variables.

        Environment Variables:
            LANGFUSE_PUBLIC_KEY: Required. Langfuse public key for authentication.
            LANGFUSE_SECRET_KEY: Required. Langfuse secret key for authentication.
            LANGFUSE_HOST: Optional. Custom Langfuse host URL. Defaults to US cloud.

        Returns:
            OpenTelemetryConfig: A Pydantic model containing Langfuse OTEL configuration.

        Raises:
            ValueError: If required keys are missing.
        rV   NrW   z_LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY must be set for Langfuse OpenTelemetry integration.rX   rY   rZ   r[   r\   r]   r^   ra   rb   rc   )rS   rT   r$   
ValueErrorr   rU   rg   rh   r   ri   rj   rk   r   )r_   r`   rl   rd   rm   rn   r   r   r   get_langfuse_otel_config2  s.   

z+LangfuseOtelLogger.get_langfuse_otel_configr_   r`   c                 C   s*   |  d| }t |  }d| S )zJ
        Get the authorization header for Langfuse OpenTelemetry.
        :zBasic )base64	b64encodeencodedecode)r_   r`   Zauth_stringrm   r   r   r   rk   g  s   
z5LangfuseOtelLogger._get_langfuse_authorization_header standard_callback_dynamic_paramsc                 C   s:   i }| d}| d}|r|rtj||d}||d< |S )z
        Construct dynamic Langfuse headers from standard callback dynamic params

        This is used for team/key based logging.

        Returns:
            dict: A dictionary of dynamic Langfuse headers
        Zlangfuse_public_keyZlangfuse_secret_keyr^   Authorization)r$   r   rk   )r   rv   Zdynamic_headersZdynamic_langfuse_public_keyZdynamic_langfuse_secret_keyrm   r   r   r   construct_dynamic_otel_headersp  s   z1LangfuseOtelLogger.construct_dynamic_otel_headers
start_timere   c                 C   s   dS )aq  
        Override to prevent creating empty proxy request spans.

        Langfuse should only receive spans for actual LLM calls, not for
        internal proxy operations (auth, postgres, proxy_pre_call, etc.).

        By returning None, we prevent the parent span from being created,
        which in turn prevents empty traces from being sent to Langfuse.
        Nr   )r   ry   re   r   r   r   )create_litellm_proxy_request_started_span  s   z<LangfuseOtelLogger.create_litellm_proxy_request_started_spanc                       dS )zC
        Langfuse should not receive service success logs.
        Nr   r   r   r   r   r   r   async_service_success_hook     z-LangfuseOtelLogger.async_service_success_hookc                    r{   )zC
        Langfuse should not receive service failure logs.
        Nr   r|   r   r   r   async_service_failure_hook  r~   z-LangfuseOtelLogger.async_service_failure_hook)N)r    r   )__name__
__module____qualname__r   staticmethodr   r   r&   r(   r9   rQ   r   r   r1   rU   r   r   rp   rk   r   rx   r   rz   r}   r   __classcell__r   r   r   r   r      sB    &b!
'4

r   )rr   r4   rS   r   typingr   r   r   r   Zlitellm._loggingr   Zlitellm.integrations.arizer   Z6litellm.integrations.langfuse.langfuse_otel_attributesr	   rf   r
   r   Z(litellm.types.integrations.langfuse_otelr   Zlitellm.types.utilsr   Zopentelemetry.tracer   _SpanZLANGFUSE_CLOUD_EU_ENDPOINTrj   r   r   r   r   r   <module>   s$    