
    Ki9_                     F   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mZ dd
lmZmZ ddlm Z m!Z!  ejD                  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ConnectionState	CSCReason	CSCResultGeoFailoverReasonPubSubDirectionget_pool_name)MetricGroup
OTelConfig)deprecated_argsdeprecated_function)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     g/home/jay/workspace/scripts/.codegraph-venv/lib/python3.12/site-packages/redis/observability/metrics.pyr   r   0   s    
 ,E-r'   r   c                   d   e Zd ZdZdZdZdedefdZdOd	Z	dOd
Z
dOdZdOdZdOdZdOdZdOdZ	 	 	 	 	 	 	 dPd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	 dQded ed!eddfd"Z ed#d$%      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d0d12      	 	 	 	 	 	 	 	 	 dRd3ed,e!dee   dee   d4ee   d/ee   dee   dee   dee   dee   d5ee   ddfd6       Z%	 	 dSd7ee&   dee   ddfd8Z'd9eded:eddfd;Z(deddfd<Z)	 	 dSd=e*d>ee   d?ee   ddfd@Z+ e$dAgdBd12      	 	 	 dTdCe!dDee   dEee   dAee   ddf
dF       Z,	 dUdGee-   ddfdHZ.	 dUdIedee/   ddfdJZ0dKeddfdLZ1e2de!fdM       Z3defdNZ4y)V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	               | _        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,        j/                  d       y )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,   s      r(   __init__zRedisMetricsCollector.__init__R   s<   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rB   s    r(   r3   z.RedisMetricsCollector._init_resiliency_metricsv   sv    !ZZ66&z 7 
 *.)B)B9!F *C *
& "ZZ665 P 7 
r'   c                 T   | j                   j                  ddd| j                  j                        | _        | j                   j                  ddd      | _        | j                   j                  d	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rG   rH   rI   #explicit_bucket_boundaries_advisoryz'redis.client.connection.relaxed_timeoutz{relaxation}z@Counts up for relaxed timeout, counts down for unrelaxed timeoutrF   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_timeoutrJ   connection_handoffconnection_countconnection_count_updownrN   s    r(   r7   z4RedisMetricsCollector._init_connection_basic_metrics   s    &*jj&A&A39040Z0Z	 'B '
# +/***K*K:Z +L +
' #'**";";2c #< #
 !% (,zz'H'H-N (I (
$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.rF   zdb.client.connection.wait_timerP   z/Time to obtain an open connection from the poolrQ   zredis.client.connection.closedrS   z"Total number of closed connectionsN)r+   rJ   connection_timeoutsrT   r,   buckets_connection_wait_timeconnection_wait_timeconnection_closedrN   s    r(   r9   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.durationrP   zCommand execution durationrQ   N)r+   rT   r,   buckets_operation_durationoperation_durationrN   s    r(   r5   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 messagesrF   N)r+   rJ   pubsub_messagesrN   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.lagrP   zkEnd-to-end lag per message, showing how stale are the messages when the application starts processing them.rQ   N)r+   rT   r,   "buckets_stream_processing_duration
stream_lagrN   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 cacherF   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+   rJ   csc_requestscsc_evictionscsc_network_savedrN   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)
        rK   Nrn   ro   )rp   rq   rs   )rr   rt      
attributes)hasattrr0   build_base_attributesupdatebuild_operation_attributesbuild_error_attributesrK   add)	rB   rn   ro   rp   rq   rr   rs   rt   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
        rL   Nrv   )rp   rq   rw   rx   )rz   r0   r{   r|   r}   r   rL   r   )rB   rn   ro   rp   rq   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
        rM   N)r   r   r   rw   rx   )rz   r0   build_geo_failover_attributesrM   r   )rB   r   r   r   r   s        r(   record_geo_failoverz)RedisMetricsCollector.record_geo_failoverC  sT     t_-!!?? @ 
 !!%%aE%::r'   	pool_nameconnection_statecounterc                     t        | d      sy| j                  j                  ||      }| j                  j	                  ||       y)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)
        r[   N)r   r   rx   )rz   r0   build_connection_attributesr[   r   )rB   r   r   r   r   s        r(   record_connection_countz-RedisMetricsCollector.record_connection_count]  sN     t67!!==- > 
 	$$((U(Cr'   z{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                     t         j                  | j                  j                  vry| j                  j                  ddd|g      | _        y)z
        Initialize observable gauge for connection count metric.

        Args:
            callback: Callback function to retrieve connection counts
        Nz%db.client.connection.count.deprecatedrS   zThe number of connections that are currently in state described by the state attribute (deprecated - use db.client.connection.count instead)rG   rH   rI   	callbacks)r   r6   r,   r2   r+   create_observable_gaugerZ   rB   r   s     r(   init_connection_countz+RedisMetricsCollector.init_connection_countt  sO     ''t{{/H/HH
 !%

 B B8e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,   r2   	csc_itemsr+   r   r   s     r(   init_csc_itemsz$RedisMetricsCollector.init_csc_items  sL     ??$++";";;DNN;;)Oj	 < 
r'   c                     t        | d      sy| j                  j                  |      }| j                  j	                  d|       y)zo
        Record a connection timeout event.

        Args:
            pool_name: Connection pool name
        r]   Nr   rw   rx   )rz   r0   r   r]   r   rB   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
        rV   Nr   rx   )rz   r0   r   r   rV   record)rB   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   rx   )rz   r0   r   r_   r   )rB   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   r   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
        rc   N)rn   ro   r   )r   rp   rq   rs   r   rr   rx   )
