I. Les MBeans (Manageable Beans)

Les MBeans sont des objets contenant les données (métriques) et les méthodes de supervision et d'administration. Ces données peuvent être consultables et/ou modifiables et ces méthodes peuvent être accessibles par la ou les consoles d'administration.

Il existe 4 types de MBean :

  • les MBeans standards qui ont leurs données et méthodes définies au moment de la conception ;
  • les MBeans dynamiques qui ont leurs données et méthodes définies au cours de l'exécution de l'application ;
  • les MBeans ouverts sont des MBeans dynamiques mais qui utilisent des classes normalisées : ainsi l'application de management n'a pas besoin d'avoir accès aux classes des MBeans ouverts de l'agent ;
  • les MBeans modèles qui sont des instances d'un MBean dynamique générique fournis par JMX et configurable.

Chaque MBean peut-être défini persistant en implémentant l'interface PersistentMBeanjavax.management.PersistentMBean (les métriques sont sauvegardés à chaque arrêt de l'agent et rechargés au redémarrage - ceci est particulièrement utile pour les MBeans avec des compteurs qui ne font que s'incrémenter).

Dans cet article nous parlerons uniquement des MBeans standards qui sont les plus utilisés.

Pour définir un MBeans standards, il faut :

  • créer la classe contenant les données (avec un accès via des getters et setters) et les méthodes de supervision et d'administration ;
  • créer l'interface que la classe précédemment créée doit implémenter avec un nom préfixé par le nom de la classe et suffixé par « MBean ».

La classe et son interface doivent se trouver dans le même package.

ExampleMBean.java
Sélectionnez
  1. package org.minetti.example; 
  2.  
  3. public interface ExampleMBean { 
  4.  
  5.     long getCounter (); 
  6.  
  7.     boolean isEnabled (); 
  8.  
  9.     void setEnabled (boolean enabled); 
  10.  
  11. } 
Example.java
Sélectionnez
  1. package org.minetti.example; 
  2.  
  3. public final class Example 
  4.         implements ExampleMBean { 
  5.  
  6.     private long counter = 0; 
  7.  
  8.     private boolean enabled = false; 
  9.  
  10.     public synchronized void incCounter () { 
  11.         this.counter++; 
  12.     } 
  13.  
  14.     public long getCounter () { 
  15.         return this.counter; 
  16.     } 
  17.  
  18.     public boolean isEnabled () { 
  19.         return this.enabled; 
  20.     } 
  21.  
  22.     public void setEnabled (boolean enabled) { 
  23.         this.enabled = enabled; 
  24.     } 
  25.  
  26. } 

Il est possible de fournir une description pour chaque membre du MBean en héritant de la classe StandardMBeanjavax.management.StandardMBean.

Une fois le MBean implémenté, il faut l'enregistrer auprès de l'agent JMX à l'aide de la méthode registerMBean :

Enregistrement du MBean
Sélectionnez
  1. final MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer (); 
  2. final Example mBean = new Example(); 
  3. ObjectName mBeanName = new ObjectName("org.minetti.example:type=Example"); 
  4. jmxServer.registerMBean(mBean, mBeanName); 

La classe ObjectName permet d'indiquer un nom au MBean. Il doit être unique et respecter le formalisme : domaine:key1=value1,key2=value2, … ,keyN=valueN

Il faudra toujours s'arranger pour que le domaine d'un ObjectName soit toujours unique pour chaque application.

Il faudra faire très attention aux applications Web, car celles-ci partagent la même machine virtuelle (JVM) que les autres applications résidentes dans le même serveur d'applications. Or l'agent JMX par défaut est unique par JVM. Cela veut dire que si par exemple vous partagez un JAR contenant des MBeans dans plusieurs applications web qui seront elle-mêmes déployées dans le même serveur d'applications, il y aura des erreurs de doublons au niveau des noms des MBeans.

Contrairement à une idée reçue, les MBeans ne sont pas forcément des singletons. Ainsi une classe peut très bien posséder plusieurs instances.

Pour dés-enregistrer un MBean, on utilise la méthode unregisterMBean :

