Skip to content

Commit 9d6e066

Browse files
committed
Python 3 support done!
1 parent 03e13d6 commit 9d6e066

File tree

15 files changed

+204
-132
lines changed

15 files changed

+204
-132
lines changed

.travis.yml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,27 @@ script:
1212
notifications:
1313
email: false
1414

15+
python:
16+
- '2.7'
17+
- '3.5'
18+
- '3.6'
19+
- '3.4'
20+
- '3.3'
21+
1522

1623
matrix:
1724
include:
1825
- python: "2.7"
1926
env: UWSGI="2.0.14"
2027

21-
# - python: "3.3"
22-
# env: UWSGI="2.0.14"
28+
- python: "3.3"
29+
env: UWSGI="2.0.14"
2330

24-
# - python: "3.4"
25-
# env: UWSGI="2.0.14"
31+
- python: "3.4"
32+
env: UWSGI="2.0.14"
2633

27-
# - python: "3.5"
28-
# env: UWSGI="2.0.14"
34+
- python: "3.5"
35+
env: UWSGI="2.0.14"
2936

30-
# - python: "3.6"
31-
# env: UWSGI="2.0.14"
37+
- python: "3.6"
38+
env: UWSGI="2.0.14"

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ test: clean-containers
4848

4949
tox: clean-containers
5050
@echo "Tox test application $(version)"
51+
rm -rf ./.tox
5152
$(DOCKER_RUN_COMMAND) "tox"
5253
@echo ""
5354

conftest.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
import time
88
from pyprometheus.storage import BaseStorage
99
from pyprometheus.utils import measure_time as measure_time_manager
10-
try:
11-
xrange = xrange
12-
except Exception:
13-
xrange = range
10+
from pyprometheus.compat import PAD_SYMBOL, xrange
1411

1512

1613
@pytest.fixture
@@ -22,7 +19,7 @@ def project_root():
2219
def run_around_tests():
2320
m = uwsgi.sharedarea_memoryview(0)
2421
for x in xrange(len(m)):
25-
m[x] = "\x00"
22+
m[x] = PAD_SYMBOL
2623

2724
yield
2825

pyprometheus/compat.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,35 @@
1717
PY2 = sys.version_info[0] == 2
1818
PY3 = sys.version_info[0] == 3
1919
PY34 = sys.version_info[0:2] >= (3, 4)
20+
21+
22+
if PY3:
23+
PAD_SYMBOL = 0
24+
else:
25+
PAD_SYMBOL = "\x00"
26+
27+
28+
try:
29+
xrange = xrange
30+
except Exception:
31+
xrange = range
32+
33+
34+
if PY3:
35+
def b(s):
36+
if isinstance(s, bytes):
37+
return s
38+
return s.encode("latin-1")
39+
40+
def u(s):
41+
return s
42+
43+
else:
44+
def b(s):
45+
return s
46+
47+
def u(s):
48+
return s
49+
# if isinstance(s, unicode):
50+
# return s
51+
# return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape")

pyprometheus/contrib/uwsgi_features.py

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from pyprometheus.const import TYPES
2222
from pyprometheus.metrics import Gauge, Counter
2323
from pyprometheus.storage import BaseStorage, LocalMemoryStorage
24-
24+
from pyprometheus import compat
2525

