o
    <‘ði9_  ã                   @   s   d 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	 er6d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mZmZmZmZmZmZ dd
lmZmZ ddlm Z m!Z! e "e#¡Z$z
ddl%m&Z& dZ'W n e(y~   dZ'dZ)dZ*dZ&dZ+Y nw G dd„ deƒZ,G dd„ dƒZ-dS )z¤
OpenTelemetry metrics collector for redis-py.

This module defines and manages all metric instruments according to
OTel semantic conventions for database clients.
é    N)ÚEnum)ÚTYPE_CHECKINGÚCallableÚOptionalÚUnion)ÚConnectionPool)ÚAsyncDatabase)ÚConnectionPoolInterface)ÚSyncDatabase)	Ú$REDIS_CLIENT_CONNECTION_CLOSE_REASONÚ$REDIS_CLIENT_CONNECTION_NOTIFICATIONÚAttributeBuilderÚConnectionStateÚ	CSCReasonÚ	CSCResultÚGeoFailoverReasonÚPubSubDirectionÚget_pool_name)ÚMetricGroupÚ
OTelConfig)Údeprecated_argsÚdeprecated_function)ÚMeterTFc                   @   s   e Zd ZdZdZdZdZdS )ÚCloseReasona  
    Enum representing the reason why a Redis client connection was closed.

    Values:
        APPLICATION_CLOSE: The connection was closed intentionally by the application
            (for example, during normal shutdown or explicit cleanup).
        ERROR: The connection was closed due to an unexpected error
            (for example, network failure or protocol error).
        HEALTHCHECK_FAILED: The connection was closed because a health check
            or liveness check for the connection failed.
    Úapplication_closeÚerrorÚhealthcheck_failedN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚAPPLICATION_CLOSEÚERRORÚHEALTHCHECK_FAILED© r$   r$   úZ/root/parts/websockify/install/lib/python3.10/site-packages/redis/observability/metrics.pyr   0   s
    r   c                   @   s4  e Zd ZdZdZdZdedefdd„Zdld
