o
    iU}                     @   s  d dl mZ d dlZd dlZd dlZd dlZd dlZ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 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 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" 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- ddl,m.Z. ddl,m/Z/ ddl,m0Z0 ddl1m2Z2 ddl1m3Z3 ddl1m4Z4 ddl1m5Z5 ddl6m7Z7 ddl8m9Z9 dd l8m:Z: dd!l8m;Z; ee<Z=G d"d# d#e>Z?G d$d% d%Z@G d&d' d'e ZAdS )(    N)Any)Optional)Union)endpoint_collection)
get_logger)is_user_code)config)get_connection   )atexit)forksafe   )JSONEncoderV2)PeriodicService)get_runtime_id)ServiceStatus)	StopWatch)version   )modules)TELEMETRY_APM_PRODUCT)TELEMETRY_EVENT_TYPE)TELEMETRY_LOG_LEVEL)TELEMETRY_NAMESPACE)get_application)get_host_info)get_python_config_vars)update_imported_dependencies)DDTelemetryErrorHandler)MetricNamespace)MetricTagType)
MetricTypec                   @   s   e Zd Zdd Zdd ZdS )LogDatac                 C   s$   t | d | d | d| dfS Nmessageleveltagsstack_trace)hashgetself r,   U/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/internal/telemetry/writer.py__hash__/   s   $zLogData.__hash__c                 C   sH   | d |d ko#| d |d ko#|  d| dko#|  d| dkS r#   )r)   )r+   otherr,   r,   r-   __eq__2   s   zLogData.__eq__N)__name__
__module____qualname__r.   r0   r,   r,   r,   r-   r"   .   s    r"   c                   @   s   e Zd ZdZdZdeddfddZedefdd	Z	d
e
dedeej fddZd
e
de
fddZdedefddZdededefddZdS )_TelemetryClientz#telemetry/proxy/api/v2/apmtelemetryzapi/v2/apmtelemetry	agentlessreturnNc                 C   sZ   |  tj|| _| || _t | _|| _ddt	d| _
|r)tjr+tj| j
d< d S d S d S )Nzapplication/jsonpython)zContent-TypezDD-Client-Library-LanguagezDD-Client-Library-Versionz
dd-api-key)get_hostr   SITE_telemetry_urlget_endpoint	_endpointr   _encoder
_agentlesstracer_version_headersAPI_KEYr+   r5   r,   r,   r-   __init__?   s   
z_TelemetryClient.__init__c                 C   s   t | j| jS N)parseurljoinr:   r<   r*   r,   r,   r-   urlN   s   z_TelemetryClient.urlrequestpayload_typec           
   
   C   s  d}d}z{zS| j |\}}| |}t }t| j}|d| j|| | }W d   n1 s3w   Y  |j	dk rNt
dt|| | j||j	 n	t
d| j|j	 W n tyt }	 zt
d| jt|	 W Y d}	~	nd}	~	ww W |dur~|  |S |dur|  w w )z,Sends a telemetry request to the trace agentNPOSTi,  zRInstrumentation Telemetry sent %d bytes in %.5fs to %s. Event(s): %s. Response: %sz<Failed to send Instrumentation Telemetry to %s. Response: %sz9Failed to send Instrumentation Telemetry to %s. Error: %s)r=   encodeget_headersr   r	   r:   rH   r<   getresponsestatuslogdebuglenelapsedrG   	Exceptionstrclose)
r+   rH   rI   respconnrb_json_headersswer,   r,   r-   
send_eventR   s@   



	 
z_TelemetryClient.send_eventc                 C   s2   | j  }|d |d< |d |d< |d |d< |S )z(Get all telemetry api v2 request headersrP   zDD-Telemetry-Debug-Enabledrequest_typezDD-Telemetry-Request-Typeapi_versionzDD-Telemetry-API-Version)r@   copy)r+   rH   rZ   r,   r,   r-   rL   o   s
   
