rrd-grapher 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/.gitignore +9 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +11 -0
  4. data/Guardfile +123 -0
  5. data/README.md +91 -0
  6. data/Rakefile +42 -0
  7. data/example_app/Gemfile +9 -0
  8. data/example_app/Guardfile +18 -0
  9. data/example_app/app.rb +38 -0
  10. data/example_app/assets/javascripts/available_rrds.coffee +13 -0
  11. data/example_app/assets/javascripts/collectd.coffee +48 -0
  12. data/example_app/config.ru +9 -0
  13. data/example_app/public/.gitignore +1 -0
  14. data/example_app/public/chosen/chosen-sprite.png +0 -0
  15. data/example_app/public/chosen/chosen.css +340 -0
  16. data/example_app/public/chosen/chosen.jquery.js +786 -0
  17. data/example_app/public/chosen/chosen.jquery.min.js +10 -0
  18. data/example_app/public/javascripts/available_rrds.js +16 -0
  19. data/example_app/public/javascripts/collectd.js +64 -0
  20. data/example_app/public/javascripts/jquery.timeago.js +148 -0
  21. data/example_app/public/stylesheets/Aristo/images/bg_fallback.png +0 -0
  22. data/example_app/public/stylesheets/Aristo/images/icon_sprite.png +0 -0
  23. data/example_app/public/stylesheets/Aristo/images/progress_bar.gif +0 -0
  24. data/example_app/public/stylesheets/Aristo/images/slider_handles.png +0 -0
  25. data/example_app/public/stylesheets/Aristo/images/ui-icons_222222_256x240.png +0 -0
  26. data/example_app/public/stylesheets/Aristo/images/ui-icons_454545_256x240.png +0 -0
  27. data/example_app/public/stylesheets/Aristo/theme.css +738 -0
  28. data/example_app/views/available_rrds.haml +26 -0
  29. data/example_app/views/collectd.haml +30 -0
  30. data/example_app/views/layout.haml +19 -0
  31. data/example_app/views/stylesheets/available_rrds.scss +7 -0
  32. data/example_notifier/Gemfile +2 -0
  33. data/example_notifier/notifier.rb +25 -0
  34. data/lib/rrd-grapher/assets/javascripts/app-dev.js +20 -0
  35. data/lib/rrd-grapher/assets/javascripts/app.js +20 -0
  36. data/lib/rrd-grapher/assets/javascripts/classes/format.coffee +35 -0
  37. data/lib/rrd-grapher/assets/javascripts/classes/graph.coffee +306 -0
  38. data/lib/rrd-grapher/assets/javascripts/classes/graph_definition.coffee +216 -0
  39. data/lib/rrd-grapher/assets/javascripts/classes/serie.coffee +13 -0
  40. data/lib/rrd-grapher/assets/javascripts/classes/size.coffee +5 -0
  41. data/lib/rrd-grapher/assets/javascripts/classes/static_line.coffee +44 -0
  42. data/lib/rrd-grapher/assets/javascripts/classes/time.coffee +17 -0
  43. data/lib/rrd-grapher/notifier/alarm_manager.rb +190 -0
  44. data/lib/rrd-grapher/notifier/alarm_trigger.rb +187 -0
  45. data/lib/rrd-grapher/notifier/alarms.rb +79 -0
  46. data/lib/rrd-grapher/notifier/collectdrb.rb +86 -0
  47. data/lib/rrd-grapher/notifier/data_struct.rb +46 -0
  48. data/lib/rrd-grapher/notifier/default_user_handler.rb +36 -0
  49. data/lib/rrd-grapher/notifier/parsers/bindata_parser.rb +144 -0
  50. data/lib/rrd-grapher/notifier/parsers/ruby_parser.rb +134 -0
  51. data/lib/rrd-grapher/notifier/structures.rb +80 -0
  52. data/lib/rrd-grapher/notifier.rb +87 -0
  53. data/lib/rrd-grapher/public/favicon.ico +0 -0
  54. data/lib/rrd-grapher/public/javascripts/app-dev.js +13709 -0
  55. data/lib/rrd-grapher/public/javascripts/app.js +4057 -0
  56. data/lib/rrd-grapher/public/javascripts/backbone/backbone.js +1155 -0
  57. data/lib/rrd-grapher/public/javascripts/backbone/backbone.min.js +32 -0
  58. data/lib/rrd-grapher/public/javascripts/backbone/underscore.js +841 -0
  59. data/lib/rrd-grapher/public/javascripts/backbone/underscore.min.js +27 -0
  60. data/lib/rrd-grapher/public/javascripts/classes/format.js +42 -0
  61. data/lib/rrd-grapher/public/javascripts/classes/graph.js +360 -0
  62. data/lib/rrd-grapher/public/javascripts/classes/graph_definition.js +298 -0
  63. data/lib/rrd-grapher/public/javascripts/classes/serie.js +32 -0
  64. data/lib/rrd-grapher/public/javascripts/classes/size.js +7 -0
  65. data/lib/rrd-grapher/public/javascripts/classes/static_line.js +48 -0
  66. data/lib/rrd-grapher/public/javascripts/classes/time.js +17 -0
  67. data/lib/rrd-grapher/public/javascripts/flot/.gitignore +4 -0
  68. data/lib/rrd-grapher/public/javascripts/flot/excanvas.min.js +1 -0
  69. data/lib/rrd-grapher/public/javascripts/flot/jquery.colorhelpers.min.js +1 -0
  70. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.crosshair.min.js +1 -0
  71. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.fillbetween.min.js +1 -0
  72. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.image.min.js +1 -0
  73. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.js +2604 -0
  74. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.navigate.min.js +1 -0
  75. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.pie.min.js +1 -0
  76. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.resize.min.js +1 -0
  77. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.selection.js +345 -0
  78. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.selection.min.js +1 -0
  79. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.stack.min.js +1 -0
  80. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.symbol.min.js +1 -0
  81. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.threshold.min.js +1 -0
  82. data/lib/rrd-grapher/public/javascripts/jquery/jquery-1.6.2.js +8981 -0
  83. data/lib/rrd-grapher/public/javascripts/jquery/jquery-1.6.2.min.js +18 -0
  84. data/lib/rrd-grapher/public/javascripts/jquery/jquery-ui-1.8.11.min.js +783 -0
  85. data/lib/rrd-grapher/public/javascripts/jquery/jquery.showtime.js +63 -0
  86. data/lib/rrd-grapher/public/javascripts/jquery/jquery.tpl.min.js +10 -0
  87. data/lib/rrd-grapher/resources.rb +14 -0
  88. data/lib/rrd-grapher/rrd.rb +238 -0
  89. data/lib/rrd-grapher/rrd_server.rb +78 -0
  90. data/lib/rrd-grapher/version.rb +4 -0
  91. data/lib/rrd-grapher/views/stylesheets/app.scss +111 -0
  92. data/lib/rrd-grapher.rb +12 -0
  93. data/rrd-grapher.gemspec +47 -0
  94. data/spec/common.rb +70 -0
  95. data/spec/data/myrouter.rrd +0 -0
  96. data/spec/data/subdata.rrd +0 -0
  97. data/spec/data/test.rrd +0 -0
  98. data/spec/factories.rb +23 -0
  99. data/spec/javascripts/helpers/jasmine-jquery-1.3.0.js +283 -0
  100. data/spec/javascripts/source/format_spec.coffee +18 -0
  101. data/spec/javascripts/source/graph_def_spec.coffee +27 -0
  102. data/spec/javascripts/source/graph_spec.coffee +63 -0
  103. data/spec/javascripts/source/serie_spec.coffee +28 -0
  104. data/spec/javascripts/source/static_line_spec.coffee +13 -0
  105. data/spec/javascripts/source/time_spec.coffee +26 -0
  106. data/spec/javascripts/support/jasmine.yml +78 -0
  107. data/spec/javascripts/support/jasmine_config.rb +23 -0
  108. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  109. data/spec/unit/alarm_manager_spec.rb +252 -0
  110. data/spec/unit/alarm_trigger_spec.rb +26 -0
  111. data/spec/unit/data_struct_spec.rb +55 -0
  112. data/spec/unit/notifier_spec.rb +45 -0
  113. data/spec/unit/parsers/bindata_parser_spec.rb +184 -0
  114. data/spec/unit/parsers/ruby_parser_spec.rb +184 -0
  115. data/spec/unit/rrd_spec.rb +50 -0
  116. data/spec/unit/structures_spec.rb +28 -0
  117. data/tests/4series.rrd +0 -0
  118. data/tests/analyze_rrd.rb +62 -0
  119. data/tests/exact.rrd +0 -0
  120. data/tests/exact2.rrd +0 -0
  121. data/tests/filler.rb +46 -0
  122. metadata +414 -0