Dés-enregistrement du MBean
Sélectionnez
  1. jmxServer.unregisterMBean(mBeanName); 

Maintenant, vous pouvez tester l'accès à votre MBean :

  1. Commencez par lancer votre application ;
  2. Dans un terminal tapez JConsole ;
  3. Dans la JConsole, connectez-vous à votre application :
    Image non disponible
  4. Cliquez sur l'onglet MBean ;
  5. En navigant vous devriez voir votre MBean :
    Image non disponible

II. Les notifications

Chaque MBean peut émettre des notifications vers l'agent JMX pour signaler, par exemple, un dysfonctionnement. Ce dernier se chargera de les renvoyer vers les différents clients abonnés aux notifications.

Pour émettre une notification, on créé un objet de la classe Notificationjavax.management.Notification. Les différents constructeurs de cette classe possèdent les paramètres suivants :

  • le type (String) qui indique la nature de la notification (par exemple : enabled.up) ;
  • la source (Object) qui contient généralement l'ObjectNamejavax.management.ObjectName du MBean émetteur de la notification ;
  • le sequenceNumber (long) qui est un numéro de séquence qui doit s'autoincrémenter pour identifier la notification ;
  • le timeStamp (long) qui est le moment où la notification a eu lieu (nombre de millisecondes écoulées depuis le 1er janvier 1970 00:00:00 UTC) ;
  • le message (String) qui contient une explication détaillée sur la notification.

Il est possible d'embarquer d'autres données dans la notification à l'aide de la méthode setUserData(Object). Dans le cas de plusieurs données, on passera à la méthode une Map.

Une fois la notification prête, il faut l'envoyer à l'agent JMX. Pour pouvoir l'envoyer, le MBean doit hériter de la classe NotificationBroadcasterSupportjavax.management.NotificationBroadcasterSupport. Ensuite, il suffit d'appeler la méthode sendNotification(Notification).

Example.java
Sélectionnez
  1. package org.minetti.example; 
  2.  
  3. import java.util.HashMap; 
  4. import java.util.Map; 
  5. import javax.management.MBeanRegistration; 
  6. import javax.management.MBeanServer; 
  7. import javax.management.Notification; 
  8. import javax.management.NotificationBroadcasterSupport; 
  9. import javax.management.ObjectName; 
  10.  
  11. public final class Example 
  12.         extends NotificationBroadcasterSupport 
  13.         implements ExampleMBean, MBeanRegistration { 
  14.  
  15.     private long counter = 0; 
  16.  
  17.     private boolean enabled = false; 
  18.  
  19.     private long sequenceNumber = 0; 
  20.  
  21.     private ObjectName mBeanName; 
  22.  
  23.     public synchronized void incCounter () { 
  24.         this.counter++; 
  25.     } 
  26.  
  27.     public long getCounter () { 
  28.         return this.counter; 
  29.     } 
  30.  
  31.     public boolean isEnabled () { 
  32.         return this.enabled; 
  33.     } 
  34.  
  35.     public synchronized void setEnabled (final boolean enabled) { 
  36.         if (enabled != this.enabled) { 
  37.             this.enabled = enabled; 
  38.             this.sequenceNumber++; 
  39.             Notification notification; 
  40.             if (this.enabled) { 
  41.                 notification = new Notification("enabled.up", this.mBeanName, this.sequenceNumber, "La propriété enabled est à TRUE"); 
  42.             } 
  43.             else { 
  44.                 notification = new Notification("enabled.down", this.mBeanName, this.sequenceNumber, "La propriété enabled est à FALSE"); 
  45.             } 
  46.             Map<String, Object> userDataMap = new HashMap<String, Object>(); 
  47.             userDataMap.put("counter", new Long(this.counter)); 
  48.             userDataMap.put("enabled", new Boolean(this.enabled)); 
  49.             notification.setUserData(userDataMap); 
  50.             sendNotification(notification); 
  51.         } 
  52.     } 
  53.  
  54.     public ObjectName preRegister (final MBeanServer server, final ObjectName name) throws Exception { 
  55.         this.mBeanName = name; 
  56.         return name; 
  57.     } 
  58.  
  59.     public void postRegister (final Boolean registrationDone) { 
  60.         // NOP 
  61.     } 
  62.  
  63.     public void preDeregister () throws Exception { 
  64.         // NOP 
  65.     } 
  66.  
  67.     public void postDeregister () { 
  68.         // NOP 
  69.     } 
  70.  
  71. } 