z_TelemetryClient.get_headersc                 C   s   |r| j S | jS rD   )AGENTLESS_ENDPOINT_V2AGENT_ENDPOINTrB   r,   r,   r-   r;   w   s   z_TelemetryClient.get_endpointsitec                 C   s.   |st jS |dkrdS |dkrdS d| dS )Nzdatad0g.comz(https://all-http-intake.logs.datad0g.comzdatadoghq.euz5https://instrumentation-telemetry-intake.datadoghq.euz)https://instrumentation-telemetry-intake./)agent_configtrace_agent_url)r+   rc   r5   r,   r,   r-   r8   z   s   z_TelemetryClient.get_host)r1   r2   r3   rb   ra   boolrC   propertyrT   rG   dictr   httplibHTTPResponser]   rL   r;   r8   r,   r,   r,   r-   r4   ;   s    r4   c                       s  e Zd ZdZedZedZee	j
Ze Zdqdedee ddf fdd	Zdefd
dZdeeeef ee f dedeeef fddZdrddZdsdeddfddZdefddZ			dtdededee dee deddfddZdsdedeeeef  fd d!Zdeeef fd"d#Zdee fd$d%Z dee fd&d'Z!deeeeef   fd(d)Z"deeeef  fd*d+Z#deeef fd,d-Z$d.ed/eddfd0d1Z%	2	dud3ed4ed5ed6ee ddf
d7d8Z&d9ee'eeef  ddfd:d;Z(dvd<ed=ed>ee ddfd?d@Z)dAedBee*e'df ddfdCdDZ+dBee*e'f dee fdEdFZ,dGedefdHdIZ-	dwdJe.dKedLe/d>ee0 ddf
dMdNZ1	dwdJe.dKedLe/d>ee0 ddf
dOdPZ2	dxdJe.dKedLe3d>ee0 ddf
dQdRZ4	dwdJe.dKedLe/d>ee0 ddf
dSdTZ5de6eeef  fdUdVZ7drdWdXZ8dydZed[eddfd\d]Z9drd^d_Z:drd`daZ;dee fdbdcZ<drdddeZ=drdfdgZ>dsdheddf fdidjZ?drdkdlZ@drdmdnZAdrdodpZB  ZCS )zTelemetryWriterz}
    Submits Instrumentation Telemetry events to the datadog agent.
    Supports v2 of the instrumentation telemetry api
    r   TNis_periodicr5   r6   c                    sf  t t| jttjdd ttj| j d | _d| _	|| _
t | _t | _t | _g | _g | _g | _g | _t | _t | _dd tD | _i | _t | _tj| _d| _tj | _!tj"| _#|d u ritj$phtj%dv}|rvtj%svt&'d	 d| _#t(|| _)| j#rt*+| j, t-+| j. | /  | 0  tj1r| 2  }r| j3| 4|t5j6 t7d
8t9|  d S d S )N
   )intervalr   r   c                 S   s   i | ]}|j d qS )Fvalue).0productr,   r,   r-   
<dictcomp>       z,TelemetryWriter.__init__.<locals>.<dictcomp>F)N z?Disabling telemetry: no Datadog API key found in agentless modeddtrace):superrl   rC   minr   HEARTBEAT_INTERVALintro   _periodic_threshold_periodic_count_is_periodicri   _integrations_queuer   
_namespaceset_logs_events_queue_queued_configs_sent_configs_configuration_queue_imported_dependencies_modules_already_importedr   _product_enablement_previous_product_enablementtime	monotonic_extended_timeEXTENDED_HEARTBEAT_INTERVAL_extended_heartbeat_intervalstartedDEBUG_debugTELEMETRY_ENABLED_enabledAGENTLESS_MODErA   rO   rP   r4   _clientr   register_fork_writerr   app_shutdowninstall_excepthookenableFORCE_START_report_app_startedappend
_get_eventr   STARTEDr   
addHandlerr   )r+   rm   r5   app_started	__class__r,   r-   rC      sF   



zTelemetryWriter.__init__c                 C   s8   | j sdS | jtjkrdS | jr|   dS tj| _dS )z
        Enable the instrumentation telemetry collection service. If the service has already been
        activated before, this method does nothing. Use ``disable`` to turn off the telemetry collection service.
        FT)r   rN   r   RUNNINGr~   startr*   r,   r,   r-   r      s   zTelemetryWriter.enablepayloadrI   c                 C   s   ||j dS )N)r   r^   rp   )r+   r   rI   r,   r,   r-   r      s   zTelemetryWriter._get_eventc                 C   s   d| _ |   dS )z
        Disable the telemetry collection service and drop the existing integrations and events
        Once disabled, telemetry collection can not be re-enabled.
        FN)r   reset_queuesr*   r,   r,   r-   disable   s   zTelemetryWriter.disableenabledc                 C   s   | j j|krd S t|| _ d S rD   )r   r>   r4   )r+   r   r,   r,   r-   enable_agentless_client   s   z'TelemetryWriter.enable_agentless_clientc                 C   s   | j o| jduo| jtju S )z?Returns True when the telemetry writer worker thread is runningN)r~   _workerrN   r   r   r*   r,   r,   r-   _is_running   s   zTelemetryWriter._is_runningrv   integration_namepatchedauto_patched	error_msgr   c                 C   s   |   sdS | jJ || jvrd|i| j|< || j| d< || j| d< |dur/|| j| d< |durK|dk| j| d< || j| d< W d   dS W d   dS 1 sVw   Y  dS )	z
        Creates and queues the names and settings of a patched module

        :param str integration_name: name of patched module
        :param bool auto_enabled: True if module is enabled in _monkey.PATCH_MODULES
        Nnamer   r   auto_enabledrv   
compatibleerror)r   _service_lockr   )r+   r   r   r   r   r   r,   r,   r-   add_integration   s   

"zTelemetryWriter.add_integrationregister_app_shutdownc                 C   sb   t  s| jr	dS d| _| t  |  |  d}tjs$tj	s$tj
r/tjtj	tj
d|d< |S )z-Sent when TelemetryWriter is enabled or forksNT)configurationproducts)
install_idinstall_typeinstall_timeinstall_signature)r   is_fork_childr   add_configurationsr   _report_configurations_report_productsr   
INSTALL_IDINSTALL_TYPEINSTALL_TIME)r+   r   r   r,   r,   r-   r     s   
z#TelemetryWriter._report_app_startedc                 C   sT   i }t  | j | jkr(| j|d< tjr dd | j D |d< |  j| j7  _|S )a8  Report a heartbeat to keep RC connections alive.

        Extended heartbeats (non-empty payload) include configurations and dependencies;
        regular heartbeats return an empty payload. Callers should queue this after
        configuration and dependencies events so values are accurately reported.
        configurationsc                 S   s   g | ]	\}}||d qS ))r   r   r,   )rr   r   r   r,   r,   r-   
<listcomp>7  s    z5TelemetryWriter._report_heartbeat.<locals>.<listcomp>dependencies)	r   r   r   r   r   r   DEPENDENCY_COLLECTIONr   items)r+   r   r,   r,   r-   _report_heartbeat,  s   

z!TelemetryWriter._report_heartbeatc                 C   sB   | j  t| j }t | _W d   |S 1 sw   Y  |S )z5Flushes and returns a list of all queued integrationsN)r   listr   valuesri   )r+   integrationsr,   r,   r-   _report_integrations=  s   

z$TelemetryWriter._report_integrationsc                 C   sD   | j  | j}| j| g | _W d   |S 1 sw   Y  |S )z7Flushes and returns a list of all queued configurationsN)r   r   r   extend)r+   r   r,   r,   r-   r   D  s   
z&TelemetryWriter._report_configurationsc                 C   sh   t jr| jsdS | j t| j}|s	 W d   dS t| j|W  d   S 1 s-w   Y  dS )z>Adds events to report imports done since the last periodic runN)	r   r   r   r   r   get_newly_imported_modulesr   r   r   )r+   newly_imported_depsr,   r,   r-   _report_dependenciesL  s   
$z$TelemetryWriter._report_dependenciesc                 C   sl   ddl m  m  m} |jjr| jsdS tjsdS | j	 t
|jjW  d   S 1 s/w   Y  dS )z[Adds a Telemetry event which sends the list of HTTP endpoints found at startup to the agentr   N)ddtrace.internal.settings.asminternalsettingsasmr   !_api_security_endpoint_collectionr   r   	endpointsr   flush'_api_security_endpoint_collection_limit)r+   asm_config_moduler,   r,   r-   _report_endpointsW  s   $z!TelemetryWriter._report_endpointsc                 C   s`   | j # | j }|D ]	\}}|| j|< qi | _dd |D W  d   S 1 s)w   Y  dS )zEAdds a Telemetry event which reports the enablement of an APM productc                 S   s   i | ]
\}}|t |d qS ))r   r   )r?   )rr   rs   rN   r,   r,   r-   rt   k  s    z4TelemetryWriter._report_products.<locals>.<dictcomp>N)r   r   r   r   )r+   r   rs   rN   r,   r,   r-   r   d  s   
$z TelemetryWriter._report_productsrs   rN   c                 C   sV   | j  | j||kr|| j|< W d   dS W d   dS 1 s$w   Y  dS )z#Updates the product enablement dictN)r   r   r)   r   )r+   rs   rN   r,   r,   r-   product_activatedm  s   "z!TelemetryWriter.product_activatedunknownconfiguration_nameconfiguration_valueorigin	config_idc                 C   s   t |trddd | D }n"t |ttfr$ddd |D }nt |tttt	t
dfs4t|}|||d}|r@||d< | j t| j|d< | j| W d   dS 1 s\w   Y  dS )	z=Creates and queues the name, origin, value of a configuration,c                 s   s&    | ]\}}d  |t|fV  qdS ):N)joinrT   rr   kvr,   r,   r-   	<genexpr>}  s   $ z4TelemetryWriter.add_configuration.<locals>.<genexpr>c                 s   s    | ]}t |V  qd S rD   )rT   )rr   r   r,   r,   r-   r     s    N)r   r   rq   r   seq_id)
isinstanceri   r   r   r   tuplerg   rT   r{   floattyper   next_sequence_configurationsr   r   )r+   r   r   r   r   r   r,   r,   r-   add_configurationt  s    
"z!TelemetryWriter.add_configurationconfiguration_listc              	   C   sX   | j  |D ]\}}}| j|||t| jd qW d   dS 1 s%w   Y  dS )z+Creates and queues a list of configurations)r   r   rq   r   N)r   r   r   r   r   )r+   r   r   rq   r   r,   r,   r-   r     s   "z"TelemetryWriter.add_configurationsr$   r'   r&   c                 C   sn   |du ri }|   r5t||jtt d}|r'ddd | D |d< |r-||d< | j| dS dS )z
        Queues log. This event is meant to send library logs to Datadog's backend through the Telemetry intake.
        This will make support cycles easier and ensure we know about potentially silent issues in libraries.
        N)r$   r%   tracer_timer   c                 S   s$   g | ]\}}d |t | f qS )z%s:%s)rT   lowerr   r,   r,   r-   r     s   $ z+TelemetryWriter.add_log.<locals>.<listcomp>r&   r'   )	r   r"   rq   r{   r   r   r   r   add)r+   r%   r$   r'   r&   datar,   r,   r-   add_log  s   
zTelemetryWriter.add_logmsgexcc                 C   s   t jrS|d u r	d n| |}d}z|d ur+t|tr&t|dkr&|d j}nt|j}W n ty>   t	j
d|fdd Y nw | jtj||d urJ|ndd|id	 d S d S )
Nr   r
   r   z/Failed to extract error type from exception: %rT)exc_inforv   
error_type)r'   r&   )r   LOG_COLLECTION_ENABLED_format_stack_tracer   r   rQ   r1   r   rS   rO   rP   r   r   ERROR)r+   r   r   r'   r   r,   r,   r-   add_error_log  s(   

zTelemetryWriter.add_error_logc              	   C   s   t |trt|dkr|\}}}nt||t|dd }}}|s#d S t|}dg}|dd  D ]-\}}}	}
t|rF|d |d q1| 	|}d| d| d	|	 d
|
 }|| q1|rn||j
 d|j d d|S )Nr
   __traceback__z"Traceback (most recent call last):iz  <REDACTED>z    <REDACTED>z  File "z", line z, in z
    .z: <REDACTED>
)r   r   rQ   r   getattr	traceback
extract_tbr   r   _format_file_pathr2   r1   r   )r+   r   exc_typerY   exc_tracebacktbformatted_tbfilenamelinenofuncnamesrclinerelative_filenameformatted_liner,   r,   r-   r     s"   



