
    OǻiX                     >   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r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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  ej@                  e!      Z"	 ddl#m$Z$ dZ% G d de      Z* G d d      Z+y# e&$ r dZ%dZ'dZ(dZ$dZ)Y 'w xY w)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	CSCReason	CSCResultGeoFailoverReasonPubSubDirectionget_pool_name)MetricGroup
OTelConfig)deprecated_args)MeterTFc                       e Zd ZdZdZdZdZy)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     Y/opt/lhia/marcimex/agent/venv/lib/python3.12/site-packages/redis/observability/metrics.pyr   r   /   s    
 ,E-r%   r   c                   .   e Zd ZdZdZdZdedefdZdId	Z	dId
Z
dIdZdIdZdIdZdIdZdIdZ	 	 	 	 	 	 	 dJdee   dee   dee   dee   dee   dee   dee   fdZdededededef
dZded   ded   defdZdeddfd Zdeddfd!Zd"eddfd#Zd$ed%   d&eddfd'Zd"ed&eddfd(Z  e!d)gd*d+,      	 	 	 	 	 	 	 	 	 dKd-ed&edee   dee   d.ee   d)ee   dee   dee   dee   dee   d/ee   ddfd0       Z"	 	 dLd1ee#   dee   ddfd2Z$d3eded4eddfd5Z%d"eddfd6Z&	 	 dLd7e'd8ee   d9ee   ddfd:Z( e!d;gd<d+,      	 	 	 dMd=ed>ee   d?ee   d;ee   ddf
d@       Z)	 dNdAee*   ddfdBZ+	 dNdCedee,   ddfdDZ-dEeddfdFZ.e/defdG       Z0defdHZ1y)O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                    t         st        d      || _        || _        t	               | _        d | _        t        j                  | j                  j                  v r| j                          t        j                  | j                  j                  v r| j                          t        j                  | j                  j                  v r| j                          t        j                  | j                  j                  v r| j!                          t        j"                  | j                  j                  v r| j%                          t        j&                  | j                  j                  v r| j)                          t        j*                  | j                  j                  v r| j-                          t.        j1                  d       y )NzROpenTelemetry API is not installed. Install it with: pip install opentelemetry-apiz!RedisMetricsCollector initialized)OTEL_AVAILABLEImportErrorr)   r*   r   attr_builderconnection_countr   
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*   s      r&   __init__zRedisMetricsCollector.__init__Q   sD   A 
 
,. $ !!T[[%>%>>))+$++";";;&&(''4;;+D+DD//1**dkk.G.GG224!:!::%%'  DKK$=$==((*??dkk777""$78r%   returnNc                     | j                   j                  ddd      | _        | j                   j                  ddd      | _        | j                   j                  dd	d
      | _        y)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rA   s    r&   r2   z.RedisMetricsCollector._init_resiliency_metricsv   sv    !ZZ66&z 7 
 *.)B)B9!F *C *
& "ZZ665 P 7 
r%   c                     | j                   j                  ddd| j                  j                        | _        | j                   j                  ddd      | _        | j                   j                  d	d
d      | _        y)z$Initialize basic connection metrics.z db.client.connection.create_timeszTime to create a new connectionrF   rG   rH   #explicit_bucket_boundaries_advisoryz'redis.client.connection.relaxed_timeoutz{relaxation}z@Counts up for relaxed timeout, counts down for unrelaxed timeoutrE   zredis.client.connection.handoffz	{handoff}zIConnections that have been handed off (e.g., after a MOVING notification)N)	r)   create_histogramr*   buckets_connection_create_timeconnection_create_timecreate_up_down_counterconnection_relaxed_timeoutrI   connection_handoffrM   s    r&   r6   z4RedisMetricsCollector._init_connection_basic_metrics   s    &*jj&A&A39040Z0Z	 'B '
# +/***K*K:Z +L +
' #'**";";2c #< #
r%   c                     | j                   j                  ddd      | _        | j                   j                  ddd| j                  j
                        | _        | j                   j                  d	d
