redis_dashboard 0.1.2 → 0.1.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a4b7fde8d3759d82ba885462c3f6dfeb7e696c4
4
- data.tar.gz: 81b2ba82809ec5ee6037f0b73df4559cf84248ea
3
+ metadata.gz: 578baab7856107a9e28a00022dbc4bdc75a5f860
4
+ data.tar.gz: 7335f0c7de979ac2e09a7a4fb06a34bce6ee90a2
5
5
  SHA512:
6
- metadata.gz: 658e9fbafd0a25c487dad985476ddd6215e13becd2b49d9dd56656fb28828f5a8c8e9b9c804994bf99c6e2bd94d0e1f1d8ef729645a754a6e82eb888272359c1
7
- data.tar.gz: 3c1894461af3c63c2648ab99e0cc74f7824c7ddd6b84765df12e21fd39b03f25495cfc0c4e38861ce4053dfa2e408854dd903336c1087d136003a56e666728bd
6
+ metadata.gz: fd7ee9d82db93a2cc17f9bc3f1992023524f01a8e088e97a520298f271896fd1a9044a7505bb887c08a146318d538dc1fac4f7d5abf352ed131ae7316d9f5d56
7
+ data.tar.gz: cbec9b324109fdd0b5e76618d1533093e55f7a61131b2c6ca2b76e804b7c89d11061cfaf6d347f27944aa9a683f233c081891956a48d277c0b90c46faa684019
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .sass-cache
2
2
  **/.DS_Store
3
+ *.gem
@@ -21,6 +21,10 @@ class RedisDashboard::Application < Sinatra::Base
21
21
  erb(:clients, locals: {clients: client.clients})
22
22
  end
23
23
 
24
+ get "/stats" do
25
+ erb(:stats, locals: {stats: client.stats})
26
+ end
27
+
24
28
  get "/slowlog" do
25
29
  erb(:slowlog, locals: {commands: client.slow_commands})
26
30
  end
@@ -60,5 +64,63 @@ class RedisDashboard::Application < Sinatra::Base
60
64
  def active_page?(path='')
61
65
  request.path_info == '/' + path
62
66
  end
67
+
68
+ def format_impact_percentage(percentage)
69
+ percentage < 1 ? "< 1 <small>%</small>" : "#{percentage.round} <small>%</small>"
70
+ end
71
+
72
+ def format_usec(usec)
73
+ "#{usec}&nbsp;<small>㎲</small>"
74
+ end
75
+
76
+ def compute_cache_hit_ratio(info)
77
+ if (total = info["keyspace_hits"].to_i + info["keyspace_misses"].to_i) > 0
78
+ info["keyspace_hits"].to_f * 100
79
+ else
80
+ 0
81
+ end
82
+ end
83
+
84
+ def clients_column_description(col)
85
+ # https://redis.io/commands/client-list
86
+ {
87
+ id: "an unique 64-bit client ID (introduced in Redis 2.8.12).",
88
+ addr: "address/port of the client",
89
+ fd: "file descriptor corresponding to the socket",
90
+ age: "total duration of the connection in seconds",
91
+ idle: "idle time of the connection in seconds",
92
+ flags: "client flags (see below)",
93
+ db: "current database ID",
94
+ sub: "number of channel subscriptions",
95
+ psub: "number of pattern matching subscriptions",
96
+ multi: "number of commands in a MULTI/EXEC context",
97
+ qbuf: "query buffer length (0 means no query pending)",
98
+ 'qbuf-f': "ree: free space of the query buffer (0 means the buffer is full)",
99
+ obl: "output buffer length",
100
+ oll: "output list length (replies are queued in this list when the buffer is full)",
101
+ omem: "output buffer memory usage",
102
+ events: "file descriptor events (see below)",
103
+ cmd: "last command played",
104
+ }[col.to_sym]
105
+ end
106
+
107
+ def client_event_description(event)
108
+ # https://redis.io/commands/client-list
109
+ {
110
+ O: "the client is a slave in MONITOR mode",
111
+ S: "the client is a normal slave server",
112
+ M: "the client is a master",
113
+ x: "the client is in a MULTI/EXEC context",
114
+ b: "the client is waiting in a blocking operation",
115
+ i: "the client is waiting for a VM I/O (deprecated)",
116
+ d: "a watched keys has been modified - EXEC will fail",
117
+ c: "connection to be closed after writing entire reply",
118
+ u: "the client is unblocked",
119
+ U: "the client is connected via a Unix domain socket",
120
+ r: "the client is in readonly mode against a cluster node",
121
+ A: "connection to be closed ASAP",
122
+ N: "no specific flag set",
123
+ }[event.to_sym]
124
+ end
63
125
  end
