Le support natif de SNMP est arrivé avec le JDK 5 d’Oracle, en même temps que les autres outils de gestion de la JVM comme jconsole, jps ou jstat. Cet article a été rédigé (et testé) avec le JRE/JDK 8 d’Oracle, mais il devrait être applicable à toutes les versions depuis la 5, à quelques détails près. En revanche, il ne s’applique pas à OpenJDK qui n’a pas le support de SNMP.
D’autres solutions, plus souples, peuvent être utilisées pour publier des informations depuis Java en SNMP, mais elles ne sont pas traitées dans cet article. Seule la technique de publication native à la JVM d’Oracle est abordée.
Configuration Java
Options de la JVM
La JVM d’Oracle offre la possibilité de publier des informations sur son fonctionnement par SNMP (en version 2c). Le support de SNMP est activé avec des propriétés système qui ressemblent beaucoup à celles pour JMX.
-
Définir le port
-Dcom.sun.management.snmp.port=8161
-
Définir le binding IP
-Dcom.sun.management.snmp.interface=0.0.0.0
-
Désactiver l’utilisation d’ACL
-Dcom.sun.management.snmp.acl=false
-
OU définir le fichier ACL
-Dcom.sun.management.snmp.acl.file=snmp.acl
Le fichier ACL contient une portion acl et une portion trap. Dans la portion acl, on définit d’abord les communities qui serviront aux clients pour se connecter. Pour chaque community, on donne un droit d’accès : read-only ou read-write. Enfin, on précise les managers, sous la forme d’une liste de hostnames, d’adresses IP ou de masques IP, qui auront le droit d’accéder.
acl = {
{
communities = monitor, tomcat
access = read-only
managers = localhost
}
{
communities = admin
access = read-write
managers = localhost
}
}
Ce fichier ne doit être accessible que par l’utilisateur qui exécute le process Java, en lecture et éventuellement en écriture :
chmod 400 snmp.acl
Avec ces options, le process Java ouvre le port 8161, en UDP. Vous pouvez le vérifier avec netstat :
netstat -pln | grep 8161
Attention, tout ce qui a été décrit ici ne marche pas avec OpenJDK. La partie SNMP du JDK d’Oracle n’a pas été portée dans OpenJDK.
Intégration dans Tomcat
Dans Tomcat, on utilise le fichier $CATALINA_HOME/bin/setenv.sh pour renseigner les propriétés système, en les mettant dans la variable d’environnement CATALINA_OPTS.
Ce fichier peut prendre la forme suivante :
CATALINA_OPTS="-Dcom.sun.management.snmp.port=8161 -Dcom.sun.management.snmp.acl.file=$CATALINA_HOME/conf/snmp.acl"
Données accessibles
Informations publiées
Le fichier MIB Java définit de façon statique les informations modifiables et celles qui sont consultables. Les informations qui me semblent les plus intéressantes sont les suivantes :
-
jvmMemoryHeapMaxSize : mémoire heap maximale (-Xmx)
-
jvmMemoryHeapInitSize : mémoire heap initiale (-Xms)
-
jvmMemoryHeapCommitted : mémoire heap allouée
-
jvmMemoryHeapUsed : mémoire heap utilisée
-
jvmMemoryNonHeapMaxSize : mémoire non-heap maximale
-
jvmMemoryNonHeapInitSize : mémoire non-heap initiale
-
jvmMemoryNonHeapCommitted : mémoire non-heap allouée
-
jvmMemoryNonHeapUsed : mémoire non-heap utilisée
-
jvmMemGCCount.3 et jvmMemGCCount.4 : nombre de collections
-
jvmMemGCTimeMs.3 et jvmMemGCTimeMs.4 : temps pris par les collections
-
jvmMemManagerName.3 et jvmMemManagerName.4 : noms des collecteurs (les suffixes 1 et 2 sont utilisés pour le CodeCache et le Metaspace)
-
jvmThreadCount : nombre de threads
-
jvmRTUptimeMs : uptime
On peut aussi avoir des informations sur les différentes zones de la heap (jvmMemPoolName.N, jvmMemPoolInitSize.N, jvmMemPoolUsed.N, jvmMemPoolCommitted.N, jvmMemPoolMaxSize.N), sur les threads (jvmThreadInstName.N, jvmThreadInstCpuTimeNs.N, jvmThreadInstLockName.N,…).
Informations modifiables
Pour savoir quelles données sont modifiables, il faut faire une recherche sur "read-write" dans le MIB. On trouve par exemple la verbosité du GC (jvmMemoryGCVerboseLevel) ou le flag de monitoring de la CPU (jvmThreadCpuTimeMonitoring).
Comment tester ?
Pour interroger la JVM et lui demander ses informations SNMP, j’ai utilisé les outils Net-SNMP en ligne de commande sur Ubuntu. Pour qu’ils fonctionnent correctement, il faut les installer et ajouter les fichiers de définitions MIB qui ne sont pas installés par défaut.
sudo apt-get install snmp snmp-mibs-downloader
sudo wget --directory-prefix=/usr/share/snmp/mibs/ http://docs.oracle.com/javase/8/docs/jre/api/management/JVM-MANAGEMENT-MIB.mib
Tester avec snmpwalk
On peut maintenant interroger notre process pour avoir toutes les informations :
snmpwalk -v2c -c tomcat localhost:8161 .
Les deux options passées ici sont obligatoires : -v pour la version de SNMP (2c, ici) et -c pour la community.
Les informations ne sont pas très lisibles car cette commande utilise des identifiants numériques (OID) pour chaque objet, comme par exemple iso.3.6.1.4.1.42.2.145.3.163.1.1.2.110.1.21.2
. Pour que ce soit plus lisible et que snmpwalk affiche des identifiants textuels (comme jvmMemGCCount.3) il faut indiquer le MIB à snmpwalk :
snmpwalk -v2c -m JVM-MANAGEMENT-MIB -c tomcat localhost:8161 .
Pour interroger une ressource précise, on remplace le '.' par un identifiant d’objet, sous forme numérique ou textuelle.
snmpwalk -v2c -m JVM-MANAGEMENT-MIB -c tomcat localhost:8161 jvmThreadDaemonCount
ou
snmpwalk -v2c -c tomcat localhost:8161 JVM-MANAGEMENT-MIB::jvmThreadDaemonCount
Cette dernière commande donne un résultat qui doit ressemble à ça :
JVM-MANAGEMENT-MIB::jvmThreadDaemonCount.0 = Gauge32: 12
On retrouve dans cette réponse l’OID, préfixé par le MIB, avec le type de la valeur (Gauge32) et la valeur elle-même. On peut affiner cette sortie avec l’option -O pour éliminer l’identifiant (-Ov), le type (-OQ) ou l’unité (-OU). La commande suivante affiche uniquement la valeur :
snmpwalk -v2c -OvUQ -c tomcat localhost:8161 JVM-MANAGEMENT-MIB::jvmThreadDaemonCount
Tester avec snmpget
snmpget a une syntaxe et un fonctionnement très proches de snmpwalk. La différence entre les deux réside dans la capacité à obtenir une liste d’objets. Par exemple les arguments passés à la JVM ont tous un OID qui commence par .1.3.6.1.4.1.42.2.145.3.163.1.1.4.20.1.2. Avec snmpwalk, en interrogeant ce nœud, on les obtient tous.
snmpwalk -v2c -m JVM-MANAGEMENT-MIB -c tomcat localhost:8161 .1.3.6.1.4.1.42.2.145.3.163.1.1.4.20.1.2
En revanche, on ne peut pas utiliser snmpget pour ce nœud. Il ne fonctionne que sur les objets de terminaison.
snmpget -v2c -m JVM-MANAGEMENT-MIB -c tomcat localhost:8161 .1.3.6.1.4.1.42.2.145.3.163.1.1.4.20.1.2.1
snmpget -v2c -m JVM-MANAGEMENT-MIB -c tomcat localhost:8161 .1.3.6.1.4.1.42.2.145.3.163.1.1.4.20.1.2.2
snmpget -v2c -m JVM-MANAGEMENT-MIB -c tomcat localhost:8161 .1.3.6.1.4.1.42.2.145.3.163.1.1.4.20.1.2.3
...
Tester avec snmpset
Pour que la commande snmpset fonctionne, il faut l’utiliser avec une community qui a des droits read-write (admin dans l’exemple d’ACL ci-dessus). La syntaxe de snmpset ressemble à celle de snmpget, à la différence prêt qu’après l’OID, on précise le type de valeur et la valeur qu’on veut enregistrer.
Par exemple, pour activer les traces des garbage collectors :
snmpset -v2c -m JVM-MANAGEMENT-MIB -c admin localhost:8161 jvmMemoryGCVerboseLevel.0 i 2