munin2graphite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,4 @@
1
+ module Graphite
2
+ class UserGraph < Graph
3
+ end
4
+ end
data/lib/graphite.rb ADDED
@@ -0,0 +1,8 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+ $:.unshift(File.join(File.dirname(__FILE__)),"graphite")
3
+ require 'graphite/base'
4
+ require 'graphite/metric'
5
+ require 'graphite/graph'
6
+ require 'graphite/my_graph'
7
+ require 'graphite/user_graph'
8
+
@@ -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
@@ -0,0 +1,8 @@
1
+ $:.unshift(File.join(File.expand_path(File.dirname(__FILE__),"munin2graphite")))
2
+ require 'rubygems'
3
+ require 'munin-ruby'
4
+ require 'carbon'
5
+ require 'graphite'
6
+ require 'munin_graph'
7
+ require 'munin2graphite/config'
8
+ require 'munin2graphite/scheduler'
@@ -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
+