pulse-meter 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/.travis.yml +4 -0
  2. data/examples/basic.ru +23 -5
  3. data/examples/basic_sensor_data.rb +15 -2
  4. data/examples/full/server.ru +2 -3
  5. data/examples/minimal/server.ru +3 -2
  6. data/lib/pulse-meter/sensor.rb +2 -1
  7. data/lib/pulse-meter/sensor/configuration.rb +3 -1
  8. data/lib/pulse-meter/sensor/hashed_indicator.rb +22 -0
  9. data/lib/pulse-meter/sensor/timeline.rb +13 -1
  10. data/lib/pulse-meter/version.rb +1 -1
  11. data/lib/pulse-meter/visualize/app.rb +6 -2
  12. data/lib/pulse-meter/visualize/base.rb +15 -0
  13. data/lib/pulse-meter/visualize/dsl/base.rb +131 -0
  14. data/lib/pulse-meter/visualize/dsl/errors.rb +0 -6
  15. data/lib/pulse-meter/visualize/dsl/layout.rb +12 -41
  16. data/lib/pulse-meter/visualize/dsl/page.rb +15 -41
  17. data/lib/pulse-meter/visualize/dsl/sensor.rb +9 -10
  18. data/lib/pulse-meter/visualize/dsl/widget.rb +18 -65
  19. data/lib/pulse-meter/visualize/dsl/widget_old.rb +95 -0
  20. data/lib/pulse-meter/visualize/dsl/widgets/area.rb +20 -0
  21. data/lib/pulse-meter/visualize/dsl/widgets/gauge.rb +12 -0
  22. data/lib/pulse-meter/visualize/dsl/widgets/line.rb +21 -0
  23. data/lib/pulse-meter/visualize/dsl/widgets/pie.rb +16 -0
  24. data/lib/pulse-meter/visualize/dsl/widgets/table.rb +19 -0
  25. data/lib/pulse-meter/visualize/layout.rb +7 -16
  26. data/lib/pulse-meter/visualize/page.rb +5 -10
  27. data/lib/pulse-meter/visualize/public/favicon.ico +0 -0
  28. data/lib/pulse-meter/visualize/public/js/application.coffee +156 -107
  29. data/lib/pulse-meter/visualize/public/js/application.js +283 -122
  30. data/lib/pulse-meter/visualize/sensor.rb +7 -13
  31. data/lib/pulse-meter/visualize/views/main.haml +8 -52
  32. data/lib/pulse-meter/visualize/views/widgets/area.haml +31 -0
  33. data/lib/pulse-meter/visualize/views/widgets/extend_options.haml +11 -0
  34. data/lib/pulse-meter/visualize/views/widgets/gauge.haml +13 -0
  35. data/lib/pulse-meter/visualize/views/widgets/line.haml +31 -0
  36. data/lib/pulse-meter/visualize/views/widgets/pie.haml +13 -0
  37. data/lib/pulse-meter/visualize/views/widgets/table.haml +23 -0
  38. data/lib/pulse-meter/visualize/widget.rb +17 -87
  39. data/lib/pulse-meter/visualize/widgets/gauge.rb +47 -0
  40. data/lib/pulse-meter/visualize/widgets/pie.rb +36 -0
  41. data/lib/pulse-meter/visualize/widgets/timeline.rb +90 -0
  42. data/lib/pulse-meter/visualizer.rb +18 -8
  43. data/perl/PulseMeter/Sensor/Base.pm +42 -0
  44. data/perl/PulseMeter/Sensor/Counter.pm +19 -0
  45. data/perl/PulseMeter/Sensor/HashedIndicator.pm +12 -0
  46. data/perl/PulseMeter/Sensor/Indicator.pm +17 -0
  47. data/perl/PulseMeter/Sensor/Timeline.pm +51 -0
  48. data/perl/PulseMeter/Sensor/Timelined/Average.pm +13 -0
  49. data/perl/PulseMeter/Sensor/Timelined/Counter.pm +12 -0
  50. data/perl/PulseMeter/Sensor/Timelined/HashedCounter.pm +12 -0
  51. data/perl/PulseMeter/Sensor/Timelined/Max.pm +18 -0
  52. data/perl/PulseMeter/Sensor/Timelined/Median.pm +8 -0
  53. data/perl/PulseMeter/Sensor/Timelined/Min.pm +18 -0
  54. data/perl/PulseMeter/Sensor/Timelined/Percentile.pm +17 -0
  55. data/perl/PulseMeter/Sensor/Timelined/UniqCounter.pm +13 -0
  56. data/perl/PulseMeter/Sensor/UniqCounter.pm +12 -0
  57. data/pulse-meter.gemspec +1 -0
  58. data/spec/pulse_meter/sensor/configuration_spec.rb +10 -2
  59. data/spec/pulse_meter/sensor/hashed_indicator_spec.rb +39 -0
  60. data/spec/pulse_meter/visualize/dsl/layout_spec.rb +8 -8
  61. data/spec/pulse_meter/visualize/dsl/page_spec.rb +29 -42
  62. data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +5 -5
  63. data/spec/pulse_meter/visualize/dsl/widget_spec.rb +1 -122
  64. data/spec/pulse_meter/visualize/dsl/widgets/area_spec.rb +44 -0
  65. data/spec/pulse_meter/visualize/dsl/widgets/gauge_spec.rb +22 -0
  66. data/spec/pulse_meter/visualize/dsl/widgets/line_spec.rb +44 -0
  67. data/spec/pulse_meter/visualize/dsl/widgets/pie_spec.rb +35 -0
  68. data/spec/pulse_meter/visualize/dsl/widgets/table_spec.rb +36 -0
  69. data/spec/pulse_meter/visualize/layout_spec.rb +3 -3
  70. data/spec/pulse_meter/visualize/page_spec.rb +2 -2
  71. data/spec/pulse_meter/visualize/sensor_spec.rb +4 -4
  72. data/spec/pulse_meter/visualize/series_extractor_spec.rb +3 -3
  73. data/spec/pulse_meter/visualize/widgets/area_spec.rb +78 -0
  74. data/spec/pulse_meter/visualize/widgets/gauge_spec.rb +63 -0
  75. data/spec/pulse_meter/visualize/widgets/line_spec.rb +77 -0
  76. data/spec/pulse_meter/visualize/widgets/pie_spec.rb +73 -0
  77. data/spec/pulse_meter/visualize/widgets/table_spec.rb +78 -0
  78. data/spec/shared_examples/dsl_widget.rb +106 -0
  79. data/spec/shared_examples/timeline_sensor.rb +32 -2
  80. metadata +75 -6
  81. data/lib/pulse-meter/visualize/dsl.rb +0 -0
  82. data/spec/pulse_meter/visualize/widget_spec.rb +0 -122
