mercredi 23 juin 2010

Supervision de WebLogic à l'aide de nagios

Afin de surveiller la consommation mémoire de nos instances WebLogic, j'ai commencé à écrire un plugin se basant sur le protocole SNMP.

Pour ceux qui ne le saurait pas, WebLogic est un serveur d'application Java propriétaire.

Ce besoin de surveillance vient du fait que les serveurs les hébergeants (des Sun V890 avec 40 Go de mémoire) sont sur le point d'arriver à saturation mémoire. Pour cette raison, nous avons donc essayé de savoir quelles instances consommées et à quelle hauteur.

Il faut dire que nous avons constaté que la mémoire allouée aux JVMs étaient le double de la mémoire physique ! Pour info, la machine héberge une centaine d'instance WebLogic en version 8.1 et Java 1.4. Comme vous vous en doutez, nous avons prévu de faire le ménage dans nos instances. Mais pour ça, il nous faudrait un petit état des lieux, d'où l'écriture d'un script.

Passons maintenant à l'écriture du script.

Premier point, il faut se débrouiller pour activer l'agent SNMP au niveau du domaine WebLogic. Nous pourrons ainsi interroger le serveur sans avoir à faire de couteuses interrogations à base de programme en java. Nous allons ensuite nous baser sur l'outil snmpwalk.

Pour mémoire, une page de référence de la MIB de ce serveur d'application est disponible à l'adresse suivante : http://download.oracle.com/docs/cd/E13222_01/wls/docs90/snmp/index.html

Commençons tout d'abord par interroger l'agent SNMP WebLogic en ligne de commande :
drayan@robinet:~$ snmpwalk -m ./BEA-WEBLOGIC-MIB.mib -c public -v 1 192.168.0.10:7061 .1.3.6.1.4.1.140.625.180
La branche .1.3.6.1.4.1.140.625.180 correspond aux informations sur les threads Java actifs. Nous pouvons également interroger la branche .1.3.6.1.4.1.140.625.340.1 pour récupérer la quantité de mémoire consommée (jvmRuntimeHeapSizeCurrent). A noter que pour connaître les instances présentes dans le domaine WebLogic, je fais appel à la branche 1.3.6.1.4.1.140.625.361.1.

Une fois enrobé tout ceci j'obtiens le script suivant :
#!/usr/bin/perl
use strict;
use File::Basename;
use Sys::Hostname;
use Getopt::Long;

my $verbose = 0;
my $show_help = 0;
my $show_version = 0;
my $snmp_address = 0;
my $instance = 0;
my $snmp_cmd = "snmpwalk -m ".dirname($0)."/../share/BEA-WEBLOGIC-MIB.mib";
my $show_only = ".*";

sub usage {
my ($msg) = @_;
$msg = "" if(!$msg);
my $name = basename($0);
print "Usage :
\$ $name [OPTION]

Get runtime information about WebLogic instance
-h --help display this help and exit.
--intance <SRVNAME>[,<>] name of the instances to check.
--only <REGEXP> show only instance corresponding to regexp.
--snmp <HOST[:PORT]> address (and port) of the snmp server.
-v --verbose verbose.

Examples:
\$ $name --port 10861 --instance srvback11,srvback12,srvback13,srvback14
".($msg ? "\n".$msg."\n" : "")
}

GetOptions(
"V" => \$show_version,
"version" => \$show_version,
"h" => \$show_help,
"help" => \$show_help,
"v" => \$verbose,
"verbose" => \$verbose,
"snmp=s" => \$snmp_address,
"instance=s" => \$instance,
"only=s" => \$show_only,
);

if($show_help) { usage(); exit(0); }
die("Please specify snmp address (--snmp host:port)") if(!$snmp_address);

if(!$instance) {
my(%instance_name, %instance_state) = ((), ());
my @tmp = ();
my ($i, $j) = (0, 0);
foreach(`$snmp_cmd -c public -v 1 $snmp_address 1.3.6.1.4.1.140.625.361.1 2> /dev/null`) {
if(/BEA-WEBLOGIC-MIB::serverLifeCycleRuntimeName.*STRING: "(\w+)"/) {
$instance_name{$i++} = $1;
} elsif(/BEA-WEBLOGIC-MIB::serverLifeCycleRuntimeState.*STRING: "(\w+)"/) {
my $label = $instance_name{$j++};
$instance_state{$label} = $1;
if($1 =~ /RUNNING/) {
print "$label is RUNNING\n" if($verbose);
push(@tmp, $label);
} else {
print "Ignoring $label\n" if($verbose);
}
}
}
$instance = join(",", @tmp);
}

my $perfdata = "";
foreach my $srv(sort(split(/,/, $instance))) {
next if(!($srv =~ /$show_only/));
my @result = `$snmp_cmd -c public\@$srv -v 1 $snmp_address .1.3.6.1.4.1.140.625.340.1 2> /dev/null`;
my($label, $current_max_heap, $free_heap);
foreach(@result) {
if(/BEA-WEBLOGIC-MIB::jvmRuntimeName.*STRING:\s+"(\w+)"/) { $label = $1; }
elsif(/BEA-WEBLOGIC-MIB::jvmRuntimeHeapFreeCurrent.*INTEGER:\s+(\d+)/) { $free_heap = $1; }
elsif(/BEA-WEBLOGIC-MIB::jvmRuntimeHeapSizeCurrent.*INTEGER:\s+(\d+)/) {
$current_max_heap = $1;
$current_max_heap = int($current_max_heap / 1048576 + .5);
$free_heap = int($free_heap / 1048576 + .5);
my $used = $current_max_heap - $free_heap;
$perfdata .= " $label=$used;$current_max_heap;$current_max_heap;0;$current_max_heap";
}
}
}

print "WebLogic memory OK|$perfdata\n";
On configure notre agent pour accepter un nouveau type de commande :
command[check_weblogic_memory]=/usr/lib/nagios/plugins/check_weblogic --snmp localhost:7061
On configure un nouveau service sous Nagios :
define service {
host_name machine-weblogic
use generic-service
service_description Suivi memoire WebLogic
check_command check_nrpe!check_weblogic_memory
}
Et hop ! Au bout de quelques jours, vous obtenez le résultat suivant (en combinaison avec pnp4nagios) :