munin2graphite 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +19 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +123 -0
- data/Rakefile +38 -0
- data/VERSION +1 -0
- data/bin/munin2graphite +16 -0
- data/bin/munin2graphite-daemon +20 -0
- data/conf/munin2graphite.conf.example +35 -0
- data/etc/munin2graphite/munin2graphite.conf.example +35 -0
- data/lib/ast_node.rb +344 -0
- data/lib/carbon.rb +36 -0
- data/lib/graphite/base.rb +30 -0
- data/lib/graphite/graph.rb +40 -0
- data/lib/graphite/metric.rb +19 -0
- data/lib/graphite/my_graph.rb +23 -0
- data/lib/graphite/user_graph.rb +4 -0
- data/lib/graphite.rb +8 -0
- data/lib/munin2graphite/config.rb +117 -0
- data/lib/munin2graphite/scheduler.rb +169 -0
- data/lib/munin2graphite.rb +8 -0
- data/lib/munin_graph.rb +136 -0
- data/munin2graphite.gemspec +96 -0
- data/test/munin2graphite/config_test.rb +53 -0
- data/test/test_config.rb +27 -0
- data/test/test_init.rb +13 -0
- data/test/test_munin.rb +43 -0
- data/test/test_munin_graph.rb +286 -0
- data/test/test_my_graph.rb +28 -0
- data/test/test_scheduler.rb +19 -0
- metadata +167 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Graphite
|
4
|
+
class Base
|
5
|
+
|
6
|
+
|
7
|
+
# connection instance (shared with every instance of the class)
|
8
|
+
def self.connection
|
9
|
+
@@init_header ||= {}
|
10
|
+
@@connection ||= Net::HTTP.new(@@endpoint)
|
11
|
+
end
|
12
|
+
|
13
|
+
# If the operation needs authentication you have to call this first
|
14
|
+
def self.authenticate(user = @@user,password = @@password)
|
15
|
+
response = self.connection.post("/account/login","nextPage=/&password=#{password}&username=#{user}")
|
16
|
+
@@init_header = {"Cookie" => response.get_fields('Set-Cookie').first}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.set_connection(endpoint,user = "",password = "")
|
20
|
+
@@endpoint = endpoint
|
21
|
+
@@user ||= user
|
22
|
+
@@password ||= password
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get
|
26
|
+
def self.get(path,args)
|
27
|
+
self.connection.get(path + "?" + args.map { |i,j| i.to_s + "=" + j }.join("&"),@@init_header)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Graphite
|
4
|
+
class Graph < Graphite::Base
|
5
|
+
attr_accessor :name,:id,:allow_children,:leaf,:url
|
6
|
+
|
7
|
+
def self.find_by_query_and_path(query,path)
|
8
|
+
graph_type = "#{self}" == "Graphite::MyGraph" ? "mygraph" : "usergraph"
|
9
|
+
return JSON.parse(self.get("/browser/#{graph_type}/",{:format => "treejson",:query => query,:path =>path}).body).map do |graphic_hash|
|
10
|
+
graphic = MyGraph.new
|
11
|
+
graphic.url = graphic_hash["graphUrl"]
|
12
|
+
graphic.name = graphic_hash["id"]
|
13
|
+
graphic.leaf = graphic_hash["leaf"] == 1
|
14
|
+
graphic.allow_children = graphic_hash["allowChildren"] == 1
|
15
|
+
graphic
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def self.descend_to_leaf(query,path)
|
21
|
+
result = []
|
22
|
+
self.find_by_query_and_path(query,path).each do |graph|
|
23
|
+
if graph.leaf
|
24
|
+
return graph
|
25
|
+
else
|
26
|
+
result << self.descend_to_leaf(graph.name + "*",graph.name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return result
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.find_all_by_query(query)
|
33
|
+
result = []
|
34
|
+
self.find_by_query_and_path(query,"").each do |graph|
|
35
|
+
result << self.descend_to_leaf(graph.name + "*",graph.name)
|
36
|
+
end
|
37
|
+
return result.flatten
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Graphite
|
4
|
+
class Metric < Graphite::Base
|
5
|
+
attr_accessor :name,:id,:allow_children,:leaf
|
6
|
+
|
7
|
+
def self.find_by_query(query)
|
8
|
+
|
9
|
+
return JSON.parse(self.get("/metrics/find",{:format => "treejson",:query => query}).body).map do |metric_hash|
|
10
|
+
metric = Metric.new
|
11
|
+
metric.name = metric_hash["text"]
|
12
|
+
metric.id = metric_hash["id"]
|
13
|
+
metric.allow_children = metric_hash["allowChildren"] == 1
|
14
|
+
metric.leaf = metric_hash["leaf"] == 1
|
15
|
+
metric
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Graphite
|
4
|
+
class MyGraph < Graph
|
5
|
+
|
6
|
+
def save!
|
7
|
+
MyGraph.get("/composer/mygraph/",:action => "save", :graphName => name,:url => url.gsub("&","%26"))
|
8
|
+
Munin2Graphite::Config.log.debug("Saving: #{name} ")
|
9
|
+
Munin2Graphite::Config.log.debug(" url: #{url} ")
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
def delete!
|
14
|
+
MyGraph.get("/composer/mygraph/",:action => "delete", :graphName => name,:url => url.gsub("&","%26"))
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns a graph by name
|
18
|
+
def self.find_by_name(name)
|
19
|
+
MyGraph.find_by_query_and_path(name,name.split(".").first).first
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/graphite.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'parseconfig'
|
2
|
+
require 'logger'
|
3
|
+
module Munin2Graphite
|
4
|
+
|
5
|
+
class Config
|
6
|
+
|
7
|
+
class NotConfiguredException < Exception; end
|
8
|
+
class ConfigFileNotFoundException < Exception; end
|
9
|
+
class MalformedConfigFileException < Exception; end
|
10
|
+
class RequiredFieldMissingException < Exception; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
# Returns the config for a given class
|
15
|
+
def config_for_class(klass)
|
16
|
+
return @config[klass.to_s.decamelize.to_sym]
|
17
|
+
end
|
18
|
+
|
19
|
+
def workers
|
20
|
+
return @config.groups
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :config
|
24
|
+
|
25
|
+
# This method will return a config class but for a given worker, so everything will be the same as in the original class
|
26
|
+
# but the config changes made in this worker
|
27
|
+
def config_for_worker(worker)
|
28
|
+
return self if worker == "global"
|
29
|
+
cloned = self.clone
|
30
|
+
cloned.config = @config.clone
|
31
|
+
cloned.config.params = @config.params.merge(@config.params[worker])
|
32
|
+
return cloned
|
33
|
+
end
|
34
|
+
|
35
|
+
def deconfigure!
|
36
|
+
@config = nil
|
37
|
+
@config_file = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def configured?
|
41
|
+
return @config_file != nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_config
|
45
|
+
begin
|
46
|
+
@config = ParseConfig.new(@config_file)
|
47
|
+
rescue Errno::ENOENT
|
48
|
+
raise ConfigFileNotFoundException.new("Error, trying to open the config file #{@config_file}")
|
49
|
+
rescue ArgumentError => exception
|
50
|
+
raise MalformedConfigFileException.new("Malformed config file '#{@config_file}' #{exception.message}")
|
51
|
+
rescue
|
52
|
+
raise "Unknown error when trying to open config file '#{@config_file}'"
|
53
|
+
end
|
54
|
+
@config
|
55
|
+
end
|
56
|
+
|
57
|
+
def check_config
|
58
|
+
fields={:carbon => [:hostname,:port],:graphite => [:endpoint,:metric_prefix,:user,:password],:scheduler => [:metrics_period,:graphs_period]}
|
59
|
+
fields.each do |k,v|
|
60
|
+
v.each do |inner_field|
|
61
|
+
field = "#{k}_#{inner_field}"
|
62
|
+
if !@config.params[field]
|
63
|
+
workers.each do |worker|
|
64
|
+
raise RequiredFieldMissingException.new("Error, required field not found in config ':#{field}' for worker #{worker}") unless @config.params[worker][field]
|
65
|
+
end
|
66
|
+
|
67
|
+
raise RequiredFieldMissingException.new("Error, required field not found in config ':#{field}'") if workers.empty?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def method_missing(method_name,*args)
|
74
|
+
if !@config
|
75
|
+
if @config_file
|
76
|
+
parse_and_check!
|
77
|
+
end
|
78
|
+
raise NotConfiguredException.new("Not Configured") unless @config
|
79
|
+
end
|
80
|
+
|
81
|
+
if method_name == :"[]"
|
82
|
+
if @config.params.has_key?(args.first.to_s)
|
83
|
+
return @config.params[args.first.to_s]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if @config.params.respond_to?method_name
|
87
|
+
return @config.params.send(method_name,*args)
|
88
|
+
end
|
89
|
+
super
|
90
|
+
end
|
91
|
+
|
92
|
+
def log
|
93
|
+
@log ||= if self["log"] == "STDOUT"
|
94
|
+
Logger.new(STDOUT)
|
95
|
+
else
|
96
|
+
Logger.new(self["log"])
|
97
|
+
end
|
98
|
+
@log.level = self["log_level"] == "DEBUG" ? Logger::DEBUG : Logger::INFO
|
99
|
+
@log
|
100
|
+
end
|
101
|
+
|
102
|
+
def config_file=(config_file)
|
103
|
+
@config_file = config_file
|
104
|
+
end
|
105
|
+
|
106
|
+
def config=(config)
|
107
|
+
@config = config
|
108
|
+
check_config
|
109
|
+
end
|
110
|
+
|
111
|
+
def parse_and_check!
|
112
|
+
parse_config
|
113
|
+
check_config
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Jose Fernandez (@magec)
|
3
|
+
# Copyright:: Copyright (c) 2011 UOC (Universitat Oberta de Catalunya)
|
4
|
+
#
|
5
|
+
# This program and entire repository is free software; you can
|
6
|
+
# redistribute it and/or modify it under the terms of the GNU
|
7
|
+
# General Public License as published by the Free Software
|
8
|
+
# Foundation; either version 2 of the License, or any later version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU General putsPublic License
|
16
|
+
# along with this program; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
require 'rufus/scheduler'
|
19
|
+
module Munin2Graphite
|
20
|
+
##
|
21
|
+
# This class holds the main scheduler of the system, it will perform the applicacion loops
|
22
|
+
class Scheduler
|
23
|
+
|
24
|
+
attr_accessor :scheduler
|
25
|
+
|
26
|
+
def initialize(config)
|
27
|
+
@config = config
|
28
|
+
end
|
29
|
+
|
30
|
+
def category_from_config(config)
|
31
|
+
config.each_line do |configline|
|
32
|
+
if configline =~ /^graph_category ([0-9A-Za-z_-]+)$/
|
33
|
+
return configline.split[1]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
return "other"
|
37
|
+
raise "CategoryNotFound in #{config}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def munin_config
|
41
|
+
return @munin_config if @munin_config
|
42
|
+
@munin_config = {}
|
43
|
+
|
44
|
+
workers.each do |worker|
|
45
|
+
@munin_config[worker] = {}
|
46
|
+
config = @config.config_for_worker(worker)
|
47
|
+
munin = Munin::Node.new(config["munin_hostname"],config["munin_port"])
|
48
|
+
nodes = config["munin_nodes"] ? config["munin_nodes"].split(",") : munin.nodes
|
49
|
+
@munin_config[worker][:nodes] = {}
|
50
|
+
nodes.each do |node|
|
51
|
+
|
52
|
+
@munin_config[worker][:nodes][node] = {:metrics => munin.list(node)}
|
53
|
+
@munin_config[worker][:nodes][node][:categories] = {}
|
54
|
+
|
55
|
+
@munin_config[worker][:nodes][node][:metrics].each do |metric|
|
56
|
+
@munin_config[worker][:nodes][node][:config] = munin.config(metric)[metric]
|
57
|
+
@munin_config[worker][:nodes][node][:raw_config] = munin.config(metric,true)[metric]
|
58
|
+
@munin_config[worker][:nodes][node][:categories][metric] = category_from_config(@munin_config[worker][:nodes][node][:raw_config])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
munin.disconnect
|
62
|
+
end
|
63
|
+
@munin_config
|
64
|
+
end
|
65
|
+
|
66
|
+
def workers
|
67
|
+
@workers ||= (@config.workers.empty? ? ["global"] : @config.workers )
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# This is the loop of the metrics scheduling
|
72
|
+
def obtain_metrics
|
73
|
+
config = @config.config_for_worker("global")
|
74
|
+
config.log.info("Obtaining metrics configuration")
|
75
|
+
munin_config
|
76
|
+
config.log.info("Getting metrics")
|
77
|
+
time = Time.now
|
78
|
+
workers.each do |worker|
|
79
|
+
config = @config.config_for_worker(worker)
|
80
|
+
config.log.info("Worker #{worker}")
|
81
|
+
|
82
|
+
metric_base = config["graphite_metric_prefix"]
|
83
|
+
|
84
|
+
threads = []
|
85
|
+
munin_config[worker][:nodes].keys.each do |node|
|
86
|
+
threads << Thread.new do
|
87
|
+
node_name = metric_base + "." + node.split(".").first
|
88
|
+
config.log.debug("Doing #{node_name}")
|
89
|
+
values = {}
|
90
|
+
config.log.debug("Asking for: #{node}")
|
91
|
+
metric_time = Time.now
|
92
|
+
metrics = munin_config[worker][:nodes][node][:metrics]
|
93
|
+
config.log.debug("Metrics " + metrics.join(","))
|
94
|
+
metrics_threads = []
|
95
|
+
categories = {}
|
96
|
+
metrics.each do |metric|
|
97
|
+
metrics_threads << Thread.new do
|
98
|
+
local_munin = Munin::Node.new(config["munin_hostname"],config["munin_port"])
|
99
|
+
values[metric] = local_munin.fetch metric
|
100
|
+
local_munin.disconnect
|
101
|
+
end
|
102
|
+
end
|
103
|
+
metrics_threads.each {|i| i.join;i.kill}
|
104
|
+
config.log.info("Done with: #{node} (#{Time.now - metric_time} s)")
|
105
|
+
carbon = Carbon.new(config["carbon_hostname"],config["carbon_port"])
|
106
|
+
string_to_send = ""
|
107
|
+
values.each do |metric,results|
|
108
|
+
category = munin_config[worker][:nodes][node][:categories][metric]
|
109
|
+
results.each do |k,v|
|
110
|
+
v.each do |c_metric,c_value|
|
111
|
+
string_to_send += "#{node_name}.#{category}.#{metric}.#{c_metric} #{c_value} #{Time.now.to_i}\n".gsub("-","_") if c_value != "U"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
send_time = Time.now
|
116
|
+
carbon.send(string_to_send)
|
117
|
+
carbon.flush
|
118
|
+
carbon.close
|
119
|
+
end
|
120
|
+
end
|
121
|
+
threads.each { |i| i.join }
|
122
|
+
end
|
123
|
+
@config.log.info("End getting metrics, elapsed time (#{Time.now - time}s)")
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# The loop of the graphics creation
|
128
|
+
def obtain_graphs
|
129
|
+
|
130
|
+
workers = @config.workers
|
131
|
+
workers = ["global"] if workers.empty?
|
132
|
+
|
133
|
+
workers.each do |worker|
|
134
|
+
time = Time.now
|
135
|
+
config = @config.config_for_worker worker
|
136
|
+
config.log.info("Begin : Sending Graph Information to Graphite for worker #{worker}")
|
137
|
+
munin = Munin::Node.new(config["munin_hostname"],config["munin_port"])
|
138
|
+
nodes = config["munin_nodes"] ? config["munin_nodes"].split(",") : munin.nodes
|
139
|
+
nodes.each do |node|
|
140
|
+
config.log.info("Graphs for #{node}")
|
141
|
+
munin.list(node).each do |metric|
|
142
|
+
config.log.info("Configuring #{metric}")
|
143
|
+
Graphite::Base.set_connection(config["carbon_hostname"])
|
144
|
+
Graphite::Base.authenticate(config["graphite_user"],config["graphite_password"])
|
145
|
+
munin_graph = MuninGraph.graph_for munin.config(metric,true)[metric]
|
146
|
+
|
147
|
+
munin_graph.config = config.merge("metric" => "#{metric}","hostname" => node.split(".").first)
|
148
|
+
config.log.debug("Saving graph #{metric}")
|
149
|
+
munin_graph.to_graphite.save!
|
150
|
+
end
|
151
|
+
end
|
152
|
+
config.log.info("End : Sending Graph Information to Graphite for worker #{worker}, elapsed time (#{Time.now - time}s)")
|
153
|
+
munin.disconnect
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
def start
|
159
|
+
@config.log.info("Scheduler started")
|
160
|
+
@scheduler = Rufus::Scheduler.start_new
|
161
|
+
obtain_metrics
|
162
|
+
@scheduler.every @config["scheduler_metrics_period"] do
|
163
|
+
obtain_metrics
|
164
|
+
end
|
165
|
+
obtain_graphs
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
data/lib/munin_graph.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'ast_node'
|
2
|
+
require 'graphite'
|
3
|
+
#
|
4
|
+
# Author:: Jose Fernandez (@magec)
|
5
|
+
# Copyright:: Copyright (c) 2011 UOC (Universitat Oberta de Catalunya)
|
6
|
+
# License:: GNU General Public License version 2 or later
|
7
|
+
#
|
8
|
+
# This program and entire repository is free software; you can
|
9
|
+
# redistribute it and/or modify it under the terms of the GNU
|
10
|
+
# General Public License as published by the Free Software
|
11
|
+
# Foundation; either version 2 of the License, or any later version.
|
12
|
+
#
|
13
|
+
# This program is distributed in the hope that it will be useful,
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16
|
+
# GNU General Public License for more details.
|
17
|
+
#
|
18
|
+
# You should have received a copy of the GNU General Public License
|
19
|
+
# along with this program; if not, write to the Free Software
|
20
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
21
|
+
|
22
|
+
|
23
|
+
##
|
24
|
+
# This class allows the transformation between graphite and munin config. It constructs an AST parsing the munin config information and
|
25
|
+
# allows to output a valid graphic in graphite url format
|
26
|
+
# Jose Fernandez 2011
|
27
|
+
#
|
28
|
+
class MuninGraph
|
29
|
+
|
30
|
+
def self.graph_for(config)
|
31
|
+
MuninGraph.new(config)
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(config)
|
35
|
+
@raw_config = config
|
36
|
+
parse_config
|
37
|
+
end
|
38
|
+
|
39
|
+
def config=(config)
|
40
|
+
@config = config
|
41
|
+
self.root.config = config
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_graphite
|
45
|
+
graph = Graphite::MyGraph.new
|
46
|
+
self.root.compile
|
47
|
+
graph.url = self.root.url
|
48
|
+
self.root.properties[:category] ||= "other"
|
49
|
+
|
50
|
+
graph.name = "#{@config["hostname"]}.#{self.root.properties["category"]}.#{self.root.properties["metric"]}"
|
51
|
+
graph.name = "#{@config["graphite_graph_prefix"]}.#{graph.name}" if @config["graphite_graph_prefix"] && @config["graphite_graph_prefix"] != ""
|
52
|
+
return graph
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :root
|
56
|
+
|
57
|
+
# This array of hashes will be used to match what kind of line we are dealing with and
|
58
|
+
# to know the corresponding ast node class
|
59
|
+
TOKENS = [
|
60
|
+
{:matcher => /^graph_title .*/, :klass => GraphTitleGlobalDeclarationNode},
|
61
|
+
{:matcher => /^create_args .*/, :klass => CreateArgsGlobalDeclarationNode},
|
62
|
+
{:matcher => /^graph_args .*/, :klass => GraphArgsGlobalDeclarationNode},
|
63
|
+
{:matcher => /^graph_category .*/, :klass => GraphCategoryGlobalDeclarationNode},
|
64
|
+
{:matcher => /^graph_info .*/, :klass => GraphInfoGlobalDeclarationNode},
|
65
|
+
{:matcher => /^graph_order .*/, :klass => GraphOrderGlobalDeclarationNode},
|
66
|
+
{:matcher => /^graph_vlabel .*/, :klass => GraphVLabelGlobalDeclarationNode},
|
67
|
+
{:matcher => /^graph_total .*/, :klass => GraphTotalGlobalDeclarationNode},
|
68
|
+
{:matcher => /^graph_scale .*/, :klass => GraphScaleGlobalDeclarationNode},
|
69
|
+
{:matcher => /^graph .*/, :klass => GraphGlobalDeclarationNode},
|
70
|
+
{:matcher => /^host_name .*/, :klass => HostNameGlobalDeclarationNode},
|
71
|
+
{:matcher => /^update .*/, :klass => UpdateGlobalDeclarationNode},
|
72
|
+
{:matcher => /^graph_period .*/, :klass => GraphPeriodGlobalDeclarationNode},
|
73
|
+
{:matcher => /^graph_vtitle .*/, :klass => GraphVTitleGlobalDeclarationNode},
|
74
|
+
{:matcher => /^service_order .*/, :klass => ServiceOrderGlobalDeclarationNode},
|
75
|
+
{:matcher => /^graph_width .*/, :klass => GraphWidthGlobalDeclarationNode},
|
76
|
+
{:matcher => /^graph_height .*/, :klass => GraphHeightGlobalDeclarationNode},
|
77
|
+
{:matcher => /^graph_printfformat .*/, :klass => GraphPrintFormatGlobalDeclarationNode},
|
78
|
+
{:matcher => /([\w_]+)\.label\ .*$/,:klass => LabelFieldPropertyNode},
|
79
|
+
{:matcher => /([\w_]+)\.cdef\ .*$/,:klass => CDefFieldPropertyNode},
|
80
|
+
{:matcher => /([\w_]+)\.draw\ .*$/,:klass => DrawFieldPropertyNode},
|
81
|
+
{:matcher => /([\w_]+)\.graph\ .*$/,:klass => GraphFieldPropertyNode},
|
82
|
+
{:matcher => /([\w_]+)\.info\ .*$/,:klass => InfoFieldPropertyNode},
|
83
|
+
{:matcher => /([\w_]+)\.extinfo\ .*$/,:klass => ExtInfoFieldPropertyNode},
|
84
|
+
{:matcher => /([\w_]+)\.max\ .*$/,:klass => MaxFieldPropertyNode},
|
85
|
+
{:matcher => /([\w_]+)\.min\ .*$/,:klass => MinFieldPropertyNode},
|
86
|
+
{:matcher => /([\w_]+)\.negative\ .*$/,:klass => NegativeFieldPropertyNode},
|
87
|
+
{:matcher => /([\w_]+)\.type\ .*$/,:klass => TypeFieldPropertyNode},
|
88
|
+
{:matcher => /([\w_]+)\.warning\ .*$/,:klass => WarningFieldPropertyNode},
|
89
|
+
{:matcher => /([\w_]+)\.critical\ .*$/,:klass => CriticalFieldPropertyNode},
|
90
|
+
{:matcher => /([\w_]+)\.colour\ .*$/,:klass => ColourFieldPropertyNode},
|
91
|
+
{:matcher => /([\w_]+)\.skipdraw\ .*$/,:klass => SkipDrawFieldPropertyNode},
|
92
|
+
{:matcher => /([\w_]+)\.sum\ .*$/,:klass => SumFieldPropertyNode},
|
93
|
+
{:matcher => /([\w_]+)\.stack\ .*$/,:klass => StackFieldPropertyNode},
|
94
|
+
{:matcher => /([\w_]+)\.linevalue\[:color\[:label\]\]\ .*$/,:klass => LineValueFieldPropertyNode},
|
95
|
+
{:matcher => /([\w_]+)\.oldname\ .*$/,:klass => OldNameFieldPropertyNode},
|
96
|
+
{:matcher => /([\w_]+)\.value\ .*$/,:klass => ValueFieldPropertyNode}
|
97
|
+
]
|
98
|
+
|
99
|
+
def parse_config
|
100
|
+
@root = ASTNode.new("")
|
101
|
+
@root.parent = nil
|
102
|
+
current_node = @root
|
103
|
+
@raw_config.each_line do |line|
|
104
|
+
# For every line of config we match against every token
|
105
|
+
TOKENS.each do |token|
|
106
|
+
if line =~ token[:matcher]
|
107
|
+
# When we find a match...
|
108
|
+
if token[:klass].new("").is_a? FieldPropertyNode
|
109
|
+
# In Property field we have to set it to a FieldDeclarationNode (an artificial node grouping those fields)
|
110
|
+
if !current_node.is_a? FieldDeclarationNode
|
111
|
+
# A new FieldDeclaration has to ve created
|
112
|
+
node = FieldDeclarationNode.new("")
|
113
|
+
node.properties[:field_name] = $1
|
114
|
+
current_node.add_child node
|
115
|
+
current_node = node
|
116
|
+
elsif current_node.properties[:field_name] != $1
|
117
|
+
if (aux = @root.children_of_class(FieldDeclarationNode).find { |i| i.properties[:field_name] == $1 } )
|
118
|
+
current_node = aux
|
119
|
+
else
|
120
|
+
# We use the one declared before (note that different metrics could not be interlaced)
|
121
|
+
node = FieldDeclarationNode.new("")
|
122
|
+
node.properties[:field_name] = $1
|
123
|
+
current_node.parent.add_child node
|
124
|
+
current_node = node
|
125
|
+
end
|
126
|
+
end
|
127
|
+
current_node.add_child token[:klass].send("new",line)
|
128
|
+
else
|
129
|
+
@root.add_child token[:klass].send("new",line)
|
130
|
+
end
|
131
|
+
break
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "munin2graphite"
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jose Fernandez (magec)"]
|
12
|
+
s.date = "2011-12-09"
|
13
|
+
s.description = "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."
|
14
|
+
s.email = "jfernandezperez@gmail.com"
|
15
|
+
s.executables = ["munin2graphite", "munin2graphite-daemon"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE.txt",
|
18
|
+
"README.markdown"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
"Gemfile",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.markdown",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"bin/munin2graphite",
|
27
|
+
"bin/munin2graphite-daemon",
|
28
|
+
"conf/munin2graphite.conf.example",
|
29
|
+
"etc/munin2graphite/munin2graphite.conf.example",
|
30
|
+
"lib/ast_node.rb",
|
31
|
+
"lib/carbon.rb",
|
32
|
+
"lib/graphite.rb",
|
33
|
+
"lib/graphite/base.rb",
|
34
|
+
"lib/graphite/graph.rb",
|
35
|
+
"lib/graphite/metric.rb",
|
36
|
+
"lib/graphite/my_graph.rb",
|
37
|
+
"lib/graphite/user_graph.rb",
|
38
|
+
"lib/munin2graphite.rb",
|
39
|
+
"lib/munin2graphite/config.rb",
|
40
|
+
"lib/munin2graphite/scheduler.rb",
|
41
|
+
"lib/munin_graph.rb",
|
42
|
+
"munin2graphite.gemspec",
|
43
|
+
"test/munin2graphite/config_test.rb",
|
44
|
+
"test/test_config.rb",
|
45
|
+
"test/test_init.rb",
|
46
|
+
"test/test_munin.rb",
|
47
|
+
"test/test_munin_graph.rb",
|
48
|
+
"test/test_my_graph.rb",
|
49
|
+
"test/test_scheduler.rb"
|
50
|
+
]
|
51
|
+
s.homepage = "http://github.com/magec/munin2graphite"
|
52
|
+
s.licenses = ["MIT"]
|
53
|
+
s.require_paths = ["lib"]
|
54
|
+
s.rubygems_version = "1.8.10"
|
55
|
+
s.summary = "Allows to post both data and graphic info from munin to graphite (https://launchpad.net/graphite)"
|
56
|
+
s.test_files = [
|
57
|
+
"test/munin2graphite/config_test.rb",
|
58
|
+
"test/test_config.rb",
|
59
|
+
"test/test_init.rb",
|
60
|
+
"test/test_munin.rb",
|
61
|
+
"test/test_munin_graph.rb",
|
62
|
+
"test/test_my_graph.rb",
|
63
|
+
"test/test_scheduler.rb"
|
64
|
+
]
|
65
|
+
|
66
|
+
if s.respond_to? :specification_version then
|
67
|
+
s.specification_version = 3
|
68
|
+
|
69
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
70
|
+
s.add_runtime_dependency(%q<rufus-scheduler>, ["= 2.0.10"])
|
71
|
+
s.add_runtime_dependency(%q<daemons>, ["= 1.1.4"])
|
72
|
+
s.add_runtime_dependency(%q<parseconfig>, [">= 0"])
|
73
|
+
s.add_runtime_dependency(%q<munin-ruby>, ["~> 0.2.1"])
|
74
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
75
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
76
|
+
s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
|
77
|
+
else
|
78
|
+
s.add_dependency(%q<rufus-scheduler>, ["= 2.0.10"])
|
79
|
+
s.add_dependency(%q<daemons>, ["= 1.1.4"])
|
80
|
+
s.add_dependency(%q<parseconfig>, [">= 0"])
|
81
|
+
s.add_dependency(%q<munin-ruby>, ["~> 0.2.1"])
|
82
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
83
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
84
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
85
|
+
end
|
86
|
+
else
|
87
|
+
s.add_dependency(%q<rufus-scheduler>, ["= 2.0.10"])
|
88
|
+
s.add_dependency(%q<daemons>, ["= 1.1.4"])
|
89
|
+
s.add_dependency(%q<parseconfig>, [">= 0"])
|
90
|
+
s.add_dependency(%q<munin-ruby>, ["~> 0.2.1"])
|
91
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
92
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
93
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|