@@ -2,16 +2,7 @@ require "pulse-meter/visualize/series_extractor"
2
2
 
3
3
  module PulseMeter
4
4
  module Visualize
5
- class Sensor
6
- attr_reader :name
7
- attr_reader :color
8
-
9
- def initialize(args)
10
- raise ArgumentError unless args.respond_to?('[]')
11
- @name = args[:sensor] or raise ArgumentError, ":sensor not specified"
12
- @color = args[:color]
13
- end
14
-
5
+ class Sensor < Base
15
6
  def last_value(now, need_incomplete=false)
16
7
  sensor = real_sensor
17
8
 
@@ -40,7 +31,7 @@ module PulseMeter
40
31
  end
41
32
 
42
33
  def annotation
43
- real_sensor.annotation
34
+ real_sensor.annotation || real_sensor.name
44
35
  end
45
36
 
46
37
  def type
@@ -50,6 +41,10 @@ module PulseMeter
50
41
  def interval
51
42
  real_sensor.interval
52
43
  end
44
+
45
+ def value
46
+ real_sensor.value
47
+ end
53
48
 
54
49
  def extractor
55
50
  PulseMeter::Visualize.extractor(self)
@@ -59,10 +54,9 @@ module PulseMeter
59
54
 
60
55
  def real_sensor
61
56
  # TODO add !temporarily! caching if this will be called too frequently
62
- PulseMeter::Sensor::Base.restore(@name)
57
+ PulseMeter::Sensor::Base.restore(name)
63
58
  end
64
59
 
65
-
66
60
  end
67
61
  end
68
62
  end
@@ -10,59 +10,15 @@
10
10
  %link{rel: 'stylesheet', href: url("/css/#{cssfile}"), type: 'text/css', media: 'screen'}
11
11
  %script{type: 'text/javascript', src: "https://www.google.com/jsapi"}
12
12
  :javascript
13
- google.load("visualization", "1", {packages:["corechart", "table"]});
13
+ google.load("visualization", "1", {packages:["corechart", "table", "gauge"]});
14
+ google.setOnLoadCallback(drawChart);
15
+ function drawChart() {
16
+ document.startApp();
17
+ }
14
18
  %body