Dans notre exemple, une notification sera émise à chaque changement de la propriété enabled.

À noter qu'un MBean peut connaître son ObjectNamejavax.management.ObjectName s'il implémente l'interface MBeanRegistrationjavax.management.MBeanRegistration (voir méthode preRegister). Ceci est très utile lorsque notre MBean n'est pas un singleton.

Maintenant, vous pouvez tester l'émission des notifications :

  1. Commencez par lancer votre application ;
  2. Dans un terminal tapez JConsole ;
  3. Dans la JConsole, connectez-vous à votre application ;
  4. Cliquez sur l'onglet MBean ;
  5. Cliquez sur l'élément Notification de votre MBean ;
  6. Cliquez sur le bouton Subscribe pour s'abonner aux notifications ;
  7. En modifiant la propriété enabled, vous devriez voir les notifications qui s'affichent :
    Image non disponible

Avec l'application JConsole, il est possible d'établir des connexions distantes. Pour cela il est impératif d'ajouter l'adaptateur RMI ou JMXMP à l'application à superviser. Il faudra privilégier le protocole JMXMP, car il a l'avantage par rapport à RMI de passer les pare-feux.

III. Le protocole SNMP

Le protocole SNMP est le standard en matière de supervision réseau. Une application qui donne un accès SNMP permet d'être contrôlée par un grand nombre de logiciels de supervision comme Nagios et Cacti.

Contrairement à JMX, l'accès aux différents métriques ne se fait pas par des objets. Tous les métriques sont rangés dans une MIB indexés par un OID. Chaque métrique doit posséder un OID unique composé d'une suite d'entiers. Par exemple l'OID 1.3.6.1.2.1.1.5.0 contient le nom donné au dispositif à superviser.

La MIB est organisée en arbre dont les entiers composant les OID correspondent aux nœuds de l'arbre. Tous les métriques de la MIB se retrouveront au niveau des feuilles de l'arbre.

Image non disponible

Les OID des métriques de type tableau doivent toujours se terminer par l'indice du tableau qui doit commencer par 1. Les OID des autres métriques doivent toujours se terminer par 0.

Le protocole SNMP définit plusieurs types de données :

  • integer32 pour les entiers compris entre -2 147 483 648 et +2 147 483 647 (équivalent du type int en Java) ;
  • unsigned32 et gauge32 pour les entiers compris entre 0 et +4 294 967 295 ;
  • counter32 pour les entiers compris entre 0 et +4 294 967 295 ;
  • counter64 pour les entiers compris entre 0 et +18 446 744 073 709 551 615 ;
  • timeTicks pour exprimer un temps en centièmes de seconde ;
  • octetString et opaque pour les chaînes de caractères ;
  • ipAddress pour les adresses IP ;
  • objectIdentifier pour les OID de la MIB.

Les types counters sont souvent utilisés par les dispositifs SNMP. Ils permettent de déduire des données sous forme de débit. Le principe est de fournir un métrique qui ne fait que s'incrémenter. Par exemple, on pourrait compter le nombre d'octets reçu par une carte réseau. Pour obtenir un débit (par exemple des octets/seconde), les clients SNMP comme Cacti calculent la différence entre 2 points de mesure puis ils le divisent par le temps écoulé entre les 2 mesures.

Le protocole SNMP est muni d'un système permettant aux dispositifs d'envoyer des alertes vers des managers SNMP pour y être traitées. Ces alertes sont appelées « traps ».

Dans la version 1 du protocole SNMP, une trap contient les informations suivantes :

  • enterprise (objectIdentifier) qui contient l'OID du métrique qui a généré la trap ;
  • agent-addr (ipAddress) qui contient l'adresse IP du dispositif SNMP ayant généré la trap ;
  • generic-trap (integer32) qui contient le code générique de la trap (voir plus loin) ;
  • specific-trap (integer32) qui contient le code spécifique de la trap, si generic-trap est égal à enterpriseSpecific ;
  • time-stamp (timeTicks) qui contient le temps écoulé entre la dernière (ré)initialisation de l'entité réseau et la génération du trap (définition selon le RFC 1157) ;
  • variable-bindings (tableau composé d'associations d'OID et de valeurs) qui contient une suite d'informations diverses.

