Skip to content

Commit 4db287e

Browse files
committed
added SLOWLOG support. finally can partially close redis#170 :)
1 parent 0340f1b commit 4db287e

File tree

4 files changed

+69
-2
lines changed

4 files changed

+69
-2
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* Added extra *SCAN commands that return iterators instead of the normal
1111
[cursor, data] type. Use scan_iter, hscan_iter, sscan_iter, and
1212
zscan_iter for iterators. Thanks Mathieu Longtin.
13+
* Added support for SLOWLOG commands. Thanks Rick van Hattem.
1314
* 2.9.1
1415
* IPv6 support. Thanks https://github.com/amashinchi
1516
* 2.9.0

redis/_compat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
nativestr = lambda x: \
4141
x if isinstance(x, str) else x.decode('utf-8', 'replace')
4242
u = lambda x: x
43-
b = lambda x: x.encode('iso-8859-1') if not isinstance(x, bytes) else x
43+
b = lambda x: x.encode('latin-1') if not isinstance(x, bytes) else x
4444
next = next
4545
unichr = chr
4646
imap = map

redis/client.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,21 @@ def parse_zscan(response, **options):
260260
return nativestr(cursor), list(izip(it, imap(score_cast_func, it)))
261261

262262

263+
def parse_slowlog(response, **options):
264+
parse = options['parse']
265+
if parse == 'LEN':
266+
return int(response)
267+
elif parse == 'RESET':
268+
return nativestr(response) == 'OK'
269+
elif parse == 'GET':
270+
return [{
271+
'id': item[0],
272+
'start_time': int(item[1]),
273+
'duration': int(item[2]),
274+
'command': b(' ').join(item[3])
275+
} for item in response]
276+
277+
263278
class StrictRedis(object):
264279
"""
265280
Implementation of the Redis protocol.
@@ -316,6 +331,7 @@ class StrictRedis(object):
316331
'CONFIG': parse_config,
317332
'DEBUG': parse_debug_object,
318333
'HGETALL': lambda r: r and pairs_to_dict(r) or {},
334+
'HSCAN': parse_hscan,
319335
'INFO': parse_info,
320336
'LASTSAVE': timestamp_to_datetime,
321337
'OBJECT': parse_object,
@@ -326,8 +342,8 @@ class StrictRedis(object):
326342
'TIME': lambda x: (int(x[0]), int(x[1])),
327343
'SENTINEL': parse_sentinel,
328344
'SCAN': parse_scan,
345+
'SLOWLOG': parse_slowlog,
329346
'SSCAN': parse_scan,
330-
'HSCAN': parse_hscan,
331347
'ZSCAN': parse_zscan
332348
}
333349
)
@@ -621,6 +637,24 @@ def slaveof(self, host=None, port=None):
621637
return self.execute_command("SLAVEOF", "NO", "ONE")
622638
return self.execute_command("SLAVEOF", host, port)
623639

640+
def slowlog_get(self, num=None):
641+
"""
642+
Get the entries from the slowlog. If ``num`` is specified, get the
643+
most recent ``num`` items.
644+
"""
645+
args = ['SLOWLOG', 'GET']
646+
if num is not None:
647+
args.append(num)
648+
return self.execute_command(*args, parse='GET')
649+
650+
def slowlog_len(self):
651+
"Get the number of items in the slowlog"
652+
return self.execute_command('SLOWLOG', 'LEN', parse='LEN')
653+
654+
def slowlog_reset(self):
655+
"Remove all items in the slowlog"
656+
return self.execute_command('SLOWLOG', 'RESET', parse='RESET')
657+
624658
def time(self):
625659
"""
626660
Returns the server time as a 2-item tuple of ints:

tests/test_commands.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,38 @@ def test_object(self, r):
9494
def test_ping(self, r):
9595
assert r.ping()
9696

97+
def test_slowlog_get(self, r):
98+
assert r.slowlog_reset()
99+
unicode_string = unichr(3456) + u('abcd') + unichr(3421)
100+
r.get(unicode_string)
101+
slowlog = r.slowlog_get()
102+
assert isinstance(slowlog, list)
103+
assert len(slowlog) == 2
104+
get_command = slowlog[0]
105+
assert isinstance(get_command['start_time'], int)
106+
assert isinstance(get_command['duration'], int)
107+
assert get_command['command'] == \
108+
b(' ').join((b('GET'), unicode_string.encode('utf-8')))
109+
110+
slowlog_reset_command = slowlog[1]
111+
assert isinstance(slowlog_reset_command['start_time'], int)
112+
assert isinstance(slowlog_reset_command['duration'], int)
113+
assert slowlog_reset_command['command'] == b('SLOWLOG RESET')
114+
115+
def test_slowlog_get_limit(self, r):
116+
assert r.slowlog_reset()
117+
r.get('foo')
118+
r.get('bar')
119+
slowlog = r.slowlog_get(1)
120+
assert isinstance(slowlog, list)
121+
assert len(slowlog) == 1
122+
assert slowlog[0]['command'] == b('GET bar')
123+
124+
def test_slowlog_length(self, r):
125+
assert r.slowlog_reset()
126+
r.get('foo')
127+
assert r.slowlog_len() == 2
128+
97129
@skip_if_server_version_lt('2.6.0')
98130
def test_time(self, r):
99131
t = r.time()

0 commit comments

Comments
 (0)