B
    .l\P                 @   s
  d dl Z d dlmZ d dlZd dlZddlmZ ddlmZm	Z	m
Z
 ddlmZmZmZmZ ddlmZ ddlmZmZ e jd	kreZd
d Zdd ZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZ G dd deZ!dS )    N)Lock   )values)ExceptionCounterInprogressTrackerTimer)MetricMETRIC_LABEL_NAME_REMETRIC_NAME_RERESERVED_METRIC_LABEL_NAME_RE)REGISTRY)floatToGoStringINF)   c             C   s   d}|r||d 7 }|r$||d 7 }||7 }|rJ| d| sJ|d| 7 }|rb| dkrbtd| | dkr| dr|d d }|S )N _)infostatesetz2Metric name is of a type that cannot have a unit: counter_totali)endswith
ValueError)Zmetric_typename	namespace	subsystemunitZ	full_name r   8lib/python3.7/site-packages/prometheus_client/metrics.py_build_full_name   s    r   c             C   s\   t |}xN|D ]F}t|s(td| t|r>td| || jkrtd| qW |S )NzInvalid label metric name: zReserved label metric name: )tupler	   matchr   r   _reserved_labelnames)cls
labelnameslr   r   r   _validate_labelnames#   s    



r%   c               @   s   e Zd ZdZdZdd Zdd Zdd Zd	d
 Zdd Z	dddde
dfddZdd Zdd Zdd Zdd Zdd Zdd ZdS )MetricWrapperBaseNr   c             C   s   | j  p| j o| jS )N)_labelnames_labelvalues)selfr   r   r   _is_observable3   s    z MetricWrapperBase._is_observablec             C   s   | j o| j S )N)r'   r(   )r)   r   r   r   
_is_parent9   s    zMetricWrapperBase._is_parentc             C   s   t | j| j| j| jS )N)r   _name_documentation_type_unit)r)   r   r   r   _get_metric<   s    zMetricWrapperBase._get_metricc             C   s
   |   gS )N)r0   )r)   r   r   r   describe?   s    zMetricWrapperBase.describec             C   s:   |   }x*|  D ]\}}}|| j| || qW |gS )N)r0   _samplesZ
add_sampler,   )r)   metricsuffixlabelsvaluer   r   r   collectB   s    zMetricWrapperBase.collectr   c	       	      C   s   t | j||||| _t| || _t|p(d| _i | _|| _|| _	t
| jsZtd| j |  rpt | _i | _|  r|   | js|r||  d S )Nr   zInvalid metric name: )r   r.   r,   r%   r'   r   r(   _kwargsr-   r/   r
   r    r   r+   r   _lock_metricsr*   _metric_initregister)	r)   r   documentationr#   r   r   r   registrylabelvaluesr   r   r   __init__H   s     
zMetricWrapperBase.__init__c          	      s   | j std|  | jr6td| tt| j | jf |rF rFtd r~t t| j krdtdt fdd| j D }n,t|t| j krtdtdd |D }| jB || j	kr| j
| jf| j| j | j|d	| j| j	|< | j	| S Q R X d
S )ar  Return the child for the given labelset.

        All metrics can have labels, allowing grouping of related time series.
        Taking a counter as an example:

            from prometheus_client import Counter

            c = Counter('my_requests_total', 'HTTP Failures', ['method', 'endpoint'])
            c.labels('get', '/').inc()
            c.labels('post', '/submit').inc()

        Labels can also be provided as keyword arguments:

            from prometheus_client import Counter

            c = Counter('my_requests_total', 'HTTP Failures', ['method', 'endpoint'])
            c.labels(method='get', endpoint='/').inc()
            c.labels(method='post', endpoint='/submit').inc()

        See the best practices on [naming](http://prometheus.io/docs/practices/naming/)
        and [labels](http://prometheus.io/docs/practices/instrumentation/#use-labels).
        z,No label names were set when constructing %sz@%s already has labels set (%s); can not chain calls to .labels()z"Can't pass both *args and **kwargszIncorrect label namesc             3   s   | ]}t  | V  qd S )N)unicode).0r$   )labelkwargsr   r   	<genexpr>   s    z+MetricWrapperBase.labels.<locals>.<genexpr>zIncorrect label countc             s   s   | ]}t |V  qd S )N)rA   )rB   r$   r   r   r   rD      s    )r=   r#   r   r?   N)r'   r   r(   dictzipsortedr   lenr9   r:   	__class__r,   r-   r/   r8   )r)   r?   rC   r   )rC   r   r5   i   s2    
zMetricWrapperBase.labelsc          	   G   sj   | j std|  t|t| j kr:tdt| j |f tdd |D }| j | j|= W d Q R X d S )Nz,No label names were set when constructing %sz+Incorrect label count (expected %d, got %s)c             s   s   | ]}t |V  qd S )N)rA   )rB   r$   r   r   r   rD      s    z+MetricWrapperBase.remove.<locals>.<genexpr>)r'   r   rH   r   r9   r:   )r)   r?   r   r   r   remove   s    zMetricWrapperBase.removec             C   s   |   r|  S |  S d S )N)r+   _multi_samples_child_samples)r)   r   r   r   r2      s    zMetricWrapperBase._samplesc          	   c   sz   | j  | j }W d Q R X xX| D ]L\}}tt| j|}x2| D ]&\}}}|t|t|  |fV  qHW q&W d S )N)	r9   r:   copyitemslistrF   r'   r2   rE   )r)   Zmetricsr5   r3   Zseries_labelsr4   Zsample_labelsr6   r   r   r   rK      s    z MetricWrapperBase._multi_samplesc             C   s   t d|  d S )Nz*_child_samples() must be implemented by %r)NotImplementedError)r)   r   r   r   rL      s    z MetricWrapperBase._child_samplesc             C   s   t d|  dS )z
        Initialize the metric object as a child, i.e. when it has labels (if any) set.

        This is factored as a separate function to allow for deferred initialization.
        z(_metric_init() must be implemented by %rN)rP   )r)   r   r   r   r;      s    zMetricWrapperBase._metric_init)__name__
__module____qualname__r.   r!   r*   r+   r0   r1   r7   r   r@   r5   rJ   r2   rK   rL   r;   r   r   r   r   r&   /   s&   	7r&   c               @   s:   e Zd ZdZdZdd ZdddZefdd	Zd
d Z	dS )Counterar  A Counter tracks counts of events or running totals.

    Example use cases for Counters:
    - Number of requests processed
    - Number of items that were inserted into a queue
    - Total amount of data that a system has processed

    Counters can only go up (and be reset when the process restarts). If your use case can go down,
    you should use a Gauge instead.

    An example for a Counter:

        from prometheus_client import Counter

        c = Counter('my_failures_total', 'Description of counter')
        c.inc()     # Increment by 1
        c.inc(1.6)  # Increment by given value

    There are utilities to count exceptions raised:

        @c.count_exceptions()
        def f():
            pass

        with c.count_exceptions():
            pass

        # Count only one type of exception
        with c.count_exceptions(ValueError):
            pass
    r   c             C   s0   t | j| j| jd | j| j| _t | _d S )Nr   )	r   
ValueClassr.   r,   r'   r(   _valuetime_created)r)   r   r   r   r;      s    "zCounter._metric_initr   c             C   s    |dk rt d| j| dS )z&Increment counter by the given amount.r   z9Counters can only be incremented by non-negative amounts.N)r   rV   inc)r)   amountr   r   r   rY      s    zCounter.incc             C   s
   t | |S )zCount exceptions in a block of code or function.

        Can be used as a function decorator or context manager.
        Increments the counter when an exception of the given
        type is raised up out of the code.
        )r   )r)   Z	exceptionr   r   r   count_exceptions   s    zCounter.count_exceptionsc             C   s   di | j  fdi | jffS )Nr   rX   )rV   getrX   )r)   r   r   r   rL      s    zCounter._child_samplesN)r   )