d      | _        y)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.rE   zdb.client.connection.wait_timerO   z/Time to obtain an open connection from the poolrP   zredis.client.connection.closed{connection}z"Total number of closed connectionsN)r)   rI   connection_timeoutsrR   r*   buckets_connection_wait_timeconnection_wait_timeconnection_closedrM   s    r&   r8   z7RedisMetricsCollector._init_connection_advanced_metrics   s    #'::#<#<0{ $= $
  %)JJ$?$?1I040X0X	 %@ %
! "&!:!:1< "; "
r%   c                 t    | j                   j                  ddd| j                  j                        | _        y)z0Initialize command execution metric instruments.zdb.client.operation.durationrO   zCommand execution durationrP   N)r)   rR   r*   buckets_operation_durationoperation_durationrM   s    r&   r4   z+RedisMetricsCollector._init_command_metrics   s4    "&**"="=/4040V0V	 #> #
r%   c                 J    | j                   j                  ddd      | _        y)z%Initialize PubSub metric instruments.zredis.client.pubsub.messagesz	{message}z&Tracks published and received messagesrE   N)r)   rI   pubsub_messagesrM   s    r&   r:   z*RedisMetricsCollector._init_pubsub_metrics   s'    #zz88/@  9  
r%   c                 t    | j                   j                  ddd| j                  j                        | _        y)z(Initialize Streaming metric instruments.zredis.client.stream.lagrO   zkEnd-to-end lag per message, showing how stale are the messages when the application starts processing them.rP   N)r)   rR   r*   "buckets_stream_processing_duration
stream_lagrM   s    r&   r<   z-RedisMetricsCollector._init_streaming_metrics   s6    **55* F040^0^	 6 
r%   c                     | j                   j                  ddd      | _        | j                   j                  ddd      | _        | j                   j                  dd	d
      | _        y)z8Initialize Client Side Caching (CSC) metric instruments.zredis.client.csc.requestsz	{request}z)The total number of requests to the cacherE   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)   rI   csc_requestscsc_evictionscsc_network_savedrM   s    r&   r>   z'RedisMetricsCollector._init_csc_metrics   su     JJ55,C 6 
 "ZZ66-= 7 
 "&!:!:1F "; "
r%   server_addressserver_portnetwork_peer_addressnetwork_peer_port
error_typeretry_attemptsis_internalc                 D   t        | d      sy| j                  j                  ||      }|j                  | j                  j	                  |||             |j                  | j                  j                  ||             | j                  j                  d|       y)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)
        rJ   Nrk   rl   )rm   rn   rp   )ro   rq      
attributes)hasattrr.   build_base_attributesupdatebuild_operation_attributesbuild_error_attributesrJ   add)	rA   rk   rl   rm   rn   ro   rp   rq   attrss	            r&   record_error_countz(RedisMetricsCollector.record_error_count   s    , t_-!!77)# 8 
 	88%9"3- 9 	
 	44%' 5 	
 	qU3r%   maint_notificationc                     t        | d      sy| j                  j                  ||      }|j                  | j                  j	                  ||             ||t
        <   | j                  j                  d|       y)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
        rK   Nrs   )rm   rn   rt   ru   )rw   r.   rx   ry   rz   r   rK   r|   )rA   rk   rl   rm   rn   r   r}   s          r&   record_maint_notification_countz5RedisMetricsCollector.record_maint_notification_count  s    $ t89!!77)# 8 

 	88%9"3 9 	
 7I23&&**1*?r%   	fail_from)r   r	   fail_toreasonc                     t        | d      sy| j                  j                  |||      }| j                  j	                  d|      S )z
        Record geo failover

        Args:
            fail_from: Database failed from
            fail_to: Database failed to
            reason: Reason for the failover
        rL   N)r   r   r   rt   ru   )rw   r.   build_geo_failover_attributesrL   r|   )rA   r   r   r   r}   s        r&   record_geo_failoverz)RedisMetricsCollector.record_geo_failover6  sT     t_-!!?? @ 
 !!%%aE%::r%   callbackc                     t         j                  | j                  j                  vr| j                  sy| j
                  j                  ddd|g      | _        y)z
        Initialize observable gauge for connection count metric.

        Args:
            callback: Callback function to retrieve connection count
        Nzdb.client.connection.countrY   z!Number of connections in the poolrF   rG   rH   	callbacks)r   r5   r*   r1   r/   r)   create_observable_gaugerA   r   s     r&   init_connection_countz+RedisMetricsCollector.init_connection_countP  sS     ((0I0II)) $

 B B-;j	 !C !