@@ -0,0 +1,184 @@
1
+ require File.expand_path('../../../common', __FILE__)
2
+ require File.expand_path('../../../../lib/rrd-grapher/notifier/parsers/ruby_parser', __FILE__)
3
+
4
+ # as helper to build packets
5
+ require File.expand_path('../../../helpers/collectdrb', __FILE__)
6
+
7
+ describe 'Collectd Ruby parser' do
8
+ before do
9
+ @parser = RRDNotifier::RubyParser
10
+ end
11
+
12
+ describe 'Simple packets' do
13
+ it 'can parse numbers' do
14
+ type, val, buffer = @parser.parse_part( Collectd::number(1, 122) )
15
+ buffer.should == ""
16
+ val.should == 122
17
+
18
+ type, val, _ = @parser.parse_part( Collectd::number(1, 2500) )
19
+ val.should == 2500
20
+
21
+ type, val, _ = @parser.parse_part( Collectd::number(1, 356798) )
22
+ val.should == 356798
23
+ end
24
+
25
+ should 'parse strings' do
26
+ type, str, _ = @parser.parse_part( Collectd::string(0, "hostname1") )
27
+ str.should == 'hostname1'
28
+
29
+ type, str, _ = @parser.parse_part( Collectd::string(0, "string with spaces") )
30
+ str.should == 'string with spaces'
31
+
32
+ type, str, _ = @parser.parse_part( Collectd::string(0, "a really long string with many words in it") )
33
+ str.should == 'a really long string with many words in it'
34
+ end
35
+
36
+ should 'parse values' do
37
+ buffer = Collectd.values([[:counter, 1034], [:derive, -4567], [:derive, 34]])
38
+ type, values, rest = @parser.parse_part( buffer )
39
+ rest.should == ""
40
+ values.should == [1034, -4567, 34]
41
+ end
42
+ end
43
+
44
+ describe 'One notification in buffer' do
45
+ before do
46
+ @now = Time.new.to_i
47
+
48
+ @pkt = ""
49
+ @pkt << Collectd.number(1, @now)
50
+ @pkt << Collectd.string(0, 'hostname')
51
+
52
+ @pkt << Collectd.string(2, 'plugin')
53
+ @pkt << Collectd.string(3, 'plugin_inst')
54
+ @pkt << Collectd.string(4, 'type')
55
+ @pkt << Collectd.string(5, 'type_inst')
56
+ @pkt << Collectd.number(257, 2) # severity
57
+ @pkt << Collectd.string(256, 'a message')
58
+ end
59
+
60
+ should 'parse the notification' do
61
+ data, rest = @parser.parse_packet(@pkt)
62
+
63
+ rest.should == ""
64
+
65
+ data.class.should == RRDNotifier::Packet
66
+ data.host.should == 'hostname'
67
+ data.time.should == @now
68
+ data.plugin.should == 'plugin'
69
+ data.plugin_instance.should == 'plugin_inst'
70
+ data.type.should == 'type'
71
+ data.type_instance.should == 'type_inst'
72
+ data.message.should == 'a message'
73
+ data.severity.should == 2
74
+
75
+ end
76
+ end
77
+
78
+ describe 'One packet in buffer' do
79
+ before do
80
+ @now = Time.new.to_i
81
+ @interval = 10
82
+ @pkt = ""
83
+ @pkt << Collectd.number(1, @now)
84
+ @pkt << Collectd.string(0, 'hostname')
85
+ @pkt << Collectd.number(7, @interval)
86
+
87
+ @pkt << Collectd.string(2, 'plugin')
88
+ @pkt << Collectd.string(3, 'plugin_inst')
89
+ @pkt << Collectd.string(4, 'type')
90
+ @pkt << Collectd.string(5, 'type_inst')
91
+
92
+ @pkt << Collectd.values([[:counter, 1034], [:gauge, 3.45]])
93
+ end
94
+
95
+ should 'parse it' do
96
+ data, rest = @parser.parse_packet(@pkt)
97
+
98
+ data.class.should == RRDNotifier::Packet
99
+ data.host.should == 'hostname'
100
+ data.time.should == @now
101
+ data.interval.should == @interval
102
+ data.plugin.should == 'plugin'
103
+ data.plugin_instance.should == 'plugin_inst'
104
+ data.type.should == 'type'
105
+ data.type_instance.should == 'type_inst'
106
+
107
+ data.values.size.should == 2
108
+ data.values[0].should == 1034
109
+ data.values[1].should == 3.45
110
+
111
+ rest.should == ""
112
+ end
113
+ end
114
+
115
+ describe "Multiple packets in buffer" do
116
+ before do
117
+ @now = Time.new.to_i
118
+ @interval = 10
119
+
120
+ @pkt = Collectd.string(0, 'hostname')
121
+ @pkt << Collectd.number(1, @now)
122
+ @pkt << Collectd.number(7, @interval)
123
+
124
+ @pkt << Collectd.string(2, 'plugin')
125
+ @pkt << Collectd.string(3, 'plugin_inst')
126
+ @pkt << Collectd.string(4, 'type')
127
+ @pkt << Collectd.string(5, 'type_inst')
128
+
129
+ @pkt << Collectd.values([[:counter, 1034], [:gauge, 3.45]])
130
+
131
+ @pkt << Collectd.string(2, 'plugin2')
132
+ @pkt << Collectd.string(3, 'plugin2_inst')
133
+ @pkt << Collectd.string(4, 'type2')
134
+ @pkt << Collectd.string(5, 'type2_inst')
135
+
136
+ @pkt << Collectd.values([[:counter, 42]])
137
+
138
+
139
+ @pkt << Collectd.string(5, 'type21_inst')
140
+ @pkt << Collectd.values([[:gauge, 3.1415927]])
141
+ end
142
+
143
+ should 'parse it' do
144
+ data = @parser.parse(@pkt)
145
+
146
+ data.size.should == 3
147
+
148
+ data[0].class.should == RRDNotifier::Packet
149
+
150
+ data[0].host.should == 'hostname'
151
+ data[0].time.should == @now
152
+ data[0].interval.should == @interval
153
+ data[0].plugin.should == 'plugin'
154
+ data[0].plugin_instance.should == 'plugin_inst'
155
+ data[0].type.should == 'type'
156
+ data[0].type_instance.should == 'type_inst'
157
+ data[0].values.size.should == 2
158
+ data[0].values[0].should == 1034
159
+ data[0].values[1].should == 3.45
160
+
161
+ data[1].host.should == 'hostname'
162
+ data[1].time.should == @now
163
+ data[1].interval.should == @interval
164
+ data[1].plugin.should == 'plugin2'
165
+ data[1].plugin_instance.should == 'plugin2_inst'
166
+ data[1].type.should == 'type2'
167
+ data[1].type_instance.should == 'type2_inst'
168
+ data[1].values.size.should == 1
169
+ data[1].values[0].should == 42
170
+
171
+ data[2].host.should == 'hostname'
172
+ data[2].time.should == @now
173
+ data[2].interval.should == @interval
174
+ data[2].plugin.should == 'plugin2'
175
+ data[2].plugin_instance.should == 'plugin2_inst'
176
+ data[2].type.should == 'type2'
177
+ data[2].type_instance.should == 'type21_inst'
178
+ data[2].values.size.should == 1
179
+ data[2].values[0].should == 3.1415927
180
+
181
+ end
182
+ end
183
+
184
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path('../../common', __FILE__)
2
+
3
+ require File.join(ROOT, 'lib/rrd-grapher/rrd')
4
+
5
+ describe 'RRD Reader' do
6
+
7
+ describe 'test.rrd' do
8
+ before do
9
+ path = File.expand_path('../../data/test.rrd', __FILE__)
10
+ @rrd = RRDReader::File.new(path)
11
+ end
12
+
13
+ [
14
+ {"cf"=>"AVERAGE", "rows"=>24, "cur_row"=>1, "pdp_per_row"=>1, "xff"=>0.5, "cdp_prep"=>0},
15
+ {"cf"=>"AVERAGE", "rows"=>10, "cur_row"=>7, "pdp_per_row"=>6, "xff"=>0.5, "cdp_prep"=>0}
16
+ ]
17
+
18
+ should 'return correct RRA' do
19
+ @rrd.rra.should.not == []
20
+
21
+ # first
22
+ with(@rrd.archives[0]) do |a|
23
+ a.cf.should == :average
24
+ a.rows.should == 24
25
+ a.current_row.should == 1
26
+ a.instance_variable_get('@pdp_per_row').should == 1
27
+ a.instance_variable_get('@xff').should == 0.5
28
+ a.instance_variable_get('@cdp_prep').should == 0
29
+
30
+ a.interval.should == 5*60 # 5 minutes
31
+ a.duration.should == 2*60*60 # 2 hours
32
+ end
33
+
34
+ # second
35
+ with(@rrd.archives[1]) do |a|
36
+ a.cf.should == :average
37
+ a.rows.should == 10
38
+ a.current_row.should == 7
39
+ a.instance_variable_get('@pdp_per_row').should == 6
40
+ a.instance_variable_get('@xff').should == 0.5
41
+ a.instance_variable_get('@cdp_prep').should == 0
42
+
43
+ a.interval.should == 30*60 # 30 minutes
44
+ a.duration.should == 5*60*60 # 5 hours
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../../common', __FILE__)
2
+ require File.expand_path('../../../lib/rrd-grapher/notifier/structures', __FILE__)
3
+
4
+ describe 'Packet' do
5
+ before do
6
+ @point = Factory(:data_point)
7
+ end
8
+
9
+ should 'return formatted plugin' do
10
+ @point.plugin = "plugin"
11
+ @point.plugin_instance = nil
12
+
13
+ @point.plugin_display.should == "plugin"
14
+
15
+ @point.plugin_instance = "instance"
16
+ @point.plugin_display.should == "plugin/instance"
17
+ end
18
+
19
+ should 'return formatted type' do
20
+ @point.type = "type"
21
+ @point.type_instance = nil
22
+
23
+ @point.type_display.should == "type"
24
+
25
+ @point.type_instance = "instance"
26
+ @point.type_display.should == "type/instance"
27
+ end
28
+ end
data/tests/4series.rrd ADDED
Binary file
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'rrd'
3
+ require 'pp'
4
+ require 'chronic_duration'
5
+
6
+
7
+
8
+ if ARGV.size != 1
9
+ puts "Usage: #{File.basename($0)} <rrd_file>"
10
+ puts "This tool will extract data from the RRD and display it"
11
+ exit(1)
12
+ end
13
+
14
+
15
+ # FILE="/Users/schmurfy/Dev/personal/rrd-faces/preprod_data/cpu-idle.rrd"
16
+ # FILE="/Users/schmurfy/Dev/personal/rrd-grapher/specs/data/test.rrd"
17
+ # FILE="/Users/schmurfy/Dev/personal/rrd-grapher/specs/myrouter.rrd"
18
+ # FILE="/Users/schmurfy/Dev/personal/rrd-grapher/specs/data/subdata.rrd"
19
+ FILE = ARGV[0]
20
+
21
+ rrd = RRD::Base.new(FILE)
22
+ raw_infos = rrd.info
23
+ infos = {
24
+ :filename => raw_infos.delete("filename"),
25
+ :rrd_version => raw_infos.delete("rrd_version"),
26
+ # data will be added in this rrd every <step> seconds
27
+ :step => raw_infos.delete("step"),
28
+ :last_update => raw_infos.delete("last_update"),
29
+ :header_size => raw_infos.delete("header_size"),
30
+ :ds => {},
31
+ :rra => []
32
+ }
33
+
34
+ # pp raw_infos
35
+
36
+ raw_infos.each do |key, val|
37
+ case key
38
+ when %r{^ds\[([a-zA-Z_]+)\]\.([a-zA-Z_]+)}
39
+ infos[:ds][$1] ||= {}
40
+ infos[:ds][$1][$2] = val
41
+
42
+ when %r{^rra\[([0-9]+)\]\.([a-zA-Z_]+)}
43
+ infos[:rra][$1.to_i] ||= {}
44
+ infos[:rra][$1.to_i][$2] = val
45
+ end
46
+ end
47
+
48
+ # pp infos
49
+
50
+ # base interval
51
+ step = infos[:step]
52
+ puts ""
53
+ infos[:rra].each do |data|
54
+ print "#{data['cf'].rjust(10)}: "
55
+
56
+ time_point = ChronicDuration.output(data['pdp_per_row'] * step)
57
+ print "a point every #{time_point} "
58
+
59
+ time_store = ChronicDuration.output(data['rows'] * (data['pdp_per_row'] * step))
60
+ puts "stored for #{time_store}"
61
+ end
62
+
data/tests/exact.rrd ADDED
Binary file
data/tests/exact2.rrd ADDED
Binary file
data/tests/filler.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'bundler/setup'
2
+ require File.expand_path('../../lib/rrd', __FILE__)
3
+
4
+ if ARGV.size != 1
5
+ puts "Usage: #{File.basename($0)} <rrd_file>"
6
+ puts "This tool will feed the rrd wil generated data"
7
+ exit(1)
8
+ end
9
+
10
+ rrd_path = ARGV[0]
11
+
12
+ rrd = RRDReader::File.new(rrd_path)
13
+
14
+ # raise "Too many ds !" if rrd.ds.size != 1
15
+
16
+ trap('INT'){ exit(0) }
17
+
18
+ # find interval
19
+ interval = rrd.step
20
+ values = []
21
+ rrd_count = rrd.ds.size
22
+
23
+ 0.upto(rrd_count - 1) do |n|
24
+ values[n] = rand(5000)
25
+ end
26
+
27
+
28
+ puts "Detected #{rrd_count} Data sources."
29
+
30
+ while true
31
+ time = Time.new
32
+ cmd_line = [time.to_i]
33
+
34
+ 0.upto(rrd_count - 1) do |n|
35
+ # new_data = [value + 1].map {|item| item.nil? ? "U" : item}
36
+ # new_data = [time.to_i] + new_data
37
+ cmd_line << (values[n] + 1) || "U"
38
+ puts "[#{n}] Written: #{values[n] + 1} at #{time.to_i}"
39
+ values[n] += rand(200) - 100
40
+ values[n] = [0, [values[n],5000].min].max
41
+ end
42
+
43
+ RRD::Wrapper.update(rrd_path, cmd_line.join(":"))
44
+
45
+ sleep(interval)
46
+ end