rQ   rR   rS   __doc__r.   r;   rY   	Exceptionr[   rL   r   r   r   r   rT      s   
	rT   c                   s   e Zd ZdZdZedZddddeddf fdd		Zd
d Z	dddZ
dddZdd Zdd Zdd Zdd Zdd Zdd Z  ZS )Gaugea  Gauge metric, to report instantaneous values.

     Examples of Gauges include:
        - Inprogress requests
        - Number of items in a queue
        - Free memory
        - Total memory
        - Temperature

     Gauges can go both up and down.

        from prometheus_client import Gauge

        g = Gauge('my_inprogress_requests', 'Description of gauge')
        g.inc()      # Increment by 1
        g.dec(10)    # Decrement by given value
        g.set(4.2)   # Set to a given value

     There are utilities for common use cases:

        g.set_to_current_time()   # Set to current unixtime

        # Increment when entered, decrement when exited.
        @g.track_inprogress()
        def f():
            pass

        with g.track_inprogress():
            pass

     A Gauge can also take its value from a callback:

        d = Gauge('data_objects', 'Number of objects')
        my_dict = {}
        d.set_function(lambda: len(my_dict))
    Zgauge)minmaxZlivesumZliveallallr   r   Nrb   c
       
   
      sL   |	| _ |	| jkrtd|	 tt| j||||||||d | j | jd< d S )NzInvalid multiprocess mode: )r   r=   r#   r   r   r   r>   r?   multiprocess_mode)_multiprocess_mode_MULTIPROC_MODESr   superr_   r@   r8   )
r)   r   r=   r#   r   r   r   r>   r?   rc   )rI   r   r   r@   *  s    

zGauge.__init__c             C   s(   t j| j| j| j| j| j| jd| _d S )N)rc   )r   rU   r.   r,   r'   r(   rd   rV   )r)   r   r   r   r;   D  s    zGauge._metric_initr   c             C   s   | j | dS )z$Increment gauge by the given amount.N)rV   rY   )r)   rZ   r   r   r   rY   J  s    z	Gauge.incc             C   s   | j |  dS )z$Decrement gauge by the given amount.N)rV   rY   )r)   rZ   r   r   r   decN  s    z	Gauge.decc             C   s   | j t| dS )zSet gauge to the given value.N)rV   setfloat)r)   r6   r   r   r   rh   R  s    z	Gauge.setc             C   s   |  t  dS )z"Set gauge to the current unixtime.N)rh   rW   )r)   r   r   r   set_to_current_timeV  s    zGauge.set_to_current_timec             C   s   t | S )zTrack inprogress blocks of code or functions.

        Can be used as a function decorator or context manager.
        Increments the gauge when the code is entered,
        and decrements when it is exited.
        )r   )r)   r   r   r   track_inprogressZ  s    zGauge.track_inprogressc             C   s
   t | jS )zTime a block of code or function, and set the duration in seconds.

        Can be used as a function decorator or context manager.
        )r   rh   )r)   r   r   r   rW   c  s    z
Gauge.timec                s    fdd}t || | _dS )zCall the provided function to return the Gauge value.

        The function must return a float, and may be called from
        multiple threads. All other methods of the Gauge become NOOPs.
        c                s   di t   ffS )Nr   )ri   )r)   )fr   r   samplesq  s    z#Gauge.set_function.<locals>.samplesN)types
MethodTyperL   )r)   rl   rm   r   )rl   r   set_functionj  s    zGauge.set_functionc             C   s   di | j  ffS )Nr   )rV   r\   )r)   r   r   r   rL   v  s    zGauge._child_samples)r   )r   )rQ   rR   rS   r]   r.   	frozensetre   r   r@   r;   rY   rg   rh   rj   rk   rW   rp   rL   __classcell__r   r   )rI   r   r_     s&   $

	r_   c               @   s:   e Zd ZdZdZdgZdd Zdd Zdd	 Zd