Le champ generic-trap peut prendre l'une des valeurs suivantes :

  • coldStart(0) qui signifie que l'entité de protocole expéditrice se réinitialise de sorte que la configuration de l'agent ou la mise en œuvre de l'entité de protocole peut en être altérée (définition selon le RFC 1157) ;
  • warmStart(1) qui signifie que l'entité de protocole expéditrice se réinitialise de sorte que ni la configuration de l'agent ni la mise en œuvre de l'entité de protocole n'en sont altérées (définition selon le RFC 1157) ;
  • linkDown(2) qui signifie que l'entité de protocole expéditrice reconnaît une défaillance dans une des liaisons de communication représentées dans la configuration de l'agent (définition selon le RFC 1157) ;
  • linkUp(3) qui signifie que l'entité de protocole expéditrice reconnaît qu'une des liaisons de communication représentées dans la configuration de l'agent est rétablie (définition selon le RFC 1157) ;
  • authenticationFailure(4) qui signifie que l'entité de protocole expéditrice est le destinataire d'un message de protocole qui n'est pas correctement authentifié. Alors que les mises en œuvre du protocole SNMP doivent être capables de générer ce trap, elles doivent aussi être capables de supprimer l'émission de tels traps via un mécanisme spécifique de la mise en œuvre (définition selon le RFC 1157) ;
  • egpNeighborLoss(5) qui signifie qu'un voisin EGP pour lequel l'entité de protocole expéditrice était un homologue EGP a été déclassé et que la relation d'homologue n'est plus obtenue (définition selon le RFC 1157) ;
  • enterpriseSpecific(6) qui signifie que l'entité de protocole expéditrice reconnaît qu'un événement spécifique de l'entreprise est survenu. Le champ specific-trap identifie le trap particulier survenu (définition selon le RFC 1157).

Dans la version 2c du protocole SNMP, une trap ne contient plus que l'information suivante :

  • variable-bindings (tableau composé d'associations d'OID et de valeurs) qui contient une suite d'informations diverses.

Pour la plupart des dispositifs SNMP v2, on retrouvera les autres informations dans variable-bindings aux OID suivants :

  • 1.3.6.1.2.1.1.3.0 pour le time-stamp ;
  • 1.3.6.1.6.3.1.1.4.1.0 pour le type de traps (generic-trap et specific-trap - voir plus loin) ;
  • 1.3.6.1.6.3.18.1.3.0 pour l'agent-addr ;
  • 1.3.6.1.6.3.18.1.4.0 pour la communauté ;
  • 1.3.6.1.6.3.1.1.4.3.0 pour l'enterprise.

Le type de traps va prendre l'un des OID suivants :

  • 1.3.6.1.6.3.1.1.5.1 pour generic-trap=coldStart ;
  • 1.3.6.1.6.3.1.1.5.2 pour generic-trap=warmStart ;
  • 1.3.6.1.6.3.1.1.5.3 pour generic-trap=linkDown ;
  • 1.3.6.1.6.3.1.1.5.4 pour generic-trap=linkUp ;
  • 1.3.6.1.6.3.1.1.5.5 pour generic-trap=authenticationFailure ;
  • 1.3.6.1.6.3.1.1.5.6 pour generic-trap=egpNeighborLoss ;
  • autre OID pour specific-trap.

IV. Intégration et configuration de snmpAdaptor4j

Pour commencer, il faut télécharger la dernière version de snmpAdaptor4j.

Décompresser l'archive téléchargée et récupérer les fichiers JAR suivants et les installer dans le CLASSPATH de l'application :

  • /lib/snmpAdaptor4j-jmx-1.1.jar ;
  • /lib/joesnmp-0.3.4.jar ;
  • /lib/log4j-1.2.16.jar.