15
- %script#widget-template{type: 'text/template'}
16
- #plotarea
17
- #chart-controls
18
- .form-inline
19
- %button#refresh.btn.btn-mini
20
- %i.icon-refresh
21
- Refresh
22
- <% if(type != 'table'){ %>
23
- %span.space
24
- %label
25
- Cutoff min:
26
- %input.btn-mini#cutoff-min
27
- %span.space
28
- %label
29
- Cutoff max:
30
- %input.btn-mini#cutoff-max
31
- <% } %>
32
- %span.space
33
- %label
34
- Refresh:
35
- %input.btn-mini#need-refresh{type: :checkbox, checked: :true}
36
- <% if(type != 'pie'){ %>
37
- %label
38
- Timespan:
39
- %select#extend-timespan-val.btn-mini.span1
40
- %option{value: 60, selected: true} 1 minute
41
- %option{value: 60 * 5} 5 minutes
42
- %option{value: 60 * 30} 30 minutes
43
- %option{value: 60 * 60 * 2} 2 hours
44
- %option{value: 60 * 60 * 6 } 6 hours
45
- %option{value: 60 * 60 * 24} 1 day
46
- %option{value: 60 * 60 * 24 * 2} 2 days
47
- %option{value: 60 * 60 * 24 * 7} 1 week
48
- %option{value: 60 * 60 * 24 * 7 * 2} 2 weeks
49
- %option{value: 60 * 60 * 24 * 30} 1 month
50
- %button#extend-timespan.btn.btn-mini
51
- <% if(type != 'table'){ %>
52
- %i.icon-arrow-left
53
- <% } else { %>
54
- %i.icon-arrow-down
55
- <% } %>
56
- Extend
57
- %button#reset-timespan.btn.btn-mini
58
- <% if(type != 'table'){ %>
59
- %i.icon-arrow-right
60
- <% } else { %>
61
- %i.icon-arrow-up
62
- <% } %>
63
- Reset
64
- <% } %>
65
- %hr
19
+
20
+ - %w(area line table pie gauge).each do |wtype|
21
+ = partial "widgets/#{wtype}"
66
22
 
67
23
  .container#main
68
24
  .row
