-
Notifications
You must be signed in to change notification settings - Fork 0
/
metrics.py
151 lines (123 loc) · 3.21 KB
/
metrics.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
"""
Module to provide easy access to submitting metrics.
Similar to logging, code can always emit metrics, but those
metrics might not go anywhere without a consumer, e.g.
statsdclient.
Call configure() to setup a consumer.
Dependencies:
- statsdclient
"""
import statsdclient
import logging
DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 8125
class NullClient(object): # pragma: no cover
"""An instrumentation 'null' client"""
def timeit(self, _metric, func, *args, **kwargs):
"""Dummy timeit"""
return func(*args, **kwargs)
def count(self, *args, **kwargs):
"""Dummy count"""
pass
def timing(self, *args):
"""Dummy timing"""
pass
def gauge(self, *args):
"""Dummy gauge"""
pass
_client = NullClient()
def configure(host=DEFAULT_HOST, port=DEFAULT_PORT, prefix=''):
"""
>>> configure()
>>> configure('localhost', 8125, 'mymetrics')
"""
global _client
logging.info("Reconfiguring metrics: {}:{}/{}".format(host, port, prefix))
_client = statsdclient.StatsdClient(host, port, prefix)
def timing(metric, value):
"""
>>> timing("metric", 33)
"""
_client.timing(metric, value)
def gauge(metric, value):
"""
>>> gauge("gauge", 23)
"""
_client.gauge(metric, value)
def count(metric, value=1, sample_rate=1):
"""
>>> count("metric")
>>> count("metric", 3)
>>> count("metric", -2)
"""
_client.count(metric, value, sample_rate)
def timeit(metric, func, *args, **kwargs):
"""
>>> import time
>>> timeit("metric", time.sleep, 0.1)
>>> resetclient()
>>> timeit("metric", time.sleep, 0.1)
"""
return _client.timeit(metric, func, *args, **kwargs)
def resetclient():
"""
Reset client to None
>>> resetclient()
"""
global _client
_client = NullClient()
def timed(prefix=None):
"""
Decorator to time execution of function.
Metric name is function name (as given under f.__name__).
Optionally provide a prefix (without the '.').
>>> @timed()
... def f():
... print('ok')
...
>>> f()
ok
>>> @timed(prefix='mymetrics')
... def g():
... print('ok')
...
>>> g()
ok
"""
def decorator(func):
"""wrap func so it is timed"""
metricname = func.__name__
if prefix:
metricname = prefix + '.' + metricname
def wrapped(*args, **kwargs):
"""wrapped function"""
return timeit(metricname, func, *args, **kwargs)
return wrapped
return decorator
def time_methods(obj, methods, prefix=None):
"""
Patch obj so calls to given methods are timed
>>> class C(object):
... def m1(self):
... return 'ok'
...
... def m2(self, arg):
... return arg
...
>>> c = C()
>>> time_methods(c, ['m1', 'm2'])
>>> c.m1()
'ok'
>>> c.m2('ok')
'ok'
>>> c = C()
>>> time_methods(c, ['m1'], 'mymetrics')
"""
if prefix:
prefix = prefix + '.'
else:
prefix = ''
for method in methods:
current_method = getattr(obj, method)
new_method = timed(prefix)(current_method)
setattr(obj, method, new_method)