Mais si vous utilisez Maven, il suffit d'ajouter la dépendance suivante dans votre fichier POM :

pom.xml
Sélectionnez
<dependency>
    <groupId>net.sf.snmpadaptor4j</groupId>
    <artifactId>snmpAdaptor4j-jmx</artifactId>
    <version>1.1</version>
</dependency>

Un adaptateur au niveau de JMX n'est qu'un simple MBean, rien de plus. Comme pour les MBeans, il faut l'enregistrer auprès de l'agent JMX :

Enregistrement de l'adaptateur
Sélectionnez
  1. final MBeanServer jmxServer = ManagementFactory.getPlatformMBeanServer(); 
  2. final URL url = Startup.class.getResource("/snmp.xml"); 
  3. final SnmpAdaptor adaptor = new SnmpAdaptor(url, true); 
  4. ObjectName adaptorName = new ObjectName("org.minetti.example:adaptor=SnmpAdaptor"); 
  5. jmxServer.registerMBean(adaptor, adaptorName); 

Une fois enregistré, il faut démarrer l'adaptateur pour qu'il puisse traiter les requêtes SNMP et envoyer des traps SNMP :

Démarrage de l'adaptateur
Sélectionnez
  1. adaptor.start(); 

Ensuite nous devons créer le fichier de configuration de l'adaptateur snmp.xml qui doit ressembler à ceci :

snmp.xml
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<snmpAdaptor4j-config
  xmlns="http://www.sf.net/snmpAdaptor4j/config/1.1"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.sf.net/snmpAdaptor4j/config/1.1
                      http://snmpAdaptor4j.sourceforge.net/xsd/snmpAdaptor4j-config-1.1.xsd">

  <daemon address="127.0.0.1" port="161" version="2">
    <readCommunity>public</readCommunity>
    <writeCommunity>private</writeCommunity>
  </daemon>

  <managers>
    <manager address="127.0.0.1" port="162" version="1" community="public"/>
  </managers>

  <roots default="1.3.6.1.4.1.99.12.8.1"/>

  <mbeans>
    <mbean name="org.minetti.example:type=Example" oid="1.1"/>
  </mbeans>

</snmpAdaptor4j-config>

Lors de la génération du JAR de votre projet, ce fichier devra se trouver à la racine.

Le tag daemon contient tous les paramétrages du serveur SNMP embarqué dans l'adaptateur. Il permet l'accès aux attributs des MBeans via le protocole SNMP.

Le tag managers contient les paramètres de connexion pour chaque manager SNMP qui devra recevoir et traiter les traps SNMP.

Le tag roots permet d'indiquer la racine de tous les OID utilisé dans l'application. Il est possible d'en indiquer plusieurs. Ici, tous nos OID commenceront par 1.3.6.1.4.1.99.12.8.1.

Et enfin le tag mbeans contient tous les MBeans qui devront être gérés par l'adaptateur. Pour chaque MBean on indiquera son OID qui fait suite à l'OID racine du tag roots. Ici, les OID de tous les attributs de notre MBean commenceront donc par 1.3.6.1.4.1.99.12.8.1.1.1.

Et pour finir nous devons créer pour chaque MBean un fichier qui doit ressembler à ceci :

Example.snmp.xml
Sélectionnez
<?xml version="1.0" encoding="utf-8"?>
<snmpAdaptor4j-mapping
  xmlns="http://www.sf.net/snmpAdaptor4j/mapping/1.1"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.sf.net/snmpAdaptor4j/mapping/1.1
                      http://snmpAdaptor4j.sourceforge.net/xsd/snmpAdaptor4j-mapping-1.1.xsd">

  <attributes>
    <attribute name="counter" type="counter64" node="1"/>
    <attribute name="enabled" type="integer32" node="2" writable="true"/>
  </attributes>

  <notifications>
    <enterprise node="2" userdata="userDataMap">
      <generic-trap notif-type="enabled.up" code="linkUp"/>
      <generic-trap notif-type="enabled.down" code="linkDown"/>
    </enterprise>
    <variable-bindings system-info="true">
      <sequence-number node="100"/>
      <message node="101"/>
      <userdata-map name="userDataMap">
        <entry key="counter" type="counter64" node="1"/>
        <entry key="enabled" type="integer32" node="2"/>
      </userdata-map>
    </variable-bindings>
  </notifications>

</snmpAdaptor4j-mapping>

Ce fichier doit se trouver dans le même package que le MBean. Son nom doit être composé du nom de la classe du MBean et se terminer par .snmp.xml (dans notre exemple il se nommera Example.snmp.xml).

Dans ce fichier, nous déclarons tous les attributs de notre MBean. Ils auront les OID suivants :

  • 1.3.6.1.4.1.99.12.8.1.1.1.1.0 pour counter (node à 1) ;
  • 1.3.6.1.4.1.99.12.8.1.1.1.2.0 pour enabled (node à 2).

La propriété writable indique que l'attribut enabled pourra être modifié via le protocole SNMP. Par défaut, les attributs ne sont pas modifiables.

Le type de donnée SNMP doit correspondre avec le type de donnée Java :

Types de données Java Types de données SNMP
integer32 unsigned32
gauge32
counter32
counter64 timeTicks octetString
opaque
ipAddress objectIdentifier
boolean (1)            
byte X X          
short X X          
int X X          
long   X X (2)      
BigInteger     X        
String         X X X
byte[]         X    
InetAddress           X  
SnmpOid             X
N'importe quel objet         Lecture uniquement    

(1) Pour le type booléen, la valeur TRUE correspond à la valeur 1 et la valeur FALSE correspond à la valeur 2.

(2) Pour le type timeTicks, la donnée Java doit être exprimée en millisecondes alors que la donnée SNMP doit être exprimée en centièmes de seconde.

Le tag notifications contient tous les paramètres nécessaires pour convertir une notification JMX en une trap SNMP.

Ici notre notification, émise à chaque changement de l'attribut enabled, va générer une trap SNMP générique linkUp ou linkDown avec l'OID 1.3.6.1.4.1.99.12.8.1.1.1.2.0 dans le champ enterprise (node à 2 dans le tag enterprise). On remarquera que la valeur du champ enterprise correspond à l'OID de l'attribut enabled.