z#TelemetryWriter._format_stack_tracer  c                 C   s|   z3d|v r| ddd dW S d|v r1d| ddd v r.| ddd  ddd W S dW S W dS  ty=   Y dS w )Nzsite-packagesr   rd   z
lib/pythonpython_stdlibz
<REDACTED>)splitlstrip
ValueError)r+   r  r,   r,   r-   r    s   z!TelemetryWriter._format_file_path	namespacer   rq   c                 C   6   | j tjks
|  r| jtj|t||| dS dS )z%
        Queues gauge metric
        N)	rN   r   r   r   r   
add_metricr!   GAUGErT   r+   r  r   rq   r&   r,   r,   r-   add_gauge_metric     z TelemetryWriter.add_gauge_metricc                 C   r  )z$
        Queues rate metric
        N)	rN   r   r   r   r   r  r!   RATErT   r  r,   r,   r-   add_rate_metric   r  zTelemetryWriter.add_rate_metricc                 C   r  )z%
        Queues count metric
        N)	rN   r   r   r   r   r  r!   COUNTrT   r  r,   r,   r-   add_count_metric  r  z TelemetryWriter.add_count_metricc                 C   r  )z-
        Queues distributions metric
        N)	rN   r   r   r   r   r  r!   DISTRIBUTIONrT   r  r,   r,   r-   add_distribution_metric  r  z'TelemetryWriter.add_distribution_metricc                 C   s:   | j  | j}t | _W d    |S 1 sw   Y  |S rD   )r   r   r   )r+   logsr,   r,   r-   _report_logs-  s   

