munin2graphite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+
7
+ gem "rufus-scheduler", "2.0.10"
8
+ gem "daemons", "1.1.4"
9
+ gem "parseconfig"
10
+ gem "munin-ruby", "~> 0.2.1"
11
+
12
+
13
+ # Add dependencies to develop your gem here.
14
+ # Include everything needed to run rake, tests, features, etc.
15
+ group :development do
16
+ gem "bundler", "~> 1.0.0"
17
+ gem "jeweler", "~> 1.5.2"
18
+ gem "yard", "~> 0.6.0"
19
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Jose Fernandez (magec)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,123 @@
1
+ munin2graphite
2
+ ===============
3
+
4
+ Munin2graphite is a munin-node to graphite translator. It works as a daemon that connects to a [munin-node](http://munin-monitoring.org/wiki/munin-node), and translates the data and the graphics into [carbon/graphite](http://graphite.wikidot.com/).
5
+
6
+ Installing
7
+ ----------
8
+
9
+ To install munin2graphite you need a working ruby virtual machine with rubygems installed. Once you've got that, It's as easy as
10
+
11
+ gem install munin2graphite
12
+
13
+ Configuring
14
+ ------------
15
+
16
+ Munin2graphite can be used to post data to graphite from any number of munin nodes you want. The idea is simple, there is bunch of workers that periodically ask for metrics to their munin-nodes and then post that data to carbon. Also, every time the daemon is run, the available graphs from the munin nodes are read, translated and posted into graphite as well.
17
+
18
+ ## Workers
19
+ You can either choose to use workers with different configuration or configure everything as global in the config file. A worker implies a new thread of execution with different configuration. Note that if you don't rewrite a given value on the worker, the one in the global config will be used.
20
+
21
+ ## Config Example
22
+ Imagine, for example, that we have two munin-nodes in two different servers (munin-node1.example.com,munin-node2.example.com). Let's say that one munin node has, in turn 2 nodes configured on it and the other just one (node1.munin-node1.example.com and node2.munin-node1.example.com). We also have one graphite server and one carbon server (carbon.example.com and graphite.example.com), they can be on the same machine on in a different one. A valid config file for this would be:
23
+
24
+ # Log config
25
+ # log: The logfile, STDOUT if stdout is needed
26
+ # log_level: Either DEBUG, INFO or WARN
27
+ log=/var/log/munin2graphite
28
+ log_level=INFO
29
+
30
+ # Carbon backend
31
+ # This has to point to the carbon backend to submit metrics
32
+ carbon_hostname=carbon.example.com
33
+ carbon_port=2003
34
+
35
+ # Graphite endpoint
36
+ # This is needed to send graph data to graphite
37
+ graphite_endpoint=http://graphite.example.com/
38
+
39
+ # User and password of the graphite web UI
40
+ graphite_user=test
41
+ graphite_password=secret
42
+
43
+ # This is the prefix you want the on metrics
44
+ graphite_metric_prefix=test.server
45
+
46
+ # The prefix you want in the graphics, note that in the UI the grapichs are shown under the user name, so the user name is also added prfixed
47
+ # to this prefix. That's why conveniently, I used 'test' (the user name) in the metric prefix
48
+ graphite_graph_prefix=server
49
+
50
+
51
+ # The period for sending the metrics
52
+ # its format is the one of rufus-scheduler
53
+ scheduler_metrics_period=1m
54
+
55
+ # The munin node hostname and its port
56
+ munin_hostname=localhost
57
+ munin_port=4949
58
+
59
+ # Apart from the global configuration, you can define workers so a new thread is opened with the new configuration,
60
+ # this is particulary useful when you have a single munin-node with several nodes configured and want to send different graphs
61
+ # with different prefixes
62
+ [node1.munin-node1]
63
+ munin_hostname=munin-node1.example.com
64
+ nodes=node1
65
+
66
+ [node2.munin-node1]
67
+ munin_hostname=munin-node1.example.com
68
+ nodes=node2
69
+
70
+ [munin-node2]
71
+ munin_hostname=munin-node1.example.com
72
+
73
+ Running it
74
+ -----------
75
+ You can run it either as a daemon or as an executable. To run it as an executable, just call it with the config file.
76
+
77
+ munin2graphite config.conf
78
+
79
+ There is also a daemon version, bassically the same thing but wrapped up with the daemons gem. Its usage is as follows. By default the config file location will be /etc/munin2graphite/munin2graphite.conf. This daemon also supports to be run from /etc/init.d by means of a symbolic link.
80
+
81
+
82
+ Usage: munin-graphite.rb <command> <options> -- <application options>
83
+
84
+ * where <command> is one of:
85
+ start start an instance of the application
86
+ stop stop all instances of the application
87
+ restart stop all instances and restart them afterwards
88
+ reload send a SIGHUP to all instances of the application
89
+ run start the application and stay on top
90
+ zap set the application to a stopped state
91
+ status show status (PID) of application instances
92
+
93
+ * and where <options> may contain several of the following:
94
+
95
+ -t, --ontop Stay on top (does not daemonize)
96
+ -f, --force Force operation
97
+ -n, --no_wait Do not wait for processes to stop
98
+
99
+ Common options:
100
+ -h, --help Show this message
101
+ --version Show version
102
+
103
+
104
+ Troubleshooting
105
+ -----------------
106
+ You better start testing the conf with the not daemonized mode and then swap to the daemon, another aproarch is to use the daemon but adding a -t (stay on top) when running.
107
+
108
+ Contributing to munin2graphite
109
+ -------------------------------
110
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
111
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
112
+ * Fork the project
113
+ * Start a feature/bugfix branch
114
+ * Commit and push until you are happy with your contribution
115
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
116
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
117
+
118
+ Copyright
119
+ -----------
120
+
121
+ Copyright (c) 2011 Jose Fernandez (magec). See LICENSE.txt for
122
+ further details.
123
+
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "munin2graphite"
18
+ gem.homepage = "http://github.com/magec/munin2graphite"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Allows to post both data and graphic info from munin to graphite (https://launchpad.net/graphite)}
21
+ gem.description = %Q{This gem will install as a daemon and can be used to connect to a graphite and a carbon backend. It will not only post the data for the metrics but also create graphs into graphite, by means of a translation from munin-node.}
22
+ gem.email = "jfernandezperez@gmail.com"
23
+ gem.authors = ["Jose Fernandez (magec)"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ task :default => :test
36
+
37
+ require 'yard'
38
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..","lib")))
3
+ require 'rubygems'
4
+ require 'munin2graphite'
5
+
6
+ if ARGV.last && File.stat(ARGV.last)
7
+ Munin2Graphite::Config.config_file = ARGV.last
8
+ else
9
+ Munin2Graphite::Config.config_file = "/etc/conf/munin2graphite.conf"
10
+ end
11
+
12
+ Thread.abort_on_exception = true
13
+
14
+ scheduler = Munin2Graphite::Scheduler.new(Munin2Graphite::Config)
15
+ scheduler.start
16
+ scheduler.scheduler.join
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ### BEGIN INIT INFO
4
+ # Provides: munin2graphite
5
+ # Required-Start: $network $remote_fs $munin-node
6
+ # Required-Stop: $null
7
+ # Default-Start: 3 5
8
+ # Default-Stop: 0 1 2 6
9
+ # Short-Description: Populates carbon agents with munin-node data
10
+ # Description: munin graphs to graphite servers
11
+ ### END INIT INFO
12
+
13
+ require 'rubygems'
14
+ require 'daemons'
15
+
16
+ THIS_FILE = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
17
+
18
+ DAEMON=File.dirname(THIS_FILE)+ "/munin2graphite"
19
+ Daemons.run(DAEMON,{:dir_mode => :system, :monitor => true})
20
+
@@ -0,0 +1,35 @@
1
+ # Log config
2
+ # log: The logfile, STDOUT if stdout is needed
3
+ # log_level: Either DEBUG, INFO or WARN
4
+ log=/var/log/munin2graphite.log
5
+ log_level=INFO
6
+
7
+ # Carbon backend
8
+ # This has to point to the carbon backend to submit metrics
9
+ carbon_hostname=localhost
10
+ carbon_port=2003
11
+
12
+ # Graphite endpoint
13
+ # This is needed to send graph data to graphite
14
+ graphite_endpoint=http://graphite/
15
+
16
+ # prefix for the metrics usually, the user name have to be put as a prefix
17
+ graphite_metric_prefix=
18
+ graphite_graph_prefix=
19
+ graphite_user=test
20
+ graphite_password=
21
+
22
+ # The period for sending the metrics and the graph info
23
+ # its format is the one of rufus-scheduler
24
+ scheduler_metrics_period=1m
25
+ scheduler_graphs_period=10m
26
+
27
+ # The munin node hostname and its port
28
+ munin_hostname=localhost
29
+ munin_port=4949
30
+
31
+ # Apart from the global configuration, you can define workers so a new thread is opened with the new configuration,
32
+ # this is particulary useful when you have a single munin-node with several nodes configured and want to send different graphs
33
+ # with different prefixes
34
+ #[test_worker1]
35
+ #munin_hostname=127.0.0.1
@@ -0,0 +1,35 @@
1
+ # Log config
2
+ # log: The logfile, STDOUT if stdout is needed
3
+ # log_level: Either DEBUG, INFO or WARN
4
+ log=/var/log/munin2graphite.log
5
+ log_level=INFO
6
+
7
+ # Carbon backend
8
+ # This has to point to the carbon backend to submit metrics
9
+ carbon_hostname=
10
+ carbon_port=2003
11
+
12
+ # Graphite endpoint
13
+ # This is needed to send graph data to graphite
14
+ graphite_endpoint=http://graphite/
15
+
16
+ # prefix for the metrics usually, the user name have to be put as a prefix
17
+ graphite_metric_prefix=
18
+ graphite_graph_prefix=
19
+ graphite_user=test
20
+ graphite_password=
21
+
22
+ # The period for sending the metrics and the graph info
23
+ # its format is the one of rufus-scheduler
24
+ scheduler_metrics_period=1m
25
+ scheduler_graphs_period=10m
26
+
27
+ # The munin node hostname and its port
28
+ munin_hostname=localhost
29
+ munin_port=4949
30
+
31
+ # Apart from the global configuration, you can define workers so a new thread is opened with the new configuration,
32
+ # this is particulary useful when you have a single munin-node with several nodes configured and want to send different graphs
33
+ # with different prefixes
34
+ #[test_worker1]
35
+ #munin_hostname=127.0.0.1
data/lib/ast_node.rb ADDED
@@ -0,0 +1,344 @@
1
+ require 'uri'
2
+
3
+ class ASTNode
4
+
5
+ attr_accessor :properties, :children, :parent , :root_node, :graph_properties
6
+
7
+ def default_colors
8
+ %w(#00CC00 #0066B3 #FF8000 #FFCC00 #330099 #990099 #CCFF00 #FF0000 #808080
9
+ #008F00 #00487D #B35A00 #B38F00 #6B006B #8FB300 #B30000 #BEBEBE
10
+ #80FF80 #80C9FF #FFC080 #FFE680 #AA80FF #EE00CC #FF8080
11
+ #666600 #FFBFFF #00FFCC #CC6699 #999900)
12
+ end
13
+
14
+ def initialize(raw_data)
15
+ @root_node = nil
16
+ @raw_data = raw_data
17
+ @children = []
18
+ @properties = {'graph_period' => "seconds","category" => "other"}
19
+ @graph_properties = {}
20
+ @graph_properties[:colorList] = default_colors
21
+ @parent = nil
22
+ end
23
+
24
+ def config=(config)
25
+ self.properties.merge!(config)
26
+ end
27
+
28
+ def root?
29
+ @root_node == nil
30
+ end
31
+
32
+ def children_of_class(klass)
33
+ children.select { |i| i.is_a? klass }
34
+ end
35
+
36
+ # Add a child to the node
37
+ def add_child(child)
38
+ if self.root?
39
+ child.root_node = self
40
+ else
41
+ child.root_node = self.root_node
42
+ end
43
+
44
+ child.parent = self
45
+ children << child
46
+ end
47
+
48
+ def compile
49
+ # The compilation is done twice cause there are certain cases where is necessary, a better implementation would control whether this is needed
50
+ # or not, but given the small impact I just do it twice
51
+ children.map{|i| i.compile} if children
52
+ children.map{|i| i.compile} if children
53
+ end
54
+
55
+ # Returns the FieldDeclaration Nodes
56
+ def targets
57
+ children_of_class(FieldDeclarationNode)
58
+ end
59
+
60
+ def process_variables(properties)
61
+ [:vtitle,:title].each do |key|
62
+ aux = properties[key]
63
+ properties[key].scan(/\$\{(.*)\}/).each do
64
+ if self.properties.has_key? $1
65
+ aux.gsub!(/\$\{#{$1}\}/,self.properties[$1])
66
+ end
67
+ end if properties[key]
68
+ properties[key] = aux
69
+
70
+ end
71
+ end
72
+
73
+ # Returns the global properties as url values
74
+ def properties_to_url
75
+
76
+ # Color List initialization
77
+ aux_graph_properties = self.graph_properties.clone
78
+ process_variables(aux_graph_properties)
79
+ aux_graph_properties[:colorList] = aux_graph_properties[:colorList].join(",") if aux_graph_properties[:colorList]
80
+
81
+ # Change of the base stuff
82
+ if self.properties[:base]
83
+ aux_graph_properties[:yMax] = aux_graph_properties[:yMax].to_f / self.properties[:base]
84
+ aux_graph_properties[:yMin] = aux_graph_properties[:yMin].to_f / self.properties[:base]
85
+ aux_graph_properties.delete :yMax
86
+ aux_graph_properties.delete :yMin
87
+ end
88
+
89
+ aux = aux_graph_properties.map{|i,j| "#{i}=#{URI.escape(j.to_s.gsub('%','percent'))}"}.join("&")
90
+ return aux
91
+ end
92
+
93
+ # This returns the url field of the graph after compiling it
94
+ def url
95
+ self.compile
96
+ url = "#{properties[:endpoint]}/render/?width=586&height=308&#{properties_to_url}&target=" + URI.escape(targets.map{|i| i.compile}.compact.join("&target="))
97
+ end
98
+
99
+ end
100
+
101
+
102
+ class GlobalDeclarationNode < ASTNode
103
+ def initialize(line)
104
+ super
105
+ line =~ /^([\w_]*)\ (.*)/
106
+ @value = $2
107
+ end
108
+ end
109
+
110
+ def string_to_ansi(string)
111
+ string.unpack("U*").map{|c|c.chr}.join
112
+ end
113
+
114
+ class GraphTitleGlobalDeclarationNode < GlobalDeclarationNode
115
+ def compile
116
+ root_node.graph_properties[:title] = @value
117
+ end
118
+ end
119
+
120
+ class GraphVLabelGlobalDeclarationNode < GlobalDeclarationNode
121
+ def compile
122
+ root_node.graph_properties[:vtitle] = @value
123
+ end
124
+ end
125
+
126
+ class CreateArgsGlobalDeclarationNode < GlobalDeclarationNode
127
+ end
128
+
129
+ class GraphArgsGlobalDeclarationNode < GlobalDeclarationNode
130
+ def compile
131
+ if @raw_data =~ /--base\ (\d+)/
132
+ self.root_node.properties[:base] = $1.to_i
133
+ end
134
+ if @raw_data =~ /.*logarithmic.*/
135
+ self.root_node.properties[:logarithmic] = true
136
+ end
137
+ end
138
+ end
139
+
140
+ class GraphCategoryGlobalDeclarationNode < GlobalDeclarationNode
141
+ def compile
142
+ root_node.properties["category"] = @value
143
+ end
144
+ end
145
+
146
+ class GraphInfoGlobalDeclarationNode < GlobalDeclarationNode; end
147
+ class GraphOrderGlobalDeclarationNode < GlobalDeclarationNode; end
148
+ class GraphTotalGlobalDeclarationNode < GlobalDeclarationNode; end
149
+ class GraphScaleGlobalDeclarationNode < GlobalDeclarationNode; end
150
+ class GraphGlobalDeclarationNode < GlobalDeclarationNode; end
151
+ class HostNameGlobalDeclarationNode < GlobalDeclarationNode
152
+ def compile
153
+ if @raw_data =~ /host_name (.*)$/
154
+ root_node.properties['hostname'] = $1
155
+ end
156
+ end
157
+ end
158
+ class UpdateGlobalDeclarationNode < GlobalDeclarationNode; end
159
+ class GraphPeriodGlobalDeclarationNode < GlobalDeclarationNode;
160
+ def compile
161
+ if @raw_data =~ /graph_period (.*)$/
162
+ root_node.properties['graph_period'] = $1
163
+ end
164
+ end
165
+ end
166
+ class GraphVTitleGlobalDeclarationNode < GlobalDeclarationNode; end
167
+ class ServiceOrderGlobalDeclarationNode < GlobalDeclarationNode; end
168
+ class GraphWidthGlobalDeclarationNode < GlobalDeclarationNode; end
169
+ class GraphHeightGlobalDeclarationNode < GlobalDeclarationNode; end
170
+ class GraphPrintFormatGlobalDeclarationNode < GlobalDeclarationNode; end
171
+
172
+
173
+ class FieldDeclarationNode < ASTNode
174
+
175
+ def metric
176
+ "#{root_node.properties['graphite_metric_prefix']}.#{root_node.properties['hostname'].split('.').first}.#{root_node.properties['category']}.#{root_node.properties['metric']}.#{children.first.metric}"
177
+ end
178
+
179
+ def compile
180
+ aux = children.first.apply_function(metric.gsub("-","_"))
181
+ children[1..-1].each do |i|
182
+ aux = i.apply_function(aux)
183
+ end if children[1..-1]
184
+ if self.root_node.properties[:logarithmic]
185
+ # NOT IMPLEMENTED the logarithmic means that a logarithmic scale is to be used not that a log function has to be implemented aux = "log(#{aux},10)"
186
+ end
187
+ if self.properties[:stacked]
188
+ aux = "stacked(#{aux})"
189
+ end
190
+ if self.properties[:is_negative]
191
+ aux = "scale(#{aux},-1)"
192
+ end
193
+ if self.properties[:alias]
194
+ aux = "alias(#{aux},'#{self.properties[:alias]}')"
195
+ end
196
+ if self.properties[:hide]
197
+ return nil
198
+ else
199
+ return aux
200
+ end
201
+ end
202
+
203
+ def index
204
+ return parent.children_of_class(FieldDeclarationNode).index(self)
205
+ end
206
+
207
+ end
208
+
209
+ class FieldPropertyNode < ASTNode
210
+ attr_accessor :metric
211
+
212
+ def initialize(line)
213
+ super
214
+ line =~ /([\w_]+)\.(\w+)\ (.*)$/
215
+ @metric = $1
216
+ @function = $2
217
+ @value = $3
218
+ end
219
+
220
+ def apply_function(operand)
221
+ return "FUNCION(#{operand})"
222
+ end
223
+
224
+ end
225
+
226
+ class LabelFieldPropertyNode < FieldPropertyNode;
227
+ def apply_function(operand)
228
+ parent.properties[:alias] = @value
229
+ return operand
230
+ end
231
+ end
232
+
233
+ class ColourFieldPropertyNode < FieldPropertyNode
234
+
235
+ def apply_function(operand)
236
+ # In this case a function can't be applied cause graphite does not allow this
237
+ # instead we modify a given
238
+ aux = @value
239
+ aux = "##{@value}" if @value =~ /[0-9A-Fa-f]{3,6}/
240
+
241
+ self.root_node.graph_properties[:colorList] ||= Array.new
242
+ self.root_node.graph_properties[:colorList][parent.index] = aux
243
+ return operand
244
+ end
245
+ end
246
+
247
+ class TypeFieldPropertyNode < FieldPropertyNode
248
+
249
+ def apply_function(operand)
250
+ if @value == "DERIVE" || @value == "COUNTER"
251
+ # The scaling is because of the minutes/seconds"
252
+ return "scale(nonNegativeDerivative(#{operand}),0.0166666666666667)"
253
+ end
254
+ operand
255
+ end
256
+ end
257
+
258
+ class DrawFieldPropertyNode < FieldPropertyNode
259
+ def apply_function(operand)
260
+ if @value == "STACK" || @value == "AREA"
261
+ parent.properties[:stacked] = true
262
+ end
263
+ return operand
264
+ end
265
+ end
266
+
267
+
268
+ class MinFieldPropertyNode < FieldPropertyNode
269
+ def apply_function(operand)
270
+ self.root_node.graph_properties[:yMin] ||= @value.to_i
271
+ self.root_node.graph_properties[:yMin] = @value.to_i if self.root_node.graph_properties[:yMin] > @value.to_i
272
+ return operand
273
+ end
274
+ end
275
+
276
+ class MaxFieldPropertyNode < FieldPropertyNode
277
+ def apply_function(operand)
278
+ self.root_node.graph_properties[:yMax] ||= @value.to_i
279
+ self.root_node.graph_properties[:yMax] = @value.to_i if self.root_node.graph_properties[:yMax] < @value.to_i
280
+ return operand
281
+ end
282
+ end
283
+
284
+ class InfoFieldPropertyNode < FieldPropertyNode
285
+ def apply_function(operand)
286
+ # puts "Info tag is currently ignored"
287
+ return operand
288
+ end
289
+ end
290
+
291
+ class WarningFieldPropertyNode < FieldPropertyNode
292
+ # Ignored
293
+ def apply_function(operand)
294
+ operand
295
+ end
296
+ end
297
+
298
+ class CriticalFieldPropertyNode < FieldPropertyNode
299
+ # Ignored
300
+ def apply_function(operand)
301
+ operand
302
+ end
303
+ end
304
+
305
+
306
+ class CDefFieldPropertyNode < FieldPropertyNode
307
+ def apply_function(operand)
308
+ if @raw_data =~ /(\w+),(\d+),\*/
309
+ return "scale(#{operand},#{$2})"
310
+ elsif @raw_data =~ /(\w+),(\d+),\//
311
+ return "scale(#{operand},#{1.0/$2.to_i})"
312
+ end
313
+ "FUNCTION(#{operand})"
314
+ end
315
+ end
316
+
317
+ class GraphFieldPropertyNode < FieldPropertyNode
318
+ def apply_function(operand)
319
+ operand
320
+ end
321
+ end
322
+
323
+ class ExtInfoFieldPropertyNode < FieldPropertyNode; end
324
+ class NegativeFieldPropertyNode < FieldPropertyNode
325
+ def apply_function(operand)
326
+ # We have to mark the other node as negative (note that for this to work we have to compile twice
327
+ node = self.root_node.targets.find { |i| i.properties[:field_name] == @value }
328
+ if node
329
+ node.properties[:is_negative] = true
330
+ # We also use the same color
331
+ # config.log.info("Begin getting metrics negative (node : #{node.index} with : #{parent.index} parent Color = root_node.graph_properties[:colorList][parent.index] ")
332
+
333
+ root_node.graph_properties[:colorList][node.index] = root_node.graph_properties[:colorList][parent.index] if root_node.graph_properties[:colorList][parent.index]
334
+ end
335
+ return operand
336
+ end
337
+ end
338
+
339
+ class SkipDrawFieldPropertyNode < FieldPropertyNode; end
340
+ class SumFieldPropertyNode < FieldPropertyNode; end
341
+ class StackFieldPropertyNode < FieldPropertyNode; end
342
+ class LineValueFieldPropertyNode < FieldPropertyNode; end
343
+ class OldNameFieldPropertyNode < FieldPropertyNode; end
344
+ class ValueFieldPropertyNode < FieldPropertyNode; end
data/lib/carbon.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'socket'
2
+ #
3
+ # Author:: Adam Jacob (<adam@hjksolutions.com>)
4
+ # Copyright:: Copyright (c) 2008 HJK Solutions, LLC
5
+ # License:: GNU General Public License version 2 or later
6
+ #
7
+ # This program and entire repository is free software; you can
8
+ # redistribute it and/or modify it under the terms of the GNU
9
+ # General Public License as published by the Free Software
10
+ # Foundation; either version 2 of the License, or any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
+
21
+ class Carbon
22
+ def initialize(chost='localhost', port=2003)
23
+ @carbon = TCPSocket.new(chost, port)
24
+ end
25
+
26
+ def send(msg)
27
+ @carbon.write(msg)
28
+ end
29
+
30
+ def flush
31
+ @carbon.flush
32
+ end
33
+ def close
34
+ @carbon.close
35
+ end
36
+ end