batsd-dash 0.3.1 → 0.5.0

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.
Files changed (54) hide show
  1. data/.rbenv-version +1 -0
  2. data/Gemfile +3 -0
  3. data/README.md +36 -79
  4. data/batsd-dash.gemspec +5 -9
  5. data/lib/batsd-dash.rb +9 -80
  6. data/lib/batsd-dash/app.rb +113 -0
  7. data/lib/batsd-dash/connection.rb +54 -0
  8. data/lib/batsd-dash/graph.rb +10 -2
  9. data/lib/batsd-dash/params.rb +10 -2
  10. data/lib/{public → batsd-dash/public}/css/d3.css +199 -100
  11. data/lib/{public → batsd-dash/public}/css/datetimepicker.css +0 -0
  12. data/lib/{public → batsd-dash/public}/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  13. data/lib/{public → batsd-dash/public}/css/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  14. data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  15. data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  16. data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  17. data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  18. data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  19. data/lib/{public → batsd-dash/public}/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  20. data/lib/{public → batsd-dash/public}/css/images/ui-icons_222222_256x240.png +0 -0
  21. data/lib/{public → batsd-dash/public}/css/images/ui-icons_2e83ff_256x240.png +0 -0
  22. data/lib/{public → batsd-dash/public}/css/images/ui-icons_454545_256x240.png +0 -0
  23. data/lib/{public → batsd-dash/public}/css/images/ui-icons_888888_256x240.png +0 -0
  24. data/lib/{public → batsd-dash/public}/css/images/ui-icons_cd0a0a_256x240.png +0 -0
  25. data/lib/{public → batsd-dash/public}/css/jquery-ui.css +0 -0
  26. data/lib/batsd-dash/public/css/public.css +419 -0
  27. data/lib/batsd-dash/public/js/d3.js +4 -0
  28. data/lib/batsd-dash/public/js/dash.js +82 -0
  29. data/lib/{public → batsd-dash/public}/js/datetimepicker.js +0 -0
  30. data/lib/{public → batsd-dash/public}/js/datetimepicker.js~ +0 -0
  31. data/lib/{public → batsd-dash/public}/js/jquery-ui.js +0 -0
  32. data/lib/{public → batsd-dash/public}/js/jquery.js +0 -0
  33. data/lib/batsd-dash/public/js/nv.d3.js +5 -0
  34. data/lib/batsd-dash/version.rb +4 -2
  35. data/lib/{views → batsd-dash/views}/layout.haml +24 -6
  36. data/lib/batsd-dash/views/loading.haml +5 -0
  37. data/lib/batsd-dash/views/missing.haml +14 -0
  38. data/lib/batsd-dash/views/root.haml +37 -0
  39. data/lib/batsd-dash/views/view.haml +60 -0
  40. data/lib/sass/_charts.scss +37 -0
  41. data/lib/{batsd-dash/sass → sass}/public.scss +102 -27
  42. data/test/helper.rb +5 -16
  43. data/test/test_dash.rb +65 -69
  44. metadata +121 -101
  45. data/lib/batsd-dash/connection_pool.rb +0 -87
  46. data/lib/public/css/public.css +0 -106
  47. data/lib/public/js/d3.js +0 -4
  48. data/lib/public/js/dash.js +0 -110
  49. data/lib/public/js/flot.js +0 -6
  50. data/lib/public/js/nv.d3.js +0 -4
  51. data/lib/views/missing.haml +0 -6
  52. data/lib/views/root.haml +0 -0
  53. data/lib/views/view.haml +0 -18
  54. data/test/test_connection_pool.rb +0 -20
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ jruby-1.7.0
data/Gemfile CHANGED
@@ -7,3 +7,6 @@ group :test do
7
7
  gem "guard-minitest"
8
8
  end
9
9
 
10
+ group :development do
11
+ gem "compass"
12
+ end
data/README.md CHANGED
@@ -1,91 +1,48 @@
1
- batsd-dash
1
+ Batsd-dash
2
2
  ==========
