munin2graphite 0.1.0
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.
- 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
|
+
|