d Z	dS )Summarya  A Summary tracks the size and number of events.

    Example use cases for Summaries:
    - Response latency
    - Request size

    Example for a Summary:

        from prometheus_client import Summary

        s = Summary('request_size_bytes', 'Request size (bytes)')
        s.observe(512)  # Observe 512 (bytes)

    Example for a Summary using time:

        from prometheus_client import Summary

        REQUEST_TIME = Summary('response_latency_seconds', 'Response latency (seconds)')

        @REQUEST_TIME.time()
        def create_response(request):
          """A dummy function"""
          time.sleep(1)

    Example for using the same Summary object as a context manager:

        with REQUEST_TIME.time():
            pass  # Logic to be timed
    ZsummaryZquantilec             C   sR   t | j| j| jd | j| j| _t | j| j| jd | j| j| _t | _	d S )N_count_sum)
r   rU   r.   r,   r'   r(   rt   ru   rW   rX   )r)   r   r   r   r;     s    ""zSummary._metric_initc             C   s   | j d | j| dS )zObserve the given amount.r   N)rt   rY   ru   )r)   rZ   r   r   r   observe  s    zSummary.observec             C   s
   t | jS )zTime a block of code or function, and observe the duration in seconds.

        Can be used as a function decorator or context manager.
        )r   rv   )r)   r   r   r   rW     s    zSummary.timec             C   s*   di | j  fdi | j fdi | jffS )Nrt   ru   rX   )rt   r\   ru   rX   )r)   r   r   r   rL     s    zSummary._child_samplesN)
rQ   rR   rS   r]   r.   r!   r;   rv   rW   rL   r   r   r   r   rs   z  s   rs   c                   s   e Zd ZdZdZdgZdddddd	d
dddddddefZddddedef fdd	Z	dd Z
dd Zdd Zdd Zdd  Z  ZS )!	Histograma  A Histogram tracks the size and number of events in buckets.

    You can use Histograms for aggregatable calculation of quantiles.

    Example use cases:
    - Response latency
    - Request size

    Example for a Histogram:

        from prometheus_client import Histogram

        h = Histogram('request_size_bytes', 'Request size (bytes)')
        h.observe(512)  # Observe 512 (bytes)

    Example for a Histogram using time:

        from prometheus_client import Histogram

        REQUEST_TIME = Histogram('response_latency_seconds', 'Response latency (seconds)')

        @REQUEST_TIME.time()
        def create_response(request):
          """A dummy function"""
          time.sleep(1)

    Example of using the same Histogram object as a context manager:

        with REQUEST_TIME.time():
            pass  # Logic to be timed

    The default buckets are intended to cover a typical web/rpc request from milliseconds to seconds.
    They can be overridden by passing `buckets` keyword argument to `Histogram`.
    Z	histogramleg{Gzt?g{Gz?g?g?g333333?g?g      ?g      ?g      ?g      ?g      @g      @g      @g      $@r   r   Nc
       
   
      s8   |  |	 tt| j||||||||d |	| jd< d S )N)r   r=   r#   r   r   r   r>   r?   buckets)_prepare_bucketsrf   rw   r@   r8   )
r)   r   r=   r#   r   r   r   r>   r?   ry   )rI   r   r   r@     s    

zHistogram.__init__c             C   sZ   dd |D }|t |kr"td|r<|d tkr<|t t|dk rPtd|| _d S )Nc             S   s   g | ]}t |qS r   )ri   )rB   br   r   r   
<listcomp>  s    z.Histogram._prepare_buckets.<locals>.<listcomp>zBuckets not in sorted order   zMust have at least two buckets)rG   r   r   appendrH   _upper_bounds)r)   ry   r   r   r   rz     s    
zHistogram._prepare_bucketsc             C   s   g | _ t | _| jd }t| j| j| jd | j| j| _	x>| j
D ]4}| j t| j| j| jd || jt|f  qDW d S )N)rx   ru   _bucket)_bucketsrW   rX   r'   r   rU   r.   r,   r(   ru   r   r   r   )r)   Zbucket_labelnamesr{   r   r   r   r;     s    