rz   r,   should_track_commandr0   r{   r|   r}   r~   rc   r   )rB   r   r   rn   ro   r   r   rr   rp   rq   rs   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   rw   rx   )	rz   r0   r   valuer   r|   r~   r`   r   )rB   r   rr   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)
        rX   Nr   rw   rx   )rz   r0   r   r   rX   r   )rB   r   r   r   r   s        r(   !record_connection_relaxed_timeoutz7RedisMetricsCollector.record_connection_relaxed_timeout7  sS     t9:!!===X6H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
        rY   Nr   rw   rx   )rz   r0   r   rY   r   r   s      r(   record_connection_handoffz/RedisMetricsCollector.record_connection_handoffL  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
        re   N)r   r   r   rw   rx   )rz   r0   build_pubsub_message_attributesre   r   )rB   r   r   r   r   s        r(   record_pubsub_messagez+RedisMetricsCollector.record_pubsub_message^  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
        rh   N)r   r   rx   )rz   r0   build_streaming_attributesrh   r   )rB   r   r   r   r   r   s         r(   record_streaming_lagz*RedisMetricsCollector.record_streaming_lagx  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')
        rk   N)r   rw   rx   )rz   r0   build_csc_attributesrk   r   )rB   r   r   s      r(   record_csc_requestz(RedisMetricsCollector.record_csc_request  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
        rl   N)r   rx   )rz   r0   r   rl   r   )rB   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
        rm   Nrx   )rz   r0   r   rm   r   )rB   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,   rN   s    r(   __repr__zRedisMetricsCollector.__repr__  s    -djj\4;;-qQQr'   )rD   N)NNNNNNN)rw   )	NNNNNNNNN)NN)NNN)N)5r   r    r!   r"   
METER_NAMEMETER_VERSIONr   r   rC   r3   r7   r9   r5   r;   r=   r?   r   strint	Exceptionboolr   r   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   
 JM"9e "9Z "9H
( 
D
*



0 )-%).2+/*.(,&*,4 ,4 c],4 'sm	,4
 $C=,4 Y',4 !,4 d^,4\"@"@ "@ "	"@
 "@  "@H;89; 67; "	;< 	DD *D 	D
 
D. G


 



0

 

(: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   r   redis.observability.configr   r   redis.utilsr   r   	getLoggerr   r@   opentelemetry.metricsr   r.   r/   Counter	HistogramUpDownCounterr   r*   r&   r'   r(   <module>r      s       ; ;7<83
 
 
 ? <			8	$	+N.$ .$U
R U
R5  NGIEMs   0B B B 