Skip to content

Commit 8a6b4c0

Browse files
authored
Merge pull request #2 from Lightricks/feature/influx_global_tags
Feature/influx global tags
2 parents b71056e + 55df670 commit 8a6b4c0

22 files changed

+631
-215
lines changed

pyformance/__init__.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22

33
from .registry import MetricsRegistry, global_registry, set_global_registry
44
from .registry import timer, counter, meter, histogram, gauge
5-
from .registry import (
6-
dump_metrics,
7-
clear,
8-
count_calls,
9-
meter_calls,
10-
hist_calls,
11-
time_calls,
12-
)
5+
from .registry import dump_metrics, clear
6+
from .decorators import count_calls, meter_calls, hist_calls, time_calls
137
from .meters.timer import call_too_long

pyformance/decorators.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import functools
2+
import sys
3+
4+
import pyformance.registry as global_registry
5+
6+
7+
def get_qualname(obj):
8+
if sys.version_info[0] > 2:
9+
return obj.__qualname__
10+
return obj.__name__
11+
12+
13+
def count_calls(original_func=None, registry=None, tags=None):
14+
"""
15+
Decorator to track the number of times a function is called.
16+
17+
:param original_func: the function to be decorated
18+
:type original_func: C{func}
19+
20+
:param registry: the registry in which to create the meter
21+
22+
:param tags: tags attached to the timer (e.g. {'region': 'us-west-1'})
23+
:type tags: C{dict}
24+
25+
:return: the decorated function
26+
:rtype: C{func}
27+
"""
28+
29+
def _decorate(fn):
30+
@functools.wraps(fn)
31+
def wrapper(*args, **kwargs):
32+
function_name = get_qualname(fn)
33+
metric_name = "%s_calls" % function_name
34+
35+
_registry = registry or global_registry
36+
_histogram = _registry.counter(metric_name, tags).inc()
37+
38+
return fn(*args, **kwargs)
39+
40+
return wrapper
41+
42+
if original_func:
43+
return _decorate(original_func)
44+
45+
return _decorate
46+
47+
48+
def meter_calls(original_func=None, registry=None, tags=None):
49+
"""
50+
Decorator to the rate at which a function is called.
51+
52+
:param original_func: the function to be decorated
53+
:type original_func: C{func}
54+
55+
:param registry: the registry in which to create the meter
56+
57+
:param tags: tags attached to the timer (e.g. {'region': 'us-west-1'})
58+
:type tags: C{dict}
59+
60+
:return: the decorated function
61+
:rtype: C{func}
62+
"""
63+
64+
def _decorate(fn):
65+
@functools.wraps(fn)
66+
def wrapper(*args, **kwargs):
67+
function_name = get_qualname(fn)
68+
metric_name = "%s_calls" % function_name
69+
70+
_registry = registry or global_registry
71+
_histogram = _registry.meter(metric_name, tags).mark()
72+
73+
return fn(*args, **kwargs)
74+
75+
return wrapper
76+
77+
if original_func:
78+
return _decorate(original_func)
79+
80+
return _decorate
81+
82+
83+
def hist_calls(original_func=None, registry=None, tags=None):
84+
"""
85+
Decorator to check the distribution of return values of a function.
86+
87+
:param original_func: the function to be decorated
88+
:type original_func: C{func}
89+
90+
:param registry: the registry in which to create the histogram
91+
92+
:param tags: tags attached to the timer (e.g. {'region': 'us-west-1'})
93+
:type tags: C{dict}
94+
95+
:return: the decorated function
96+
:rtype: C{func}
97+
"""
98+
def _decorate(fn):
99+
@functools.wraps(fn)
100+
def wrapper(*args, **kwargs):
101+
function_name = get_qualname(fn)
102+
metric_name = "%s_calls" % function_name
103+
104+
_registry = registry or global_registry
105+
_histogram = _registry.histogram(metric_name, tags)
106+
107+
rtn = fn(*args, **kwargs)
108+
if type(rtn) in (int, float):
109+
_histogram.update(rtn)
110+
return rtn
111+
112+
return wrapper
113+
114+
if original_func:
115+
return _decorate(original_func)
116+
117+
return _decorate
118+
119+
120+
def time_calls(original_func=None, registry=None, tags=None):
121+
"""
122+
Decorator to time the execution of the function.
123+
124+
:param original_func: the function to be decorated
125+
:type original_func: C{func}
126+
127+
:param registry: the registry in which to create the timer
128+
129+
:param tags: tags attached to the timer (e.g. {'region': 'us-west-1'})
130+
:type tags: C{dict}
131+
132+
:return: the decorated function
133+
:rtype: C{func}
134+
"""
135+
def _decorate(fn):
136+
@functools.wraps(fn)
137+
def wrapper(*args, **kwargs):
138+
function_name = get_qualname(fn)
139+
metric_name = "%s_calls" % function_name
140+
141+
_registry = registry or global_registry
142+
_timer = _registry.timer(metric_name, tags)
143+
144+
with _timer.time(fn=function_name):
145+
return fn(*args, **kwargs)
146+
147+
return wrapper
148+
149+
if original_func:
150+
return _decorate(original_func)
151+
152+
return _decorate

pyformance/meters/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
from .histogram import Histogram
44
from .timer import Timer
55
from .gauge import Gauge, CallbackGauge, SimpleGauge
6+
from .base_metric import BaseMetric

