#!/usr/bin/perl #%# family=auto #%# capabilities=autoconf suggest # # This is a munin plugin to monitor java instances (old generation memory, garbage collection stats etc) # It uses jps and jstat to fetch information. These tools work reliably with jdk6 and work with jdk1.5 # Author: Oles Hnatkevych # # Parameters: # # config # autoconf # suggest # # Configuration variables # # Global environment variables: # # JVMS - list of instances to monitor, example: env.JVMS confluence jira fisheye # JAVA_HOME - Override location of JDK, example: env.JAVA_HOME /usr/java/jdk1.6.0_06 # WGET - path to wget binary, example: env.WGET /usr/bin/wget # if WGET is defined, then it will be used to trigger a script that performs garbage collection # # Environment variables per instance: # # JVM__PID - path to file that contains PID of running java process to monitor # JVM__USER - username to swith to before runnint jstat and jps # JVM__JPSRE - regular expression (substring) to filter jps output to find pid of target jvm # JVM__JAVAHOME - if defined, overrides JAVA_HOME for that instance # JVM__GCURL - if defined along with WGET, wget will trigger fetching of that URL (to force garbage collection) # # Either PID or JPSRE must be defined to find PID # To force garbage collection you can create a file gc.jsp with just one row and put into ROOT directory of Apache Tomcat # <% System.gc(); %> # # Example of configuration in plugins-conf.d/jvm2 # # [jvm2_*] # user root # env.JVMS confluence jira # env.JAVA_HOME /usr/java/jdk1.6.0_06 # env.WGET /usr/bin/wget # # env.JVM_confluence_PID /home/confluence/catalina-base/temp/catalina.pid # env.JVM_confluence_USER confluence # env.JVM_confluence_GCURL http://localhost:19180/gc.jsp # # env.JVM_confluence_JPSRE /home/confluence/catalina-base/ # # env.JVM_confluence_JAVAHOME /usr/java/jdk1.6.0_06 # # env.JVM_jira_PID /home/jira/catalina-base/temp/catalina.pid # env.JVM_jira_USER jira # env.JVM_jira_GCURL http://localhost:19280/gc.jsp # # env.JVM_jira_JPSRE /home/jira/catalina-base/ # # env.JVM_jira_JAVAHOME /usr/java/jdk1.6.0_06 # # use strict; no strict "refs"; my $JVMS = $ENV{JVMS}; my $JAVA_HOME = $ENV{JAVA_HOME}; my $WGET = $ENV{WGET}; my $JVM_PIDFILE; my $GC_URL; my $JVM_USER='root'; my $JPS_RE; my $COMMAND = "jps -lv"; my $COMMAND2 = "jstat"; my $jvm_pid; my @GC=(); my @GCCAP=(); my $arg = shift; my $testname; my $jvmname; #----------------------------------------------- if ($arg eq 'autoconf') { if ($JVMS ne "" ) { print "yes\n"; exit 0; } else { print "no\n"; exit 1; } } #----------------------------------------------- if ($arg eq "suggest") { foreach my $jvm (split(/\s+/,$JVMS)) { print "${jvm}_gcold\n"; print "${jvm}_gcoldpc\n"; print "${jvm}_gctime\n"; print "${jvm}_gccap\n"; } exit; } #----------------------------------------------- if ($0 =~ /jvm2_(\w+)_(gcold|gctime|gccap|gcoldpc)$/) { $jvmname = $1; $testname = $2; if ($ENV{"JVM_${jvmname}_PID"}) { $JVM_PIDFILE = $ENV{"JVM_${jvmname}_PID"}; } if ($ENV{"JVM_${jvmname}_JAVAHOME"}) { $JAVA_HOME = $ENV{"JVM_${jvmname}_JAVAHOME"}; } if ($ENV{"JVM_${jvmname}_JPSRE"}) { $JPS_RE = $ENV{"JVM_${jvmname}_JPSRE"}; } if ($ENV{"JVM_${jvmname}_USER"}) { $JVM_USER = $ENV{"JVM_${jvmname}_USER"}; } if ($ENV{"JVM_${jvmname}_USER"}) { $JVM_USER = $ENV{"JVM_${jvmname}_USER"}; } if ($ENV{"JVM_${jvmname}_GCURL"}) { $GC_URL = $ENV{"JVM_${jvmname}_GCURL"}; } if ($JPS_RE eq "" && $JVM_PIDFILE eq "") { print STDERR "No definitions for $jvmname!\n"; exit 1; } } else { print STDERR "Not proper script name: $0\n"; exit 1; } #----------------------------------------------- if ($arg eq 'config') { my $funcname = "print_config_${testname}"; if (defined &$funcname) { &$funcname(); exit; } else { print STDERR "No config for $testname was defined\n"; exit 1; } exit; } #----------------------------------------------- $jvm_pid = get_jvm_pid(); get_status(); if ($testname eq "gcold") { print "oc.value ".(int ($GC[6] * 1024))."\n"; print "ou.value ".(int ($GC[7] * 1024))."\n"; } elsif ($testname eq "gcoldpc") { print "oldpc.value ".(int (100 * $GC[7] / $GC[6]))."\n"; } elsif ($testname eq "gctime") { print "ygct.value ".(int (@GC[11] * 1000))."\n"; print "fgct.value ".(int (@GC[13] * 1000))."\n"; print "gct.value " .(int (@GC[14] * 1000))."\n"; } elsif ($testname eq "gccap") { print "ec.value ". (int (@GCCAP[5] * 1024))."\n"; print "s0c.value ".(int (@GCCAP[3] * 1024))."\n"; print "s1c.value ".(int (@GCCAP[4] * 1024))."\n"; print "pc.value ". (int (@GCCAP[13] * 1024))."\n"; } else { print STDERR "No processing for test $testname\n"; exit 1; } #----------------------------------------------- sub print_config_gcold { print <; # first line is legend @GC = split /\s+/, ; close(SERVICE); $cmd = "/bin/su -m $JVM_USER -c \"$JAVA_HOME/bin/$COMMAND2 -gccapacity $jvm_pid\" |"; open(SERVICE, $cmd) or die("Could not execute $cmd: $!"); ; # first line is legend @GCCAP = split /\s+/, ; close(SERVICE); } #----------------------------------------------- sub get_jvm_pid { my $pid = 0; if ($JVM_PIDFILE ne "") { $pid = `cat $JVM_PIDFILE`; $pid =~ /(\d+)/; $pid = $1; # print STDERR "pid by pidfile: $pid\n"; return $pid; #-------------------------- } my @jps = split(/\n/,`$JAVA_HOME/bin/$COMMAND`); foreach my $line (@jps) { next if ($line =~ /sun\.tools\.jps\.Jps/); # skip our jps itself if ($JPS_RE ne "") { next unless ($line =~ /$JPS_RE/); } next unless ($line =~ /^(\d+) (\S+)/); $pid = $1; } # print STDERR "pid by regexp: $pid\n"; return $pid; }