dasht 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.agignore +3 -0
  3. data/Gemfile +14 -0
  4. data/Gemfile.lock +88 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +329 -0
  7. data/Rakefile +51 -0
  8. data/VERSION +1 -0
  9. data/assets/css/style.css +123 -0
  10. data/assets/images/background.jpg +0 -0
  11. data/assets/js/Chart.min.js +11 -0
  12. data/assets/js/dasht.js +141 -0
  13. data/assets/js/jquery-1.11.3.min.js +5 -0
  14. data/assets/js/masonry.pkgd.min.js +9 -0
  15. data/assets/js/mustache.min.js +1 -0
  16. data/assets/js/underscore-min.js +6 -0
  17. data/assets/plugins/chart.css +11 -0
  18. data/assets/plugins/chart.html +2 -0
  19. data/assets/plugins/chart.js +50 -0
  20. data/assets/plugins/map.css +17 -0
  21. data/assets/plugins/map.html +4 -0
  22. data/assets/plugins/map.js +125 -0
  23. data/assets/plugins/scroll.css +2 -0
  24. data/assets/plugins/scroll.html +2 -0
  25. data/assets/plugins/scroll.js +14 -0
  26. data/assets/plugins/value.css +18 -0
  27. data/assets/plugins/value.html +4 -0
  28. data/assets/plugins/value.js +26 -0
  29. data/examples/simple_heroku_dashboard.rb +34 -0
  30. data/lib/dasht.rb +25 -0
  31. data/lib/dasht/array_monkeypatching.rb +5 -0
  32. data/lib/dasht/base.rb +117 -0
  33. data/lib/dasht/board.rb +108 -0
  34. data/lib/dasht/collector.rb +33 -0
  35. data/lib/dasht/list.rb +93 -0
  36. data/lib/dasht/log_thread.rb +94 -0
  37. data/lib/dasht/metric.rb +82 -0
  38. data/lib/dasht/rack_app.rb +74 -0
  39. data/lib/dasht/reloader.rb +28 -0
  40. data/screenshot_1.png +0 -0
  41. data/test/helper.rb +34 -0
  42. data/test/test_list.rb +65 -0
  43. data/test/test_metric.rb +58 -0
  44. data/tests.rb +6 -0
  45. data/views/dashboard.erb +27 -0
  46. metadata +189 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f77078178e8204348094a1edfb6a156b73312e40
