sidekiq-spy 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +119 -0
- data/Rakefile +11 -0
- data/bin/sidekiq-spy +99 -0
- data/lib/sidekiq-spy.rb +11 -0
- data/lib/sidekiq-spy/app.rb +74 -0
- data/lib/sidekiq-spy/config.rb +34 -0
- data/lib/sidekiq-spy/display/panel.rb +81 -0
- data/lib/sidekiq-spy/display/screen.rb +82 -0
- data/lib/sidekiq-spy/display/subpanel.rb +47 -0
- data/lib/sidekiq-spy/spy/stats.rb +73 -0
- data/lib/sidekiq-spy/translatable.rb +32 -0
- data/lib/sidekiq-spy/version.rb +5 -0
- data/sidekiq-spy.gemspec +27 -0
- data/test/fixtures/redis_info.json +61 -0
- data/test/helper.rb +6 -0
- data/test/sidekiq-spy/app_test.rb +60 -0
- data/test/sidekiq-spy/config_test.rb +140 -0
- data/test/sidekiq-spy/spy/stats_test.rb +125 -0
- data/test/sidekiq-spy/version_test.rb +12 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7a20cacb912beed5baf1c80012a87e5115dae2bf
|
4
|
+
data.tar.gz: 1db3848aa6af319f5037ee72dc6720683735d53d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ed49f93281287bbc32d5a5b7629a85d5489e50e35bbae88e16369e764644d87f697593c610a5e149e65d9a4aff8041dc902b2901782d4b2e061e7930e8bc0cef
|
7
|
+
data.tar.gz: d16b91fb061442fb4ec76ed66e415cb10e3ab5776bab6b7c77e5893c88d666072c09559b35870b222151a68005a22f5332be5e57b9aad0a7ce06a014d54a38ed
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
sidekiq-spy
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0.0
|
data/.travis.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- jruby-19mode
|
5
|
+
- rbx-19mode
|
6
|
+
- 2.0.0
|
7
|
+
notifications:
|
8
|
+
email:
|
9
|
+
recipients:
|
10
|
+
- tp@tiredpixel.com
|
11
|
+
- sidekiq.spy@librelist.com
|
12
|
+
matrix:
|
13
|
+
allow_failures:
|
14
|
+
- rvm: 1.9.3
|
15
|
+
- rvm: jruby-19mode
|
16
|
+
- rvm: rbx-19mode
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 tiredpixel
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Sidekiq Spy
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/sidekiq-spy.png)](http://badge.fury.io/rb/sidekiq-spy)
|
4
|
+
[![Build Status](https://travis-ci.org/tiredpixel/sidekiq-spy.png?branch=master,develop)](https://travis-ci.org/tiredpixel/sidekiq-spy)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/tiredpixel/sidekiq-spy.png)](https://codeclimate.com/github/tiredpixel/sidekiq-spy)
|
6
|
+
[![Coverage Status](https://coveralls.io/repos/tiredpixel/sidekiq-spy/badge.png?branch=master,develop)](https://coveralls.io/r/tiredpixel/sidekiq-spy)
|
7
|
+
|
8
|
+
[Sidekiq](https://github.com/mperham/sidekiq) monitoring in the console.
|
9
|
+
A bit like Sidekiq::Web. But without the web.
|
10
|
+
|
11
|
+
So, Sidekiq is a beautiful thing. :) But if you know the sadness of wanting to
|
12
|
+
see how your workers are doing at-a-glance when SSHed into a remote box with
|
13
|
+
no web server, this one's for you. <3
|
14
|
+
|
15
|
+
This project is so hot out of the oven you might need mitts. But it's already
|
16
|
+
functional, with the main statistics from the Sidekiq::Web homepage. In time,
|
17
|
+
it would be nice to add the Workers, Queues, Retries, and Scheduled tabs, too.
|
18
|
+
|
19
|
+
More sleep lost by [tiredpixel](http://www.tiredpixel.com).
|
20
|
+
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
Install using:
|
25
|
+
|
26
|
+
$ gem install sidekiq-spy
|
27
|
+
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
View the available options:
|
32
|
+
|
33
|
+
$ sidekiq-spy --help
|
34
|
+
|
35
|
+
If you're connecting to `redis://127.0.0.1:6379/0` with no namespace you can
|
36
|
+
simply:
|
37
|
+
|
38
|
+
$ sidekiq-spy
|
39
|
+
|
40
|
+
To use a connection string URL:
|
41
|
+
|
42
|
+
$ sidekiq-spy -u redis://da.example.com:237/42
|
43
|
+
|
44
|
+
Or, if you prefer your options like your Hi-Fi:
|
45
|
+
|
46
|
+
$ sidekiq-spy -h da.example.com -p 237 -d 42
|
47
|
+
|
48
|
+
Maybe you're using [Resque](https://github.com/resque/resque)? Sssh!
|
49
|
+
We won't tell anyone! ;) (Resque is awesome, too!)
|
50
|
+
|
51
|
+
$ sidekiq-spy -n resque
|
52
|
+
|
53
|
+
That's about it.
|
54
|
+
|
55
|
+
|
56
|
+
## ASCII Art (a.k.a. Screenshot)
|
57
|
+
|
58
|
+
Sidekiq Spy 0.0.1 | 01:02:58 +0100
|
59
|
+
redis: 127.0.0.1:6379/0|namespace:
|
60
|
+
redis version: 2.6.11|uptime (d): 8|connections: 3
|
61
|
+
memory: 4.84M|memory peak: 13.52M|
|
62
|
+
|
63
|
+
busy: 0|retries: 0|processed: 1304
|
64
|
+
enqueued: 0|scheduled: 0|failed: 1236
|
65
|
+
|
66
|
+
|
67
|
+
## Stay Tuned
|
68
|
+
|
69
|
+
We have a [Librelist](http://librelist.com) mailing list!
|
70
|
+
To subscribe, send an email to <sidekiq.spy@librelist.com>.
|
71
|
+
To unsubscribe, send an email to <sidekiq.spy-unsubscribe@librelist.com>.
|
72
|
+
There be [archives](http://librelist.com/browser/sidekiq.spy/).
|
73
|
+
That was easy.
|
74
|
+
|
75
|
+
|
76
|
+
## Growing Like Flowers
|
77
|
+
|
78
|
+
Dear Me, Here is a vague wishlist:
|
79
|
+
|
80
|
+
- more tests for the display parts
|
81
|
+
- Workers table on main page
|
82
|
+
- Queues page
|
83
|
+
- Retries page
|
84
|
+
- Scheduled page
|
85
|
+
- a little control to go with your monitoring, maybe...
|
86
|
+
|
87
|
+
|
88
|
+
## Contributions
|
89
|
+
|
90
|
+
Contributions are embraced with much love and affection!
|
91
|
+
Please fork the repository and wizard your magic, preferably with plenty of
|
92
|
+
fairy-dust sprinkled over the tests. ;)
|
93
|
+
Then send me a pull request. Simples!
|
94
|
+
If you'd like to discuss what you're doing or planning to do, or if you get
|
95
|
+
stuck on something, then just wave. :)
|
96
|
+
|
97
|
+
Do whatever makes you happy. We'll probably still like you. :)
|
98
|
+
|
99
|
+
Tests are written using [minitest](https://github.com/seattlerb/minitest),
|
100
|
+
which is included by default in Ruby 1.9 onwards. To run all tests:
|
101
|
+
|
102
|
+
rake test
|
103
|
+
|
104
|
+
Or, if you're of that turn of mind, use [TURN](https://github.com/TwP/turn)
|
105
|
+
(`gem install turn`):
|
106
|
+
|
107
|
+
turn test/sidekiq-spy/
|
108
|
+
|
109
|
+
|
110
|
+
## Blessing
|
111
|
+
|
112
|
+
May you find peace, and help others to do likewise.
|
113
|
+
|
114
|
+
|
115
|
+
## Licence
|
116
|
+
|
117
|
+
© [tiredpixel](http://www.tiredpixel.com) 2013.
|
118
|
+
It is free software, released under the MIT License, and may be redistributed
|
119
|
+
under the terms specified in `LICENSE`.
|
data/Rakefile
ADDED
data/bin/sidekiq-spy
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$stdout.sync = true
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
require File.expand_path('../../lib/sidekiq-spy', __FILE__)
|
8
|
+
|
9
|
+
|
10
|
+
# = Parse opts
|
11
|
+
|
12
|
+
options = {}
|
13
|
+
|
14
|
+
OptionParser.new do |opts|
|
15
|
+
opts.version = "v#{SidekiqSpy::VERSION}"
|
16
|
+
|
17
|
+
opts.banner = opts.ver
|
18
|
+
|
19
|
+
opts.separator ""
|
20
|
+
opts.separator "Usage: sidekiq-spy [OPTIONS]"
|
21
|
+
|
22
|
+
opts.on("-u", "--url URL",
|
23
|
+
"Redis connection string URL"
|
24
|
+
) { |o| options[:url] = o }
|
25
|
+
|
26
|
+
opts.on("-h", "--host HOSTNAME",
|
27
|
+
"Redis hostname (default: 127.0.0.1)"
|
28
|
+
) { |o| options[:host] = o }
|
29
|
+
|
30
|
+
opts.on("-p", "--port PORT", Integer,
|
31
|
+
"Redis port (default: 6379)"
|
32
|
+
) { |o| options[:port] = o }
|
33
|
+
|
34
|
+
opts.on("-d", "--database DATABASE", Integer,
|
35
|
+
"Redis database (default: 0)"
|
36
|
+
) { |o| options[:database] = o }
|
37
|
+
|
38
|
+
opts.on("-n", "--namespace NAMESPACE",
|
39
|
+
"Redis namespace (default: '')"
|
40
|
+
) { |o| options[:namespace] = o }
|
41
|
+
|
42
|
+
opts.on("-i", "--interval INTERVAL", Integer,
|
43
|
+
"Refresh every INTERVAL s (default: 5)"
|
44
|
+
) { |o| options[:interval] = o }
|
45
|
+
|
46
|
+
opts.separator ""
|
47
|
+
opts.separator "Examples:"
|
48
|
+
|
49
|
+
opts.separator [
|
50
|
+
"sidekiq-spy",
|
51
|
+
"sidekiq-spy -u redis://da.example.com:237/42",
|
52
|
+
"sidekiq-spy -h da.example.com -p 237 -d 42",
|
53
|
+
"sidekiq-spy -n resque -i 1",
|
54
|
+
].map { |e| " #{e}" }
|
55
|
+
|
56
|
+
opts.separator ""
|
57
|
+
|
58
|
+
opts.on_tail("--help",
|
59
|
+
"Output (this) help and exit"
|
60
|
+
) do
|
61
|
+
puts opts
|
62
|
+
exit
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on_tail("--version",
|
66
|
+
"Output version and exit"
|
67
|
+
) do
|
68
|
+
puts opts.ver
|
69
|
+
exit
|
70
|
+
end
|
71
|
+
end.parse!
|
72
|
+
|
73
|
+
|
74
|
+
# = Create app
|
75
|
+
|
76
|
+
@app = SidekiqSpy::App.new
|
77
|
+
|
78
|
+
|
79
|
+
# = Configure
|
80
|
+
|
81
|
+
@app.configure do |c|
|
82
|
+
params = [
|
83
|
+
:url,
|
84
|
+
:host,
|
85
|
+
:port,
|
86
|
+
:database,
|
87
|
+
:namespace,
|
88
|
+
:interval,
|
89
|
+
]
|
90
|
+
|
91
|
+
params.each { |p| c.send("#{p}=", options[p]) unless options[p].nil? }
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# = Run app
|
96
|
+
|
97
|
+
trap('INT') { @app.stop }
|
98
|
+
|
99
|
+
@app.start
|
data/lib/sidekiq-spy.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.expand_path('../sidekiq-spy/version', __FILE__)
|
2
|
+
require File.expand_path('../sidekiq-spy/config', __FILE__)
|
3
|
+
|
4
|
+
require File.expand_path('../sidekiq-spy/translatable', __FILE__)
|
5
|
+
require File.expand_path('../sidekiq-spy/app', __FILE__)
|
6
|
+
|
7
|
+
require File.expand_path('../sidekiq-spy/spy/stats', __FILE__)
|
8
|
+
|
9
|
+
require File.expand_path('../sidekiq-spy/display/screen', __FILE__)
|
10
|
+
require File.expand_path('../sidekiq-spy/display/panel', __FILE__)
|
11
|
+
require File.expand_path('../sidekiq-spy/display/subpanel', __FILE__)
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
class App
|
6
|
+
|
7
|
+
attr_reader :running
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@running = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def config
|
14
|
+
@config ||= Config.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def configure
|
18
|
+
yield config
|
19
|
+
|
20
|
+
configure_sidekiq
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
begin
|
25
|
+
@running = true
|
26
|
+
|
27
|
+
setup
|
28
|
+
|
29
|
+
while @running do
|
30
|
+
refresh
|
31
|
+
|
32
|
+
@sleep_timer = config.interval
|
33
|
+
|
34
|
+
while @running && @sleep_timer > 0
|
35
|
+
sleep 1
|
36
|
+
|
37
|
+
@sleep_timer -= 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
ensure
|
41
|
+
cleanup
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def stop
|
46
|
+
@running = false
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def configure_sidekiq
|
52
|
+
Sidekiq.configure_client do |sidekiq_config|
|
53
|
+
sidekiq_config.logger = nil
|
54
|
+
sidekiq_config.redis = {
|
55
|
+
:url => config.url,
|
56
|
+
:namespace => config.namespace,
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def setup
|
62
|
+
@screen = Display::Screen.new
|
63
|
+
end
|
64
|
+
|
65
|
+
def refresh
|
66
|
+
@screen.refresh
|
67
|
+
end
|
68
|
+
|
69
|
+
def cleanup
|
70
|
+
@screen.close if @screen
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
class Config
|
6
|
+
|
7
|
+
attr_accessor :host
|
8
|
+
attr_accessor :port
|
9
|
+
attr_accessor :database
|
10
|
+
attr_accessor :namespace
|
11
|
+
attr_accessor :interval
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@host = '127.0.0.1'
|
15
|
+
@port = 6379
|
16
|
+
@database = 0
|
17
|
+
@namespace = nil
|
18
|
+
@interval = 5
|
19
|
+
end
|
20
|
+
|
21
|
+
def url=(url)
|
22
|
+
url = URI.parse(url)
|
23
|
+
|
24
|
+
@host = url.host unless url.host.empty?
|
25
|
+
@port = url.port unless url.path.empty?
|
26
|
+
@database = url.path.tr('/', '').to_i unless url.path.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
def url
|
30
|
+
"redis://#{@host}:#{@port}/#{@database}"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
module Display
|
6
|
+
class Panel
|
7
|
+
|
8
|
+
def initialize(height, width, top, left, structure, opts = {})
|
9
|
+
@height = height
|
10
|
+
@width = width
|
11
|
+
@top = top
|
12
|
+
@left = left
|
13
|
+
|
14
|
+
@dividers = {
|
15
|
+
:left => opts[:divider_l].to_s,
|
16
|
+
:right => opts[:divider_r].to_s,
|
17
|
+
}
|
18
|
+
|
19
|
+
@divider_length = @dividers.values.map(&:length).inject(:+)
|
20
|
+
|
21
|
+
@window = Curses::Window.new(@height, @width, @top, @left)
|
22
|
+
|
23
|
+
@subpanels = build_subpanels(structure)
|
24
|
+
end
|
25
|
+
|
26
|
+
def close
|
27
|
+
@window.close
|
28
|
+
end
|
29
|
+
|
30
|
+
def refresh
|
31
|
+
@subpanels.each(&:refresh) # build changes
|
32
|
+
|
33
|
+
@window.refresh # push changes to window
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def build_subpanels(structure)
|
39
|
+
subpanels = []
|
40
|
+
|
41
|
+
structure.each_with_index do |row, i|
|
42
|
+
next if row.nil? # skip blank rows
|
43
|
+
|
44
|
+
row_cols = row.map { |e| e[0] }.inject(:+)
|
45
|
+
|
46
|
+
col_width = (@width / row_cols) + @divider_length
|
47
|
+
|
48
|
+
col_i = 0
|
49
|
+
|
50
|
+
row.each_with_index do |(tag_cols, data_l, data_r), row_i|
|
51
|
+
first_col = row_i == 0
|
52
|
+
last_col = row_i + 1 == row.length
|
53
|
+
|
54
|
+
tag_col_width = if last_col
|
55
|
+
@width - ((row_cols - tag_cols) * col_width)
|
56
|
+
else
|
57
|
+
tag_cols * col_width
|
58
|
+
end
|
59
|
+
|
60
|
+
subpanels << Display::Subpanel.new(
|
61
|
+
@window,
|
62
|
+
1,
|
63
|
+
tag_col_width,
|
64
|
+
i,
|
65
|
+
col_i,
|
66
|
+
:data_l => data_l,
|
67
|
+
:data_r => data_r,
|
68
|
+
:divider_l => (@dividers[:left] unless first_col),
|
69
|
+
:divider_r => (@dividers[:right] unless last_col)
|
70
|
+
)
|
71
|
+
|
72
|
+
col_i += tag_col_width
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
subpanels
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'curses'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
module Display
|
6
|
+
class Screen
|
7
|
+
|
8
|
+
include Translatable
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
Curses.init_screen
|
12
|
+
Curses.nl
|
13
|
+
Curses.noecho
|
14
|
+
Curses.curs_set(0)
|
15
|
+
|
16
|
+
@height = Curses.lines
|
17
|
+
@width = Curses.cols
|
18
|
+
|
19
|
+
@panels = {
|
20
|
+
:header => panel_header,
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
@panels.each { |pname, panel| panel.close }
|
26
|
+
|
27
|
+
Curses.close_screen
|
28
|
+
end
|
29
|
+
|
30
|
+
def refresh
|
31
|
+
@panels.each { |pname, panel| panel.refresh }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def panel_header
|
37
|
+
stats = Spy::Stats.new
|
38
|
+
|
39
|
+
structure = [
|
40
|
+
[
|
41
|
+
[1, t[:program], nil],
|
42
|
+
[1, nil, -> { Time.now.strftime("%T %z") }],
|
43
|
+
],
|
44
|
+
[
|
45
|
+
[2, t[:redis][:connection], -> { stats.connection }],
|
46
|
+
[1, t[:redis][:namespace], -> { stats.namespace }],
|
47
|
+
],
|
48
|
+
[
|
49
|
+
[1, t[:redis][:version], -> { stats.redis_version }],
|
50
|
+
[1, t[:redis][:uptime], -> { stats.uptime }],
|
51
|
+
[1, t[:redis][:connections], -> { stats.connections }],
|
52
|
+
],
|
53
|
+
[
|
54
|
+
[1, t[:redis][:memory], -> { stats.memory }],
|
55
|
+
[1, t[:redis][:memory_peak], -> { stats.memory_peak }],
|
56
|
+
[1, nil, nil],
|
57
|
+
],
|
58
|
+
nil,
|
59
|
+
[
|
60
|
+
[1, t[:sidekiq][:busy], -> { stats.busy }],
|
61
|
+
[1, t[:sidekiq][:retries], -> { stats.retries }],
|
62
|
+
[1, t[:sidekiq][:processed], -> { stats.processed }],
|
63
|
+
],
|
64
|
+
[
|
65
|
+
[1, t[:sidekiq][:enqueued], -> { stats.enqueued }],
|
66
|
+
[1, t[:sidekiq][:scheduled], -> { stats.scheduled }],
|
67
|
+
[1, t[:sidekiq][:failed], -> { stats.failed }],
|
68
|
+
],
|
69
|
+
nil,
|
70
|
+
]
|
71
|
+
|
72
|
+
opts = {
|
73
|
+
:divider_l => t[:divider][:left],
|
74
|
+
:divider_r => t[:divider][:right],
|
75
|
+
}
|
76
|
+
|
77
|
+
Display::Panel.new(structure.length, @width, 0, 0, structure, opts)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module SidekiqSpy
|
2
|
+
module Display
|
3
|
+
class Subpanel
|
4
|
+
|
5
|
+
def initialize(window, height, width, top, left, opts = {})
|
6
|
+
@window = window
|
7
|
+
@height = height
|
8
|
+
@width = width
|
9
|
+
@top = top
|
10
|
+
@left = left
|
11
|
+
|
12
|
+
@data = {
|
13
|
+
:left => opts[:data_l],
|
14
|
+
:right => opts[:data_r],
|
15
|
+
}
|
16
|
+
|
17
|
+
@dividers = {
|
18
|
+
:left => opts[:divider_l].to_s,
|
19
|
+
:right => opts[:divider_r].to_s,
|
20
|
+
}
|
21
|
+
|
22
|
+
@content_width = @width - @dividers.values.map(&:length).inject(:+)
|
23
|
+
end
|
24
|
+
|
25
|
+
def refresh
|
26
|
+
new_current = content(@data[:left], @data[:right], @content_width)
|
27
|
+
|
28
|
+
unless new_current == @data[:current] # don't redraw if hasn't changed
|
29
|
+
@window.setpos(@top, @left)
|
30
|
+
@window.addstr(@dividers[:left] + new_current + @dividers[:right])
|
31
|
+
end
|
32
|
+
|
33
|
+
@data[:current] = new_current
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def content(data_l, data_r, width)
|
39
|
+
l = data_l.is_a?(Proc) ? data_l.call : data_l.to_s
|
40
|
+
r = data_r.is_a?(Proc) ? data_r.call : data_r.to_s
|
41
|
+
|
42
|
+
l + "%#{width - l.length}s" % r
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
|
4
|
+
module SidekiqSpy
|
5
|
+
module Spy
|
6
|
+
class Stats
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@stats = Sidekiq::Stats.new
|
10
|
+
@workers = Sidekiq::Workers.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def connection
|
14
|
+
redis { |c| "#{c.client.location}/#{c.client.db}" }
|
15
|
+
end
|
16
|
+
|
17
|
+
def namespace
|
18
|
+
redis { |c| c.namespace if c.respond_to?(:namespace) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def redis_version
|
22
|
+
redis { |c| c.info['redis_version'] }
|
23
|
+
end
|
24
|
+
|
25
|
+
def uptime
|
26
|
+
redis { |c| c.info['uptime_in_days'] }
|
27
|
+
end
|
28
|
+
|
29
|
+
def connections
|
30
|
+
redis { |c| c.info['connected_clients'] }
|
31
|
+
end
|
32
|
+
|
33
|
+
def memory
|
34
|
+
redis { |c| c.info['used_memory_human'] }
|
35
|
+
end
|
36
|
+
|
37
|
+
def memory_peak
|
38
|
+
redis { |c| c.info['used_memory_peak_human'] }
|
39
|
+
end
|
40
|
+
|
41
|
+
def busy
|
42
|
+
@workers.size
|
43
|
+
end
|
44
|
+
|
45
|
+
def enqueued
|
46
|
+
@stats.enqueued
|
47
|
+
end
|
48
|
+
|
49
|
+
def retries
|
50
|
+
@stats.retry_size
|
51
|
+
end
|
52
|
+
|
53
|
+
def scheduled
|
54
|
+
@stats.scheduled_size
|
55
|
+
end
|
56
|
+
|
57
|
+
def processed
|
58
|
+
@stats.processed
|
59
|
+
end
|
60
|
+
|
61
|
+
def failed
|
62
|
+
@stats.failed
|
63
|
+
end
|
64
|
+
|
65
|
+
# private
|
66
|
+
|
67
|
+
def redis
|
68
|
+
Sidekiq.redis { |c| yield c }
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SidekiqSpy
|
2
|
+
module Translatable
|
3
|
+
|
4
|
+
def t
|
5
|
+
{
|
6
|
+
divider: {
|
7
|
+
left: "",
|
8
|
+
right: "|",
|
9
|
+
},
|
10
|
+
program: "Sidekiq Spy #{VERSION}",
|
11
|
+
redis: {
|
12
|
+
connection: "redis:",
|
13
|
+
namespace: "namespace:",
|
14
|
+
version: "redis version:",
|
15
|
+
uptime: "uptime (d):",
|
16
|
+
connections: "connections:",
|
17
|
+
memory: "memory:",
|
18
|
+
memory_peak: "memory peak:",
|
19
|
+
},
|
20
|
+
sidekiq: {
|
21
|
+
busy: "busy:",
|
22
|
+
retries: "retries:",
|
23
|
+
processed: "processed:",
|
24
|
+
enqueued: "enqueued:",
|
25
|
+
scheduled: "scheduled:",
|
26
|
+
failed: "failed:",
|
27
|
+
},
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/sidekiq-spy.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sidekiq-spy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sidekiq-spy"
|
8
|
+
spec.version = SidekiqSpy::VERSION
|
9
|
+
spec.authors = ["tiredpixel"]
|
10
|
+
spec.email = ["tp@tiredpixel.com"]
|
11
|
+
spec.description = %q{Sidekiq monitoring in the console. A bit like Sidekiq::Web. But without the web.}
|
12
|
+
spec.summary = %q{Sidekiq monitoring in the console.}
|
13
|
+
spec.homepage = "https://github.com/tiredpixel/sidekiq-spy"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "sidekiq", "~> 2.15"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
|
26
|
+
spec.add_development_dependency 'coveralls'
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
{
|
2
|
+
"redis_version":"666.6.11",
|
3
|
+
"redis_git_sha1":"00000000",
|
4
|
+
"redis_git_dirty":"0",
|
5
|
+
"redis_mode":"standalone",
|
6
|
+
"os":"Darwin 12.5.0 x86_64",
|
7
|
+
"arch_bits":"64",
|
8
|
+
"multiplexing_api":"kqueue",
|
9
|
+
"gcc_version":"4.2.1",
|
10
|
+
"process_id":"339",
|
11
|
+
"run_id":"9b69467d5190215ef1ce1f8a0c78818c3cf54576",
|
12
|
+
"tcp_port":"6379",
|
13
|
+
"uptime_in_seconds":"648366",
|
14
|
+
"uptime_in_days":"7",
|
15
|
+
"hz":"10",
|
16
|
+
"lru_clock":"1852328",
|
17
|
+
"connected_clients":"8",
|
18
|
+
"client_longest_output_list":"0",
|
19
|
+
"client_biggest_input_buf":"0",
|
20
|
+
"blocked_clients":"1",
|
21
|
+
"used_memory":"5406656",
|
22
|
+
"used_memory_human":"5.16M",
|
23
|
+
"used_memory_rss":"643072",
|
24
|
+
"used_memory_peak":"5388592",
|
25
|
+
"used_memory_peak_human":"5.14M",
|
26
|
+
"used_memory_lua":"31744",
|
27
|
+
"mem_fragmentation_ratio":"0.12",
|
28
|
+
"mem_allocator":"libc",
|
29
|
+
"loading":"0",
|
30
|
+
"rdb_changes_since_last_save":"0",
|
31
|
+
"rdb_bgsave_in_progress":"0",
|
32
|
+
"rdb_last_save_time":"1381023714",
|
33
|
+
"rdb_last_bgsave_status":"ok",
|
34
|
+
"rdb_last_bgsave_time_sec":"-1",
|
35
|
+
"rdb_current_bgsave_time_sec":"-1",
|
36
|
+
"aof_enabled":"0",
|
37
|
+
"aof_rewrite_in_progress":"0",
|
38
|
+
"aof_rewrite_scheduled":"0",
|
39
|
+
"aof_last_rewrite_time_sec":"-1",
|
40
|
+
"aof_current_rewrite_time_sec":"-1",
|
41
|
+
"aof_last_bgrewrite_status":"ok",
|
42
|
+
"total_connections_received":"18",
|
43
|
+
"total_commands_processed":"110742",
|
44
|
+
"instantaneous_ops_per_sec":"5",
|
45
|
+
"rejected_connections":"0",
|
46
|
+
"expired_keys":"0",
|
47
|
+
"evicted_keys":"0",
|
48
|
+
"keyspace_hits":"21487",
|
49
|
+
"keyspace_misses":"59742",
|
50
|
+
"pubsub_channels":"0",
|
51
|
+
"pubsub_patterns":"0",
|
52
|
+
"latest_fork_usec":"0",
|
53
|
+
"role":"master",
|
54
|
+
"connected_slaves":"0",
|
55
|
+
"used_cpu_sys":"57.24",
|
56
|
+
"used_cpu_user":"47.85",
|
57
|
+
"used_cpu_sys_children":"0.00",
|
58
|
+
"used_cpu_user_children":"0.00",
|
59
|
+
"db0":"keys=49,expires=3",
|
60
|
+
"db1":"keys=3,expires=0"
|
61
|
+
}
|
data/test/helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.expand_path('../../helper', __FILE__)
|
2
|
+
|
3
|
+
require File.expand_path('../../../lib/sidekiq-spy', __FILE__)
|
4
|
+
|
5
|
+
|
6
|
+
describe SidekiqSpy::App do
|
7
|
+
|
8
|
+
before do
|
9
|
+
@app = SidekiqSpy::App.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it "sets status not-running" do
|
13
|
+
@app.running.must_equal false
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#start" do
|
17
|
+
before do
|
18
|
+
@app.configure do |c|
|
19
|
+
c.interval = 10
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "sets status running within 1s" do
|
24
|
+
thread_app = Thread.new { @app.start }
|
25
|
+
|
26
|
+
sleep 1 # patience, patience; give app time to start
|
27
|
+
|
28
|
+
@app.running.must_equal true
|
29
|
+
|
30
|
+
Thread.kill(thread_app)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "stops running within 2s" do
|
34
|
+
thread_app = Thread.new { @app.start }
|
35
|
+
|
36
|
+
sleep 1 # patience, patience; give app time to start
|
37
|
+
|
38
|
+
@app.stop; t0 = Time.now
|
39
|
+
|
40
|
+
thread_app.join(3)
|
41
|
+
|
42
|
+
Thread.kill(thread_app)
|
43
|
+
|
44
|
+
assert_operator (Time.now - t0), :<=, 2
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#stop" do
|
49
|
+
before do
|
50
|
+
@app.instance_variable_set(:@running, true)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "sets status not-running" do
|
54
|
+
@app.stop
|
55
|
+
|
56
|
+
@app.running.must_equal false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require File.expand_path('../../helper', __FILE__)
|
2
|
+
|
3
|
+
require File.expand_path('../../../lib/sidekiq-spy/config', __FILE__)
|
4
|
+
require File.expand_path('../../../lib/sidekiq-spy/app', __FILE__)
|
5
|
+
|
6
|
+
|
7
|
+
describe SidekiqSpy::Config do
|
8
|
+
|
9
|
+
before do
|
10
|
+
@app = SidekiqSpy::App.new
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "default" do
|
14
|
+
before do
|
15
|
+
@config = SidekiqSpy::Config.new
|
16
|
+
end
|
17
|
+
|
18
|
+
it "sets host to 127.0.0.1" do
|
19
|
+
@config.host.must_equal '127.0.0.1'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sets port to 6379" do
|
23
|
+
@config.port.must_equal 6379
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets database to 0" do
|
27
|
+
@config.database.must_equal 0
|
28
|
+
end
|
29
|
+
|
30
|
+
it "sets namespace to nil" do
|
31
|
+
@config.namespace.must_be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "sets interval to 5" do
|
35
|
+
@config.interval.must_equal 5
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "configure block main" do
|
40
|
+
before do
|
41
|
+
@app.configure do |c|
|
42
|
+
c.namespace = 'resque'
|
43
|
+
c.interval = 1
|
44
|
+
end
|
45
|
+
|
46
|
+
@config = @app.config
|
47
|
+
end
|
48
|
+
|
49
|
+
it "configures namespace" do
|
50
|
+
@config.namespace.must_equal 'resque'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "configures interval" do
|
54
|
+
@config.interval.must_equal 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "configure block url" do
|
59
|
+
before do
|
60
|
+
@app.configure do |c|
|
61
|
+
c.url = 'redis://da.example.com:237/42'
|
62
|
+
end
|
63
|
+
|
64
|
+
@config = @app.config
|
65
|
+
end
|
66
|
+
|
67
|
+
it "configures host" do
|
68
|
+
@config.host.must_equal 'da.example.com'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "configures port" do
|
72
|
+
@config.port.must_equal 237
|
73
|
+
end
|
74
|
+
|
75
|
+
it "configures database" do
|
76
|
+
@config.database.must_equal 42
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "configure block url-brief" do
|
81
|
+
before do
|
82
|
+
@app.configure do |c|
|
83
|
+
c.url = 'redis://da.example.com'
|
84
|
+
end
|
85
|
+
|
86
|
+
@config = @app.config
|
87
|
+
end
|
88
|
+
|
89
|
+
it "configures host" do
|
90
|
+
@config.host.must_equal 'da.example.com'
|
91
|
+
end
|
92
|
+
|
93
|
+
it "configures port" do
|
94
|
+
@config.port.must_equal 6379
|
95
|
+
end
|
96
|
+
|
97
|
+
it "configures database" do
|
98
|
+
@config.database.must_equal 0
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "configure block non-url" do
|
103
|
+
before do
|
104
|
+
@app.configure do |c|
|
105
|
+
c.host = 'da.example.com'
|
106
|
+
c.port = 237
|
107
|
+
c.database = 42
|
108
|
+
end
|
109
|
+
|
110
|
+
@config = @app.config
|
111
|
+
end
|
112
|
+
|
113
|
+
it "configures host" do
|
114
|
+
@config.host.must_equal 'da.example.com'
|
115
|
+
end
|
116
|
+
|
117
|
+
it "configures port" do
|
118
|
+
@config.port.must_equal 237
|
119
|
+
end
|
120
|
+
|
121
|
+
it "configures database" do
|
122
|
+
@config.database.must_equal 42
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#url" do
|
127
|
+
before do
|
128
|
+
@config = SidekiqSpy::Config.new
|
129
|
+
|
130
|
+
@config.host = 'da.example.com'
|
131
|
+
@config.port = 237
|
132
|
+
@config.database = 42
|
133
|
+
end
|
134
|
+
|
135
|
+
it "returns connection string URL" do
|
136
|
+
@config.url.must_equal 'redis://da.example.com:237/42'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'redis/namespace'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require File.expand_path('../../../helper', __FILE__)
|
5
|
+
|
6
|
+
require File.expand_path('../../../../lib/sidekiq-spy/spy/stats', __FILE__)
|
7
|
+
|
8
|
+
|
9
|
+
describe SidekiqSpy::Spy::Stats do
|
10
|
+
|
11
|
+
before do
|
12
|
+
@redis = Redis::Namespace.new('resque', :redis => Redis.new)
|
13
|
+
|
14
|
+
Sidekiq.configure_client do |config|
|
15
|
+
config.redis = ConnectionPool.new(:size => 1, &proc { @redis })
|
16
|
+
end
|
17
|
+
|
18
|
+
@fixtures = {
|
19
|
+
:redis_info => JSON.parse(File.read(
|
20
|
+
File.expand_path('../../../fixtures/redis_info.json', __FILE__)
|
21
|
+
)),
|
22
|
+
}
|
23
|
+
|
24
|
+
@sidekiq_stats = Minitest::Mock.new
|
25
|
+
@sidekiq_stats.expect(:enqueued, 16776977673)
|
26
|
+
@sidekiq_stats.expect(:retry_size, 924984826746)
|
27
|
+
@sidekiq_stats.expect(:scheduled_size, 317321542620)
|
28
|
+
@sidekiq_stats.expect(:processed, 923531545885)
|
29
|
+
@sidekiq_stats.expect(:failed, 779187529140)
|
30
|
+
|
31
|
+
@sidekiq_workers = Minitest::Mock.new
|
32
|
+
@sidekiq_workers.expect(:size, 162165179294)
|
33
|
+
|
34
|
+
Sidekiq::Stats.stub(:new, @sidekiq_stats) do
|
35
|
+
Sidekiq::Workers.stub(:new, @sidekiq_workers) do
|
36
|
+
@stats = SidekiqSpy::Spy::Stats.new
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#connection" do
|
42
|
+
it "returns stat connection" do
|
43
|
+
@redis.client.stub(:location, 'da.example.com:237') do
|
44
|
+
@redis.client.stub(:db, 42) do
|
45
|
+
@stats.connection.must_equal 'da.example.com:237/42'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#namespace" do
|
52
|
+
it "returns stat namespace" do
|
53
|
+
@stats.namespace.must_equal 'resque'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#uptime" do
|
58
|
+
it "returns stat uptime" do
|
59
|
+
@redis.stub(:info, @fixtures[:redis_info]) do
|
60
|
+
@stats.uptime.must_equal '7'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#connections" do
|
66
|
+
it "returns stat connections" do
|
67
|
+
@redis.stub(:info, @fixtures[:redis_info]) do
|
68
|
+
@stats.connections.must_equal '8'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#memory" do
|
74
|
+
it "returns stat memory" do
|
75
|
+
@redis.stub(:info, @fixtures[:redis_info]) do
|
76
|
+
@stats.memory.must_equal '5.16M'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#memory_peak" do
|
82
|
+
it "returns stat memory_peak" do
|
83
|
+
@redis.stub(:info, @fixtures[:redis_info]) do
|
84
|
+
@stats.memory_peak.must_equal '5.14M'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#busy" do
|
90
|
+
it "returns stat busy" do
|
91
|
+
@stats.busy.must_equal 162165179294
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#enqueued" do
|
96
|
+
it "returns stat enqueued" do
|
97
|
+
@stats.enqueued.must_equal 16776977673
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#retries" do
|
102
|
+
it "returns stat retries" do
|
103
|
+
@stats.retries.must_equal 924984826746
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#scheduled" do
|
108
|
+
it "returns stat scheduled" do
|
109
|
+
@stats.scheduled.must_equal 317321542620
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#processed" do
|
114
|
+
it "returns stat processed" do
|
115
|
+
@stats.processed.must_equal 923531545885
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#failed" do
|
120
|
+
it "returns stat failed" do
|
121
|
+
@stats.failed.must_equal 779187529140
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path('../../helper', __FILE__)
|
2
|
+
|
3
|
+
require File.expand_path('../../../lib/sidekiq-spy/version', __FILE__)
|
4
|
+
|
5
|
+
|
6
|
+
describe "SidekiqSpy::VERSION" do
|
7
|
+
|
8
|
+
it "uses major.minor.patch" do
|
9
|
+
SidekiqSpy::VERSION.must_match /\A\d+\.\d+\.\d+\z/
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq-spy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- tiredpixel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sidekiq
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.15'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coveralls
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Sidekiq monitoring in the console. A bit like Sidekiq::Web. But without
|
70
|
+
the web.
|
71
|
+
email:
|
72
|
+
- tp@tiredpixel.com
|
73
|
+
executables:
|
74
|
+
- sidekiq-spy
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- .ruby-gemset
|
80
|
+
- .ruby-version
|
81
|
+
- .travis.yml
|
82
|
+
- Gemfile
|
83
|
+
- LICENSE.txt
|
84
|
+
- README.md
|
85
|
+
- Rakefile
|
86
|
+
- bin/sidekiq-spy
|
87
|
+
- lib/sidekiq-spy.rb
|
88
|
+
- lib/sidekiq-spy/app.rb
|
89
|
+
- lib/sidekiq-spy/config.rb
|
90
|
+
- lib/sidekiq-spy/display/panel.rb
|
91
|
+
- lib/sidekiq-spy/display/screen.rb
|
92
|
+
- lib/sidekiq-spy/display/subpanel.rb
|
93
|
+
- lib/sidekiq-spy/spy/stats.rb
|
94
|
+
- lib/sidekiq-spy/translatable.rb
|
95
|
+
- lib/sidekiq-spy/version.rb
|
96
|
+
- sidekiq-spy.gemspec
|
97
|
+
- test/fixtures/redis_info.json
|
98
|
+
- test/helper.rb
|
99
|
+
- test/sidekiq-spy/app_test.rb
|
100
|
+
- test/sidekiq-spy/config_test.rb
|
101
|
+
- test/sidekiq-spy/spy/stats_test.rb
|
102
|
+
- test/sidekiq-spy/version_test.rb
|
103
|
+
homepage: https://github.com/tiredpixel/sidekiq-spy
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.1.9
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Sidekiq monitoring in the console.
|
127
|
+
test_files:
|
128
|
+
- test/fixtures/redis_info.json
|
129
|
+
- test/helper.rb
|
130
|
+
- test/sidekiq-spy/app_test.rb
|
131
|
+
- test/sidekiq-spy/config_test.rb
|
132
|
+
- test/sidekiq-spy/spy/stats_test.rb
|
133
|
+
- test/sidekiq-spy/version_test.rb
|