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.
- data/.rbenv-version +1 -0
- data/Gemfile +3 -0
- data/README.md +36 -79
- data/batsd-dash.gemspec +5 -9
- data/lib/batsd-dash.rb +9 -80
- data/lib/batsd-dash/app.rb +113 -0
- data/lib/batsd-dash/connection.rb +54 -0
- data/lib/batsd-dash/graph.rb +10 -2
- data/lib/batsd-dash/params.rb +10 -2
- data/lib/{public → batsd-dash/public}/css/d3.css +199 -100
- data/lib/{public → batsd-dash/public}/css/datetimepicker.css +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-icons_222222_256x240.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-icons_454545_256x240.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-icons_888888_256x240.png +0 -0
- data/lib/{public → batsd-dash/public}/css/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/{public → batsd-dash/public}/css/jquery-ui.css +0 -0
- data/lib/batsd-dash/public/css/public.css +419 -0
- data/lib/batsd-dash/public/js/d3.js +4 -0
- data/lib/batsd-dash/public/js/dash.js +82 -0
- data/lib/{public → batsd-dash/public}/js/datetimepicker.js +0 -0
- data/lib/{public → batsd-dash/public}/js/datetimepicker.js~ +0 -0
- data/lib/{public → batsd-dash/public}/js/jquery-ui.js +0 -0
- data/lib/{public → batsd-dash/public}/js/jquery.js +0 -0
- data/lib/batsd-dash/public/js/nv.d3.js +5 -0
- data/lib/batsd-dash/version.rb +4 -2
- data/lib/{views → batsd-dash/views}/layout.haml +24 -6
- data/lib/batsd-dash/views/loading.haml +5 -0
- data/lib/batsd-dash/views/missing.haml +14 -0
- data/lib/batsd-dash/views/root.haml +37 -0
- data/lib/batsd-dash/views/view.haml +60 -0
- data/lib/sass/_charts.scss +37 -0
- data/lib/{batsd-dash/sass → sass}/public.scss +102 -27
- data/test/helper.rb +5 -16
- data/test/test_dash.rb +65 -69
- metadata +121 -101
- data/lib/batsd-dash/connection_pool.rb +0 -87
- data/lib/public/css/public.css +0 -106
- data/lib/public/js/d3.js +0 -4
- data/lib/public/js/dash.js +0 -110
- data/lib/public/js/flot.js +0 -6
- data/lib/public/js/nv.d3.js +0 -4
- data/lib/views/missing.haml +0 -6
- data/lib/views/root.haml +0 -0
- data/lib/views/view.haml +0 -18
- data/test/test_connection_pool.rb +0 -20
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
jruby-1.7.0
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,91 +1,48 @@
|
|
1
|
-
|
1
|
+
Batsd-dash
|
2
2
|
==========
|
3
3
|
|
4
|
-
|
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
|
-
|
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
|
-
###
|
12
|
+
### Documentation
|
9
13
|
|
10
|
-
|
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
|
-
|
24
|
+
### About
|
13
25
|
|
14
|
-
|
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
|
-
|
17
|
-
|
18
|
-
require 'batsd-dash'
|
29
|
+
### License
|
19
30
|
|
20
|
-
|
21
|
-
BatsdDash::ConnectionPool.settings = { host:'localhost', port: 8127, pool_size: 8 }
|
31
|
+
Copyright (c) 2012 Michael J Coyne & Brian O'Connor
|
22
32
|
|
23
|
-
|
24
|
-
|
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
|
-
|
27
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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 =
|
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
|
-
|
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 "
|
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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
data/lib/batsd-dash/graph.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# helpers for parsing and validating input
|
2
|
-
module
|
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
|
|