zTelemetryWriter._report_logsc                 C   s   ddl m} |d d S )Nr   )coreztelemetry.periodic)ddtrace.internalr%  dispatch)r+   r%  r,   r,   r-   	_dispatch3  s   zTelemetryWriter._dispatchFforce_flushshutting_downc              
   C   sh  g }| j t| j }r-| D ]\}}| D ]\}}|r+|| ||d| qq|   }	rA|| dt|	it	j
 | jr`|s`| j| jk r]|  jd7  _|r[| j| dS d| _|   }
rp| |
t	jg| }|   }r|| d|it	j |   }r|| d|it	j |   }r|| |t	j |   }r|| d|it	j |   }r|| d	|it	j |rt s|| i t	j |   }r|| |t	j  n
|| |t	j! | "  }r|| d
#dd |D }t$t%% t& dt'| j(| j)t*t+j,t+j-t+j.t/ |t	j0j1d	}| 2  | j34|| dS )a  Process and send telemetry events in batches.

        This method handles the periodic collection and sending of telemetry data with two main timing intervals:
        1. Metrics collection interval (10 seconds by default): Collects metrics and logs
        2. Heartbeat interval (60 seconds by default): Sends all collected data to the telemetry endpoint

        The method follows this flow:
        1. Collects metrics and logs that have accumulated since last collection
        2. If not at heartbeat interval and not force_flush:
           - Queues the metrics and logs for future sending
           - Returns early
        3. At heartbeat interval or force_flush:
           - Collects app status (started, product changes)
           - Collects integration changes
           - Collects configuration changes
           - Collects dependency changes
           - Collects stored events (ex: metrics and logs)
           - Sends everything as a single batched request

        Args:
            force_flush: If True, bypasses the heartbeat interval check and sends immediately
            shutting_down: If True, includes app-closing event in the batch

        Note:
            - Metrics are collected every 10 seconds to ensure accurate time-based data
            - All data is sent in a single batch every 60 seconds to minimize network overhead
            - A heartbeat event is always included to keep RC connections alive
            - Multiple event types are combined into a single message-batch request
        )r  seriesr#  r   Nr   r   r   r   r   z, c                 S   s   g | ]}|d  qS )r^   r,   )rr   eventr,   r,   r-   r     ru   z,TelemetryWriter.periodic.<locals>.<listcomp>v2)	r   
runtime_idr_   r   rP   applicationhostr   r^   )5r   r   r   ro   r   r   r   r$  r   r   LOGSr~   r}   r|   r   r   r   r   r   PRODUCT_CHANGEr   INTEGRATIONS_CHANGEr   	ENDPOINTSr   CLIENT_CONFIGURATION_CHANGEr   DEPENDENCIES_LOADEDr   r   SHUTDOWNr   EXTENDED_HEARTBEAT	HEARTBEAT_report_eventsr   r{   r   r   r   _sequence_payloadsr   r   r   SERVICEVERSIONENVr   MESSAGE_BATCHrq   r(  r   r]   )r+   r)  r*  eventsnamespace_metricsrI   
namespacesr  metricsr#  app_started_payloadr   intsr   configsdepsheartbeat_payloadqueued_eventspayload_typesbatch_eventr,   r,   r-   periodic9  sb   


