Skip to content

Commit

Permalink
Merge pull request #3 from claws/add_decorator_tests
Browse files Browse the repository at this point in the history
decorators test and docs cleanup
  • Loading branch information
claws committed Aug 5, 2016
2 parents cdf41a2 + fb0fd90 commit 5e7ed51
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 51 deletions.
2 changes: 1 addition & 1 deletion aioprometheus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
from .registry import Registry, CollectorRegistry
from .service import Service

__version__ = "16.08.03"
__version__ = "16.08.05"
33 changes: 26 additions & 7 deletions aioprometheus/collectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,19 @@ def set_value(self, labels: LabelsType, value: NumericValueType) -> None:
self.values[labels] = value

def get_value(self, labels: LabelsType) -> NumericValueType:
''' Gets a value in the container, exception if isn't present '''
''' Gets a value in the container.
:raises: KeyError if an item with matching labels is not present.
'''
return self.values[labels]

def get(self, labels: LabelsType) -> NumericValueType:
''' Handy alias '''
''' Gets a value in the container.
Handy alias for `get_value`.
:raises: KeyError if an item with matching labels is not present.
'''
return self.get_value(labels)

def _label_names_correct(self, labels: LabelsType) -> bool:
Expand Down Expand Up @@ -180,7 +188,10 @@ class Counter(Collector):
kind = MetricsTypes.counter

def get(self, labels: LabelsType) -> NumericValueType:
''' Get gets the counter of an arbitrary group of labels '''
''' Get gets the Counter value matching an arbitrary group of labels.
:raises: KeyError if an item with matching labels is not present.
'''
return self.get_value(labels)

def set(self, labels: LabelsType, value: NumericValueType) -> None:
Expand Down Expand Up @@ -232,7 +243,10 @@ def set(self, labels: LabelsType, value: NumericValueType) -> None:
self.set_value(labels, value)

def get(self, labels: LabelsType) -> NumericValueType:
''' Get gets the Gauge of an arbitrary group of labels'''
''' Get gets the Gauge value matching an arbitrary group of labels.
:raises: KeyError if an item with matching labels is not present.
'''
return self.get_value(labels)

def inc(self, labels: LabelsType) -> None:
Expand Down Expand Up @@ -317,8 +331,10 @@ def add(self, labels: LabelsType, value: NumericValueType) -> None:
def get(self,
labels: LabelsType) -> Dict[Union[float, str], NumericValueType]:
'''
Return a dict containing the sum, count and 0.5, 0.9 and 0.99
percentiles.
Get gets a dict of values, containing the sum, count and percentiles,
matching an arbitrary group of labels.
:raises: KeyError if an item with matching labels is not present.
'''
return_data = {} # type: Dict[Union[float, str], NumericValueType]

Expand Down Expand Up @@ -388,7 +404,10 @@ def add(self, labels: LabelsType, value: NumericValueType) -> None:
def get(self,
labels: LabelsType) -> Dict[Union[float, str], NumericValueType]:
'''
Return a dict containing the sum, count and buckets.
Get gets a dict of values, containing the sum, count and buckets,
matching an arbitrary group of labels.
:raises: KeyError if an item with matching labels is not present.
'''
return_data = {} # type: Dict[Union[float, str], NumericValueType]

Expand Down
26 changes: 13 additions & 13 deletions aioprometheus/decorators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'''
This module provides metrics decorators
This module provides some convenience decorators for metrics
'''