d„Z	dldd„Z
dldd„Zdldd„Zdldd„Zdldd„Zdldd„Z														dmdee dee dee dee dee dee dee fdd „Zdedededed!ef
d"d#„Zd$ed% d&ed% d'efd(d)„Z	*dnd+ed,ed-edd	fd.d/„Zed0d1d2�d3edd	fd4d5„ƒZd3edd	fd6d7„Zd+edd	fd8d9„Z d:ed; d<e!dd	fd=d>„Z"d+ed<e!dd	fd?d@„Z#e$dAgdBdCdD�																		dodEed<e!dee dee dFee dAee dee dee dee dee dGee dd	fdHdI„ƒZ%				dpdJee& dee dd	fdKdL„Z'dMed!edNedd	fdOdP„Z(d+edd	fdQdR„Z)				dpdSe*dTee dUee dd	fdVdW„Z+e$dXgdYdCdD�						dqdZe!d[ee d\ee dXee dd	f
d]d^„ƒZ,		drd_ee- dd	fd`da„Z.		drdbed'ee/ dd	fdcdd„Z0deedd	fdfdg„Z1e2de!fdhdi„ƒZ3defdjdk„Z4d	S )sÚRedisMetricsCollectorap  
    Collects and records OpenTelemetry metrics for Redis operations.

    This class manages all metric instruments and provides methods to record
    various Redis operations including connection pool events, command execution,
    and cluster-specific operations.

    Args:
        meter: OpenTelemetry Meter instance
        config: OTel configuration object
    zredis-pyz1.0.0ÚmeterÚconfigc                 C   sÈ   t stdƒ‚|| _|| _tƒ | _tj| jjv r|  	¡  tj
| jjv r&|  ¡  tj| jjv r1|  ¡  tj| jjv r<|  ¡  tj| jjv rG|  ¡  tj| jjv rR|  ¡  tj| jjv r]|  ¡  t d¡ d S )NzROpenTelemetry API is not installed. Install it with: pip install opentelemetry-apiz!RedisMetricsCollector initialized)ÚOTEL_AVAILABLEÚImportErrorr'   r(   r   Úattr_builderr   Ú
RESILIENCYÚmetric_groupsÚ_init_resiliency_metricsÚCOMMANDÚ_init_command_metricsÚCONNECTION_BASICÚ_init_connection_basic_metricsÚCONNECTION_ADVANCEDÚ!_init_connection_advanced_metricsÚPUBSUBÚ_init_pubsub_metricsÚ	STREAMINGÚ_init_streaming_metricsÚCSCÚ_init_csc_metricsÚloggerÚinfo)Úselfr'   r(   r$   r$   r%   Ú__init__R   s,   ÿzRedisMetricsCollector.__init__ÚreturnNc                 C   ó@   | j jdddd�| _| j jdddd�| _| j jdd	d
d�| _dS )zInitialize resiliency metrics.zredis.client.errorsz{error}z`A counter of all errors (both returned to the user and handled internally in the client library)©ÚnameÚunitÚdescriptionz&redis.client.maintenance.notificationsz{notification}z,Tracks server-side maintenance notificationsz"redis.client.geofailover.failoversz{geofailover}z6Total count of failovers happened using MultiDbClient.N)r'   Úcreate_counterÚclient_errorsÚmaintenance_notificationsÚgeo_failovers©r=   r$   r$   r%   r.   v   ó   ýýýz.RedisMetricsCollector._init_resiliency_metricsc                 C   s`   | j jddd| jjd�| _| j jdddd�| _| j jd	d
dd�| _d| _	| j jdddd�| _
dS )z$Initialize basic connection metrics.z db.client.connection.create_timeÚszTime to create a new connection©rB   rC   rD   Ú#explicit_bucket_boundaries_advisoryz'redis.client.connection.relaxed_timeoutz{relaxation}z@Counts up for relaxed timeout, counts down for unrelaxed timeoutrA   zredis.client.connection.handoffz	{handoff}zIConnections that have been handed off (e.g., after a MOVING notification)Nzdb.client.connection.countú{connection}z4Number of connections currently in the pool by state)r'   Úcreate_histogramr(   Úbuckets_connection_create_timeÚconnection_create_timeÚcreate_up_down_counterÚconnection_relaxed_timeoutrE   Úconnection_handoffÚconnection_countÚconnection_count_updownrI   r$   r$   r%   r2   Š   s,   üýý
ýz4RedisMetricsCollector._init_connection_basic_metricsc                 C   sF   | j jdddd�| _| j jddd| jjd�| _| j jd	d
dd�| _dS )z'Initialize advanced connection metrics.zdb.client.connection.timeoutsz	{timeout}zaThe number of connection timeouts that have occurred trying to obtain a connection from the pool.rA   zdb.client.connection.wait_timerK   z/Time to obtain an open connection from the poolrL   zredis.client.connection.closedrN   z"Total number of closed connectionsN)r'   rE   Úconnection_timeoutsrO   r(   Úbuckets_connection_wait_timeÚconnection_wait_timeÚconnection_closedrI   r$   r$   r%   r4   ¬   s    ýüýz7RedisMetricsCollector._init_connection_advanced_metricsc                 C   ó   | j jddd| jjd�| _dS )z0Initialize command execution metric instruments.zdb.client.operation.durationrK   zCommand execution durationrL   N)r'   rO   r(   Úbuckets_operation_durationÚoperation_durationrI   r$   r$   r%   r0   Á   ó   üz+RedisMetricsCollector._init_command_metricsc                 C   s   | j jdddd�| _dS )z%Initialize PubSub metric instruments.zredis.client.pubsub.messagesz	{message}z&Tracks published and received messagesrA   N)r'   rE   Úpubsub_messagesrI   r$   r$   r%   r6   Ê   s
   ýz*RedisMetricsCollector._init_pubsub_metricsc                 C   r[   )z(Initialize Streaming metric instruments.zredis.client.stream.lagrK   zkEnd-to-end lag per message, showing how stale are the messages when the application starts processing them.rL   N)r'   rO   r(   Ú"buckets_stream_processing_durationÚ