2626
try:
2727
import uwsgi
@@ -45,7 +45,9 @@ class UWSGICollector(object):
4545
"""
4646
def __init__(self, namespace, labels={}):
4747
self._namespace = namespace
48+
4849
self._labels = tuple(sorted(labels.items(), key=lambda x: x[0]))
50+
self._labels_names = tuple(label[0] for label in self._labels)
4951
self._collectors = self.declare_metrics()
5052

5153
@property
@@ -70,29 +72,30 @@ def metric_name(self, name):
7072
return ":".join([self._namespace, name])
7173

7274
def declare_metrics(self):
75+
7376
return {
74-
"memory": Gauge(self.metric_name("uwsgi_memory_bytes"), "UWSGI memory usage in bytes", ("type",) + self._labels),
75-
"processes": Gauge(self.metric_name("processes_total"), "Number of UWSGI processes", self._labels),
76-
"worker_status": Gauge(self.metric_name("worker_status_totla"), "Current workers status", self._labels),
77-
"total_requests": Gauge(self.metric_name("requests_total"), "Total processed request", self._labels),
78-
"buffer_size": Gauge(self.metric_name("buffer_size_bytes"), "UWSGI buffer size in bytes", self._labels),
79-
"started_on": Gauge(self.metric_name("started_on"), "UWSGI started on timestamp", self._labels),
80-
"cores": Gauge(self.metric_name("cores"), "system cores", self._labels),
81-
82-
83-
"process:respawn_count": Gauge(self.metric_name("process:respawn_count"), "Process respawn count", ("id", ) + self._labels),
84-
"process:last_spawn": Gauge(self.metric_name("process:last_spawn"), "Process last spawn", ("id", ) + self._labels),
85-
"process:signals": Gauge(self.metric_name("process:signals"), "Process signals total", ("id", ) + self._labels),
86-
"process:avg_rt": Gauge(self.metric_name("process:avg_rt"), "Process average response time", ("id", ) + self._labels),
87-
"process:tx": Gauge(self.metric_name("process:tx"), "Process transmitted data", ("id",) + self._labels),
88-
89-
"process:status": Gauge(self.metric_name("process:status"), "Process status", ("id", "status") + self._labels),
90-
"process:running_time": Gauge(self.metric_name("process:running_time"), "Process running time", ("id", ) + self._labels),
91-
"process:exceptions": Gauge(self.metric_name("process:exceptions"), "Process exceptions", ("id", ) + self._labels),
92-
"process:requests": Gauge(self.metric_name("process:requests"), "Process requests", ("id", ) + self._labels),
93-
"process:delta_requests": Gauge(self.metric_name("process:delta_requests"), "Process delta_requests", ("id", ) + self._labels),
94-
"process:rss": Gauge(self.metric_name("process:rss"), "Process rss memory", ("id", ) + self._labels),
95-
"process:vsz": Gauge(self.metric_name("process:vzs"), "Process vsz address space", ("id", ) + self._labels),
77+
"memory": Gauge(self.metric_name("uwsgi_memory_bytes"), "UWSGI memory usage in bytes", ("type",) + self._labels_names),
78+
"processes": Gauge(self.metric_name("processes_total"), "Number of UWSGI processes", self._labels_names),
79+
"worker_status": Gauge(self.metric_name("worker_status_totla"), "Current workers status", self._labels_names),
80+
"total_requests": Gauge(self.metric_name("requests_total"), "Total processed request", self._labels_names),
81+
"buffer_size": Gauge(self.metric_name("buffer_size_bytes"), "UWSGI buffer size in bytes", self._labels_names),
82+
"started_on": Gauge(self.metric_name("started_on"), "UWSGI started on timestamp", self._labels_names),
83+
"cores": Gauge(self.metric_name("cores"), "system cores", self._labels_names),
84+
85+
86+
"process:respawn_count": Gauge(self.metric_name("process:respawn_count"), "Process respawn count", ("id", ) + self._labels_names),
87+
"process:last_spawn": Gauge(self.metric_name("process:last_spawn"), "Process last spawn", ("id", ) + self._labels_names),
88+
"process:signals": Gauge(self.metric_name("process:signals"), "Process signals total", ("id", ) + self._labels_names),
89+
"process:avg_rt": Gauge(self.metric_name("process:avg_rt"), "Process average response time", ("id", ) + self._labels_names),
90+
"process:tx": Gauge(self.metric_name("process:tx"), "Process transmitted data", ("id",) + self._labels_names),
91+
92+
"process:status": Gauge(self.metric_name("process:status"), "Process status", ("id", "status") + self._labels_names),
93+
"process:running_time": Gauge(self.metric_name("process:running_time"), "Process running time", ("id", ) + self._labels_names),
94+
"process:exceptions": Gauge(self.metric_name("process:exceptions"), "Process exceptions", ("id", ) + self._labels_names),
95+
"process:requests": Gauge(self.metric_name("process:requests"), "Process requests", ("id", ) + self._labels_names),
96+
"process:delta_requests": Gauge(self.metric_name("process:delta_requests"), "Process delta_requests", ("id", ) + self._labels_names),
97+
"process:rss": Gauge(self.metric_name("process:rss"), "Process rss memory", ("id", ) + self._labels_names),
98+
"process:vsz": Gauge(self.metric_name("process:vzs"), "Process vsz address space", ("id", ) + self._labels_names),
9699
}
97100

98101
def collect(self):
@@ -108,7 +111,6 @@ def collect(self):
108111
for x in self.get_workers_samples(uwsgi.workers()):
109112
yield x
110113

111-
112114
def get_workers_samples(self, workers):
113115
"""Read worker stats and create samples
114116
@@ -122,15 +124,15 @@ def get_workers_samples(self, workers):
122124
for worker in workers:
123125
labels = self._labels + (("id", worker["id"]),)
124126
metric.add_sample(labels, metric.build_sample(labels,
125-
( (TYPES.GAUGE, metric.name, "", labels, worker[name]), )))
127+
( (TYPES.GAUGE, metric.name, "", labels, worker[name]), ))) # noqa
126128