Le tag variable-bindings contient toutes les règles pour peupler le champ variable-bindings de la trap SNMP. Ici nous allons retrouver les informations suivantes :

  • le numéro de séquence de la notification à l'OID 1.3.6.1.4.1.99.12.8.1.1.1.100.0 ;
  • le message de la notification à l'OID 1.3.6.1.4.1.99.12.8.1.1.1.101.0 ;
  • la valeur de l'élément counter de la map stockée dans le champ userData, à l'OID 1.3.6.1.4.1.99.12.8.1.1.1.1.0 (contenu de l'attribut counter) ;
  • la valeur de l'élément enabled de la map stockée dans le champ userData, à l'OID 1.3.6.1.4.1.99.12.8.1.1.1.2.0 (contenu de l'attribut enabled).

Mais nous retrouverons aussi les informations suivantes à propos de l'application (system-info=true) :

  • le nom de l'application à l'OID 1.3.6.1.2.1.1.5.0 (system.sysName.0) ;
  • la description de l'application à l'OID 1.3.6.1.2.1.1.1.0 (system.sysDescr.0) ;
  • la localisation de l'application à l'OID 1.3.6.1.2.1.1.6.0 (system.sysLocation.0) ;
  • le contact administrant l'application à l'OID 1.3.6.1.2.1.1.4.0 (system.sysContact.0).

Le code suivant permet de positionner les valeurs de ces informations :

Mise à jour des informations sur l'application
Sélectionnez
  1. adaptor.getSystemInfo().setSysName("Example"); 
  2. adaptor.getSystemInfo().setSysDescr("Application test JMX avec SNMP"); 
  3. adaptor.getSystemInfo().setSysLocation("Ordinateur local"); 
  4. adaptor.getSystemInfo().setSysContact("Administrateur <root@localhost>"); 

À noter qu'il est possible d'inscrire l'objet SystemInfo comme un MBean :

Enregistrement du MBean SystemInfo
Sélectionnez
  1. ObjectName name = new ObjectName("org.minetti.example:class=SystemInfo"); 
  2. jmxServer.registerMBean(adaptor.getSystemInfo(), name); 

V. Tests

Une fois l'intégration et la configuration de l'adaptateur SNMP terminée, nous devons faire quelques tests pour s'assurer que tout fonctionne.

Pour commencer, installer Net-SNMP.

Lancer votre application Java et taper la commande suivante :

 
Sélectionnez
snmpwalk -v2c -Os -c public 127.0.0.1 .1

Qui doit retourner ceci :

 
Sélectionnez
sysDescr.0 = STRING: Application test JMX avec SNMP
sysObjectID.0 = OID: enterprises.99.12.8.1
sysUpTimeInstance = Timeticks: (8228) 0:01:22.28
sysContact.0 = STRING: Administrateur <root@localhost>
sysName.0 = STRING: Example
sysLocation.0 = STRING: Ordinateur local
enterprises.42.2.145.3.163.1.1.1.1.0 = Gauge32: 1594
enterprises.42.2.145.3.163.1.1.1.2.0 = Counter64: 1594
enterprises.42.2.145.3.163.1.1.1.3.0 = Counter64: 0
enterprises.42.2.145.3.163.1.1.2.1.0 = Gauge32: 0
enterprises.42.2.145.3.163.1.1.2.10.0 = Counter64: 16777216
enterprises.42.2.145.3.163.1.1.2.11.0 = Counter64: 3513432
enterprises.42.2.145.3.163.1.1.2.12.0 = Counter64: 16252928
enterprises.42.2.145.3.163.1.1.2.13.0 = Counter64: 259522560
enterprises.42.2.145.3.163.1.1.2.20.0 = Counter64: 35815424
enterprises.42.2.145.3.163.1.1.2.21.0 = Counter64: 17118008
enterprises.42.2.145.3.163.1.1.2.22.0 = Counter64: 36405248
enterprises.42.2.145.3.163.1.1.2.23.0 = Counter64: 123731968
enterprises.42.2.145.3.163.1.1.3.1.0 = Gauge32: 7
enterprises.42.2.145.3.163.1.1.3.2.0 = Gauge32: 4
enterprises.42.2.145.3.163.1.1.3.3.0 = Counter32: 7
enterprises.42.2.145.3.163.1.1.3.4.0 = Counter64: 7
enterprises.42.2.145.3.163.1.1.3.5.0 = Counter64: 7
enterprises.42.2.145.3.163.1.1.4.1.0 = STRING: "3936@cheops"
enterprises.42.2.145.3.163.1.1.4.2.0 = STRING: "Java HotSpot(TM) Client VM"
enterprises.42.2.145.3.163.1.1.4.3.0 = STRING: "Sun Microsystems Inc."
enterprises.42.2.145.3.163.1.1.4.4.0 = STRING: "20.5-b03"
enterprises.42.2.145.3.163.1.1.4.5.0 = STRING: "Java Virtual Machine Specification"
enterprises.42.2.145.3.163.1.1.4.6.0 = STRING: "Sun Microsystems Inc."
enterprises.42.2.145.3.163.1.1.4.7.0 = STRING: "1.0"
enterprises.42.2.145.3.163.1.1.4.8.0 = STRING: "1.2"
enterprises.42.2.145.3.163.1.1.4.11.0 = Counter64: 82641
enterprises.42.2.145.3.163.1.1.4.12.0 = Counter64: 1363799834968
enterprises.42.2.145.3.163.1.1.5.1.0 = STRING: "Windows XP"
enterprises.42.2.145.3.163.1.1.5.2.0 = STRING: "x86"
enterprises.42.2.145.3.163.1.1.5.3.0 = STRING: "5.1"
enterprises.42.2.145.3.163.1.1.5.4.0 = INTEGER: 2
enterprises.99.12.8.1.1.1.1.0 = Counter64: 2
enterprises.99.12.8.1.1.1.2.0 = INTEGER: 2
End of MIB

Cette commande permet de lister tous le contenu de la MIB. Vous devriez voir vos métriques à partir de l'OID 1.3.6.1.4.1.99.12.8.1.1.1.

Pour tester l'envoi de traps SNMP, nous devons mettre en place un agent chargé de les traiter. Nous utiliserons snmptrapd fourni avec Net-SNMP.

Configurer l'agent snmptrapd. Pour cela le fichier /etc/snmp/snmptrapd.conf doit contenir la ligne suivante :

snmptrapd.conf
Sélectionnez
authCommunity log,execute,net public

Ici, toutes les traps reçues seront tracées dans un fichier logs (syslog ou /var/log/snmptrapd.log).

  1. Démarrer l'agent snmptrapd.
  2. démarrer votre application.
  3. modifier la propriété enabled.

Le fichier de logs devrait ressembler à ceci :

snmptrapd.log
Sélectionnez
Created directory: C:/progra~1/netsnmp/snmp/persist/mib_indexes
NET-SNMP version 5.7
gethostbyname not available
2013-03-21 11:05:02 192.168.0.229(via UDP: [127.0.0.1]:3182->[0.0.0.0]:0) TRAP, SNMP v1, community public
    SNMPv2-SMI::enterprises.99.12.8.1.1.1.2.0 Link Up Trap (0) Uptime: 375 days, 5:40:40.19
    SNMPv2-SMI::enterprises.99.12.8.1.1.1.2.0 = INTEGER: 1    SNMPv2-MIB::sysDescr.0 = STRING: Application test JMX avec SNMP    SNMPv2-SMI::enterprises.99.12.8.1.1.1.1.0 = Counter64: 0    SNMPv2-MIB::sysName.0 = STRING: Example    SNMPv2-MIB::sysLocation.0 = STRING: Ordinateur local    SNMPv2-SMI::enterprises.99.12.8.1.1.1.100.0 = Gauge32: 1    SNMPv2-MIB::sysContact.0 = STRING: Administrateur <root@localhost>    SNMPv2-SMI::enterprises.99.12.8.1.1.1.101.0 = STRING: "La propriété enabled est à TRUE"
2013-03-21 11:05:04 192.168.0.229(via UDP: [127.0.0.1]:3182->[0.0.0.0]:0) TRAP, SNMP v1, community public
    SNMPv2-SMI::enterprises.99.12.8.1.1.1.2.0 Link Down Trap (0) Uptime: 375 days, 5:40:42.34
    SNMPv2-SMI::enterprises.99.12.8.1.1.1.2.0 = INTEGER: 2    SNMPv2-MIB::sysDescr.0 = STRING: Application test JMX avec SNMP    SNMPv2-SMI::enterprises.99.12.8.1.1.1.1.0 = Counter64: 0    SNMPv2-MIB::sysName.0 = STRING: Example    SNMPv2-MIB::sysLocation.0 = STRING: Ordinateur local    SNMPv2-SMI::enterprises.99.12.8.1.1.1.100.0 = Gauge32: 2    SNMPv2-MIB::sysContact.0 = STRING: Administrateur <root@localhost>    SNMPv2-SMI::enterprises.99.12.8.1.1.1.101.0 = STRING: "La propriété enabled est à FALSE"

Ici, nous voyons que l'agent SNMP a reçu 2 traps :

  • une trap Link Up lorsque l'attribut enabled a été mis à TRUE ;
  • et une trap Link Down lorsque l'attribut enabled a été rebasculé à FALSE.

VI. Conclusion

Comme nous l'avons vu, superviser une application Java n'est pas vraiment compliquée. L'intégration d'un adaptateur SNMP est un véritable plus permettant ainsi l'exploitation de nos métriques à travers des applications comme Nagios et Cacti.

snmpAdaptor4j est un adaptateur SNMP très simple à intégrer. La mise en œuvre du protocole SNMP pour chaque métrique se fait à l'aide de fichiers XML sans aucun ajout de codes au niveau des MBeans. De plus, il prend en compte les notifications JMX pour les transcrire en traps SNMP.

Vous pouvez télécharger l'exemple présenté dans cet article.

VII. Liens

VIII. Remerciements

Je tiens à remercier keulkeul pour sa relecture technique et l'aide qu'il m'a apporté pour mon 1er article, ainsi que zoom61 par sa relecture.