##// END OF EJS Templates
statsd: fix unicode tags generation as we use str now
super-admin -
r4795:1a40cc02 default
parent child Browse files
Show More
@@ -1,128 +1,131 b''
1 from __future__ import absolute_import, division, unicode_literals
1 from __future__ import absolute_import, division, unicode_literals
2
2
3 import re
3 import re
4 import random
4 import random
5 from collections import deque
5 from collections import deque
6 from datetime import timedelta
6 from datetime import timedelta
7 from repoze.lru import lru_cache
7 from repoze.lru import lru_cache
8
8
9 from .timer import Timer
9 from .timer import Timer
10
10
11 TAG_INVALID_CHARS_RE = re.compile(r"[^\w\d_\-:/\.]", re.UNICODE)
11 TAG_INVALID_CHARS_RE = re.compile(
12 r"[^\w\d_\-:/\.]",
13 #re.UNICODE
14 )
12 TAG_INVALID_CHARS_SUBS = "_"
15 TAG_INVALID_CHARS_SUBS = "_"
13
16
14
17
15 @lru_cache(maxsize=500)
18 @lru_cache(maxsize=500)
16 def _normalize_tags_with_cache(tag_list):
19 def _normalize_tags_with_cache(tag_list):
17 return [TAG_INVALID_CHARS_RE.sub(TAG_INVALID_CHARS_SUBS, tag) for tag in tag_list]
20 return [TAG_INVALID_CHARS_RE.sub(TAG_INVALID_CHARS_SUBS, tag) for tag in tag_list]
18
21
19
22
20 def normalize_tags(tag_list):
23 def normalize_tags(tag_list):
21 # We have to turn our input tag list into a non-mutable tuple for it to
24 # We have to turn our input tag list into a non-mutable tuple for it to
22 # be hashable (and thus usable) by the @lru_cache decorator.
25 # be hashable (and thus usable) by the @lru_cache decorator.
23 return _normalize_tags_with_cache(tuple(tag_list))
26 return _normalize_tags_with_cache(tuple(tag_list))
24
27
25
28
26 class StatsClientBase(object):
29 class StatsClientBase(object):
27 """A Base class for various statsd clients."""
30 """A Base class for various statsd clients."""
28
31
29 def close(self):
32 def close(self):
30 """Used to close and clean up any underlying resources."""
33 """Used to close and clean up any underlying resources."""
31 raise NotImplementedError()
34 raise NotImplementedError()
32
35
33 def _send(self):
36 def _send(self):
34 raise NotImplementedError()
37 raise NotImplementedError()
35
38
36 def pipeline(self):
39 def pipeline(self):
37 raise NotImplementedError()
40 raise NotImplementedError()
38
41
39 def timer(self, stat, rate=1, tags=None):
42 def timer(self, stat, rate=1, tags=None):
40 return Timer(self, stat, rate, tags)
43 return Timer(self, stat, rate, tags)
41
44
42 def timing(self, stat, delta, rate=1, tags=None):
45 def timing(self, stat, delta, rate=1, tags=None):
43 """
46 """
44 Send new timing information.
47 Send new timing information.
45
48
46 `delta` can be either a number of milliseconds or a timedelta.
49 `delta` can be either a number of milliseconds or a timedelta.
47 """
50 """
48 if isinstance(delta, timedelta):
51 if isinstance(delta, timedelta):
49 # Convert timedelta to number of milliseconds.
52 # Convert timedelta to number of milliseconds.
50 delta = delta.total_seconds() * 1000.
53 delta = delta.total_seconds() * 1000.
51 self._send_stat(stat, '%0.6f|ms' % delta, rate, tags)
54 self._send_stat(stat, '%0.6f|ms' % delta, rate, tags)
52
55
53 def incr(self, stat, count=1, rate=1, tags=None):
56 def incr(self, stat, count=1, rate=1, tags=None):
54 """Increment a stat by `count`."""
57 """Increment a stat by `count`."""
55 self._send_stat(stat, '%s|c' % count, rate, tags)
58 self._send_stat(stat, '%s|c' % count, rate, tags)
56
59
57 def decr(self, stat, count=1, rate=1, tags=None):
60 def decr(self, stat, count=1, rate=1, tags=None):
58 """Decrement a stat by `count`."""
61 """Decrement a stat by `count`."""
59 self.incr(stat, -count, rate, tags)
62 self.incr(stat, -count, rate, tags)
60
63
61 def gauge(self, stat, value, rate=1, delta=False, tags=None):
64 def gauge(self, stat, value, rate=1, delta=False, tags=None):
62 """Set a gauge value."""
65 """Set a gauge value."""
63 if value < 0 and not delta:
66 if value < 0 and not delta:
64 if rate < 1:
67 if rate < 1:
65 if random.random() > rate:
68 if random.random() > rate:
66 return
69 return
67 with self.pipeline() as pipe:
70 with self.pipeline() as pipe:
68 pipe._send_stat(stat, '0|g', 1)
71 pipe._send_stat(stat, '0|g', 1)
69 pipe._send_stat(stat, '%s|g' % value, 1)
72 pipe._send_stat(stat, '%s|g' % value, 1)
70 else:
73 else:
71 prefix = '+' if delta and value >= 0 else ''
74 prefix = '+' if delta and value >= 0 else ''
72 self._send_stat(stat, '%s%s|g' % (prefix, value), rate, tags)
75 self._send_stat(stat, '%s%s|g' % (prefix, value), rate, tags)
73
76
74 def set(self, stat, value, rate=1):
77 def set(self, stat, value, rate=1):
75 """Set a set value."""
78 """Set a set value."""
76 self._send_stat(stat, '%s|s' % value, rate)
79 self._send_stat(stat, '%s|s' % value, rate)
77
80
78 def _send_stat(self, stat, value, rate, tags=None):
81 def _send_stat(self, stat, value, rate, tags=None):
79 self._after(self._prepare(stat, value, rate, tags))
82 self._after(self._prepare(stat, value, rate, tags))
80
83
81 def _prepare(self, stat, value, rate, tags=None):
84 def _prepare(self, stat, value, rate, tags=None):
82 if rate < 1:
85 if rate < 1:
83 if random.random() > rate:
86 if random.random() > rate:
84 return
87 return
85 value = '%s|@%s' % (value, rate)
88 value = '%s|@%s' % (value, rate)
86
89
87 if self._prefix:
90 if self._prefix:
88 stat = '%s.%s' % (self._prefix, stat)
91 stat = '%s.%s' % (self._prefix, stat)
89
92
90 res = '%s:%s%s' % (
93 res = '%s:%s%s' % (
91 stat,
94 stat,
92 value,
95 value,
93 ("|#" + ",".join(normalize_tags(tags))) if tags else "",
96 ("|#" + ",".join(normalize_tags(tags))) if tags else "",
94 )
97 )
95 return res
98 return res
96
99
97 def _after(self, data):
100 def _after(self, data):
98 if data:
101 if data:
99 self._send(data)
102 self._send(data)
100
103
101
104
102 class PipelineBase(StatsClientBase):
105 class PipelineBase(StatsClientBase):
103
106
104 def __init__(self, client):
107 def __init__(self, client):
105 self._client = client
108 self._client = client
106 self._prefix = client._prefix
109 self._prefix = client._prefix
107 self._stats = deque()
110 self._stats = deque()
108
111
109 def _send(self):
112 def _send(self):
110 raise NotImplementedError()
113 raise NotImplementedError()
111
114
112 def _after(self, data):
115 def _after(self, data):
113 if data is not None:
116 if data is not None:
114 self._stats.append(data)
117 self._stats.append(data)
115
118
116 def __enter__(self):
119 def __enter__(self):
117 return self
120 return self
118
121
119 def __exit__(self, typ, value, tb):
122 def __exit__(self, typ, value, tb):
120 self.send()
123 self.send()
121
124
122 def send(self):
125 def send(self):
123 if not self._stats:
126 if not self._stats:
124 return
127 return
125 self._send()
128 self._send()
126
129
127 def pipeline(self):
130 def pipeline(self):
128 return self.__class__(self)
131 return self.__class__(self)
General Comments 0
You need to be logged in to leave comments. Login now