3
3
 
4
- Configurable dashboard for [batsd-server](https://github.com/noahhl/batsd).
4
+ Batds-dash is a configurable dashboard for [batsd-server](https://github.com/noahhl/batsd).
5
+ The front-end uses [NVD3](http://nvd3.org/) for rendering graphs. The back-end uses
6
+ [Sinatra](github.com/sinatra/sinatra/) for the actual web application.
5
7
 
6
- ## Setup
8
+ The application server is designed to use a threaded [connection pool](https://github.com/mperham/connection_pool).
9
+ Thus, it is suggested that you run Batsd-dash on JRuby or Rubinius in order
10
+ to take full advantage of threaded processing.
7
11
 
8
- ### Install
12
+ ### Documentation
9
13
 
10
- To install batsd-dash, simply install the gem
14
+ * [Installation and
15
+ Configuration](https://github.com/mikeycgto/batsd-dash/wiki/Installation-and-Configuration)
16
+ * [Running the
17
+ Application](https://github.com/mikeycgto/batsd-dash/wiki/Running-the-Application)
18
+ * [Viewing
19
+ Graphs](https://github.com/mikeycgto/batsd-dash/wiki/Viewing-Graphs)
20
+ * [Data API](https://github.com/mikeycgto/batsd-dash/wiki/Data-API)
21
+ * [Custom Pages](https://github.com/mikeycgto/batsd-dash/wiki/Custom-Pages)
22
+ * [Contributing](https://github.com/mikeycgto/batsd-dash/wiki/Contributing)
11
23
 
12
- gem install batsd-dash
24
+ ### About
13
25
 
14
- ### Configuration
26
+ This is project is maintained and developed by [@mikeycgto](https://twitter.com/mikeycgto)
27
+ and [@btoconnor](https://twitter.com/btoconnor) mainly for use on [BreakBase](http://breakbase.com).
15
28
 
16
- Here is a sample rackup file (`config.ru`):
17
-
18
- require 'batsd-dash'
29
+ ### License
19
30
 
20
- # set batsd server setting
21
- BatsdDash::ConnectionPool.settings = { host:'localhost', port: 8127, pool_size: 8 }
31
+ Copyright (c) 2012 Michael J Coyne & Brian O'Connor
22
32
 
23
- # run the app
24
- run BatsdDash::App
33
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this
34
+ software and associated documentation files (the "Software"), to deal in the Software
35
+ without restriction, including without limitation the rights to use, copy, modify,
36
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
37
+ permit persons to whom the Software is furnished to do so, subject to the following
38
+ conditions:
25
39
 
26
- Rack is very powerful. You can password protect your batsd-dash instance
27
- by using `Rack::Auth::Basic` or `Rack::Auth::Digest::MD5`.
40
+ The above copyright notice and this permission notice shall be included in all copies
41
+ or substantial portions of the Software.
28
42
 
29
- ## Viewing Graphs
30
-
31
- Graphs are rendered using [nv.d3](http://nvd3.com/), a powerful graph
32
- and visualization library.
33
-
34
- Since rendering is all done on the client, we make use of hash based
35
- navigation in order to reduce the amount of requests while still
36
- maintaining 'linkability'.
37
-
38
- For example, to view a graph for the counter `a.b` statistic, you would need
39
- to make the following request from your browser:
40
-
41
- /graph#counters=a.b
42
-
43
- The graph view will provide you with a date time picker to make selecting
44
- different time ranges easier. Graphs are updated when you press the
45
- 'View' button or when the URL is updated.
46
-
47
- It's possible to view more than one metric at the same time. To do this,
48
- visit the following route from your browser:
49
-
50
- /graph#counters=a.b,c.d
51
-
52
- You can also view different datatypes at the same time:
53
-
54
- /graph#counters=a.b&timers=x.y
55
-
56
- __NOTE__: As of now, a single y-axis is used when datatypes are mixed.
57
- Soon, we will add support for multiple axis when viewing mixed types.
58
-
59
- ## Data API
60
-
61
- The application provides a simple JSON-based API for accessing data from
62
- the batds data server. The data API accepts similar parameters as the
63
- graph view but uses traditional query strings instead:
64
-
65
- /data?counters[]=a.b&counters[]=c.d&timers[]=x.y
66
-
67
- The data API also accepts a `start` and `stop` unix timestamp parameter
68
- for accessing different ranges of data. Note that, the data API will
69
- only respond with JSON if the `Accept` header to set to `application/json`!
70
-
71
- ## Graph and Render Options
72
-
73
- 1. Zerofill:
74
- __TODO__ Add details about zerofill
75
-
76
-
77
- ## Development
78
-
79
- ### Asset Management
80
-
81
- We use Sass for CSS within this project. If you make any changes to the Sass
82
- files, ensure you recompile the CSS. This is done by running:
83
-
84
- compass compile --force --output-style compact --environment production --sass-dir lib/batsd-dash/sass --css-dir lib/public/css
85
-
86
- Additionally, it is highly recommended you use thin for development since this
87
- app uses EventMachine.
88
-
89
- ## About
90
-
91
- This is project is maintained and developed by the people behind [BreakBase](http://breakbase.com) ([@mikeycgto](https://twitter.com/mikeycgto) and [@btoconnor](https://twitter.com/btoconnor))
43
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
44
+ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
45
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
46
+ FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
47
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
48
+ DEALINGS IN THE SOFTWARE.
data/batsd-dash.gemspec CHANGED
@@ -4,7 +4,7 @@ require 'batsd-dash/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "batsd-dash"
7
- s.version = BatsdDash::VERSION
7
+ s.version = Batsd::Dash::VERSION
8
8
 
9
9
  s.authors = ["mikeycgto", "btoconnor"]
10
10
  s.email = ["mikeycgto@gmail.com", "gatzby3jr@gmail.com"]
@@ -21,18 +21,14 @@ Gem::Specification.new do |s|
21
21
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
22
  s.require_paths = ["lib"]
23
23
 
24
- # specify any dependencies here; for example:
25
- s.add_dependency "sinatra"
26
- s.add_dependency "sinatra-contrib"
27
- s.add_dependency "sinatra-synchrony", "~> 0.3.2"
24
+ s.add_dependency "connection_pool"
28
25
 
26
+ s.add_dependency "sinatra"
29
27
  s.add_dependency "haml"
30
- s.add_dependency "yajl-ruby"
31
28
 
32
29
  s.add_development_dependency "rake"
33
30
  s.add_development_dependency "minitest"
34
- s.add_development_dependency "mocha"
35
- s.add_development_dependency "turn"
36
31
 
37
- s.add_development_dependency "thin"
32
+ s.add_development_dependency "sinatra-contrib"
33
+ s.add_development_dependency "mocha"
38
34
  end
data/lib/batsd-dash.rb CHANGED
@@ -1,83 +1,12 @@
1
- require 'yajl'
2
- require 'sinatra/base'
3
- require 'sinatra/synchrony'
4
- #require 'sinatra/reloader' if ENV['RACK_ENV'] == 'development'
5
-
6
- %w[connection_pool graph params version].each { |file| require "batsd-dash/#{file}" }
7
-
8
- module BatsdDash
9
- class App < Sinatra::Base
10
- #configure(:development) { register Sinatra::Reloader }
11
-
12
- configure do
13
- register Sinatra::Synchrony
14
- helpers ParamsHelper, GraphHelper, ConnectionHelpers
15
-
16
- set :haml, :format => :html5
17
-
18
- EM::Synchrony.next_tick { ConnectionPool::initialize_connection_pool }
19
- end
20
-
21
- helpers do
22
- def render_error(msg)
23
- render_json 400, error: msg
24
- end
25
-
26
- def render_json(code = 200, json)
27
- halt code, String === json ? json : Yajl::Encoder.encode(json)
28
- end
29
- end
30
-
31
- get "/" do
32
- haml :root
33
- end
34
-
35
- get "/version", :provides => :json do
36
- render_json version: BatsdDash::VERSION
37
- end
38
-
39
- get "/available", :provides => :json do
40
- connection_pool.async_available_list.callback do |json|
41
- render_json json
42
- end
43
- end
44
-
45
- # this route renders the template (with codes for the graph)
46
- get "/graph", :provides => :html do
47
- haml :view
48
- end
49
-
50
- # actual data API route
51
- get "/data", :provides => :json do
52
- statistics = parse_statistics
53
- range = parse_time_range
54
-
55
- return render_error('Invalid time range') unless range
56
- return render_error('Invalid metrics') if statistics.empty?
57
-
58
- results = []
59
- options = { range: range.dup.map { |n| n * 1000 } }
60
-
61
- statistics.each do |datatype, metrics|
62
- metrics.each do |metric|
63
- statistic = "#{datatype}:#{metric}"
64
- deferrable = connection_pool.async_values(statistic, range)
65
-
66
- deferrable.errback { |e| return render_error(e.message) }
67
- deferrable.callback do |json|
68
- options[:interval] ||= json['interval']
69
- options[:zero_fill] = !statistic.start_with?('gauges') && params[!:no_zero_fill]
70
-
71
- points = json[statistic] || []
72
- values = values_for_graph(points, options)
73
-
74
- results << { key: metric, type: datatype[0..-2], values: values }
75
- end
76
- end
77
- end
78
-
79
- cache_control :no_cache, :no_store
80
- render_json range: options[:range], interval: options[:interval], results: results
1
+ module Batsd
2
+ module Dash
3
+ class << self
4
+ attr_accessor :config
81
5
  end
82
6
  end
83
7
  end
8
+
9
+ require 'batsd-dash/version'
10
+ require 'batsd-dash/connection'
11
+ require 'batsd-dash/params'
12
+ require 'batsd-dash/graph'
@@ -0,0 +1,113 @@
1
+ require 'sinatra/base'
2
+ require 'haml'
3
+ require 'json'
4
+
5
+ module Batsd::Dash
6
+ class App < Sinatra::Base
7
+ configure(:development) { disable :show_exceptions }
8
+
9
+ configure do
10
+ helpers ParamsHelper, GraphHelper
11
+ set :haml, format: :html5
12
+ set :raise_errors, false
13
+
14
+ config = Batsd::Dash::config.dup || {}
15
+
16
+ set :views, [views, config.delete(:view_path)].compact
17
+ set :host, config.delete(:host) || 'localhost'
18
+ set :port, config.delete(:port) || 8127
19
+
20
+ set :view_names, [:root, :view, :missing, :layout, :loading]
21
+
22
+ @connection_pool = ConnectionPool.new(config) do
23
+ Connection.new(host, port)
24
+ end
25
+ end
26
+
27
+ helpers do
28
+ def find_template(views, name, engine, &block)
29
+ path = settings.view_names.include?(name) ? views.first : views.last
30
+
31
+ super path, name, engine, &block
32
+ end
33
+
34
+ def render_error(msg)
35
+ render_json 400, error: msg
36
+ end
37
+
38
+ def render_json(code = 200, json)
39
+ halt code, String === json ? json : JSON.dump(json)
40
+ end
41
+
42
+ def connection_pool
43
+ @connection_pool ||= self.class.instance_variable_get(:@connection_pool)
44
+ end
45
+ end
46
+
47
+ error Connection::SocketError do
48
+ render_json error: env['sinatra.error'].message
49
+ end
50
+
51
+ get "/", provides: :html do
52
+ haml :root
53
+ end
54
+
55
+ get "/graph", provides: :html do
56
+ haml :view
57
+ end
58
+
59
+ get %r[/([A-Za-z0-9-_]+)$], provides: :html do
60
+ begin
61
+ haml params[:captures].first.to_sym, locals: { user_template: true }
62
+ rescue Errno::ENOENT
63
+ haml :missing
64
+ end
65
+ end
66
+
67
+ get "/version", provides: :json do
68
+ render_json version: BatsdDash::VERSION
69
+ end
70
+
71
+ get "/available", provides: :json do
72
+ connection_pool.with do |conn|
73
+ render_json conn.available
74
+ end
75
+ end
76
+
77
+ # actual data API route
78
+ get "/data", :provides => :json do
79
+ cache_control :no_cache, :no_store
80
+
81
+ statistics = parse_statistics
82
+ range = parse_time_range
83
+
84
+ return render_error('Invalid time range') unless range
85
+ return render_error('Invalid metrics') if statistics.empty?
86
+
87
+ options = { range: range.dup.map { |n| n * 1000 } }
88
+ results = []
89
+
90
+ connection_pool.with do |conn|
91
+ statistics.each do |datatype, metrics|
92
+ metrics.each do |metric|
93
+ statistic = "#{datatype}:#{metric}"
94
+ json = conn.values(statistic, range)
95
+
96
+ next unless json
97
+
98
+ options[:interval] ||= json['interval']
99
+ options[:zero_fill] = statistic !~ /^gauges/i && !params[:no_zero_fill]
100
+
101
+ points = json[statistic] || []
102
+ values = values_for_graph(points, options)
103
+
104
+ results << { key: metric, type: datatype[0..-2], values: values }
105
+ end
106
+ end
107
+ end
108
+
109
+ render_json range: options[:range], interval: options[:interval], results: results
110
+ end
111
+ end
112
+ end
113
+
@@ -0,0 +1,54 @@
1
+ require 'socket'
2
+ require 'connection_pool'
3
+
4
+ module Batsd::Dash
5
+ class Connection
6
+ class SocketError < Exception; end
7
+
8
+ attr_reader :socket
9
+
10
+ def initialize(host, port)
11
+ @host = host
12
+ @port = port
13
+
14
+ connect_socket
15
+ end
16
+
17
+ def available
18
+ query 'available'
19
+ end
20
+
21
+ def values(statistic, range)
22
+ query "values #{statistic} #{range[0]} #{range[1]}"
23
+ end
24
+
25
+ private
26
+
27
+ def reset_socket
28
+ @socket = nil
29
+ end
30
+
31
+ def connect_socket
32
+ @socket = TCPSocket.new(@host, @port)
33
+
34
+ rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT
35
+ reset_socket
36
+ end
37
+
38
+ def query(command, attempts = 0)
39
+ connect_socket unless socket
40
+
41
+ raise SocketError.new('Socket not Connected') if socket.nil?
42
+
43
+ socket.puts command
44
+ JSON.parse socket.gets
45
+
46
+ rescue Errno::EPIPE
47
+ reset_socket
48
+
49
+ if attempts < 5
50
+ query command, attempts + 1
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,10 +1,14 @@
1
1
  # helpers for parsing and validating input
2
- module BatsdDash
2
+ module Batsd::Dash
3
3
  module GraphHelper
4
4
  ##
5
5
  # This method works directly against values. It will tranform all
6
6
  # datapoint to an array where the first element is a milisecond
7
7
  # timestamp and the second is a float value data point.
8
+ #
9
+ # @param [Array] values array of datapoints
10
+ # @param [Hash] opts optional options hash
11
+ # @return [Array] modified values array
8
12
  def values_for_graph(values, opts = {})
9
13
  return values if values.empty?
10
14
 
@@ -37,7 +41,11 @@ module BatsdDash
37
41
  end
38
42
 
39
43
  ##
40
- # Transform a point at a given index
44
+ # Transform a point at a given index. Works against
45
+ # values array
46
+ #
47
+ # @param [Integer] index
48
+ # @param [Array] values array of values
41
49
  def transform_point_at!(index, values)
42
50
  data_pt = values[index]
43
51