pyformance/meters/base_metric.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class BaseMetric(object):
2+
3+
"""
4+
Abstract class for grouping common properties of metrics, such as tags
5+
"""
6+
7+
def __init__(self, key, tags=None):
8+
self.key = key
9+
self.tags = tags or {}
10+
11+
def get_tags(self):
12+
return self.tags
13+
14+
def get_key(self):
15+
return self.key
16+
17+
def __hash__(self):
18+
if not self.tags:
19+
return hash(self.key)
20+
21+
return hash((self.key, frozenset(self.tags.items())))
22+
23+
def __eq__(self, other):
24+
if not isinstance(other, BaseMetric):
25+
return False
26+
27+
return self.key == other.key and set(self.tags) == set(other.tags)

pyformance/meters/counter.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
from threading import Lock
2+
from .base_metric import BaseMetric
23

34

4-
class Counter(object):
5+
class Counter(BaseMetric):
56

67
"""
78
An incrementing and decrementing metric
89
"""
910

10-
def __init__(self):
11-
super(Counter, self).__init__()
11+
def __init__(self, key, tags=None):
12+
super(Counter, self).__init__(key, tags)
1213
self.lock = Lock()
1314
self.counter = 0
1415

pyformance/meters/gauge.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
class Gauge(object):
1+
from .base_metric import BaseMetric
2+
3+
4+
class Gauge(BaseMetric):
25

36
"""
47
A base class for reading of a particular.
@@ -26,9 +29,9 @@ class CallbackGauge(Gauge):
2629
A Gauge reading for a given callback
2730
"""
2831

29-
def __init__(self, callback):
32+
def __init__(self, callback, key, tags=None):
3033
"constructor expects a callable"
31-
super(CallbackGauge, self).__init__()
34+
super(CallbackGauge, self).__init__(key, tags)
3235
self.callback = callback
3336

3437
def get_value(self):
@@ -42,9 +45,9 @@ class SimpleGauge(Gauge):
4245
A gauge which holds values with simple getter- and setter-interface
4346
"""
4447

45-
def __init__(self, value=float("nan")):
48+
def __init__(self, key, value=float("nan"), tags=None):
4649
"constructor accepts initial value"
47-
super(SimpleGauge, self).__init__()
50+
super(SimpleGauge, self).__init__(key, tags)
4851
self._value = value
4952

5053
def get_value(self):

pyformance/meters/histogram.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
import time
22
import math
33
from threading import Lock
4+
from .base_metric import BaseMetric
45
from ..stats.samples import ExpDecayingSample, DEFAULT_SIZE, DEFAULT_ALPHA
56

67

7-
class Histogram(object):
8+
class Histogram(BaseMetric):
89

910
"""
1011
A metric which calculates the distribution of a value.
1112
"""
1213

13-
def __init__(self, size=DEFAULT_SIZE, alpha=DEFAULT_ALPHA, clock=time, sample=None):
14+
def __init__(
15+
self,
16+
key,
17+
size=DEFAULT_SIZE,
18+
alpha=DEFAULT_ALPHA,
19+
clock=time,
20+
sample=None,
21+
tags=None
22+
):
1423
"""
1524
Creates a new instance of a L{Histogram}.
1625
"""
17-
super(Histogram, self).__init__()
26+
super(Histogram, self).__init__(key, tags)
1827
self.lock = Lock()
1928
self.clock = clock
2029
if sample is None:

pyformance/meters/meter.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import time
22
from threading import Lock
3+
from .base_metric import BaseMetric
34
from ..stats.moving_average import ExpWeightedMovingAvg
45

56

6-
class Meter(object):
7+
class Meter(BaseMetric):
78

89
"""
910
A meter metric which measures mean throughput and one-, five-, and fifteen-minute
1011
exponentially-weighted moving average throughputs.
1112
"""
1213

13-
def __init__(self, clock=time):
14-
super(Meter, self).__init__()
14+
def __init__(self, key, clock=time, tags=None):
15+
super(Meter, self).__init__(key, tags)
1516
self.lock = Lock()
1617
self.clock = clock
1718
self.clear()

pyformance/meters/timer.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import time
2+
from .base_metric import BaseMetric
23

34
try:
45
from blinker import Namespace
@@ -14,7 +15,7 @@
1415
call_too_long = None
1516

1617

17-
class Timer(object):
18+
class Timer(BaseMetric):
1819

1920
"""
2021
A timer metric which aggregates timing durations and provides duration statistics, plus
@@ -24,16 +25,25 @@ class Timer(object):
2425

2526
def __init__(
2627
self,
28+
key,
2729
threshold=None,
2830
size=DEFAULT_SIZE,
2931
alpha=DEFAULT_ALPHA,
3032
clock=time,
3133
sink=None,
3234
sample=None,
35+
tags=None
3336
):
34-
super(Timer, self).__init__()
35-
self.meter = Meter(clock=clock)
36-
self.hist = Histogram(size=size, alpha=alpha, clock=clock, sample=sample)
37+
super(Timer, self).__init__(key, tags)
38+
self.meter = Meter(key=key, tags=tags, clock=clock)
39+
self.hist = Histogram(
40+
key=key,
41+
tags=tags,
42+
size=size,
43+
alpha=alpha,
44+
clock=clock,
45+
sample=sample
46+
)
3747
self.sink = sink
3848
self.threshold = threshold
3949

0 commit comments

Comments
 (0)