zTelemetryWriter.periodicc                 C   s    | j r
| jddd |   d S )NT)r)  r*  )r   rL  r   r*   r,   r,   r-   r     s   zTelemetryWriter.app_shutdownc                 C   s6   g | _ t | _| j  t | _i | _g | _g | _	d S rD   )
r   ri   r   r   r   r   r   r   r   r   r*   r,   r,   r-   r     s   

zTelemetryWriter.reset_queuesc                 C   s8   | j  | j}g | _W d   |S 1 sw   Y  |S )z1Flushes and returns a list of all telemtery eventN)r   r   )r+   r@  r,   r,   r-   r:    s   
zTelemetryWriter._report_eventsc                 C   s   |    d S rD   )r   r*   r,   r,   r-   r     s   zTelemetryWriter._fork_writerc                 C   s   t d| _t d| _d S )Nr   )	itertoolscountr;  r   r*   r,   r,   r-   _restart_sequence  s   z!TelemetryWriter._restart_sequencer   c                    s.   t t| j|i | |r| jdd d S d S )Nr   )timeout)rx   rl   _stop_servicer   )r+   r   argskwargsr   r,   r-   rQ    s   zTelemetryWriter._stop_servicec                 C   s@  |d ur|}|j r|j }|j s	|jjj}|jjj}d|v r&| d|d |f |tjj	}d|v rd|v r|
d}|
d}	|d |	krt|d |	kr||	d  }
d|v rb|
d}||d  }
| tjddd	|
fd
|jff d||t|}| j|
d|d | d }r| j| |tj |   t|||S )Nzddtrace/z%Unhandled exception from ddtrace coderw   contribr   r   r   integration_errorsr   r   z{}:{} {}T)r   F)tb_nexttb_framef_codeco_firstlinenoco_filenamer   r  ospathsepindexrQ   r   r   TRACERSr1   formatrT   r   r   r   r   r   r   r   r   rl   _ORIGINAL_EXCEPTHOOK)r+   tprq   root_tracebackr  r  r  	dir_partsddtrace_indexcontrib_indexr   internal_indexr   r   r,   r,   r-   _telemetry_excepthook  s<   




z%TelemetryWriter._telemetry_excepthookc                 C   s   | j t_dS )zOInstall a hook that intercepts unhandled exception and send metrics about them.N)rh  sys
excepthookr*   r,   r,   r-   r        z"TelemetryWriter.install_excepthookc                 C   s   t jt_dS )z(Uninstall the global tracer except hook.N)rl   ra  ri  rj  r*   r,   r,   r-   uninstall_excepthook  rk  z$TelemetryWriter.uninstall_excepthook)TN)r6   N)T)NNrv   )r   N)rv   NrD   )r   N)FF)Dr1   r2   r3   __doc__rM  rN  r;  r   staticmethodri  rj  ra  r[  getcwdCWDrg   r   rC   r   r   ri   rT   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   BaseExceptionr   r   r  r   r   r    r  r  r{   r   r"  r   r$  r(  rL  r   r   r:  r   rO  rQ  rh  r   rl  __classcell__r,   r,   r   r-   rl      s    


 7



  	
   





d
	



+rl   )Bhttp.clientclientrj   rM  r[  ri  r   r  typingr   r   r   urllib.parserE   ddtrace.internal.endpointsr   ddtrace.internal.loggerr   ddtrace.internal.packagesr    ddtrace.internal.settings._agentr   re   $ddtrace.internal.settings._telemetryddtrace.internal.utils.httpr	   r   r   r   encodingr   rL  r   runtimer   servicer   
utils.timer   utils.versionr   r?   rv   r   	constantsr   r   r   r   r   r   r   r   r   loggingr   metrics_namespacesr   r    r!   r1   rO   ri   r"   r4   rl   r,   r,   r,   r-   <module>   sR   I