64
126
  end
@@ -28,8 +28,11 @@ class RedisDashboard::Client
28
28
  connection.info
29
29
  end
30
30
 
31
- def close
32
- connection.close if connection
31
+ def stats
32
+ stats = connection.info("commandstats").sort { |a, b| b.last["usec"].to_i <=> a.last["usec"].to_i }
33
+ total = stats.reduce(0) { |total, stat| total += stat.last["usec"].to_i }
34
+ stats.each { |stat| stat.last["impact"] = stat.last["usec"].to_f * 100 / total }
35
+ stats
33
36
  end
34
37
 
35
38
  def slow_commands(length = 128) # 128 is the default slowlog-max-len
@@ -43,6 +46,10 @@ class RedisDashboard::Client
43
46
  end.sort{ |left, right| right.microseconds <=> left.microseconds }
44
47
  end
45
48
 
49
+ def close
50
+ connection.close if connection
51
+ end
52
+
46
53
  private
47
54
 
48
55
  def connection
@@ -2,13 +2,17 @@
2
2
  <table>
3
3
  <thead>
4
4
  <% for key in (keys = clients.first.keys) %>
5
- <th><%= key %></th>
5
+ <th title="<%= clients_column_description key %>"><%= key %></th>
6
6
  <% end %>
7
7
  </thead>
8
8
  <% for client in clients %>
9
9
  <tr>
10
10
  <% for key in keys %>
11
- <td><%= client[key] %></td>
11
+ <% if key == "events" %>
12
+ <td title="<%= client_event_description client[key] %>"><%= client[key] %></td>
13
+ <% else %>
14
+ <td><%= client[key] %></td>
15
+ <% end %>
12
16
  <% end %>
13
17
  </tr>
14
18
  <% end %>
@@ -8,3 +8,9 @@
8
8
  <% end %>
9
9
  </table>
10
10
  </div>
11
+
12
+ <a href="https://raw.githubusercontent.com/antirez/redis/4.0/redis.conf">
13
+ <svg viewBox="0 0 24 24">
14
+ <path d="M14,3V5H17.59L7.76,14.83L9.17,16.24L19,6.41V10H21V3M19,19H5V5H12V3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V12H19V19Z" />
15
+ </svg> Redis config documentation
16
+ </a>
@@ -18,6 +18,10 @@
18
18
  <span class="label">Commands per second</span>
19
19
  <span><%= info["instantaneous_ops_per_sec"] %></span>
20
20
  </div>
21
+ <div>
22
+ <span class="label">Cache hit ratio</span>
23
+ <span><%= format_impact_percentage compute_cache_hit_ratio(info) %></span>
24
+ </div>
21
25
  </div>
22
26
  </div>
23
27
  <% end %>
@@ -19,6 +19,7 @@
19
19
  <a class="page-menu-item <%= 'active' if active_page?('info') %>" href="<%= url("/info?id=#{redis_id}") %>">Info</a>
20
20
  <a class="page-menu-item <%= 'active' if active_page?('config') %>" href="<%= url("/config?id=#{redis_id}") %>">Config</a>
21
21
  <a class="page-menu-item <%= 'active' if active_page?('clients') %>" href="<%= url("/clients?id=#{redis_id}") %>">Clients</a>
22
+ <a class="page-menu-item <%= 'active' if active_page?('stats') %>" href="<%= url("/stats?id=#{redis_id}") %>">Stats</a>
22
23
  <a class="page-menu-item <%= 'active' if active_page?('slowlog') %>" href="<%= url("/slowlog?id=#{redis_id}") %>">Slowlog</a>
23
24
  </div>
24
25
  <% end %>
@@ -11,7 +11,7 @@
11
11
  <tr>
12
12
  <td><%= cmd.id %></td>
13
13
  <td class="date"><%= epoch_to_short_date_time cmd.timestamp %></td>
14
- <td><%= cmd.microseconds %></td>
14
+ <td class="number"><%= format_usec cmd.microseconds %></td>
15
15
  <td><%= cmd.command.join(" ") %></td>
16
16
  </tr>
17
17
  <% end %>
@@ -0,0 +1,20 @@
1
+ <div class="table">
2
+ <table>
3
+ <tr>
4
+ <th>Command</th>
5
+ <th>Total time</th>
6
+ <th>Calls</th>
7
+ <th>AVG time</th>
8
+ <th>Impact</th>
9
+ </tr>
10
+ <% for (key,hash) in stats %>
11
+ <tr>
12
+ <td class="key"><%= key %></td>
13
+ <td class="number"><%= format_usec hash["usec"] %></td>
14
+ <td class="number"><%= hash["calls"] %></td>
15
+ <td class="number"><%= format_usec hash["usec_per_call"] %></td>
16
+ <td class="number"><%= format_impact_percentage hash["impact"] %></td>
17
+ </tr>
18
+ <% end %>
19
+ </table>
20
+ </div>
@@ -19,9 +19,8 @@ td,
19
19
  th {
20
20
  border-bottom: 1px solid $color-light;
21
21
  padding: 12px 12px 11px;
22
- text-align: left;
23
22
  line-height: 24px;
24
- }
23
+ }
25
24
 
26
25
  th {
27
26
  font-weight: 400;
@@ -29,6 +28,7 @@ th {
29
28
  font-size: .694rem;
30
29
  letter-spacing: 2px;
31
30
  text-transform: uppercase;
31
+ text-align: center;
32
32
  }
33
33
 
34
34
  td.key {
@@ -41,4 +41,9 @@ td.key {
41
41
 
42
42
  td.date {
43
43
  white-space: nowrap;
44
+ text-align: right;
45
+ }
46
+
47
+ td.number {
48
+ text-align: right;
44
49
  }
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = "redis_dashboard"
6
- spec.version = "0.1.2"
6
+ spec.version = "0.1.3"
7
7
  spec.authors = ["Alexis Bernard"]
8
8
  spec.email = ["alexis@bernard.io"]
9
9
  spec.summary = "Sinatra app to monitor Redis servers."
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_dashboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexis Bernard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-19 00:00:00.000000000 Z
11
+ date: 2018-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -47,6 +47,7 @@ files:
47
47
  - lib/redis_dashboard/views/info.erb
48
48
  - lib/redis_dashboard/views/layout.erb
49
49
  - lib/redis_dashboard/views/slowlog.erb
50
+ - lib/redis_dashboard/views/stats.erb
50
51
  - lib/redis_dashboard/views/stylesheets/base.scss
51
52
  - lib/redis_dashboard/views/stylesheets/colors.scss
52
53
  - lib/redis_dashboard/views/stylesheets/link.scss
@@ -77,9 +78,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
78
  version: '0'
78
79
  requirements: []
79
80
  rubyforge_project:
80
- rubygems_version: 2.4.8
81
+ rubygems_version: 2.5.1
81
82
  signing_key:
82
83
  specification_version: 4
83
84
  summary: Sinatra app to monitor Redis servers.
84
85
  test_files: []
85
- has_rdoc: