redis-stat 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +5 -3
- data/lib/redis-stat.rb +59 -35
- data/lib/redis-stat/option.rb +20 -31
- data/lib/redis-stat/version.rb +1 -1
- data/redis-stat.gemspec +1 -0
- data/test/test_redis-stat.rb +6 -11
- metadata +17 -1
data/README.md
CHANGED
@@ -11,7 +11,7 @@ gem install redis-stat
|
|
11
11
|
## Usage
|
12
12
|
|
13
13
|
```
|
14
|
-
usage: redis-stat [HOST[:PORT]] [INTERVAL [COUNT]]
|
14
|
+
usage: redis-stat [HOST[:PORT] ...] [INTERVAL [COUNT]]
|
15
15
|
|
16
16
|
--csv=OUTPUT_CSV_FILE_PATH Save the result in CSV format
|
17
17
|
-v, --verbose Show more info
|
@@ -26,11 +26,13 @@ redis-stat
|
|
26
26
|
|
27
27
|
redis-stat 1
|
28
28
|
|
29
|
-
redis-stat
|
29
|
+
redis-stat 1 10
|
30
30
|
|
31
31
|
redis-stat localhost:6380 1 10
|
32
32
|
|
33
|
-
redis-stat localhost:6380
|
33
|
+
redis-stat localhost localhost:6380 localhost:6381 5
|
34
|
+
|
35
|
+
redis-stat localhost localhost:6380 1 10 --csv=/tmp/output.csv --verbose
|
34
36
|
```
|
35
37
|
|
36
38
|
## Screenshot
|
data/lib/redis-stat.rb
CHANGED
@@ -5,6 +5,7 @@ require 'redis'
|
|
5
5
|
require 'tabularize'
|
6
6
|
require 'ansi'
|
7
7
|
require 'csv'
|
8
|
+
require 'parallelize'
|
8
9
|
|
9
10
|
class RedisStat
|
10
11
|
DEFAULT_TERM_WIDTH = 180
|
@@ -12,7 +13,11 @@ class RedisStat
|
|
12
13
|
|
13
14
|
def initialize options = {}
|
14
15
|
@options = RedisStat::Option::DEFAULT.merge options
|
15
|
-
@
|
16
|
+
@hosts = @options[:hosts]
|
17
|
+
@redises = @hosts.map { |e|
|
18
|
+
host, port = e.split(':')
|
19
|
+
Redis.new(Hash[ {:host => host, :port => port}.select { |k, v| v } ])
|
20
|
+
}
|
16
21
|
@max_count = @options[:count]
|
17
22
|
@count = 0
|
18
23
|
@colors = @options[:colors] || COLORS
|
@@ -25,12 +30,30 @@ class RedisStat
|
|
25
30
|
csv = File.open(@options[:csv], 'w') if @options[:csv]
|
26
31
|
update_term_size!
|
27
32
|
|
28
|
-
|
33
|
+
|
29
34
|
begin
|
35
|
+
# Warm-up
|
36
|
+
@redises.each { |r| r.info }
|
37
|
+
|
30
38
|
@started_at = Time.now
|
39
|
+
prev_info = nil
|
31
40
|
loop do
|
32
|
-
info =
|
41
|
+
info = {}.insensitive
|
42
|
+
class << info
|
43
|
+
def sumf label
|
44
|
+
(self[label] || []).map(&:to_f).inject(:+)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
33
48
|
info[:at] = Time.now.to_f
|
49
|
+
@redises.pmap(@redises.length) { |redis|
|
50
|
+
redis.info.insensitive
|
51
|
+
}.each do |rinfo|
|
52
|
+
rinfo.each do |k, v|
|
53
|
+
info[k] ||= []
|
54
|
+
info[k] << v
|
55
|
+
end
|
56
|
+
end
|
34
57
|
|
35
58
|
output info, prev_info, csv
|
36
59
|
|
@@ -98,9 +121,9 @@ private
|
|
98
121
|
|
99
122
|
movement = nil
|
100
123
|
if @count == 0
|
101
|
-
movement = 0
|
102
124
|
output_static_info info
|
103
125
|
|
126
|
+
movement = 0
|
104
127
|
if file
|
105
128
|
file.puts CSV.generate_line(info_output.map { |pair|
|
106
129
|
LABELS[pair.first] || pair.first
|
@@ -147,30 +170,28 @@ private
|
|
147
170
|
end
|
148
171
|
|
149
172
|
def output_static_info info
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
@os.puts
|
172
|
-
ansi(:bold) { pair.first } + ' : ' + pair.last
|
173
|
-
}
|
173
|
+
tab = Tabularize.new(
|
174
|
+
:unicode => false, :align => :right,
|
175
|
+
:hborder => ansi(:black, :bold) { '-' },
|
176
|
+
:vborder => ansi(:black, :bold) { '|' },
|
177
|
+
:iborder => ansi(:black, :bold) { '+' }
|
178
|
+
)
|
179
|
+
tab << [nil] + @hosts.map { |h| ansi(:bold, :green) { h } }
|
180
|
+
tab.separator!
|
181
|
+
[
|
182
|
+
:redis_version,
|
183
|
+
:process_id,
|
184
|
+
:uptime_in_seconds,
|
185
|
+
:uptime_in_days,
|
186
|
+
:gcc_version,
|
187
|
+
:role,
|
188
|
+
:connected_slaves,
|
189
|
+
:aof_enabled,
|
190
|
+
:vm_enabled
|
191
|
+
].each do |key|
|
192
|
+
tab << [ansi(:bold) { key }] + info[key]
|
193
|
+
end
|
194
|
+
@os.puts tab
|
174
195
|
end
|
175
196
|
|
176
197
|
def init_table info_output
|
@@ -179,6 +200,7 @@ private
|
|
179
200
|
:hborder => ansi(:black, :bold) { '-' },
|
180
201
|
:iborder => ansi(:black, :bold) { '+' },
|
181
202
|
:vborder => ' ',
|
203
|
+
:ellipsis => ansi(:bold) { '>' },
|
182
204
|
:pad_left => 0,
|
183
205
|
:pad_right => 0,
|
184
206
|
:screen_width => @term_width
|
@@ -200,8 +222,8 @@ private
|
|
200
222
|
dur = prev_info && (info[:at] - prev_info[:at])
|
201
223
|
|
202
224
|
get_diff = lambda do |label|
|
203
|
-
if dur
|
204
|
-
(info
|
225
|
+
if dur && dur > 0
|
226
|
+
(info.sumf(label) - prev_info.sumf(label)) / dur
|
205
227
|
else
|
206
228
|
nil
|
207
229
|
end
|
@@ -214,8 +236,8 @@ private
|
|
214
236
|
val = get_diff.call(key)
|
215
237
|
[humanize_number(val), val]
|
216
238
|
when :keys
|
217
|
-
val = Hash[ info.select { |k, v| k =~ /^db[0-9]+$/ } ].values.inject(0) { |sum,
|
218
|
-
sum + Hash[ v.split(',').map { |e| e.split '=' } ]['keys'].to_i
|
239
|
+
val = Hash[ info.select { |k, v| k =~ /^db[0-9]+$/ } ].values.inject(0) { |sum, vs|
|
240
|
+
sum + vs.map { |v| Hash[ v.split(',').map { |e| e.split '=' } ]['keys'].to_i }.inject(:+)
|
219
241
|
}
|
220
242
|
[humanize_number(val), val]
|
221
243
|
when :evicted_keys_per_second, :expired_keys_per_second, :keyspace_hits_per_second,
|
@@ -223,11 +245,13 @@ private
|
|
223
245
|
val = get_diff.call(key.to_s.gsub(/_per_second$/, '').to_sym)
|
224
246
|
[humanize_number(val), val]
|
225
247
|
when :total_commands_processed, :evicted_keys, :expired_keys, :keyspace_hits, :keyspace_misses
|
226
|
-
|
248
|
+
val = info.sumf(key)
|
249
|
+
[humanize_number(val.to_i), val]
|
227
250
|
when :used_memory, :used_memory_rss, :aof_current_size, :aof_base_size
|
228
|
-
|
251
|
+
val = info.sumf(key)
|
252
|
+
[humanize_number(val.to_i, 1024, 'B'), val]
|
229
253
|
else
|
230
|
-
info
|
254
|
+
format_number info.sumf(key)
|
231
255
|
end
|
232
256
|
end
|
233
257
|
|
data/lib/redis-stat/option.rb
CHANGED
@@ -3,8 +3,7 @@ require 'optparse'
|
|
3
3
|
class RedisStat
|
4
4
|
module Option
|
5
5
|
DEFAULT = {
|
6
|
-
:
|
7
|
-
:port => 6379,
|
6
|
+
:hosts => ['127.0.0.1:6379'],
|
8
7
|
:interval => 2,
|
9
8
|
:count => nil,
|
10
9
|
:csv => nil
|
@@ -15,7 +14,7 @@ module Option
|
|
15
14
|
|
16
15
|
options = DEFAULT.dup
|
17
16
|
opts = ::OptionParser.new { |opts|
|
18
|
-
opts.banner = "usage: redis-stat [HOST[:PORT]] [INTERVAL [COUNT]]"
|
17
|
+
opts.banner = "usage: redis-stat [HOST[:PORT] ...] [INTERVAL [COUNT]]"
|
19
18
|
opts.separator ''
|
20
19
|
|
21
20
|
opts.on('--csv=OUTPUT_CSV_FILE_PATH', 'Save the result in CSV format') do |v|
|
@@ -41,33 +40,13 @@ module Option
|
|
41
40
|
opts.parse! argv
|
42
41
|
|
43
42
|
is_number = lambda { |str| str =~ /^([0-9]\.?[0-9]*)$|^([1-9][0-9]*)$/ }
|
44
|
-
set_options = lambda { |host_port, interval, count|
|
45
|
-
if host_port
|
46
|
-
host, port = host_port.split(':')
|
47
|
-
options[:host] = host
|
48
|
-
options[:port] = port.to_i if port
|
49
|
-
end
|
50
43
|
|
51
|
-
|
52
|
-
|
53
|
-
}
|
44
|
+
numbers, hosts = argv.partition { |e| is_number.call e }
|
45
|
+
interval, count = numbers.map(&:to_f)
|
54
46
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
set_options.call nil, argv.first, nil
|
59
|
-
else
|
60
|
-
set_options.call argv.first, nil, nil
|
61
|
-
end
|
62
|
-
when 2
|
63
|
-
if is_number.call argv.first
|
64
|
-
set_options.call nil, argv.first, argv.last
|
65
|
-
else
|
66
|
-
set_options.call argv.first, argv.last, nil
|
67
|
-
end
|
68
|
-
when 3
|
69
|
-
set_options.call *argv
|
70
|
-
end
|
47
|
+
options[:interval] = interval if interval
|
48
|
+
options[:count] = count if count
|
49
|
+
options[:hosts] = hosts unless hosts.empty?
|
71
50
|
|
72
51
|
validate options
|
73
52
|
|
@@ -92,9 +71,19 @@ module Option
|
|
92
71
|
raise ArgumentError.new("Invalid count: #{count}")
|
93
72
|
end
|
94
73
|
|
95
|
-
|
96
|
-
|
97
|
-
raise ArgumentError.new("
|
74
|
+
hosts = options[:hosts]
|
75
|
+
if hosts.empty?
|
76
|
+
raise ArgumentError.new("Redis host not given")
|
77
|
+
end
|
78
|
+
|
79
|
+
hosts.each do |host|
|
80
|
+
host, port = host.split(':')
|
81
|
+
if port
|
82
|
+
port = port.to_i
|
83
|
+
unless port > 0 && port < 65536
|
84
|
+
raise ArgumentError.new("Invalid port: #{port}")
|
85
|
+
end
|
86
|
+
end
|
98
87
|
end
|
99
88
|
end
|
100
89
|
end
|
data/lib/redis-stat/version.rb
CHANGED
data/redis-stat.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_runtime_dependency "redis", '~> 3.0.1'
|
20
20
|
gem.add_runtime_dependency "tabularize", '~> 0.2.4'
|
21
21
|
gem.add_runtime_dependency "insensitive_hash", '~> 0.2.4'
|
22
|
+
gem.add_runtime_dependency "parallelize", '~> 0.4.0'
|
22
23
|
|
23
24
|
gem.add_development_dependency 'test-unit'
|
24
25
|
end
|
data/test/test_redis-stat.rb
CHANGED
@@ -43,8 +43,7 @@ class TestRedisStat < Test::Unit::TestCase
|
|
43
43
|
|
44
44
|
options = RedisStat::Option.parse(%w[localhost:1000 20])
|
45
45
|
assert_equal({
|
46
|
-
:
|
47
|
-
:port => 1000,
|
46
|
+
:hosts => ['localhost:1000'],
|
48
47
|
:interval => 20,
|
49
48
|
:count => nil,
|
50
49
|
:csv => nil
|
@@ -52,8 +51,7 @@ class TestRedisStat < Test::Unit::TestCase
|
|
52
51
|
|
53
52
|
options = RedisStat::Option.parse(%w[localhost:1000 20 30])
|
54
53
|
assert_equal({
|
55
|
-
:
|
56
|
-
:port => 1000,
|
54
|
+
:hosts => ['localhost:1000'],
|
57
55
|
:interval => 20,
|
58
56
|
:count => 30,
|
59
57
|
:csv => nil
|
@@ -61,8 +59,7 @@ class TestRedisStat < Test::Unit::TestCase
|
|
61
59
|
|
62
60
|
options = RedisStat::Option.parse(%w[20])
|
63
61
|
assert_equal({
|
64
|
-
:
|
65
|
-
:port => 6379,
|
62
|
+
:hosts => ['127.0.0.1:6379'],
|
66
63
|
:interval => 20,
|
67
64
|
:count => nil,
|
68
65
|
:csv => nil
|
@@ -70,8 +67,7 @@ class TestRedisStat < Test::Unit::TestCase
|
|
70
67
|
|
71
68
|
options = RedisStat::Option.parse(%w[20 30])
|
72
69
|
assert_equal({
|
73
|
-
:
|
74
|
-
:port => 6379,
|
70
|
+
:hosts => ['127.0.0.1:6379'],
|
75
71
|
:interval => 20,
|
76
72
|
:count => 30,
|
77
73
|
:csv => nil
|
@@ -79,8 +75,7 @@ class TestRedisStat < Test::Unit::TestCase
|
|
79
75
|
|
80
76
|
options = RedisStat::Option.parse(%w[localhost:8888 10 --csv=/tmp/a.csv])
|
81
77
|
assert_equal({
|
82
|
-
:
|
83
|
-
:host => 'localhost',
|
78
|
+
:hosts => ['localhost:8888'],
|
84
79
|
:interval => 10,
|
85
80
|
:count => nil,
|
86
81
|
:csv => '/tmp/a.csv',
|
@@ -101,7 +96,7 @@ class TestRedisStat < Test::Unit::TestCase
|
|
101
96
|
def test_start
|
102
97
|
csv = '/tmp/redis-stat.csv'
|
103
98
|
cnt = 50
|
104
|
-
rs = RedisStat.new :interval => 0.
|
99
|
+
rs = RedisStat.new :hosts => %w[localhost] * 5, :interval => 0.1, :count => cnt, :verbose => true, :csv => csv
|
105
100
|
rs.start $stdout
|
106
101
|
|
107
102
|
assert_equal cnt + 1, File.read(csv).lines.to_a.length
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-stat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -75,6 +75,22 @@ dependencies:
|
|
75
75
|
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: 0.2.4
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: parallelize
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.4.0
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.4.0
|
78
94
|
- !ruby/object:Gem::Dependency
|
79
95
|
name: test-unit
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|