redis_web_manager 0.1.6 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +2 -0
- data/.travis.yml +1 -0
- data/Gemfile.lock +23 -1
- data/README.md +95 -4
- data/Rakefile +1 -1
- data/app/controllers/redis_web_manager/actions_controller.rb +15 -3
- data/app/controllers/redis_web_manager/application_controller.rb +4 -0
- data/app/controllers/redis_web_manager/clients_controller.rb +1 -1
- data/app/controllers/redis_web_manager/configuration_controller.rb +1 -1
- data/app/controllers/redis_web_manager/dashboard_controller.rb +23 -3
- data/app/controllers/redis_web_manager/information_controller.rb +1 -1
- data/app/controllers/redis_web_manager/keys_controller.rb +135 -0
- data/app/helpers/redis_web_manager/application_helper.rb +16 -0
- data/app/helpers/redis_web_manager/dashboard_helper.rb +1 -1
- data/app/views/redis_web_manager/dashboard/index.html.erb +20 -1
- data/app/views/redis_web_manager/keys/edit.html.erb +14 -0
- data/app/views/redis_web_manager/keys/index.html.erb +54 -0
- data/app/views/redis_web_manager/keys/show.html.erb +30 -0
- data/app/views/redis_web_manager/shared/_header.html.erb +12 -2
- data/app/views/redis_web_manager/shared/_status.html.erb +2 -2
- data/bin/rails +1 -1
- data/config/routes.rb +8 -0
- data/lib/redis_web_manager.rb +1 -1
- data/lib/redis_web_manager/action.rb +1 -1
- data/lib/redis_web_manager/data.rb +16 -0
- data/lib/redis_web_manager/version.rb +1 -1
- data/redis_web_manager.gemspec +6 -4
- data/spec/controllers/redis_web_manager/actions_controller_spec.rb +16 -1
- data/spec/controllers/redis_web_manager/clients_controller_spec.rb +1 -1
- data/spec/controllers/redis_web_manager/keys_controller_spec.rb +139 -0
- data/spec/helpers/application_helper_spec.rb +13 -1
- data/spec/helpers/dashboard_helper_spec.rb +1 -1
- data/spec/redis_web_manager_data_spec.rb +23 -0
- data/spec/routing/actions_controller_spec.rb +6 -0
- data/spec/routing/keys_controller_spec.rb +39 -0
- data/spec/spec_helper.rb +6 -0
- metadata +295 -342
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e48c79b5d3723da1e569b6ab98470b268a694b6f3d39a08666945a4349c09666
|
4
|
+
data.tar.gz: f92ce3f1270fdfbf2c41744aa0c6f6c210dc4bd015ed44b645e924d814ffc3f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2246f99e9a53f9bc9cec38b06e95b967250cbab37104544f80f058d06402c6130d7d1f010e7b52cd71428a8c7d45a7d1c806f6628a372a368929119b4d7c8d4
|
7
|
+
data.tar.gz: eac5fb2aea1185697a9ae819b06817b206db4adba61371462a182e5ab3ccf5d9430ddb4a03de80f1045bd4a7d33fa605d7958e07311146f605c4052644bab538
|
data/.coveralls.yml
ADDED
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
redis_web_manager (0.1.
|
4
|
+
redis_web_manager (0.1.6)
|
5
|
+
pagy (~> 3.7)
|
5
6
|
rails (>= 5.2, < 7)
|
6
7
|
redis (~> 4.1.0)
|
7
8
|
|
@@ -65,13 +66,21 @@ GEM
|
|
65
66
|
zeitwerk (~> 2.2)
|
66
67
|
builder (3.2.4)
|
67
68
|
concurrent-ruby (1.1.5)
|
69
|
+
coveralls (0.8.23)
|
70
|
+
json (>= 1.8, < 3)
|
71
|
+
simplecov (~> 0.16.1)
|
72
|
+
term-ansicolor (~> 1.3)
|
73
|
+
thor (>= 0.19.4, < 2.0)
|
74
|
+
tins (~> 1.6)
|
68
75
|
crass (1.0.6)
|
69
76
|
diff-lcs (1.3)
|
77
|
+
docile (1.3.2)
|
70
78
|
erubi (1.9.0)
|
71
79
|
globalid (0.4.2)
|
72
80
|
activesupport (>= 4.2.0)
|
73
81
|
i18n (1.8.2)
|
74
82
|
concurrent-ruby (~> 1.0)
|
83
|
+
json (2.3.0)
|
75
84
|
loofah (2.4.0)
|
76
85
|
crass (~> 1.0.2)
|
77
86
|
nokogiri (>= 1.5.9)
|
@@ -87,6 +96,7 @@ GEM
|
|
87
96
|
nio4r (2.5.2)
|
88
97
|
nokogiri (1.10.7)
|
89
98
|
mini_portile2 (~> 2.4.0)
|
99
|
+
pagy (3.7.2)
|
90
100
|
rack (2.1.2)
|
91
101
|
rack-test (1.1.0)
|
92
102
|
rack (>= 1.0, < 3)
|
@@ -135,6 +145,11 @@ GEM
|
|
135
145
|
rspec-mocks (~> 3.8)
|
136
146
|
rspec-support (~> 3.8)
|
137
147
|
rspec-support (3.9.2)
|
148
|
+
simplecov (0.16.1)
|
149
|
+
docile (~> 1.1)
|
150
|
+
json (>= 1.8, < 3)
|
151
|
+
simplecov-html (~> 0.10.0)
|
152
|
+
simplecov-html (0.10.2)
|
138
153
|
sprockets (4.0.0)
|
139
154
|
concurrent-ruby (~> 1.0)
|
140
155
|
rack (> 1, < 3)
|
@@ -142,8 +157,13 @@ GEM
|
|
142
157
|
actionpack (>= 4.0)
|
143
158
|
activesupport (>= 4.0)
|
144
159
|
sprockets (>= 3.0.0)
|
160
|
+
sync (0.5.0)
|
161
|
+
term-ansicolor (1.7.1)
|
162
|
+
tins (~> 1.0)
|
145
163
|
thor (1.0.1)
|
146
164
|
thread_safe (0.3.6)
|
165
|
+
tins (1.24.0)
|
166
|
+
sync
|
147
167
|
tzinfo (1.2.6)
|
148
168
|
thread_safe (~> 0.1)
|
149
169
|
websocket-driver (0.7.1)
|
@@ -155,8 +175,10 @@ PLATFORMS
|
|
155
175
|
ruby
|
156
176
|
|
157
177
|
DEPENDENCIES
|
178
|
+
coveralls (~> 0.8)
|
158
179
|
redis_web_manager!
|
159
180
|
rspec-rails (= 4.0.0.beta3)
|
181
|
+
simplecov (~> 0.16)
|
160
182
|
|
161
183
|
BUNDLED WITH
|
162
184
|
2.1.4
|
data/README.md
CHANGED
@@ -1,9 +1,28 @@
|
|
1
1
|
# RedisWebManager
|
2
2
|
|
3
|
-
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/redis_web_manager.svg)](https://badge.fury.io/rb/redis_web_manager)
|
4
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/55600fe789679fe62d8b/maintainability)](https://codeclimate.com/github/OpenGems/redis_web_manager/maintainability)
|
5
|
+
[![Build Status](https://travis-ci.org/OpenGems/redis_web_manager.svg?branch=master)](https://travis-ci.org/OpenGems/redis_web_manager)
|
6
|
+
[![security](https://hakiri.io/github/OpenGems/redis_web_manager/master.svg)](https://hakiri.io/github/OpenGems/redis_web_manager/master)
|
7
|
+
![Gem](https://img.shields.io/gem/dt/redis_web_manager)
|
8
|
+
[![Coverage Status](https://coveralls.io/repos/github/OpenGems/redis_web_manager/badge.svg?branch=master)](https://coveralls.io/github/OpenGems/redis_web_manager?branch=master)
|
4
9
|
|
5
|
-
|
6
|
-
|
10
|
+
Web interface that allows you to manage easily your Redis instance (see keys, memory used, connected client, etc...).
|
11
|
+
|
12
|
+
### Check your stats
|
13
|
+
The Dashboard allows you tu check the Memory usage, CPU and Redis clients.
|
14
|
+
|
15
|
+
![RedisWebManager Dashboard](images/images_dashboard.png)
|
16
|
+
|
17
|
+
### Manage your redis keys
|
18
|
+
You can easily edit and delete any keys stored in your redis database.
|
19
|
+
|
20
|
+
![RedisWebManager Keys](images/images_keys.png)
|
21
|
+
|
22
|
+
### Keep an eye on your redis clients
|
23
|
+
Check how many clients are connected and their infos.
|
24
|
+
|
25
|
+
![RedisWebManager Clients](images/images_clients.png)
|
7
26
|
|
8
27
|
## Installation
|
9
28
|
Add this line to your application's Gemfile:
|
@@ -22,8 +41,80 @@ Or install it yourself as:
|
|
22
41
|
$ gem install redis_web_manager
|
23
42
|
```
|
24
43
|
|
44
|
+
Add the custom route in your `routes.rb`:
|
45
|
+
```
|
46
|
+
mount RedisWebManager::Engine => '/redis_web_manager'
|
47
|
+
```
|
48
|
+
|
49
|
+
Access to RedisWebManager at `/redis_web_manager`
|
50
|
+
|
51
|
+
## Configuration
|
52
|
+
|
53
|
+
You can configure RedisWebManager:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
# initializers/redis_web_manager.rb
|
57
|
+
|
58
|
+
RedisWebManager.configure do |config|
|
59
|
+
config.redis = Redis.new(db: 1) # Default Redis.new (Instance of Redis)
|
60
|
+
config.lifespan = 2.days # Default 15.days (Lifespan of each keys for dashboard)
|
61
|
+
config.authenticate = proc {
|
62
|
+
authenticate_or_request_with_http_basic do |username, password|
|
63
|
+
username == 'TEST' && password == 'TEST'
|
64
|
+
end
|
65
|
+
} # Default nil (Authenticate method to secure tools)
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
## Collect data for dashboard
|
70
|
+
|
71
|
+
In order to have data on your dashboard you must collect the data like this:
|
72
|
+
```ruby
|
73
|
+
data = RedisWebManager::Data.new
|
74
|
+
data.perform
|
75
|
+
```
|
76
|
+
|
77
|
+
If you are using a system to run background tasks in your application (like Sidekiq, Sucker Punch or ActiveJob), you can write your own background task to update the dashboard statistics.
|
78
|
+
|
79
|
+
Sidekiq exemple:
|
80
|
+
```ruby
|
81
|
+
class DashboardWorker
|
82
|
+
include Sidekiq::Worker
|
83
|
+
|
84
|
+
def perform
|
85
|
+
data = RedisWebManager::Data.new
|
86
|
+
data.perform
|
87
|
+
end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
Sucker Punch exemple:
|
92
|
+
```ruby
|
93
|
+
class DashboardJob
|
94
|
+
include SuckerPunch::Job
|
95
|
+
|
96
|
+
def perform
|
97
|
+
data = RedisWebManager::Data.new
|
98
|
+
data.perform
|
99
|
+
end
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
## Todo
|
106
|
+
* [ ] Add filters to redis keys (filter by type, by expiration date...)
|
107
|
+
* [ ] Add graph for most used commands
|
108
|
+
* [ ] Manage multiple redis instances
|
109
|
+
* [ ] Real time chart update
|
110
|
+
* [ ] Alert system (ex: triggered when memory is peaking)
|
111
|
+
* [ ] Command line interface to manage your redis database
|
112
|
+
* [ ] Logs interface
|
113
|
+
|
114
|
+
|
25
115
|
## Contributing
|
26
|
-
|
116
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/OpenGems/redis_web_manager. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
27
117
|
|
28
118
|
## License
|
119
|
+
|
29
120
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
@@ -2,10 +2,22 @@
|
|
2
2
|
|
3
3
|
module RedisWebManager
|
4
4
|
class ActionsController < ApplicationController
|
5
|
+
# DELETE /reset
|
6
|
+
def reset
|
7
|
+
data.flush
|
8
|
+
redirect_to root_url
|
9
|
+
end
|
10
|
+
|
5
11
|
# DELETE /flushdb
|
6
|
-
def flushdb
|
12
|
+
def flushdb
|
13
|
+
action.flushdb
|
14
|
+
redirect_to root_url
|
15
|
+
end
|
7
16
|
|
8
17
|
# DELETE /flushall
|
9
|
-
def flushall
|
18
|
+
def flushall
|
19
|
+
action.flushall
|
20
|
+
redirect_to root_url
|
21
|
+
end
|
10
22
|
end
|
11
|
-
end
|
23
|
+
end
|
@@ -4,11 +4,31 @@ module RedisWebManager
|
|
4
4
|
class DashboardController < ApplicationController
|
5
5
|
# GET /dashboard
|
6
6
|
def index
|
7
|
+
@information = stats.map { |k, v| { name: k.to_s.humanize, value: v } }
|
7
8
|
@status = info.status
|
8
9
|
@url = connection.id
|
9
|
-
@memory =
|
10
|
-
@cpu =
|
11
|
-
@client =
|
10
|
+
@memory = keys_by_type(data.keys, :memory)
|
11
|
+
@cpu = keys_by_type(data.keys, :cpu)
|
12
|
+
@client = keys_by_type(data.keys, :client)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def stats
|
18
|
+
@stats ||= info.stats.symbolize_keys.slice(:redis_version,
|
19
|
+
:redis_mode,
|
20
|
+
:arch_bits,
|
21
|
+
:process_id,
|
22
|
+
:os,
|
23
|
+
:role,
|
24
|
+
:connected_clients,
|
25
|
+
:blocked_clients,
|
26
|
+
:uptime_in_days,
|
27
|
+
:used_memory_human)
|
28
|
+
end
|
29
|
+
|
30
|
+
def keys_by_type(keys, value)
|
31
|
+
keys.map { |key| key.slice(:date, value) }.sort_by { |key| key[:date] }
|
12
32
|
end
|
13
33
|
end
|
14
34
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pagy'
|
4
|
+
require 'pagy/extras/array'
|
5
|
+
require 'pagy/extras/bootstrap'
|
6
|
+
|
7
|
+
module RedisWebManager
|
8
|
+
class KeysController < ApplicationController
|
9
|
+
include ::Pagy::Backend
|
10
|
+
|
11
|
+
# GET /keys
|
12
|
+
def index
|
13
|
+
query = params[:query].presence
|
14
|
+
@keys = if query.present?
|
15
|
+
info.search(query).map { |key| format_key(key) }
|
16
|
+
else
|
17
|
+
info.keys.map { |key| format_key(key) }
|
18
|
+
end
|
19
|
+
@status = info.status
|
20
|
+
@url = connection.id
|
21
|
+
@pagy, @keys = pagy_array(@keys)
|
22
|
+
end
|
23
|
+
|
24
|
+
# GET /key/:key
|
25
|
+
def show
|
26
|
+
key = params[:key].presence
|
27
|
+
redirect_to keys_url if key.nil?
|
28
|
+
@key = format_key(key)
|
29
|
+
end
|
30
|
+
|
31
|
+
# GET /key/:key
|
32
|
+
def edit
|
33
|
+
key = params[:key].presence
|
34
|
+
redirect_to keys_url if key.nil?
|
35
|
+
@key = format_key(key)
|
36
|
+
end
|
37
|
+
|
38
|
+
# PUT /key/:key
|
39
|
+
def update
|
40
|
+
old_key = params[:old_name].presence
|
41
|
+
new_name = params[:new_name].presence
|
42
|
+
redirect_to keys_url if old_key.nil? || new_name.nil?
|
43
|
+
action.rename(old_key, new_name)
|
44
|
+
redirect_to keys_url
|
45
|
+
end
|
46
|
+
|
47
|
+
# DELETE /key/:key
|
48
|
+
def destroy
|
49
|
+
key = params[:key].presence
|
50
|
+
redirect_to keys_url if key.nil?
|
51
|
+
action.del(key)
|
52
|
+
redirect_to keys_url
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def item_type(value)
|
58
|
+
['json', JSON.parse(value)]
|
59
|
+
rescue JSON::ParserError
|
60
|
+
['string', value]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get values for Redis List type
|
64
|
+
def get_list(key)
|
65
|
+
start = 0
|
66
|
+
stop = 99
|
67
|
+
|
68
|
+
length = info.llen(key)
|
69
|
+
values = info.lrange(key, start, stop).map.with_index do |e, i|
|
70
|
+
type, value = item_type(e)
|
71
|
+
{ type: type, value: value, index: start + i }
|
72
|
+
end
|
73
|
+
|
74
|
+
{ length: length, values: values }
|
75
|
+
end
|
76
|
+
|
77
|
+
# Get values for Redis Set type
|
78
|
+
def get_set(key)
|
79
|
+
values = info.smembers(key).map do |e|
|
80
|
+
type, value = item_type(e)
|
81
|
+
{ type: type, value: value }
|
82
|
+
end
|
83
|
+
|
84
|
+
{ values: values }
|
85
|
+
end
|
86
|
+
|
87
|
+
# Get values for Redis Zset type
|
88
|
+
def get_zset(key)
|
89
|
+
values = info.zrange(key, 0, -1, withscores: true).map do |e, score|
|
90
|
+
type, value = item_type(e)
|
91
|
+
{ type: type, value: value, score: score }
|
92
|
+
end
|
93
|
+
|
94
|
+
{ values: values }
|
95
|
+
end
|
96
|
+
|
97
|
+
# Get values for Redis Hash type
|
98
|
+
def get_hash(key)
|
99
|
+
value = Hash[info.hgetall(key).map do |k, v|
|
100
|
+
type, value = item_type(v)
|
101
|
+
[k, { type: type, value: value }]
|
102
|
+
end]
|
103
|
+
|
104
|
+
{ value: value }
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_value(key)
|
108
|
+
type = info.type(key)
|
109
|
+
case type
|
110
|
+
when 'string'
|
111
|
+
{ value: info.get(key) }
|
112
|
+
when 'list'
|
113
|
+
get_list(key)
|
114
|
+
when 'set'
|
115
|
+
get_set(key)
|
116
|
+
when 'zset'
|
117
|
+
get_zset(key)
|
118
|
+
when 'hash'
|
119
|
+
get_hash(key)
|
120
|
+
else
|
121
|
+
{ value: 'Not found' }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def format_key(key)
|
126
|
+
{
|
127
|
+
key: key,
|
128
|
+
expire: info.expire(key),
|
129
|
+
node: get_value(key),
|
130
|
+
type: info.type(key),
|
131
|
+
memory: info.memory_usage(key)
|
132
|
+
}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|