4
+ data.tar.gz: d6f2ec380d325fbfdb3c21e670d5f6231c262b1f
5
+ SHA512:
6
+ metadata.gz: 59b6155601555c608ae696025073479cb6d3cd600aea05223a2a9914fae6553463217cf5fecd70e60760369ba2ba5a82bade15373a40e8669c4a676bb7d0641a
7
+ data.tar.gz: 8910d4cca0bf1bdb872ba0f0f66739bed5549c0c6c71e414fad25af7c5bb2708a40081bca1ad2a5ef2145d325a1fdb897ea47278aaee3d5a1f6a5c8d3f0f3eb4
@@ -0,0 +1,3 @@
1
+ *min*.js
2
+ *min*css
3
+ d3.v3.js
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'rack', "~> 1.6"
4
+
5
+ # Add dependencies to develop your gem here.
6
+ # Include everything needed to run rake, tests, features, etc.
7
+ group :development do
8
+ gem "shoulda", ">= 0"
9
+ gem "rdoc", "~> 3.12"
10
+ gem "bundler", "~> 1.0"
11
+ gem "jeweler", "~> 2.0.1"
12
+ gem "simplecov", ">= 0"
13
+ gem "test-unit", "~> 3"
14
+ end
@@ -0,0 +1,88 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (4.2.3)
5
+ i18n (~> 0.7)
6
+ json (~> 1.7, >= 1.7.7)
7
+ minitest (~> 5.1)
8
+ thread_safe (~> 0.3, >= 0.3.4)
9
+ tzinfo (~> 1.1)
10
+ addressable (2.3.8)
11
+ builder (3.2.2)
12
+ descendants_tracker (0.0.4)
13
+ thread_safe (~> 0.3, >= 0.3.1)
14
+ docile (1.1.5)
15
+ faraday (0.9.1)
16
+ multipart-post (>= 1.2, < 3)
17
+ git (1.2.9.1)
18
+ github_api (0.12.4)
19
+ addressable (~> 2.3)
20
+ descendants_tracker (~> 0.0.4)
21
+ faraday (~> 0.8, < 0.10)
22
+ hashie (>= 3.4)
23
+ multi_json (>= 1.7.5, < 2.0)
24
+ nokogiri (~> 1.6.6)
25
+ oauth2
26
+ hashie (3.4.2)
27
+ highline (1.7.3)
28
+ i18n (0.7.0)
29
+ jeweler (2.0.1)
30
+ builder
31
+ bundler (>= 1.0)
32
+ git (>= 1.2.5)
33
+ github_api
34
+ highline (>= 1.6.15)
35
+ nokogiri (>= 1.5.10)
36
+ rake
37
+ rdoc
38
+ json (1.8.3)
39
+ jwt (1.5.1)
40
+ mini_portile (0.6.2)
41
+ minitest (5.7.0)
42
+ multi_json (1.11.2)
43
+ multi_xml (0.5.5)
44
+ multipart-post (2.0.0)
45
+ nokogiri (1.6.6.2)
46
+ mini_portile (~> 0.6.0)
47
+ oauth2 (1.0.0)
48
+ faraday (>= 0.8, < 0.10)
49
+ jwt (~> 1.0)
50
+ multi_json (~> 1.3)
51
+ multi_xml (~> 0.5)
52
+ rack (~> 1.2)
53
+ power_assert (0.2.2)
54
+ rack (1.6.4)
55
+ rake (10.4.2)
56
+ rdoc (3.12.2)
57
+ json (~> 1.4)
58
+ shoulda (3.5.0)
59
+ shoulda-context (~> 1.0, >= 1.0.1)
60
+ shoulda-matchers (>= 1.4.1, < 3.0)
61
+ shoulda-context (1.2.1)
62
+ shoulda-matchers (2.8.0)
63
+ activesupport (>= 3.0.0)
64
+ simplecov (0.10.0)
65
+ docile (~> 1.1.0)
66
+ json (~> 1.8)
67
+ simplecov-html (~> 0.10.0)
68
+ simplecov-html (0.10.0)
69
+ test-unit (3.0.8)
70
+ power_assert
71
+ thread_safe (0.3.5)
72
+ tzinfo (1.2.2)
73
+ thread_safe (~> 0.1)
74
+
75
+ PLATFORMS
76
+ ruby
77
+
78
+ DEPENDENCIES
79
+ bundler (~> 1.0)
80
+ jeweler (~> 2.0.1)
81
+ rack (~> 1.6)
82
+ rdoc (~> 3.12)
83
+ shoulda
84
+ simplecov
85
+ test-unit (~> 3)
86
+
87
+ BUNDLED WITH
88
+ 1.10.5
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015 Rusty Klophaus
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,329 @@
1
+ # Dasht
2
+
3
+ Dasht is a framework for building beautiful, developer-focused application dashboards. Dasht is especially good at displaying high-level application stats in real-time on a wall-mounted monitor.
4
+
5
+ > "You can't manage what you don't measure." - Peter Drucker
6
+
7
+ Dasht works best with a Twelve-Factor (Heroku style) app. Specifically, your app should treat [logs as event streams](http://12factor.net/logs). Dasht lets you detect events with regular expressions, turn the events into metrics, then publish the metrics to a dashboard.
8
+
9
+ A typical Dasht dashboard takes just a few minutes of coding and is usually less than 100 lines of Ruby.
10
+
11
+ Dasht is a Ruby / Rack application by [Rusty Klophaus](http://rusty.io), open-sourced under the MIT license.
12
+
13
+ # Getting Started
14
+
15
+ Let's make the following dashboard for your Heroku app.
16
+
17
+ ![Dasht Screen Shot](screenshot_1.png)
18
+
19
+ First, copy the Ruby code below to a file called `my_dashboard.rb`.
20
+
21
+ ```ruby
22
+ require 'dasht'
23
+
24
+ application = ARGV[0]
25
+
26
+ dasht do |d|
27
+ # Consume Heroku logs.
28
+ d.start "heroku logs --tail --app #{application}" do |l|
29
+ # Track some metrics.
30
+ d.count :lines, /.+/
31
+
32
+ d.count :bytes, /.+/ do |match|
33
+ match[0].length
34
+ end
35
+
36
+ d.append :visitors, /for (\d+\.\d+\.\d+\.\d+) at/ do |matches|
37
+ matches[1]
38
+ end
39
+ end
40
+
41
+ counter = 0
42
+ d.interval :counter do
43
+ sleep 1
44
+ counter += 1
45
+ end
46
+
47
+ # Publish a board.
48
+ d.board do |b|
49
+ b.value :counter, :title => "Counter"
50
+ b.value :lines, :title => "Number of Lines"
51
+ b.value :bytes, :title => "Number of Bytes"
52
+ b.chart :bytes, :title => "Chart of Bytes", :periods => 10
53
+ b.map :visitors, :title => "Visitors", :width => 12, :height => 9
54
+ end
55
+ end
56
+ ```
57
+
58
+ Then, run the following commands in your shell:
59
+
60
+ ```sh
61
+ # Install the gem.
62
+ gem install dasht
63
+
64
+ # Create a dashboard.
65
+ vi my_dashboard.rb
66
+
67
+ # Run the dashboard.
68
+ ruby my_dashboard.rb $APPNAME
69
+
70
+ # Open the dashboard.
71
+ open http://localhost:8080
72
+ ```
73
+
74
+ Look in the [examples](https://github.com/rustyio/dasht/tree/master/examples) folder for more example dashboards..
75
+
76
+ # Documentation
77
+
78
+ ## Creating a Dasht Instance
79
+
80
+ To create a Dasht instance, simply require the library and then call the global `dasht` method with a block.
81
+
82
+ ```ruby
83
+ require 'dasht'
84
+
85
+ dasht do |d|
86
+ # ...Your metrics and dashboards...
87
+ end
88
+ ```
89
+
90
+ There are a number of global settings that can be specified at the instance level, with their corresponding defaults:
91
+
92
+ ```ruby
93
+ dasht do |d|
94
+ # Set the web port.
95
+ b.port = 8080
96
+
97
+ # Set the amount of history to keep.
98
+ b.history = 60 * 60
99
+
100
+ # Set a background color.
101
+ b.background = "#334455"
102
+
103
+ # Or, set a background image.
104
+ # b.background = "url(http://path/to/image.png)"
105
+
106
+ # Set the default resolution.
107
+ b.default_resolution = 60
108
+
109
+ # Set the default refresh rate.
110
+ b.default_refresh = 5
111
+
112
+ # Set the default tile width.
113
+ b.default_width = 3
114
+
115
+ # Set the default tile height.
116
+ b.default_height = 3
117
+
118
+ # Set the default number of periods.
119
+ b.default_periods
120
+
121
+ # ...Your metrics and dashboards...
122
+ end
123
+ ```
124
+
125
+
126
+ ## Injesting Data
127
+
128
+ Dasht gets data by running a command (or tailing a log file) and listening to the output. A single Dasht instance can listen to multiple sources. If the command ends for some reason, it is automatically restarted.
129
+
130
+ Some examples:
131
+
132
+ ```ruby
133
+ # Start a command, process the output.
134
+ d.start("heroku logs --tail --app my_application") do |l|
135
+ ...
136
+ end
137
+
138
+ # Tail a file, process the new data.
139
+ d.tail("/path/to/my_application.log") do |l|
140
+ ...
141
+ end
142
+ ```
143
+
144
+ There is also an interval type meant for querying external data sources. It simply runs in a loop. Remember to include a `sleep` statement!.
145
+
146
+ ```ruby
147
+ # Query external data. Acts as a gauge, and sets the metric to the
148
+ # return value of the block.
149
+ d.interval :my_metric do
150
+ sleep 5
151
+ hash = JSON.parse(Net::HTTP.get("http://website/some/api.json"))
152
+ hash["value"]
153
+ end
154
+ ```
155
+
156
+ ## Metrics
157
+
158
+ Dasht tries to apply each new log line against a series of user-defined regular expressions. When a regular expression matches, Dasht updates the corresponding metric.
159
+
160
+ There are a number of pre-defined metric types:
161
+
162
+ + `gauge` - Set a metric.
163
+ + `count` - Increment a metric by some amount. (defaults to 1 if no block is provided).
164
+ + `min` - Update the minimum value.
165
+ + `max` - Update the maximum value.
166
+ + `append` - Create a list of values. Useful for non-numeric data such as geographic locations.
167
+
168
+ Unless otherwise noted, all metric definitions require a block. The block should convert the regular expression match into a value. Metrics should be kept as simple and compact as possible to keep memory requirements low. (Dasht uses an extremely simple structure to store time-series data. It doesn't go to great lengths to be especially resource efficient.)
169
+
170
+ Some examples:
171
+
172
+ ```ruby
173
+ d.start "some command" do |l|
174
+ # Track the total number of log lines processed.
175
+ l.count :lines, /.+/
176
+
177
+ # Track the total size of the logs, in bytes.
178
+ l.count :bytes, /.+/ do |match|
179
+ match[0].length
180
+ end
181
+
182
+ # Track the maximum response time.
183
+ l.max :max_response, /Completed 200 OK in (\d+)ms/ do |match|
184
+ match[1].to_i
185
+ end
186
+
187
+ # Track visitor IP addresses.
188
+ l.append :visitors, /Started GET .* for (\d+\.\d+\.\d+\.\d+) at/ do |matches|
189
+ matches[1]
190
+ end
191
+ end
192
+ ```
193
+
194
+ You can also define your own metric types with the `event` command. The `op` parameter is a symbol referring to any [Array](http://ruby-doc.org/core-2.2.0/Array.html) instance method. If the built-in Array methods don't do what you need, you can monkey-patch the array class to add new methods.
195
+
196
+ ```ruby
197
+ # Format is d.event(metric, regex, op, &block). The definition below
198
+ # would set the metric to the first occurance of some metric value
199
+ # for a given timeframe.
200
+ l.event(:my_metric, /some-regex/, :first) do |match|
201
+ match[1].to_i
202
+ end
203
+ ```
204
+
205
+ ## Boards
206
+
207
+ A single Dasht instance can host multiple dashboards. Dashboards are defined like this:
208
+
209
+ ```ruby
210
+ # Publish a board, accessible through "/boards/my_board"
211
+ d.board :my_board do |b|
212
+ ...
213
+ end
214
+
215
+ # Publish the default board, accessible through "/"
216
+ d.board do |b|
217
+ ...
218
+ end
219
+ ```
220
+
221
+ Each dashboard can have a number of different settings, documented below with their corresponding defaults:
222
+
223
+ ```ruby
224
+ d.board do |b|
225
+ # Set a background color.
226
+ b.background = "#334455"
227
+
228
+ # Or, set a background image.
229
+ # b.background = "url(http://path/to/image.png)"
230
+
231
+ # Set the default resolution.
232
+ b.default_resolution = 60
233
+
234
+ # Set the default refresh rate.
235
+ b.default_refresh = 5
236
+
237
+ # Set the default tile width.
238
+ b.default_width = 3
239
+
240
+ # Set the default tile height.
241
+ b.default_height = 3
242
+
243
+ # Set the default number of periods.
244
+ b.default_periods
245
+ end
246
+ ```
247
+ Each dashboard can be filled with tiles that display various key metrics about the app. Each dashboard is split into a 12x12 grid. Tiles by default take up a 3x3 spot. The height and width of each tile can be adjusted with a per-tile setting.
248
+
249
+ Dasht tries to make dashboards look nice with minimal effort in the following ways:
250
+
251
+ + The dashboard itself gracefully stretches to fill the entire screen for most reasonable monitor sizes, even in portrait orientation.
252
+ + Tile elements are designed to be slightly transparent, so they look nice with any background color or image.
253
+ + Dasht uses [Masonry](http://masonry.desandro.com/) to pack tiles into a reasonably compact and visually pleasing layout.
254
+ + Text is automatically scaled up or down to be as large as possible while still fitting into available space.
255
+ + Dasht is responsive and looks nice on mobile devices and tables. That said, the target platform is a large monitor.
256
+
257
+ ## Tiles
258
+
259
+ Metrics can be published by placing tiles on a dashboard. Dasht comes with a handful of tile types.
260
+
261
+ All tiles respond to the following options:
262
+
263
+ + `:title` - The title of the tile.
264
+ + `:resolution` - The resolution of the tile. Defaults to the board or instance default. If none specified, defaults to 60, meaning that it will load data for the last minute.
265
+ + `:refresh` - The refresh rate of the tile. Defaults to the board or instance default. If none specified, defaults to 5, meaning that it will load fresh data every 5 seconds.
266
+ + `:width` - The width of the tile, an integer from 1 to 12. Defaults to 3.
267
+ + `:height` - The height of the tile, an integer from 1 to 12. Defaults to 3.
268
+
269
+ Individual tiles have additional attributes.
270
+
271
+ Dasht is extensible. New tiles are relatively easy to write. A simple tile plugin takes around 30 lines of Javascript. See the [existing plugins](https://github.com/rustyio/dasht/tree/master/assets/plugins) for examples.
272
+
273
+ ### Value Tile
274
+
275
+ Display a single numeric value.
276
+
277
+ ```ruby
278
+ b.value :my_metric, :title => "My Title"
279
+ ```
280
+
281
+ ### Map Tile
282
+
283
+ Drop pins on a map corresponding to either a physical addresses ("123 Main Street...") or an IP address ("216.58.217.142"). The metric attached to the map should use the `append` metric type, and the block should return the address string. See `examples/simple_heroku_dashboard.rb` for an example.
284
+
285
+ ```ruby
286
+ b.map :visitors, :title => "Visitors"
287
+ ```
288
+
289
+ ### Chart Tile
290
+
291
+ Show a simple line chart of the metric. This will display the value of the metric for a number of periods in history. For example, if the resolution is 60, and periods is set to 10, then the chart will show the last rolling 10 minutes of history.
292
+
293
+ ```ruby
294
+ b.chart :my_metric, :title => "My Title", :periods => 10
295
+ ```
296
+
297
+ ### A Tile With Many Settings
298
+
299
+ Here is how other settings are set.
300
+
301
+ ```ruby
302
+ b.value :my_metric, :title => "My Title",
303
+ :resolution => 10, :refresh => 1, :width => 6, :height => 2
304
+ ```
305
+
306
+ # Future Plans
307
+
308
+ A bucket of ideas for the future:
309
+
310
+ + Fix up 'scroll' tile.
311
+ + Create a 'delta' tile. (Up / down X percent.)
312
+ + Read data in batches to reduce browser resource usage.
313
+ + Load user defined plugins.
314
+
315
+ # Contributing
316
+
317
+ To contribute, please create a pull request with a good description and either a unit test or a sample dashboard that exercises the new feature.
318
+
319
+ # License
320
+
321
+ The MIT License (MIT)
322
+
323
+ Copyright (c) 2015 Rusty Klophaus
324
+
325
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
326
+
327
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
328
+
329
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.