memdash 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +22 -0
  6. data/README.md +58 -0
  7. data/Rakefile +22 -0
  8. data/config.ru +7 -0
  9. data/lib/generators/memdash/active_record_generator.rb +17 -0
  10. data/lib/generators/memdash/templates/migration.rb +12 -0
  11. data/lib/memdash.rb +9 -0
  12. data/lib/memdash/active_record.rb +2 -0
  13. data/lib/memdash/active_record/client.rb +13 -0
  14. data/lib/memdash/active_record/report.rb +13 -0
  15. data/lib/memdash/client.rb +26 -0
  16. data/lib/memdash/configuration.rb +11 -0
  17. data/lib/memdash/server.rb +50 -0
  18. data/lib/memdash/server/public/charts.js +136 -0
  19. data/lib/memdash/server/public/cross_scratches.png +0 -0
  20. data/lib/memdash/server/public/jqplot.canvasAxisTickRenderer.js +243 -0
  21. data/lib/memdash/server/public/jqplot.canvasAxisTickRenderer.min.js +57 -0
  22. data/lib/memdash/server/public/jqplot.canvasTextRenderer.min.js +57 -0
  23. data/lib/memdash/server/public/jqplot.dateAxisRenderer.min.js +57 -0
  24. data/lib/memdash/server/public/jquery.jqplot.min.css +1 -0
  25. data/lib/memdash/server/public/jquery.jqplot.min.js +57 -0
  26. data/lib/memdash/server/public/reset.css +260 -0
  27. data/lib/memdash/server/public/style.css +66 -0
  28. data/lib/memdash/server/views/application.erb +24 -0
  29. data/lib/memdash/server/views/overview.erb +19 -0
  30. data/memdash.gemspec +25 -0
  31. data/screenshot.png +0 -0
  32. data/spec/memdash_spec.rb +31 -0
  33. data/spec/spec_helper.rb +3 -0
  34. data/spec/support/adapters/active_record.rb +11 -0
  35. data/spec/support/dalli.rb +15 -0
  36. data/spec/support/database_cleaner.rb +16 -0
  37. data/spec/support/memcached.rb +6 -0
  38. data/spec/support/schema.rb +12 -0
  39. metadata +204 -0