"
zHistogram._metric_initc             C   sB   | j | x0t| jD ]"\}}||kr| j| d P qW dS )zObserve the given amount.r   N)ru   rY   	enumerater   r   )r)   rZ   iboundr   r   r   rv     s
    zHistogram.observec             C   s
   t | jS )zTime a block of code or function, and observe the duration in seconds.

        Can be used as a function decorator or context manager.
        )r   rv   )r)   r   r   r   rW     s    zHistogram.timec             C   s   g }d}x@t | jD ]2\}}|| j|  7 }|ddt|i|f qW |di |f |di | j f |di | jf t|S )Nr   r   rx   rt   ru   rX   )	r   r   r   r\   r   r   ru   rX   r   )r)   rm   Zaccr   r   r   r   r   rL     s    zHistogram._child_samples)rQ   rR   rS   r]   r.   r!   r   ZDEFAULT_BUCKETSr   r@   rz   r;   rv   rW   rL   rr   r   r   )rI   r   rw     s    ""rw   c               @   s,   e Zd ZdZdZdd Zdd Zdd Zd	S )
Infoa  Info metric, key-value pairs.

     Examples of Info include:
        - Build information
        - Version information
        - Potential target metadata

     Example usage:
        from prometheus_client import Info

        i = Info('my_build', 'Description of info')
        i.info({'version': '1.2.3', 'buildhost': 'foo@bar'})

     Info metrics do not work in multiprocess mode.
    r   c             C   s   t | j| _t | _i | _d S )N)rh   r'   _labelname_setr   r9   rV   )r)   r   r   r   r;   9  s    zInfo._metric_initc          	   C   sB   | j | r"td| j|f | j t|| _W dQ R X dS )zSet info metric.z8Overlapping labels for Info metric, metric: %s child: %sN)r   intersectionkeysr   r'   r9   rE   rV   )r)   valr   r   r   r   >  s
    z	Info.infoc          	   C   s    | j  d| jdffS Q R X d S )NZ_infog      ?)r9   rV   )r)   r   r   r   rL   F  s    zInfo._child_samplesN)rQ   rR   rS   r]   r.   r;   r   rL   r   r   r   r   r   '  s
   r   c                   sL   e Zd ZdZdZddddeddf fdd	Zdd	 Zd
d Zdd Z	  Z
S )Enuma`  Enum metric, which of a set of states is true.

     Example usage:
        from prometheus_client import Enum

        e = Enum('task_state', 'Description of enum',
          states=['starting', 'running', 'stopped'])
        e.state('running')

     The first listed state will be the default.
     Enum metrics do not work in multiprocess mode.
    r   r   r   Nc
       
   
      s\   t t| j||||||||d ||kr6td|f |	sHtd|f |	 | jd< | _d S )N)r   r=   r#   r   r   r   r>   r?   z&Overlapping labels for Enum metric: %sz&No states provided for Enum metric: %sstates)rf   r   r@   r   r8   _states)
r)   r   r=   r#   r   r   r   r>   r?   r   )rI   r   r   r@   Z  s    
zEnum.__init__c             C   s   d| _ t | _d S )Nr   )rV   r   r9   )r)   r   r   r   r;   u  s    zEnum._metric_initc          	   C   s$   | j  | j|| _W dQ R X dS )zSet enum metric state.N)r9   r   indexrV   )r)   stater   r   r   r   y  s    z
Enum.statec          	      s*    j   fddt jD S Q R X d S )Nc                s.   g | ]&\}}d  j |i| jkr$dndfqS )r   r   r   )r,   rV   )rB   r   s)r)   r   r   r|     s   z'Enum._child_samples.<locals>.<listcomp>)r9   r   r   )r)   r   )r)   r   rL   ~  s    
zEnum._child_samples)rQ   rR   rS   r]   r.   r   r@   r;   r   rL   rr   r   r   )rI   r   r   K  s   r   )"sysZ	threadingr   rW   rn   r   r   Zcontext_managersr   r   r   Zmetrics_corer   r	   r
   r   r>   r   Zutilsr   r   version_infostrrA   r   r%   objectr&   rT   r_   rs   rw   r   r   r   r   r   r   <module>   s(   
 <y9t$