pulse-meter 0.2.1 → 0.2.2

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 (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
+