redis-stat 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|