diff options
author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-11-09 19:00:10 +0000 |
---|---|---|
committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-11-09 19:00:10 +0000 |
commit | 87aea8b6eec95a139cd3a35c5f7033d454a24cfb (patch) | |
tree | 6c842555700434a88b583a69fc17a95dfad42ea4 | |
parent | 51882d98289eea6b362ea99231d480728e937797 (diff) | |
download | puppet-87aea8b6eec95a139cd3a35c5f7033d454a24cfb.tar.gz puppet-87aea8b6eec95a139cd3a35c5f7033d454a24cfb.tar.xz puppet-87aea8b6eec95a139cd3a35c5f7033d454a24cfb.zip |
Fixing rrdgraph report (as marked in #334); also, expanding the docs on all of the existing reports.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1839 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r-- | lib/puppet/metric.rb | 82 | ||||
-rw-r--r-- | lib/puppet/reports/rrdgraph.rb | 113 | ||||
-rw-r--r-- | lib/puppet/reports/store.rb | 7 | ||||
-rw-r--r-- | lib/puppet/reports/tagmail.rb | 24 | ||||
-rwxr-xr-x | test/other/report.rb | 18 |
5 files changed, 195 insertions, 49 deletions
diff --git a/lib/puppet/metric.rb b/lib/puppet/metric.rb index 6702018dc..3749d257f 100644 --- a/lib/puppet/metric.rb +++ b/lib/puppet/metric.rb @@ -32,18 +32,22 @@ module Puppet end end - def create + def create(start = nil) Puppet.config.use(:metrics) + start ||= Time.now.to_i - 5 + path = self.path args = [ path, - "--start", Time.now.to_i - 5, + "--start", start, "--step", Puppet[:rrdinterval] ] - @values.each { |value| - args.push "DS:%s:GAUGE:600:U:U" % value[0] + values.each { |value| + # the 7200 is the heartbeat -- this means that any data that isn't + # more frequently than every two hours gets thrown away + args.push "DS:%s:GAUGE:7200:U:U" % [value[0]] } args.push "RRA:AVERAGE:0.5:1:300" @@ -54,37 +58,50 @@ module Puppet end end + def dump + puts RRD.info(self.path) + end + def graph(range = nil) unless Puppet.features.rrd? Puppet.warning "RRD library is missing; cannot graph metrics" return end - args = [self.path.sub(/rrd$/,"png")] - args.push("--title",self.label) - args.push("--imgformat","PNG") - args.push("--interlace") + unit = 60 * 60 * 24 colorstack = %w{#ff0000 #00ff00 #0000ff #099000 #000990 #f00990 #0f0f0f} - i = 0 - defs = [] - lines = [] - @values.zip(colorstack).each { |value,color| - next if value.nil? - # this actually uses the data label - defs.push("DEF:%s=%s:%s:AVERAGE" % [value[0],self.path,value[0]]) - lines.push("LINE3:%s%s:%s" % [value[0],color,value[1]]) - } - args << defs - args << lines - args.flatten! - if range - args.push("--start",range[0],"--end",range[1]) - end - begin - RRD.graph(*args) - rescue => detail - Puppet.err "Failed to graph %s: %s" % [self.name,detail] + {:daily => unit, :weekly => unit * 7, :monthly => unit * 30, :yearly => unit * 365}.each do |name, time| + file = self.path.sub(/\.rrd$/, "-%s.png" % name) + args = [file] + + args.push("--title",self.label) + args.push("--imgformat","PNG") + args.push("--interlace") + i = 0 + defs = [] + lines = [] + #p @values.collect { |s,l| s } + values.zip(colorstack).each { |value,color| + next if value.nil? + # this actually uses the data label + defs.push("DEF:%s=%s:%s:AVERAGE" % [value[0],self.path,value[0]]) + lines.push("LINE2:%s%s:%s" % [value[0],color,value[1]]) + } + args << defs + args << lines + args.flatten! + if range + args.push("--start",range[0],"--end",range[1]) + else + args.push("--start", Time.now.to_i - time, "--end", Time.now.to_i) + end + + begin + RRD.graph(*args) + rescue => detail + Puppet.err "Failed to graph %s: %s" % [self.name,detail] + end end end @@ -117,21 +134,26 @@ module Puppet return end unless FileTest.exists?(self.path) - self.create + self.create(time - 5) end # XXX this is not terribly error-resistant args = [time] - @values.each { |value| + values.each { |value| args.push value[2] } arg = args.join(":") begin - RRD.update(self.path,args.join(":")) + RRD.update(self.path,arg) + #system("rrdtool updatev %s '%s'" % [self.path, arg]) rescue => detail raise Puppet::Error, "Failed to update %s: %s" % [self.name,detail] end end + + def values + @values.sort { |a, b| a[1] <=> b[1] } + end end end diff --git a/lib/puppet/reports/rrdgraph.rb b/lib/puppet/reports/rrdgraph.rb index 2c405c051..86f54bf5d 100644 --- a/lib/puppet/reports/rrdgraph.rb +++ b/lib/puppet/reports/rrdgraph.rb @@ -1,14 +1,98 @@ require 'puppet' Puppet::Server::Report.newreport(:rrdgraph) do - desc "Graph some data about hosts." + desc "Graph all available data about hosts using the RRD library. You + must have the RRD binary library installed to use this report, which + you can get from [Tobias Oetiker's site](http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/pub/contrib/). + + This report will create, manage, and graph RRD database files for each + of the metrics generated during transactions, and it will create a + few simple html files to display the reporting host's graphs. At this + point, it will not create a common index file to display links to + all hosts. + + All RRD files and graphs get created in the ``rrddir`` directory. If + you want to serve these publicly, you should be able to just alias that + directory in a web server." - def process - time = Time.now.to_i + def hostdir + unless defined? @hostdir + @hostdir = File.join(Puppet[:rrddir], self.host) + end + @hostdir + end + + def htmlfile(type, graphs, field) + file = File.join(hostdir, "%s.html" % type) + File.open(file, "w") do |of| + of.puts "<html><head><title>%s graphs for %s</title></head><body>" % + [type.capitalize, host] + + graphs.each do |graph| + if field == :first + name = graph.sub(/-\w+.png/, '').capitalize + else + name = graph.sub(/\w+-/, '').sub(".png", '').capitalize + end + of.puts "<img src=%s><br>" % graph + end + of.puts "</body></html>" + end - host = self.host + return file + end - hostdir = File.join(Puppet[:rrddir], host) + def mkhtml + images = Dir.entries(hostdir).find_all { |d| d =~ /\.png/ } + + periodorder = %w{daily weekly monthly yearly} + + periods = {} + types = {} + images.each do |n| + type, period = n.sub(".png", '').split("-") + periods[period] ||= [] + types[type] ||= [] + periods[period] << n + types[type] << n + end + + files = [] + # Make the period html files + periodorder.each do |period| + unless ary = periods[period] + raise "Could not find graphs for %s" % period + end + files << htmlfile(period, ary, :first) + end + + # make the type html files + types.sort { |a,b| a[0] <=> b[0] }.each do |type, ary| + newary = [] + periodorder.each do |period| + if graph = ary.find { |g| g.include?("-%s.png" % period) } + newary << graph + else + raise "Could not find %s-%s graph" % [type, period] + end + end + + files << htmlfile(type, newary, :second) + end + + File.open(File.join(hostdir, "index.html"), "w") do |of| + of.puts "<html><head><title>Report graphs for %s</title></head><body>" % + host + files.each do |file| + of.puts "<a href='#{File.basename(file)}'>%s</a><br/>" % + File.basename(file).sub(".html",'').capitalize + end + of.puts "</body></html>" + end + end + + def process(time = nil) + time ||= Time.now.to_i unless File.directory?(hostdir) # Some hackishness to create the dir @@ -19,19 +103,16 @@ Puppet::Server::Report.newreport(:rrdgraph) do config.use(:reports) end - File.open(File.join(hostdir, "index.html"),"w") { |of| - of.puts "<html><body>" - self.metrics.each do |name, metric| - metric.basedir = hostdir - metric.store(time) + self.metrics.each do |name, metric| + metric.basedir = hostdir + metric.store(time) - metric.graph - - of.puts "<img src=%s.png><br>" % name - end + metric.graph + end - of.puts "</body></html>" - } + unless FileTest.exists?(File.join(hostdir, "index.html")) + mkhtml() + end end end diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb index e4a2b1fe5..e3a3481ad 100644 --- a/lib/puppet/reports/store.rb +++ b/lib/puppet/reports/store.rb @@ -12,7 +12,12 @@ Puppet::Server::Report.newreport(:store, :useyaml => true) do Puppet.config.use(:reporting) - desc "Store the yaml report on disk" + desc "Store the yaml report on disk. Each host sends its report as a YAML dump + and this just stores the file on disk, in the ``reportdir`` directory. + + These files collect quickly -- one every half hour -- so it is a good idea + to perform some maintenance on them if you use this report (it's the only + default report)." def mkclientdir(client, dir) config = Puppet::Config.new diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb index 2a00ea4c1..6018c6424 100644 --- a/lib/puppet/reports/tagmail.rb +++ b/lib/puppet/reports/tagmail.rb @@ -15,7 +15,29 @@ Puppet.config.setdefaults(:reporting, require 'net/smtp' Puppet::Server::Report.newreport(:tagmail) do - desc "Send email reports." + desc "This report sends specific log messages to specific email addresses + based on the tags in the log messages. See the + [tag documentation](../advanced/tags.html) for more information on tags. + + To use this report, you must create a ``tagmail.conf`` (in the location + specified by ``tagmap``). This is a simple file that maps tags to + email addresses: Any log messages in the report that match the specified + tags will be sent to the specified email addresses. + + Tags must be comma-separated, and they can be negated so that messages + only match when they do not have that tag. The tags are separated from + the email addresses by a colon, and the email addresses should also + be comma-separated. + + Lastly, there is an ``all`` tag that will always match all log messages. + + Here is an example tagmail.conf: + + all: me@domain.com + webserver, !mailserver: httpadmins@domain.com + + " + def process unless FileTest.exists?(Puppet[:tagmap]) Puppet.notice "Cannot send tagmail report; no tagmap file %s" % diff --git a/test/other/report.rb b/test/other/report.rb index 433a0d8d8..939d87aaf 100755 --- a/test/other/report.rb +++ b/test/other/report.rb @@ -122,11 +122,27 @@ class TestReports < Test::Unit::TestCase report.process } - hostdir = File.join(Puppet[:rrddir], report.host) + hostdir = nil + assert_nothing_raised do + hostdir = report.hostdir + end + + assert(hostdir, "Did not get hostdir back") assert(FileTest.directory?(hostdir), "Host rrd dir did not get created") index = File.join(hostdir, "index.html") assert(FileTest.exists?(index), "index file was not created") + + # Now make sure it creaets each of the rrd files + %w{changes resources time}.each do |type| + file = File.join(hostdir, "%s.rrd" % type) + assert(FileTest.exists?(file), "Did not create rrd file for %s" % type) + + daily = file.sub ".rrd", "-daily.png" + assert(FileTest.exists?(daily), + "Did not make daily graph for %s" % type) + end + end else $stderr.puts "Install RRD for metric reporting tests" |