127129
yield metric
128130

129131
metric = self._collectors["process:status"]
130132
for worker in workers:
131133
labels = self._labels + (("id", worker["id"]), ("status", worker["status"]))
132134
metric.add_sample(labels, metric.build_sample(labels,
133-
( (TYPES.GAUGE, metric.name, "", self._labels + (("id", worker["id"]), ("status", worker["status"])), 1), )))
135+
( (TYPES.GAUGE, metric.name, "", self._labels + (("id", worker["id"]), ("status", worker["status"])), 1), ))) # noqa
134136

135137
yield metric
136138

@@ -141,15 +143,15 @@ def get_sample(self, name, value):
141143
:param value:
142144
"""
143145
metric = self._collectors[name]
144-
return metric.build_samples([(self._labels, ( (TYPES.GAUGE, metric.name, "", self._labels, float(value)), ))])
146+
return metric.build_samples([(self._labels, ( (TYPES.GAUGE, metric.name, "", self._labels, float(value)), ))]) # noqa
145147

146148
def get_memory_samples(self):
147149
"""Get memory usage samples
148150
"""
149151
metric = self._collectors["memory"]
150152
return metric.build_samples(
151-
[(self._labels + (("type", "rss"),), ( (TYPES.GAUGE, metric.name, "", self._labels + (("type", "rss"),), uwsgi.mem()[0]), )),
152-
(self._labels + (("type", "vsz"),), ( (TYPES.GAUGE, metric.name, "", self._labels + (("type", "vsz"),), uwsgi.mem()[1]), ))])
153+
[(self._labels + (("type", "rss"),), ( (TYPES.GAUGE, metric.name, "", self._labels + (("type", "rss"),), uwsgi.mem()[0]), )), # noqa
154+
(self._labels + (("type", "vsz"),), ( (TYPES.GAUGE, metric.name, "", self._labels + (("type", "vsz"),), uwsgi.mem()[1]), ))]) # noqa
153155

154156

155157
class UWSGIStorage(BaseStorage):
@@ -199,7 +201,6 @@ def metric_name(self, name):
199201
"""
200202
return ":".join([self._namespace, name])
201203

202-
203204
@staticmethod
204205
def get_unique_id():
205206
try:
@@ -221,7 +222,7 @@ def declare_metrics(self):
221222
def collect(self):
222223
labels = self._labels + (("sharedarea", self._sharedarea_id), ("id", self.get_unique_id()))
223224
metric = self._collectors["memory_sync"]
224-
metric.add_sample(labels, metric.build_sample(labels, ( (TYPES.GAUGE, metric.name, "", labels, self._syncs), )))
225+
metric.add_sample(labels, metric.build_sample(labels, ( (TYPES.GAUGE, metric.name, "", labels, self._syncs), ))) # noqa
225226

226227
yield metric
227228

@@ -230,16 +231,15 @@ def collect(self):
230231
# yield metric
231232
metric = self._collectors["memory_size"]
232233

233-
metric.add_sample(labels, metric.build_sample(labels, ( (TYPES.GAUGE, metric.name, "", labels, self.get_area_size()), )))
234+
metric.add_sample(labels, metric.build_sample(labels, ( (TYPES.GAUGE, metric.name, "", labels, self.get_area_size()), ))) # noqa
234235

235236
yield metric
236237

237238
metric = self._collectors["num_keys"]
238-
metric.add_sample(labels, metric.build_sample(labels, ( (TYPES.GAUGE, metric.name, "", labels, len(self._positions)), )))
239+
metric.add_sample(labels, metric.build_sample(labels, ( (TYPES.GAUGE, metric.name, "", labels, len(self._positions)), ))) # noqa
239240

240241
yield metric
241242

242-
243243
@property
244244
def m(self):
245245
return self._m
@@ -279,12 +279,12 @@ def get_area_size_with_lock(self):
279279
return self.get_area_size()
280280

281281
def get_slice(self, start, size):
282-
return slice(start, start+size)
282+
return slice(start, start + size)
283283

284284
def get_area_size(self):
285285
"""Read area size from uwsgi
286286
"""
287-
return struct.unpack(b"i", self.m[self.get_slice(self.AREA_SIZE_POSITION, self.AREA_SIZE_SIZE)])[0]
287+
return struct.unpack(b"i", self.m[self.get_slice(self.AREA_SIZE_POSITION, self.AREA_SIZE_SIZE)].tobytes())[0]
288288

289289
def init_area_size(self):
290290
return self.update_area_size(self.AREA_SIZE_SIZE)
@@ -298,7 +298,6 @@ def update_area_sign(self):
298298
self._sign = os.urandom(self.SIGN_SIZE)
299299
self.m[self.get_slice(self.SIGN_POSITION, self.SIGN_SIZE)] = self._sign
300300

301-
302301
def get_area_sign(self):
303302
"""Get current area sign from memory
304303
"""
@@ -353,21 +352,25 @@ def get_string_padding(self, key):
353352
http://stackoverflow.com/questions/11642210/computing-padding-required-for-n-byte-alignment
354353
:param key: encoded string
355354
"""
356-
#return (4 - (len(key) % 4)) % 4
355+
return (4 - (len(key) % 4)) % 4
356+
357+
# return (8 - (len(key) + 4) % 4)
357358

358-
return (8 - (len(key) + 4) % 8)
359+
def get_string_padded_len(self, key):
360+
padding = self.get_string_padding(key)
361+
return len(key) + padding
359362

360363
def get_key_size(self, key):
361364
"""Calculate how many memory need key
362365
:param key: key string
363366
"""
364-
return len(self.serialize_key(key)) + self.KEY_SIZE_SIZE + self.KEY_VALUE_SIZE
365-
367+
return self.get_string_padded_len(self.serialize_key(key)) + self.KEY_SIZE_SIZE + self.KEY_VALUE_SIZE
366368

367369
def get_binary_string(self, key, value):
368-
item_template = "=i{0}sd".format(len(key)).encode()
370+
padded_string_len = self.get_string_padded_len(key)
371+
item_template = "=i{0}sd".format(padded_string_len).encode()
369372

370-
return struct.pack(item_template, len(key), key, value)
373+
return struct.pack(item_template, padded_string_len, compat.b(key), value)
371374

372375
def init_key(self, key, init_value=0.0):
373376
"""Initialize memory for key
@@ -393,24 +396,23 @@ def read_key_string(self, position, size):
393396
:param position: int offset for key string
394397
:param size: int key size in bytes to read
395398
"""
396-
key_string_bytes = self.m[self.get_slice(position, size)]
397-
return struct.unpack(b"{0}s".format(size), key_string_bytes)[0]
398-
399+
key_string_bytes = self.m[self.get_slice(position, size)].tobytes()
400+
return struct.unpack(compat.b("{0}s".format(size)), key_string_bytes)[0].strip(compat.b("\x00"))
399401

400402
def read_key_value(self, position):
401403
"""Read float value of position
402404
403405
:param position: int offset for key value float
404406
"""
405-
key_value_bytes = self.m[self.get_slice(position, self.KEY_VALUE_SIZE)]
407+
key_value_bytes = self.m[self.get_slice(position, self.KEY_VALUE_SIZE)].tobytes()
406408
return struct.unpack(b"d", key_value_bytes)[0]
407409

408410
def read_key_size(self, position):
409411
"""Read key size from position
410412
411413
:param position: int offset for 4-byte key size
412414
"""
413-
key_size_bytes = self.m[self.get_slice(position, self.KEY_SIZE_SIZE)]
415+
key_size_bytes = self.m[self.get_slice(position, self.KEY_SIZE_SIZE)].tobytes()
414416
return struct.unpack(b"i", key_size_bytes)[0]
415417

416418
def write_key_value(self, position, value):
@@ -558,7 +560,7 @@ def __len__(self):
558560

559561
def clear(self):
560562
for x in xrange(self.AREA_SIZE_SIZE + self.AREA_SIZE_SIZE):
561-
self.m[x] = "\x00"
563+
self.m[x] = compat.PAD_SYMBOL
562564

563565
self._positions.clear()
564566

pyprometheus/managers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
default_timer = time.time
1818

19+
1920
class BaseManager(object):
2021
def __call__(self, f):
2122
@wraps(f)

0 commit comments

Comments
 (0)