@@ -0,0 +1,260 @@
1
+ /* http://meyerweb.com/eric/tools/css/reset/
2
+ v2.0 | 20110126
3
+ License: none (public domain)
4
+ */
5
+
6
+ html, body, div, span, applet, object, iframe,
7
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8
+ a, abbr, acronym, address, big, cite, code,
9
+ del, dfn, em, img, ins, kbd, q, s, samp,
10
+ small, strike, strong, sub, sup, tt, var,
11
+ b, u, i, center,
12
+ dl, dt, dd, ol, ul, li,
13
+ fieldset, form, label, legend,
14
+ table, caption, tbody, tfoot, thead, tr, th, td,
15
+ article, aside, canvas, details, embed,
16
+ figure, figcaption, footer, header, hgroup,
17
+ menu, nav, output, ruby, section, summary,
18
+ time, mark, audio, video {
19
+ margin: 0;
20
+ padding: 0;
21
+ border: 0;
22
+ font-size: 100%;
23
+ font: inherit;
24
+ vertical-align: baseline;
25
+ }
26
+ /* HTML5 display-role reset for older browsers */
27
+ article, aside, details, figcaption, figure,
28
+ footer, header, hgroup, menu, nav, section {
29
+ display: block;
30
+ }
31
+ body {
32
+ line-height: 1;
33
+ }
34
+ ol, ul {
35
+ list-style: none;
36
+ }
37
+ blockquote, q {
38
+ quotes: none;
39
+ }
40
+ blockquote:before, blockquote:after,
41
+ q:before, q:after {
42
+ content: '';
43
+ content: none;
44
+ }
45
+ table {
46
+ border-collapse: collapse;
47
+ border-spacing: 0;
48
+ }
49
+ /*!
50
+ * Bootstrap v2.0.2
51
+ *
52
+ * Copyright 2012 Twitter, Inc
53
+ * Licensed under the Apache License v2.0
54
+ * http://www.apache.org/licenses/LICENSE-2.0
55
+ *
56
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
57
+ */
58
+ .clearfix {
59
+ *zoom: 1;
60
+ }
61
+ .clearfix:before,
62
+ .clearfix:after {
63
+ display: table;
64
+ content: "";
65
+ }
66
+ .clearfix:after {
67
+ clear: both;
68
+ }
69
+ .hide-text {
70
+ overflow: hidden;
71
+ text-indent: 100%;
72
+ white-space: nowrap;
73
+ }
74
+ .input-block-level {
75
+ display: block;
76
+ width: 100%;
77
+ min-height: 28px;
78
+ /* Make inputs at least the height of their button counterpart */
79
+
80
+ /* Makes inputs behave like true block-level elements */
81
+
82
+ -webkit-box-sizing: border-box;
83
+ -moz-box-sizing: border-box;
84
+ -ms-box-sizing: border-box;
85
+ box-sizing: border-box;
86
+ }
87
+ .row {
88
+ margin-left: -20px;
89
+ *zoom: 1;
90
+ }
91
+ .row:before,
92
+ .row:after {
93
+ display: table;
94
+ content: "";
95
+ }
96
+ .row:after {
97
+ clear: both;
98
+ }
99
+ [class*="span"] {
100
+ float: left;
101
+ margin-left: 20px;
102
+ }
103
+ .container,
104
+ .navbar-fixed-top .container,
105
+ .navbar-fixed-bottom .container {
106
+ width: 940px;
107
+ }
108
+ .span12 {
109
+ width: 940px;
110
+ }
111
+ .span11 {
112
+ width: 860px;
113
+ }
114
+ .span10 {
115
+ width: 780px;
116
+ }
117
+ .span9 {
118
+ width: 700px;
119
+ }
120
+ .span8 {
121
+ width: 620px;
122
+ }
123
+ .span7 {
124
+ width: 540px;
125
+ }
126
+ .span6 {
127
+ width: 460px;
128
+ }
129
+ .span5 {
130
+ width: 380px;
131
+ }
132
+ .span4 {
133
+ width: 300px;
134
+ }
135
+ .span3 {
136
+ width: 220px;
137
+ }
138
+ .span2 {
139
+ width: 140px;
140
+ }
141
+ .span1 {
142
+ width: 60px;
143
+ }
144
+ .offset12 {
145
+ margin-left: 980px;
146
+ }
147
+ .offset11 {
148
+ margin-left: 900px;
149
+ }
150
+ .offset10 {
151
+ margin-left: 820px;
152
+ }
153
+ .offset9 {
154
+ margin-left: 740px;
155
+ }
156
+ .offset8 {
157
+ margin-left: 660px;
158
+ }
159
+ .offset7 {
160
+ margin-left: 580px;
161
+ }
162
+ .offset6 {
163
+ margin-left: 500px;
164
+ }
165
+ .offset5 {
166
+ margin-left: 420px;
167
+ }
168
+ .offset4 {
169
+ margin-left: 340px;
170
+ }
171
+ .offset3 {
172
+ margin-left: 260px;
173
+ }
174
+ .offset2 {
175
+ margin-left: 180px;
176
+ }
177
+ .offset1 {
178
+ margin-left: 100px;
179
+ }
180
+ .row-fluid {
181
+ width: 100%;
182
+ *zoom: 1;
183
+ }
184
+ .row-fluid:before,
185
+ .row-fluid:after {
186
+ display: table;
187
+ content: "";
188
+ }
189
+ .row-fluid:after {
190
+ clear: both;
191
+ }
192
+ .row-fluid > [class*="span"] {
193
+ float: left;
194
+ margin-left: 2.127659574%;
195
+ }
196
+ .row-fluid > [class*="span"]:first-child {
197
+ margin-left: 0;
198
+ }
199
+ .row-fluid > .span12 {
200
+ width: 99.99999998999999%;
201
+ }
202
+ .row-fluid > .span11 {
203
+ width: 91.489361693%;
204
+ }
205
+ .row-fluid > .span10 {
206
+ width: 82.97872339599999%;
207
+ }
208
+ .row-fluid > .span9 {
209
+ width: 74.468085099%;
210
+ }
211
+ .row-fluid > .span8 {
212
+ width: 65.95744680199999%;
213
+ }
214
+ .row-fluid > .span7 {
215
+ width: 57.446808505%;
216
+ }
217
+ .row-fluid > .span6 {
218
+ width: 48.93617020799999%;
219
+ }
220
+ .row-fluid > .span5 {
221
+ width: 40.425531911%;
222
+ }
223
+ .row-fluid > .span4 {
224
+ width: 31.914893614%;
225
+ }
226
+ .row-fluid > .span3 {
227
+ width: 23.404255317%;
228
+ }
229
+ .row-fluid > .span2 {
230
+ width: 14.89361702%;
231
+ }
232
+ .row-fluid > .span1 {
233
+ width: 6.382978723%;
234
+ }
235
+ .container {
236
+ margin-left: auto;
237
+ margin-right: auto;
238
+ *zoom: 1;
239
+ }
240
+ .container:before,
241
+ .container:after {
242
+ display: table;
243
+ content: "";
244
+ }
245
+ .container:after {
246
+ clear: both;
247
+ }
248
+ .container-fluid {
249
+ padding-left: 20px;
250
+ padding-right: 20px;
251
+ *zoom: 1;
252
+ }
253
+ .container-fluid:before,
254
+ .container-fluid:after {
255
+ display: table;
256
+ content: "";
257
+ }
258
+ .container-fluid:after {
259
+ clear: both;
260
+ }
@@ -0,0 +1,66 @@
1
+ html {
2
+ background: #efefef url(cross_scratches.png) repeat 0 0;
3
+ font-family: Helvetica, sans-serif;
4
+ font-size: 16px;
5
+ font-weight: 700;
6
+ line-height: 24px;
7
+ color: #3e3e3e;
8
+ }
9
+ body {
10
+ padding: 0;
11
+ margin: 0;
12
+ }
13
+ .container {
14
+ text-shadow: 0 1px rgba(255,255,255,.8);
15
+ }
16
+ .hero-stats {
17
+ margin-bottom: 20px;
18
+ padding-top: 20px;
19
+ background: #fefefe;
20
+ color: #4d4d4d;
21
+ border-bottom: 1px solid rgba(0,0,0,.3);
22
+ box-shadow: 0 1px 2px rgba(0,0,0,.2);
23
+ }
24
+ .hero-stats .row {
25
+ margin-left: auto;
26
+ margin-bottom: 20px;
27
+ }
28
+ .hero-stats .row li:first-child {
29
+ margin-left: 0;
30
+ }
31
+ ol {
32
+ width: 940px;
33
+ margin: 0 auto;
34
+ }
35
+ li {
36
+ font-weight: 300;
37
+ }
38
+ .count {
39
+ font-weight: 700;
40
+ font-size: 48px;
41
+ display: block;
42
+ }
43
+ .row {
44
+ margin-bottom: 40px;
45
+ }
46
+
47
+ footer {
48
+ margin: 0;
49
+ padding: 8px 0 30px 0;
50
+ font-size: 13px;
51
+ font-weight: 300;
52
+ text-align: right;
53
+ background: #fefefe;
54
+ border-top: 1px solid rgba(0,0,0,.2);
55
+ }
56
+ footer p {
57
+ width: 940px;
58
+ margin: 0 auto;
59
+ }
60
+
61
+ .jqplot-target {
62
+ font-family: Helvetica, sans-serif;
63
+ }
64
+ .jqplot-axis {
65
+ font-weight: 300;
66
+ }
@@ -0,0 +1,24 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Memdash</title>
6
+ <link href="<%= u 'reset.css' %>" media="screen" rel="stylesheet" type="text/css">
7
+ <link href="<%= u 'jquery.jqplot.min.css' %>" media="screen" rel="stylesheet" type="text/css">
8
+ <link href="<%= u 'style.css' %>" media="screen" rel="stylesheet" type="text/css">
9
+ </head>
10
+ <body>
11
+ <%= yield %>
12
+
13
+ <footer>
14
+ <p>Powered by <a href="http://github.com/bryckbost/memdash">Memdash</a>.</p>
15
+ </footer>
16
+
17
+ <script src="http://code.jquery.com/jquery-1.7.2.min.js" type="text/javascript"></script>
18
+ <script src="<%= u 'jquery.jqplot.min.js' %>" type="text/javascript"></script>
19
+ <script src="<%= u 'jqplot.canvasTextRenderer.min.js' %>" type="text/javascript"></script>
20
+ <script src="<%= u 'jqplot.canvasAxisTickRenderer.min.js' %>" type="text/javascript"></script>
21
+ <script src="<%= u 'jqplot.dateAxisRenderer.min.js' %>" type="text/javascript"></script>
22
+ <script src="<%= u 'charts.js' %>" type="text/javascript"></script>
23
+ </body>
24
+ </html>
@@ -0,0 +1,19 @@
1
+ <div class="hero-stats">
2
+ <ol class="row">
3
+ <li class="span4"><span class="count"><%= miss_ratio_percentage(@last_report.stats.map{|_, v| v["get_hits"].to_f}.sum, @last_report.stats.map{|_, v| v["get_misses"].to_f}.sum).round(2) %>%</span>Cache miss ratio</li>
4
+ <li class="span4"><span class="count"><%= @last_report.stats.map{|_, v| v["curr_items"]}.sum %></span>Current items in memcache</li>
5
+ <li class="span4"><span class="count"><%= (@last_report.stats.map{|_,v| v["bytes"].to_i}.sum / 1024.0 / 1024.0).round(2) %>/<%= @last_report.stats.map{|_,v| v["limit_maxbytes"].to_i}.sum / 1024 / 1024 %> MB</span>Current memory usage</li>
6
+ </ol>
7
+ </div>
8
+
9
+ <section class="container">
10
+ <div class="row">
11
+ <div id="gets-sets" class="span6" data-gets='<%= @gets %>' data-sets='<%= @sets %>'></div>
12
+ <div id="hits-misses" class="span6" data-hits='<%= @hits %>' data-misses='<%= @misses %>'></div>
13
+ </div>
14
+
15
+ <div class="row">
16
+ <div id="memory-usage" class="span6" data-limit-maxbytes='<%= @limit_maxbytes %>' data-bytes='<%= @bytes %>'></div>
17
+ <div id="current-items" class="span6" data-current-items='<%= @current_items %>'></div>
18
+ </div>
19
+ </section>
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'memdash'
5
+ gem.version = '0.0.1'
6
+
7
+ gem.authors = ['Brian Ryckbost', 'Steve Richert']
8
+ gem.email = ['bryckbost@gmail.com', 'steve.richert@gmail.com']
9
+ gem.description = 'A dashboard for your memcache'
10
+ gem.summary = 'A dashboard for your memcache'
11
+ gem.homepage = 'https://github.com/bryckbost/memdash'
12
+
13
+ gem.add_dependency 'activerecord', '~> 3.0'
14
+ gem.add_dependency 'dalli', '~> 2.0'
15
+ gem.add_dependency 'sinatra', '~> 1.3'
16
+
17
+ gem.add_development_dependency 'database_cleaner'
18
+ gem.add_development_dependency 'rake'
19
+ gem.add_development_dependency 'rspec'
20
+ gem.add_development_dependency 'sqlite3'
21
+
22
+ gem.files = `git ls-files`.split($\)
23
+ gem.test_files = gem.files.grep(/^spec\//)
24
+ gem.require_paths = ['lib']
25
+ end
Binary file
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Memdash do
4
+ before do
5
+ Memdash.ttl = 2
6
+ end
7
+
8
+ it 'records gets' do
9
+ expect{ dalli.get('key') }.to change{ reports_count }.by(1)
10
+ end
11
+
12
+ it 'waits between recording gets' do
13
+ dalli.get('key')
14
+ sleep 1
15
+ expect{ dalli.get('key') }.to_not change{ reports_count }
16
+ sleep 2
17
+ expect{ dalli.get('key') }.to change{ reports_count }.by(1)
18
+ end
19
+
20
+ it 'records sets' do
21
+ expect{ dalli.set('key', 'value') }.to change{ reports_count }.by(1)
22
+ end
23
+
24
+ it 'waits between recording sets' do
25
+ dalli.set('key', 'value')
26
+ sleep 1
27
+ expect{ dalli.set('key', 'value') }.to_not change{ reports_count }
28
+ sleep 2
29
+ expect{ dalli.set('key', 'value') }.to change{ reports_count }.by(1)
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ require "support/adapters/#{ENV['ADAPTER']}" if ENV['ADAPTER']
2
+
3
+ Dir[File.expand_path('../support/*.rb', __FILE__)].each{|f| require f }
@@ -0,0 +1,11 @@
1
+ require 'memdash/active_record'
2
+
3
+ module ActiveRecordHelpers
4
+ def reports_count
5
+ Memdash::ActiveRecord::Report.count
6
+ end
7
+ end
8
+
9
+ RSpec.configure do |config|
10
+ config.include ActiveRecordHelpers
11
+ end