@@ -0,0 +1,31 @@
1
+ %script.widget-template{type: 'text/template', 'data-widget-type' => 'area'}
2
+ #plotarea
3
+ #chart-controls
4
+ .form-inline
5
+ %button#refresh.btn.btn-mini
6
+ %i.icon-refresh
7
+ Refresh
8
+ %span.space
9
+ %label
10
+ Cutoff min:
11
+ %input.btn-mini#cutoff-min
12
+ %span.space
13
+ %label
14
+ Cutoff max:
15
+ %input.btn-mini#cutoff-max
16
+ %span.space
17
+ %label
18
+ Refresh:
19
+ %input.btn-mini#need-refresh{type: :checkbox, checked: :true}
20
+ %label
21
+ Timespan:
22
+ %select#extend-timespan-val.btn-mini.span1
23
+ = partial "widgets/extend_options"
24
+ %button#extend-timespan.btn.btn-mini
25
+ %i.icon-arrow-left
26
+ Extend
27
+ %button#reset-timespan.btn.btn-mini
28
+ %i.icon-arrow-right
29
+ Reset
30
+ %hr
31
+
@@ -0,0 +1,11 @@
1
+ %option{value: 60, selected: true} 1 minute
2
+ %option{value: 60 * 5} 5 minutes
3
+ %option{value: 60 * 30} 30 minutes
4
+ %option{value: 60 * 60 * 2} 2 hours
5
+ %option{value: 60 * 60 * 6 } 6 hours
6
+ %option{value: 60 * 60 * 24} 1 day
7
+ %option{value: 60 * 60 * 24 * 2} 2 days
8
+ %option{value: 60 * 60 * 24 * 7} 1 week
9
+ %option{value: 60 * 60 * 24 * 7 * 2} 2 weeks
10
+ %option{value: 60 * 60 * 24 * 30} 1 month
11
+
@@ -0,0 +1,13 @@
1
+ %script.widget-template{type: 'text/template', 'data-widget-type' => 'gauge'}
2
+ #plotarea
3
+ #chart-controls
4
+ .form-inline
5
+ %button#refresh.btn.btn-mini
6
+ %i.icon-refresh
7
+ Refresh
8
+ %span.space
9
+ %label
10
+ Refresh:
11
+ %input.btn-mini#need-refresh{type: :checkbox, checked: :true}
12
+ %hr
13
+
@@ -0,0 +1,31 @@
1
+ %script.widget-template{type: 'text/template', 'data-widget-type' => 'line'}
2
+ #plotarea
3
+ #chart-controls
4
+ .form-inline
5
+ %button#refresh.btn.btn-mini
6
+ %i.icon-refresh
7
+ Refresh
8
+ %span.space
9
+ %label
10
+ Cutoff min:
11
+ %input.btn-mini#cutoff-min
12
+ %span.space
13
+ %label
14
+ Cutoff max:
15
+ %input.btn-mini#cutoff-max
16
+ %span.space
17
+ %label
18
+ Refresh:
19
+ %input.btn-mini#need-refresh{type: :checkbox, checked: :true}
20
+ %label
21
+ Timespan:
22
+ %select#extend-timespan-val.btn-mini.span1
23
+ = partial "widgets/extend_options"
24
+ %button#extend-timespan.btn.btn-mini
25
+ %i.icon-arrow-left
26
+ Extend
27
+ %button#reset-timespan.btn.btn-mini
28
+ %i.icon-arrow-right
29
+ Reset
30
+ %hr
31
+
@@ -0,0 +1,13 @@
1
+ %script.widget-template{type: 'text/template', 'data-widget-type' => 'pie'}
2
+ #plotarea
3
+ #chart-controls
4
+ .form-inline
5
+ %button#refresh.btn.btn-mini
6
+ %i.icon-refresh
7
+ Refresh
8
+ %span.space
9
+ %label
10
+ Refresh:
11
+ %input.btn-mini#need-refresh{type: :checkbox, checked: :true}
12
+ %hr
13
+
@@ -0,0 +1,23 @@
1
+ %script.widget-template{type: 'text/template', 'data-widget-type' => 'table'}
2
+ #plotarea
3
+ #chart-controls
4
+ .form-inline
5
+ %button#refresh.btn.btn-mini
6
+ %i.icon-refresh
7
+ Refresh
8
+ %span.space
9
+ %label
10
+ Refresh:
11
+ %input.btn-mini#need-refresh{type: :checkbox, checked: :true}
12
+ %label
13
+ Timespan:
14
+ %select#extend-timespan-val.btn-mini.span1
15
+ = partial "widgets/extend_options"
16
+ %button#extend-timespan.btn.btn-mini
17
+ %i.icon-arrow-down
18
+ Extend
19
+ %button#reset-timespan.btn.btn-mini
20
+ %i.icon-arrow-up
21
+ Reset
22
+ %hr
23
+
@@ -2,60 +2,29 @@ module PulseMeter
2
2
  module Visualize
3
3
  class Error < StandardError; end
4
4
 
5
- class Widget
6
- class NotATimelinedSensorInWidget < PulseMeter::Visualize::Error; end
7
- class DifferentSensorIntervalsInWidget < PulseMeter::Visualize::Error; end
8
-
9
- attr_reader :sensors
10
- attr_reader :title
11
- attr_reader :type
12
- attr_reader :width
13
- attr_reader :values_label
14
- attr_reader :show_last_point
15
- attr_reader :redraw_interval
16
- attr_reader :timespan
17
-
18
- def initialize(args)
19
- raise ArgumentError unless args.respond_to?('[]')
20
- @title = args[:title] or raise ArgumentError, ":title not specified"
21
- @sensors = args[:sensors] or raise ArgumentError, ":sensors not specified"
22
- @type = args[:type] or raise ArgumentError, ":type not specified"
23
- @width = args[:width]
24
- @values_label = args[:values_label]
25
- @show_last_point = args[:show_last_point] || false
26
- @redraw_interval = args[:redraw_interval]
27
- @timespan = args[:timespan]
5
+ class Widget < Base
6
+ def initialize(opts)
7
+ super
8
+ @opts[:sensors] ||= []
28
9
  end
29
10
 
30
- def data(options = {})
31
- ensure_sensor_match!
32
- real_timespan = options[:timespan] || timespan
11
+ def data
33
12
  {
34
- title: title,
35
13
  type: type,
36
- values_title: values_label,
14
+ title: title,
15
+ redraw_interval: redraw_interval,
37
16
  width: width,
38
- interval: redraw_interval,
39
- series: series_data(real_timespan),
40
- timespan: timespan
17
+ gchart_options: gchart_options,
18
+ values_title: values_label
41
19
  }
42
20
  end
43
21
 
44
- protected
45
-
46
- def series_data(tspan)
47
- case type
48
- when :line
49
- line_series_data(tspan)
50
- when :area
51
- line_series_data(tspan)
52
- when :pie
53
- pie_series_data
54
- when :table
55
- line_series_data(tspan)
56
- end
22
+ def type
23
+ self.class.to_s.split('::').last.downcase
57
24
  end
58
25
 
26
+ protected
27
+
59
28
  def ensure_sensor_match!
60
29
  intervals = []
61
30
  sensors.each do |s|
@@ -71,51 +40,12 @@ module PulseMeter
71
40
  end
72
41
  end
73
42
 
74
- def line_series_data(tspan)
75
- now = Time.now
76
- sensor_datas = sensors.map{ |s|
77
- s.timeline_data(now, tspan, show_last_point)
78
- }
79
- rows = []
80
- titles = []
81
- series_options = []
82
- datas = []
83
- sensor_datas.each do |sensor_data|
84
- sensor_data.each do |tl|
85
- titles << tl[:name]
86
- series_options << {color: tl[:color]}
87
- datas << tl[:data]
88
- end
89
- end
90
- unless datas.empty?
91
- first = datas.shift
92
- first.each_with_index do |tl_data, row_num|
93
- rows << datas.each_with_object([tl_data[:x], tl_data[:y]]) do |data_col, row|
94
- row << data_col[row_num][:y]
95
- end
96
- end
97
- end
98
- {
99
- titles: titles,
100
- rows: rows,
101
- options: series_options
102
- }
103
- end
104
43
 
105
- def pie_series_data
106
- values = []
107
- slice_options = []
108
- now = Time.now
109
- sensors.each do |s|
110
- s.last_point_data(now, show_last_point).each do |point_data|
111
- values << [point_data[:name], point_data[:y]]
112
- slice_options << {color: point_data[:color]}
113
- end
44
+ def gauge_series_data
45
+ ensure_gauge_indicators!
46
+ sensors.map do |s|
47
+ [s.annotation, s.value]
114
48
  end
115
- {
116
- data: values,
117
- options: slice_options
118
- }
119
49
  end
120
50
 
121
51
  end
@@ -0,0 +1,47 @@
1
+ module PulseMeter
2
+ module Visualize
3
+ module Widgets
4
+ class Gauge < PulseMeter::Visualize::Widget
5
+ class NotAnIndicatorSensorInGaugeWidget < PulseMeter::Visualize::Error; end
6
+
7
+ def data(options = {})
8
+ super().merge({
9
+ series: values_data
10
+ })
11
+ end
12
+
13
+ protected
14
+
15
+ def ensure_gauge_indicators!
16
+ sensors.each do |s|
17
+ unless s.type <= PulseMeter::Sensor::Indicator || s.type <= PulseMeter::Sensor::HashedIndicator
18
+ raise NotAnIndicatorSensorInGaugeWidget, "Sensor #{s.name} is not an indicator(PulseMeter::Sensor::Indicator or PulseMeter::Sensor::HashedIndicator)"
19
+ end
20
+ end
21
+ end
22
+
23
+ def values_data
24
+ ensure_gauge_indicators!
25
+ gauges = []
26
+ sensors.map do |s|
27
+ s_type = s.type
28
+ case
29
+ when s_type == PulseMeter::Sensor::Indicator
30
+ gauges << [s.annotation, s.value]
31
+ when s_type == PulseMeter::Sensor::HashedIndicator
32
+ s.value.each_pair do |k, v|
33
+ gauge_title = "#{s.annotation}: #{k}"
34
+ gauges << [gauge_title, v]
35
+ end
36
+ end
37
+ end
38
+ gauges
39
+ end
40
+
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+
47
+
@@ -0,0 +1,36 @@
1
+ module PulseMeter
2
+ module Visualize
3
+ module Widgets
4
+ class Pie < PulseMeter::Visualize::Widget
5
+
6
+ def data(options = {})
7
+ super().merge({
8
+ series: slice_data
9
+ })
10
+ end
11
+
12
+ protected
13
+
14
+ def slice_data
15
+ values = []
16
+ slice_options = []
17
+ now = Time.now
18
+ sensors.each do |s|
19
+ s.last_point_data(now, show_last_point).each do |point_data|
20
+ values << [point_data[:name], point_data[:y]]
21
+ slice_options << {color: point_data[:color]}
22
+ end
23
+ end
24
+ {
25
+ data: values,
26
+ options: slice_options
27
+ }
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+
36
+