import asyncio
Expand All @@ -13,7 +13,7 @@
def timer(metric: Summary,
labels: Dict[str, str] = None) -> Callable[..., Any]:
'''
This decorator provides a way for users to time code in seconds.
This decorator provides a convenient way to time a callable.
This decorator function wraps a function with code to calculate how long
the wrapped function takes to execute and updates the metric with the
Expand All @@ -29,12 +29,12 @@ def timer(metric: Summary,
'''
if not isinstance(metric, Summary):
raise Exception(
'time decorator expects a Summary metric but got: {}'.format(
'timer decorator expects a Summary metric but got: {}'.format(
metric))

def measure(func):
'''
This function wraps a decorated function with timing and metric
This function wraps a decorated callable with timing and metric
updating logic.
:param func: the callable to be timed.
Expand All @@ -43,11 +43,11 @@ def measure(func):
'''
@wraps(func)
async def func_wrapper(*args, **kwds):
start_time = time.time()
start_time = time.monotonic()
rv = func(*args, **kwds)
if isinstance(rv, asyncio.Future) or asyncio.iscoroutine(rv):
rv = await rv
metric.add(labels, time.time() - start_time)
metric.add(labels, time.monotonic() - start_time)
return rv

return func_wrapper
Expand All @@ -58,8 +58,8 @@ async def func_wrapper(*args, **kwds):
def inprogress(metric: Gauge,
labels: Dict[str, str] = None) -> Callable[..., Any]:
'''
This decorator provides a way for users to track in-progress requests
(or other things) in some piece of code/function.
This decorator provides a convenient way to track in-progress requests
(or other things) in a callable.
This decorator function wraps a function with code to track how many
of the measured items are in progress.
Expand All @@ -81,7 +81,7 @@ def inprogress(metric: Gauge,

def track(func):
'''
This function wraps a decorated function with metric incremeting
This function wraps a decorated callable with metric incremeting
and decrementing logic.
:param func: the callable to be tracked.
Expand All @@ -105,8 +105,8 @@ async def func_wrapper(*args, **kwds):
def count_exceptions(metric: Counter,
labels: Dict[str, str] = None) -> Callable[..., Any]:
'''
This decorator provides a way for users to track in-progress requests
(or other things) in some piece of code/function.
This decorator provides a convenient way to track count exceptions
generated in a callable.
This decorator function wraps a function with code to track how many
exceptions occur.
Expand All @@ -120,12 +120,12 @@ def count_exceptions(metric: Counter,
'''
if not isinstance(metric, Counter):
raise Exception(
'inprogess decorator expects a Counter metric but got: {}'.format(
'count_exceptions decorator expects a Counter metric but got: {}'.format(
metric))

def track(func):
'''
This function wraps a decorated function with metric incremeting
This function wraps a decorated callable with metric incremeting
logic.
:param func: the callable to be tracked.
Expand Down
12 changes: 5 additions & 7 deletions aioprometheus/discovery/etcd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@

from aio_etcd.client import Client as EtcdClient
from .agent import IDiscoveryAgent
from typing import Optional

# imports only used for type annotations
if False:
from asyncio.base_events import BaseEventLoop
from ..service import Service
from asyncio.base_events import BaseEventLoop
from ..service import Service


logger = logging.getLogger(__name__)
Expand All @@ -29,7 +27,7 @@ class EtcdAgent(IDiscoveryAgent):
def __init__(self,
service_name: str,
tags=(),
loop: Optional['BaseEventLoop'] = None,
loop: BaseEventLoop = None,
**kwargs) -> None:
'''
Expand All @@ -46,7 +44,7 @@ def __init__(self,
self.loop = loop or asyncio.get_event_loop()
self.client = EtcdClient(loop=self.loop, **kwargs)

async def register(self, metrics_server: 'Service') -> None:
async def register(self, metrics_server: Service) -> None:
'''
Register a Prometheus metrics server with etcd.
Expand All @@ -62,7 +60,7 @@ async def register(self, metrics_server: 'Service') -> None:
url=metrics_server.url)
await self.client.write(key, json.dumps(value))

async def deregister(self, metrics_server: 'Service') -> None:
async def deregister(self, metrics_server: Service) -> None:
'''
Register a Prometheus metrics server from etcd.
Expand Down
5 changes: 2 additions & 3 deletions aioprometheus/formats/binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from typing import cast, Callable, Dict, List, Tuple, Union

# imports only used for type annotations
if False:
from ..registry import CollectorRegistry
from ..registry import CollectorRegistry

# typing aliases
LabelsType = Dict[str, str]
Expand Down Expand Up @@ -202,7 +201,7 @@ def marshall_collector(self,

return pb_metric_family

def marshall(self, registry: 'CollectorRegistry') -> bytes:
def marshall(self, registry: CollectorRegistry) -> bytes:
''' Marshall the collectors in the registry into binary protocol
buffer format.
Expand Down
5 changes: 2 additions & 3 deletions aioprometheus/formats/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from typing import cast, Callable, Dict, List, Tuple, Union

# imports only used for type annotations
if False:
from ..registry import CollectorRegistry
from ..registry import CollectorRegistry

# typing aliases
LabelsType = Dict[str, str]
Expand Down Expand Up @@ -221,7 +220,7 @@ def marshall_collector(self, collector: CollectorsType) -> str:
result = sorted(self.marshall_lines(collector))
return LINE_SEPARATOR_FMT.join(result)

def marshall(self, registry: 'CollectorRegistry') -> bytes:
def marshall(self, registry: CollectorRegistry) -> bytes:
''' Marshalls a full registry (various collectors) into a bytes
object '''

Expand Down
13 changes: 6 additions & 7 deletions aioprometheus/pusher.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
from .formats import BinaryFormatter

# imports only used for type annotations
if False:
from asyncio.base_events import BaseEventLoop
from .registry import CollectorRegistry
from asyncio.base_events import BaseEventLoop
from .registry import CollectorRegistry


class Pusher(object):
Expand All @@ -25,7 +24,7 @@ class Pusher(object):
def __init__(self,
job_name: str,
addr: str,
loop: 'BaseEventLoop' = None) -> None:
loop: BaseEventLoop = None) -> None:
'''
:param job_name: The name of the job.
Expand All @@ -45,7 +44,7 @@ def __init__(self,
self.path = urljoin(self.addr, self.PATH.format(job_name))

async def add(self,
registry: 'CollectorRegistry') -> aiohttp.web.Response:
registry: CollectorRegistry) -> aiohttp.web.Response:
'''
Add works like replace, but only metrics with the same name as the
newly pushed metrics are replaced.
Expand All @@ -58,7 +57,7 @@ async def add(self,
return resp

async def replace(self,
registry: 'CollectorRegistry') -> aiohttp.web.Response:
registry: CollectorRegistry) -> aiohttp.web.Response:
'''
``replace`` pushes new values for a group of metrics to the push
gateway.
Expand All @@ -77,7 +76,7 @@ async def replace(self,
return resp

async def delete(self,
registry: 'CollectorRegistry') -> aiohttp.web.Response:
registry: CollectorRegistry) -> aiohttp.web.Response:
'''
``delete`` deletes metrics from the push gateway. All metrics with
the grouping key specified in the URL are deleted.
Expand Down
12 changes: 6 additions & 6 deletions aioprometheus/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
from typing import Set

# imports only used for type annotations
if False:
from asyncio.base_events import BaseEventLoop, Server
from ssl import SSLContext
from asyncio.base_events import BaseEventLoop, Server
from ssl import SSLContext


logger = logging.getLogger(__name__)
Expand All @@ -37,7 +36,7 @@ class Service(object):

def __init__(self,
registry: Registry = None,
loop: 'BaseEventLoop' = None) -> None:
loop: BaseEventLoop = None) -> None:
'''
Initialise the Prometheus metrics service.
Expand Down Expand Up @@ -73,7 +72,8 @@ def url(self) -> str:
raise Exception(
"No URL available, Prometheus metrics server is not running")

host, port = self._svr.sockets[0].getsockname()
# IPv4 returns 2-tuple, IPv6 returns 4-tuple
host, port, *_ = self._svr.sockets[0].getsockname()
scheme = "http{}".format('s' if self._https else '')
url = "{scheme}://{host}:{port}{metrics_url}".format(
scheme=scheme,
Expand All @@ -85,7 +85,7 @@ def url(self) -> str:
async def start(self,
addr: str = '',
port: int = 0,
ssl: 'SSLContext' = None,
ssl: SSLContext = None,
metrics_url: str = DEFAULT_METRICS_PATH,
discovery_agent=None) -> None:
''' Start the prometheus metrics HTTP(S) server.
Expand Down
5 changes: 5 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@
'Miscellaneous'),
]

# -- suppress specific warnings -------------------------------------------

suppress_warnings = ['image.nonlocal_uri']


# -- Custom config to work around readthedocs.org #1139 -------------------

def run_apidoc(_):
Expand Down

0 comments on commit 5e7ed51

Please sign in to comment.