stream_lagrI   r$   r$   r%   r8   Ò   r^   z-RedisMetricsCollector._init_streaming_metricsc                 C   r@   )z8Initialize Client Side Caching (CSC) metric instruments.zredis.client.csc.requestsz	{request}z)The total number of requests to the cacherA   zredis.client.csc.evictionsz
{eviction}z#The total number of cache evictionszredis.client.csc.network_savedÚByz,The total number of bytes saved by using CSCN)r'   rE   Úcsc_requestsÚcsc_evictionsÚcsc_network_savedrI   r$   r$   r%   r:   Û   rJ   z'RedisMetricsCollector._init_csc_metricsÚserver_addressÚserver_portÚnetwork_peer_addressÚnetwork_peer_portÚ
error_typeÚretry_attemptsÚis_internalc           	      C   s`   t | dƒsdS | jj||d�}| | jj|||d�¡ | | jj||d�¡ | jjd|d� dS )a�  
        Record error count

        Args:
            server_address: Server address
            server_port: Server port
            network_peer_address: Network peer address
            network_peer_port: Network peer port
            error_type: Error type
            retry_attempts: Retry attempts
            is_internal: Whether the error is internal (e.g., timeout, network error)
        rF   N©rf   rg   )rh   ri   rk   )rj   rl   é   ©Ú
attributes)Úhasattrr+   Úbuild_base_attributesÚupdateÚbuild_operation_attributesÚbuild_error_attributesrF   Úadd)	r=   rf   rg   rh   ri   rj   rk   rl   Úattrsr$   r$   r%   Úrecord_error_countñ   s(   
þýÿþÿz(RedisMetricsCollector.record_error_countÚmaint_notificationc                 C   sP   t | dƒsdS | jj||d�}| | jj||d�¡ ||t< | jjd|d� dS )a7  
        Record maintenance notification count

        Args:
            server_address: Server address
            server_port: Server port
            network_peer_address: Network peer address
            network_peer_port: Network peer port
            maint_notification: Maintenance notification
        rG   Nrm   )rh   ri   rn   ro   )rq   r+   rr   rs   rt   r   rG   rv   )r=   rf   rg   rh   ri   ry   rw   r$   r$   r%   Úrecord_maint_notification_count  s   
þþÿz5RedisMetricsCollector.record_maint_notification_countÚ	fail_from)r
   r   Úfail_toÚreasonc                 C   s0   t | dƒsdS | jj|||d�}| jjd|d�S )z´
        Record geo failover

        Args:
            fail_from: Database failed from
            fail_to: Database failed to
            reason: Reason for the failover
        rH   N)r{   r|   r}   rn   ro   )rq   r+   Úbuild_geo_failover_attributesrH   rv   )r=   r{   r|   r}   rw   r$   r$   r%   Úrecord_geo_failoverC  s   
ýz)RedisMetricsCollector.record_geo_failoverrn   Ú	pool_nameÚconnection_stateÚcounterc                 C   s2   t | dƒsdS | jj||d�}| jj||d� dS )a  
        Record a connection count change for a single state.

        Args:
            pool_name: Connection pool name
            connection_state: State to update (IDLE or USED)
            counter: Number to add (positive) or subtract (negative)
        rV   N)r€   r�   ro   )rq   r+   Úbuild_connection_attributesrV   rv   )r=   r€   r�   r‚   rw   r$   r$   r%   Úrecord_connection_count]  s   
þz-RedisMetricsCollector.record_connection_countz{Connection count is now tracked via record_connection_count(). This functionality will be removed in the next major versionz7.4.0)r}   ÚversionÚcallbackc                 C   s.   t j| jjvr	dS | jjddd|gd�| _dS )zŸ
        Initialize observable gauge for connection count metric.

        Args:
            callback: Callback function to retrieve connection counts
        Nz%db.client.connection.count.deprecatedrN   zŒThe number of connections that are currently in state described by the state attribute (deprecated - use db.client.connection.count instead)©rB   rC   rD   Ú	callbacks)r   r1   r(   r-   r'   Úcreate_observable_gaugerU   ©r=   r†   r$   r$   r%   Úinit_connection_countt  s   ûz+RedisMetricsCollector.init_connection_countc                 C   s4   t j| jjvr| jsdS | jjddd|gd�| _dS )z–
        Initialize observable gauge for CSC items metric.

        Args:
            callback: Callback function to retrieve CSC items count
        Nzredis.client.csc.itemsz{item}z5The total number of cached responses currently storedr‡   )r   r9   r(   r-   Ú	csc_itemsr'   r‰   rŠ   r$   r$   r%   Úinit_csc_items‘  s   
üz$RedisMetricsCollector.init_csc_itemsc                 C   ó0   t | dƒsdS | jj|d�}| jjd|d� dS )zo
        Record a connection timeout event.

        Args:
            pool_name: Connection pool name
        rW   N©r€   rn   ro   )rq   r+   rƒ   rW   rv   ©r=   r€   rw   r$   r$   r%   Úrecord_connection_timeout¥  s   
z/RedisMetricsCollector.record_connection_timeoutÚconnection_pool)r	   r   Úduration_secondsc                 C   s4   t | dƒsdS | jjt|ƒd�}| jj||d� dS )zÁ
        Record time taken to create a new connection.

        Args:
            connection_pool: Connection pool implementation
            duration_seconds: Creation time in seconds
        rQ   Nr�   ro   )rq   r+   rƒ   r   rQ   Úrecord)r=   r’   r“   rw   r$   r$   r%   Úrecord_connection_create_time²  s   
ÿz3RedisMetricsCollector.record_connection_create_timec                 C   s0   t | dƒsdS | jj|d�}| jj||d� dS )z·
        Record time taken to obtain a connection from the pool.

        Args:
            pool_name: Connection pool name
            duration_seconds: Wait time in seconds
        rY   Nr�   ro   )rq   r+   rƒ   rY   r”   )r=   r€   r“   rw   r$   r$   r%   Úrecord_connection_wait_timeÆ  ó   
z1RedisMetricsCollector.record_connection_wait_timeÚ
batch_sizezXThe batch_size argument is no longer used and will be removed in the next major version.z7.2.1)Úargs_to_warnr}   r…   Úcommand_nameÚdb_namespaceÚis_blockingc              	   C   st   t | dƒsdS | j |¡sdS | jj|||d�}| | jj|||	|
|d�¡ | | jj|d�¡ | jj	||d� dS )aÀ  
        Record command execution duration.

        Args:
            command_name: Redis command name (e.g., 'GET', 'SET', 'MULTI')
            duration_seconds: Execution time in seconds
            server_address: Redis server address
            server_port: Redis server port
            db_namespace: Redis database index
            batch_size: Number of commands in batch (for pipelines/transactions)
            error_type: Error type if operation failed
            network_peer_address: Resolved peer address
            network_peer_port: Peer port number
            retry_attempts: Number of retry attempts made
            is_blocking: Whether the operation is a blocking command
        r]   N)rf   rg   r›   )rš   rh   ri   rk   rœ   ©rj   ro   )
rq   r(   Úshould_track_commandr+   rr   rs   rt   ru   r]   r”   )r=   rš   r“   rf   rg   r›   r˜   rj   rh   ri   rk   rœ   rw   r$   r$   r%   Úrecord_operation_durationÚ  s0   
#ýûÿ
ÿÿz/RedisMetricsCollector.record_operation_durationÚclose_reasonc                 C   sN   t | dƒsdS | j ¡ }|r|j|t< | | jj|d�¡ | jjd|d� dS )zÍ
        Record a connection closed event.

        Args:
            close_reason: Reason for closing (e.g. 'error', 'application_close')
            error_type: Error type if closed due to error
        rZ   Nr�   rn   ro   )	rq   r+   rƒ   Úvaluer   rs   ru   rZ   rv   )r=   r    rj   rw   r$   r$   r%   Úrecord_connection_closed  s   


ÿÿz.RedisMetricsCollector.record_connection_closedÚconnection_nameÚrelaxedc                 C   s@   t | dƒsdS | jj|d�}||t< | jj|rdnd|d� dS )a
  
        Record a connection timeout relaxation event.

        Args:
            connection_name: Connection name
            maint_notification: Maintenance notification type
            relaxed: True to count up (relaxed), False to count down (unrelaxed)
        rS   Nr�   rn   éÿÿÿÿro   )rq   r+   rƒ   r   rS   rv   )r=   r£   ry   r¤   rw   r$   r$   r%   Ú!record_connection_relaxed_timeout7  s
   
z7RedisMetricsCollector.record_connection_relaxed_timeoutc                 C   rŽ   )z‘
        Record a connection handoff event (e.g., after MOVING notification).

        Args:
            pool_name: Connection pool name
        rT   Nr�   rn   ro   )rq   r+   rƒ   rT   rv   r�   r$   r$   r%   Úrecord_connection_handoffL  ó   

z/RedisMetricsCollector.record_connection_handoffÚ	directionÚchannelÚshardedc                 C   s4   t | dƒsdS | jj|||d�}| jjd|d� dS )zò
        Record a PubSub message (published or received).

        Args:
            direction: Message direction ('publish' or 'receive')
            channel: Pub/Sub channel name
            sharded: True if sharded Pub/Sub channel
        r_   N)r©   rª   r«   rn   ro   )rq   r+   Úbuild_pubsub_message_attributesr_   rv   )r=   r©   rª   r«   rw   r$   r$   r%   Úrecord_pubsub_message^  s   
ýz+RedisMetricsCollector.record_pubsub_messageÚconsumer_namez[The consumer_name argument is no longer used and will be removed in the next major version.Úlag_secondsÚstream_nameÚconsumer_groupc                 C   s2   t | dƒsdS | jj||d�}| jj||d� dS )zí
        Record the lag of a streaming message.

        Args:
            lag_seconds: Lag in seconds
            stream_name: Stream name
            consumer_group: Consumer group name
            consumer_name: Consumer name
        ra   N)r°   r±   ro   )rq   r+   Úbuild_streaming_attributesra   r”   )r=   r¯   r°   r±   r®   rw   r$   r$   r%   Úrecord_streaming_lagx  s   
þz*RedisMetricsCollector.record_streaming_lagÚresultc                 C   rŽ   )z}
        Record a Client Side Caching (CSC) request.

        Args:
            result: CSC result ('hit' or 'miss')
        rc   N)r´   rn   ro   )rq   r+   Úbuild_csc_attributesrc   rv   )r=   r´   rw   r$   r$   r%   Úrecord_csc_request˜  r¨   z(RedisMetricsCollector.record_csc_requestÚcountc                 C   s0   t | dƒsdS | jj|d�}| jj||d� dS )zœ
        Record a Client Side Caching (CSC) eviction.

        Args:
            count: Number of evictions
            reason: Reason for eviction
        rd   N)r}   ro   )rq   r+   rµ   rd   rv   )r=   r·   r}   rw   r$   r$   r%   Úrecord_csc_eviction¨  r—   z)RedisMetricsCollector.record_csc_evictionÚbytes_savedc                 C   s,   t | dƒsdS | j ¡ }| jj||d� dS )z”
        Record the number of bytes saved by using Client Side Caching (CSC).

        Args:
            bytes_saved: Number of bytes saved
        re   Nro   )rq   r+   rµ   re   rv   )r=   r¹   rw   r$   r$   r%   Úrecord_csc_network_savedº  s   


z.RedisMetricsCollector.record_csc_network_savedc                   C   s   t  ¡ S )z
        Get monotonic time for duration measurements.

        Returns:
            Current monotonic time in seconds
        )ÚtimeÚ	monotonicr$   r$   r$   r%   Úmonotonic_timeÌ  s   z$RedisMetricsCollector.monotonic_timec                 C   s   d| j › d| j› d�S )NzRedisMetricsCollector(meter=z	, config=ú))r'   r(   rI   r$   r$   r%   Ú__repr__Ö  s   zRedisMetricsCollector.__repr__)r?   N)NNNNNNN)rn   )	NNNNNNNNN)NN)NNN)N)5r   r   r   r    Ú
METER_NAMEÚMETER_VERSIONr   r   r>   r.   r2   r4   r0   r6   r8   r:   r   ÚstrÚintÚ	ExceptionÚboolrx   rz   r   r   r   r   r„   r   r   r‹   r�   r‘   Úfloatr•   r–   r   rŸ   r   r¢   r¦   r§   r   r­   r³   r   r¶   r   r¸   rº   Ústaticmethodr½   r¿   r$   r$   r$   r%   r&   B   sš   
$

"

	

	øþýüûúù
ø.þýüû
ú$þý
üüþýü
ûýþýþ
ýþý
üþý
üý	ôþýüûúùø	÷
öõôó?ýþý
üþýü
ûþ
ýüþýü
ûýûþýüûúþþ
ýýþý
üþ
ý	r&   ).r    Úloggingr»   Úenumr   Útypingr   r   r   r   Úredis.asyncio.connectionr   Úredis.asyncio.multidb.databaser   Úredis.connectionr	   Úredis.multidb.databaser
   Úredis.observability.attributesr   r   r   r   r   r   r   r   r   Úredis.observability.configr   r   Úredis.utilsr   r   Ú	getLoggerr   r;   Úopentelemetry.metricsr   r)   r*   ÚCounterÚ	HistogramÚUpDownCounterr   r&   r$   r$   r$   r%   Ú<module>   s4    ,
û