r%   c                     t         j                  | j                  j                  vr| j                  sy| j
                  j                  ddd|g      | _        y)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   r=   r*   r1   	csc_itemsr)   r   r   s     r&   init_csc_itemsz$RedisMetricsCollector.init_csc_itemsg  sL     ??$++";";;DNN;;)Oj	 < 
r%   	pool_namec                     t        | d      sy| j                  j                  |      }| j                  j	                  d|       y)zo
        Record a connection timeout event.

        Args:
            pool_name: Connection pool name
        rZ   Nr   rt   ru   )rw   r.   build_connection_attributesrZ   r|   rA   r   r}   s      r&   record_connection_timeoutz/RedisMetricsCollector.record_connection_timeout{  sD     t23!!==	=R  $$Q5$9r%   connection_pool)r
   r   duration_secondsc                     t        | d      sy| j                  j                  t        |            }| j                  j                  ||       y)z
        Record time taken to create a new connection.

        Args:
            connection_pool: Connection pool implementation
            duration_seconds: Creation time in seconds
        rT   Nr   ru   )rw   r.   r   r   rT   record)rA   r   r   r}   s       r&   record_connection_create_timez3RedisMetricsCollector.record_connection_create_time  sQ     t56!!==#O4 > 
 	##**+;*Nr%   c                     t        | d      sy| j                  j                  |      }| j                  j	                  ||       y)z
        Record time taken to obtain a connection from the pool.

        Args:
            pool_name: Connection pool name
            duration_seconds: Wait time in seconds
        r\   Nr   ru   )rw   r.   r   r\   r   )rA   r   r   r}   s       r&   record_connection_wait_timez1RedisMetricsCollector.record_connection_wait_time  sE     t34!!==	=R!!(()9e(Lr%   
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   versioncommand_namedb_namespaceis_blockingc           	         t        | d      sy| j                  j                  |      sy| j                  j	                  |||      }|j                  | j                  j                  |||	|
|             |j                  | j                  j                  |             | j                  j                  ||       y)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)rk   rl   r   )r   rm   rn   rp   r   ro   ru   )
rw   r*   should_track_commandr.   rx   ry   rz   r{   r`   r   )rA   r   r   rk   rl   r   r   ro   rm   rn   rp   r   r}   s                r&   record_operation_durationz/RedisMetricsCollector.record_operation_duration  s    F t12 {{//= !!77)#% 8 
 	88)%9"3-' 9 	
 	44% 5 	

 	&&'7E&Jr%   close_reasonc                    t        | d      sy| j                  j                         }|r|j                  |t        <   |j                  | j                  j                  |             | j                  j                  d|       y)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
        r]   Nr   rt   ru   )	rw   r.   r   valuer   ry   r{   r]   r|   )rA   r   ro   r}   s       r&   record_connection_closedz.RedisMetricsCollector.record_connection_closed  s}     t01!!==?:F:L:LE6744% 5 	
 	""1"7r%   connection_namerelaxedc                     t        | d      sy| j                  j                  |      }||t        <   | j                  j                  |rdnd|       y)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)
        rV   N)r   rt   ru   )rw   r.   r   r   rV   r|   )rA   r   r   r   r}   s        r&   !record_connection_relaxed_timeoutz7RedisMetricsCollector.record_connection_relaxed_timeout  s[     t9:!!==+ > 
 7I23''++AbU+Sr%   c                     t        | d      sy| j                  j                  |      }| j                  j	                  d|       y)z
        Record a connection handoff event (e.g., after MOVING notification).

        Args:
            pool_name: Connection pool name
        rW   Nr   rt   ru   )rw   r.   r   rW   r|   r   s      r&   record_connection_handoffz/RedisMetricsCollector.record_connection_handoff$  sD     t12!!==	=R##A%#8r%   	directionchannelshardedc                     t        | d      sy| j                  j                  |||      }| j                  j	                  d|       y)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
        rb   N)r   r   r   rt   ru   )rw   r.   build_pubsub_message_attributesrb   r|   )rA   r   r   r   r}   s        r&   record_pubsub_messagez+RedisMetricsCollector.record_pubsub_message6  sR     t./!!AA B 

 	  u 5r%   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                     t        | d      sy| j                  j                  ||      }| j                  j	                  ||       y)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
        re   N)r   r   ru   )rw   r.   build_streaming_attributesre   r   )rA   r   r   r   r   r}   s         r&   record_streaming_lagz*RedisMetricsCollector.record_streaming_lagP  sK    * t\*!!<<#) = 
 	{u=r%   resultc                     t        | d      sy| j                  j                  |      }| j                  j	                  d|       y)z}
        Record a Client Side Caching (CSC) request.

        Args:
            result: CSC result ('hit' or 'miss')
        rh   N)r   rt   ru   )rw   r.   build_csc_attributesrh   r|   )rA   r   r}   s      r&   record_csc_requestz(RedisMetricsCollector.record_csc_requestp  sC     t^,!!66f6EaE2r%   countc                     t        | d      sy| j                  j                  |      }| j                  j	                  ||       y)z
        Record a Client Side Caching (CSC) eviction.

        Args:
            count: Number of evictions
            reason: Reason for eviction
        ri   N)r   ru   )rw   r.   r   ri   r|   )rA   r   r   r}   s       r&   record_csc_evictionz)RedisMetricsCollector.record_csc_eviction  sC     t_-!!66f6Eu7r%   bytes_savedc                     t        | d      sy| j                  j                         }| j                  j	                  ||       y)z
        Record the number of bytes saved by using Client Side Caching (CSC).

        Args:
            bytes_saved: Number of bytes saved
        rj   Nru   )rw   r.   r   rj   r|   )rA   r   r}   s      r&   record_csc_network_savedz.RedisMetricsCollector.record_csc_network_saved  s?     t01!!668"";5"Ar%   c                  *    t        j                         S )z
        Get monotonic time for duration measurements.

        Returns:
            Current monotonic time in seconds
        )time	monotonicr$   r%   r&   monotonic_timez$RedisMetricsCollector.monotonic_time  s     ~~r%   c                 <    d| j                    d| j                   dS )NzRedisMetricsCollector(meter=z	, config=))r)   r*   rM   s    r&   __repr__zRedisMetricsCollector.__repr__  s    -djj\4;;-qQQr%   )rC   N)NNNNNNN)	NNNNNNNNN)NN)NNN)N)2r   r   r   r    
METER_NAMEMETER_VERSIONr   r   rB   r2   r6   r8   r4   r:   r<   r>   r   strint	Exceptionboolr~   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(   A   s]   
 JM#9e #9Z #9J
(
*
*



0 )-%).2+/*.(,&*,4 ,4 c],4 'sm	,4
 $C=,4 Y',4 !,4 d^,4\"@"@ "@ "	"@
 "@  "@H;89; 67; "	;4

 

.

 

(:3 :4 :OJKO  O 
	O(MM  M 
	M( "^i )-%)&*$(*..2+/(,&*;K;K  ;K !	;K
 c];K sm;K SM;K Y';K 'sm;K $C=;K !;K d^;K 
;K
;K~ /3*.8{+8 Y'8 
	86TT  T 	T
 
T.99 
9* "&"&	6"6 #6 $	6
 
64 %&l &*(,'+>> c]> !	>
  }> 
>
>: '+3#3 
3& '+88 #8 
	8$BB 
B$  E    R# Rr%   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   redis.observability.configr   r   redis.utilsr   	getLoggerr   r?   opentelemetry.metricsr   r,   r-   Counter	HistogramUpDownCounterr   r(   r$   r%   r&   <module>r      s       ; ;7<83	 	 	 ? '			8	$	+N.$ .$n	R n	R5  NGIEMs   ,B
 
BB