Ajouter des traces avec Byteman

Ne vous est-il jamais arrivé de tomber sur un soucis sur une application en production, le log ne produisant qu’un message abscons (voir aucun message) et ne vous aidant absolument pas à la résolution de votre problème. Bien sûr, comme il s’agit de production, on ne peux pas se permettre de modifier le code (si par hasard il est à notre disposition) et de relivrer afin de rajouter des traces un peu partout.

Comment faire pour s’en sortir ? Avant de vous énerver et de maudire le développeur sur 12 générations, je vous propose de jeter un œil sur Byteman. Byteman va nous permettre de modifier le code compilé à l’aide de règles avant le démarrage de notre programme.

Prenons un exemple simple, voici la classe dans laquelle le problème apparaît :

package org.alexthomazo.blog.byteman;

import java.io.File;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {
	
	private static Logger log = LoggerFactory.getLogger(App.class);
	
	public static void main(String[] args) {
		List<String> files = Arrays.asList("/dir/inexistant", "/other/also-inexistant");
		
		for (String file : files) {
			if (!checkFile(file)) log.warn("File inexistant");
		}
	}
	
	private static boolean checkFile(String filename) {
		return new File(filename).exists();
	}
}

Si on execute cette classe, la sortie console va ressembler à ça :

18:36:56.136 [main] WARN  org.alexthomazo.blog.bm.App - File inexistant
18:36:56.178 [main] WARN  org.alexthomazo.blog.bm.App - File inexistant

On se rend tout de suite compte qu’avec ces logs on ne peut pas déterminer quel fichier est inexistant. C’est ici que Byteman entre en jeu. Il va nous permettre de rajouter une ligne de log lors de l’appel de la méthode checkFile().

Téléchargez la dernière version sur le site de Byteman (binaries + docs) : http://www.jboss.org/byteman/downloads
Même si Byteman ne s’installe pas à proprement parler, il est plus simple de l’utiliser en ajoutant des variables d’environnement :

export BYTEMAN_HOME=/downloaddir/byteman/
export PATH=${PATH}:${BYTEMAN_HOME}/bin
set BYTEMAN_HOME=C:\Downloads\byteman

Ajustez bien sûr le répertoire de téléchargement à l’endroit où vous avez décompressé Byteman.

Byteman fonctionne à l’aide de fichiers décrivant des règles permettant de rajouter du code aux endroits qui nous intéressent. Dans notre cas, nous voulons ajouter un log à l’entrée de la méthode checkFile(). Voici le fichier pour effectuer cela :

RULE display file checked
CLASS App
METHOD checkFile
AT ENTRY
IF true
DO org.alexthomazo.blog.byteman.App.logger.info("checking file [" + $1 + "]" )
ENDRULE

Chaque règle comporte différents attibuts :

  • RULE: Nom de la règle
  • CLASS: Classe sur laquelle ajouter le code
  • METHOD: Méthode sur laquelle ajouter le code
  • AT ENTRY: On souhaite ajouter notre code à l’entrée de la méthode
  • IF: L’exécution du code peut être conditionné, ici nous souhaitons l’exécuter à chaque appel donc on indique true
  • DO: Code a exécuter, $0 représente this, $1 le 1er paramètre de la fonction, $2, le 2ème, etc…
  • ENDRULE: Marqueur de fin de règle

Dans notre exemple la règle est assez simple, on exécute à l’entrée de la méthode checkFile, le code org.alexthomazo.blog.byteman.App.logger.info(« checking file [ » + $1 + « ] » ). Comme logger est une variable statique, nous devons l’appeler à l’aide du nom de sa classe. Si la variable avait été une variable normale, il aurait fallu utiliser $0.logger.

Voyons maintenant comment lancer Byteman. Il existe deux méthodes, la première en spécifiant toutes les options à java, la deuxième en utilisant le script fourni par Byteman. Voici un exemple pour Linux et Windows

$ java -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=script:addlog.btm -jar byteman-test-0.0.1-SNAPSHOT.jar
OU
$ bmjava.sh -l addlog.btm -jar byteman-test-0.0.1-SNAPSHOT.jar
> java -javaagent:%BYTEMAN_HOME%/lib/byteman.jar=script:addlog.btm -jar byteman-test-0.0.1-SNAPSHOT.jar
OU
> bmjava -l addlog.btm -jar byteman-test-0.0.1-SNAPSHOT.jar

Attention, sous Windows vous devez vous assurer d’avoir le répertoire bin de Byteman dans votre path pour exécuter la deuxième méthode.

Voici ce que devrait maintenant afficher la console :

15:46:05.390 [main] INFO  org.alexthomazo.blog.byteman.App - checking file [/dir/inexistant]
15:46:05.404 [main] WARN  org.alexthomazo.blog.byteman.App - File inexistant
15:46:05.404 [main] INFO  org.alexthomazo.blog.byteman.App - checking file [/other/also-inexistant]
15:46:05.405 [main] WARN  org.alexthomazo.blog.byteman.App - File inexistant

Et voilà, vous récupérez le nom du fichier sur lequel le test est effectué et vous pouvez débloquer votre problème 🙂

Si par hasard vous n’avez pas les sources, je vous conseille d’utiliser JD-GUI qui fait du bon boulot pour vous les fournir 😛

La seule petite contrainte à tout ça, c’est qu’il faut au moins Java 6. Même si cela devrait être maintenant assez répandu, il existe encore pas mal de fous qui utilisent encore Java 5 (voir 1.4) :p

N’hésitez pas à creuser dans la doc, il y’a plein d’autres options : http://www.jboss.org/byteman/documentation (comme l’ajout de règle à la volée sur un programme en cours d’exécution)

Laisser un commentaire


NOTE - Vous pouvez utiliser les éléments et attributs HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>