diff --git a/plugins/other/tomcat b/plugins/other/tomcat new file mode 100755 index 00000000..db63ce69 --- /dev/null +++ b/plugins/other/tomcat @@ -0,0 +1,283 @@ +#!/usr/bin/ruby +# +# Plugin to monitor the Tomcat servers. +# +# Original Author: Rune Nordboe Skillingstad +# Rewrite: laxis 2008.05 +# +# Requirements: +# - Needs access to http://:@localhost:8080/manager/status?XML=true (or modify the +# address for another host). A munin-user in $CATALINA_HOME/conf/tomcat-users.xml +# should be set up for this to work. +# - libxml-ruby +# +# Install: +# - copy script to /etc/munin +# - cd /etc/munin +# - ./tomcat install +# +# Tip: To see if it's already set up correctly, just run this plugin +# with the parameter "autoconf". If you get a "yes", everything should +# work like a charm already. +# +# tomcat-users.xml example: +# +# +# Parameters supported: +# +# config +# autoconf +# install +# +# Configurable variables +# +# host - Destination host +# port - HTTP port numbers +# timeout - Connection timeout +# request - Override default status-url +# user - Manager username +# password - Manager password +# connector - Connector to query, defaults to "http-".$PORT +# +# Sample config: +# [tomcat_*] +# env.host 127.0.0.1 +# env.port 8080 +# env.request /manager/status?XML=true +# env.user munin +# env.password pass +# env.timeout 30 +# env.connector jk-8009 +# +# Magic markers: +#%# family=auto +#%# capabilities=autoconf + + +require 'net/http' +require 'xml/libxml' + +@host = ENV.member?('host') ? ENV['host']: "127.0.0.1" +@port = ENV.member?('port') ? ENV['port']: 8080 +@request = ENV.member?('request') ? ENV['request']: "/manager/status?XML=true" +@user = ENV.member?('user') ? ENV['user']: "munin" +@password = ENV.member?('password') ? ENV['password']: "munin" +@timeout = ENV.member?('timeout') ? ENV['timeout']: 30 +@connector = ENV.member?('connector') ? ENV['connector']: "http-#{@port}"; + +# hash +w = { + "jvmMemory" => { "max" => "U", + "total" => "U", + "used" => "U" }, + "threadInfo" => { "maxThreads" => "U", + "currentThreadCount" => "U", + "currentThreadsBusy" => "U" }, + "requestMaxTime" => { "maxTime" => "U" }, + "requestTime" => { "avgTime" => "U" }, + "requestCount" => { "requestCount" => "U", + "errorCount" => "U" }, + "requestBytes" => { "bytesReceived" => "U", + "bytesSent" => "U" } + } + +# http request +def getstat() + Net::HTTP.start(@host, @port) do |http| + http.open_timeout = @timeout + req = Net::HTTP::Get.new(@request) + req.basic_auth @user, @password + response = http.request(req) + response.value() + return response.body + end rescue begin + return false + end +end + +def autoconf() + begin + if getstat() + puts "yes" + return 0 + end + rescue + puts "no (#{$!})" + return 1 + end +end + +if ARGV[0] == "autoconf" + exit autoconf() +end + +if ARGV[0] == "install" + exit if autoconf() != 0 + Dir["plugins/tomcat*"].each { |f| + print "removing #{f}\n" + File.unlink f + } + w.each { |k, v| + print "installing plugins/tomcat_#{k}\n" + File.symlink "../tomcat", "plugins/tomcat_#{k}" if ! FileTest.symlink? "plugins/tomcat_#{k}" + } + exit +end + +# open stderr +e = IO.new(2, "w") + +mode = $0.gsub /.*\/tomcat_/, "" +if mode =~ /tomcat/ then + e.puts "Invalid mode" + exit 1 +end + +# munin config request +if ARGV[0] == "config" + puts "graph_title tomcat_#{mode}" + puts "graph_args -l 0 --base 1000" + #print "graph_order " + #w[mode].each { |k, v| + #print "#{k} " + #} + #puts + case mode + when "jvmMemory" + puts "graph_category tomcat" + puts "graph_vlabel bytes" + puts "graph_order max total used" + w[mode].each { |k, v| + puts "#{k}.label #{k}" + puts "#{k}.type GAUGE" + puts "#{k}.min 0" + puts "#{k}.draw AREA" + } + when "requestCount" + puts "graph_category tomcat" + puts "graph_order requestCount errorCount" + puts "graph_vlabel Request / sec" + w[mode].each { |k, v| + puts "#{k}.label #{k}" + puts "#{k}.type COUNTER" + puts "#{k}.min 0" + puts "#{k}.draw AREA" if k == "requestCount" + puts "#{k}.draw LINE2" if k != "requestCount" + } + when "requestBytes" + puts "graph_category tomcat" + puts "graph_vlabel bytes in (-) / out (+) per ${graph_period}" + w[mode].each { |k, v| + puts "#{k}.label #{k}" + puts "#{k}.type DERIVE" + puts "#{k}.min 0" + puts "#{k}.graph no" if k == "bytesReceived" + puts "#{k}.negative bytesReceived" if k == "bytesSent" + + } + when "requestMaxTime" + puts "graph_category tomcat" + puts "graph_vlabel sec" + w[mode].each { |k, v| + puts "#{k}.label #{k}" + puts "#{k}.type GAUGE" + puts "#{k}.min 0" + puts "#{k}.draw LINE2" + } + when "requestTime" + puts "graph_category tomcat" + puts "graph_vlabel Average RequestTime (sec) / Request" + w[mode].each { |k, v| + puts "#{k}.label #{k}" + puts "#{k}.type GAUGE" + puts "#{k}.min 0" + puts "#{k}.draw LINE2" + } + when "threadInfo" + puts "graph_category tomcat" + puts "graph_order maxThreads currentThreadCount currentThreadsBusy" + w[mode].each { |k, v| + puts "#{k}.label #{k}" + puts "#{k}.type GAUGE" + puts "#{k}.min 0" + puts "#{k}.draw AREA" + } + end + exit 0 +end + + +# XML parsolasa +begin + parser = XML::Parser.string(getstat()) + doc = parser.parse +end rescue begin + e.puts "Parse error" + exit 1 +end + +# root element kivalasztasa +root = doc.root +if root.name != "status" + e.puts "Invalid XML" + exit 1 +end + +# copy jvm memory datas to hash +node = doc.find('//status/jvm/memory').first +w["jvmMemory"]["used"] = node.property("total").to_i - node.property("free").to_i +w["jvmMemory"]["total"] = node.property("total") +w["jvmMemory"]["max"] = node.property("max") + +# copy connector datas to hash +doc.find('//status/connector').each do |node| +if node.property("name") == @connector + node.each do |child| + if child.name == "threadInfo" + w["threadInfo"]["maxThreads"] = child.property("maxThreads") + w["threadInfo"]["currentThreadCount"] = child.property("currentThreadCount") + w["threadInfo"]["currentThreadsBusy"] = child.property("currentThreadsBusy") + end + if child.name == "requestInfo" + w["requestMaxTime"]["maxTime"] = child.property("maxTime") + w["requestTime"]["avgTime"] = sprintf "%.2f", (child.property("processingTime").to_f / child.property("requestCount").to_f / 1000) + w["requestCount"]["requestCount"] = child.property("requestCount") + w["requestCount"]["errorCount"] = child.property("errorCount") + w["requestBytes"]["bytesReceived"] = child.property("bytesReceived") + w["requestBytes"]["bytesSent"] = child.property("bytesSent") + end + end + end +end + +# print result +w[mode].each do |k, v| + printf "#{k}.value %s\n", v +end + +# XML Output: +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +#