Le débogage d'application web est pénible et qui n'a pas été usé par l'utilisation intensive de traces qui au final n'apporte rien, si ce n'est de pourrir un peu plus l'application et la rendre encore moins performante qu'avant...
Une des solutions pour remédier au problème est probablement le débogage à distance. Celui qui concernera le plus de monde sera probablement le débogage d'une application web sous Tomcat. Elle est très simple à mettre en place. Il suffit d'activer JPDA au niveau de la JVM qui lance le conteneur java et d'indiquer le port sur lequel le client de débogage (Eclipse) pourra se connecter.
Les options JVM sont généralement les suivantes :
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044
Avec suspend=y le conteneur doit attendre la connection d'un client pour se lancer. Ceci permet de déboguer depuis le tout début du lancement du serveur d'application.
En fait, les scripts de tomcat contiennent déjà tout cela et il suffit en fait de placer au tout début du script $TOMCAT_HOME/catalina.sh les variables d'environnement suivantes :
JPDA_ADDRESS=10088
JPDA_TRANSPORT=dt_socket
JPDA_SUSPEND=n

Remarques :

  1. on laissera de côté le script $TOMCAT_HOME/startup.sh qui n'apporte pas grand chose si ce n'est trouver le bon exécutable catalina... ensuite on ne peut pas lui passer le paramètre jpda car celui-ci doit être placé DEVANT "start"
  2. on peut aussi mettre ces variables dans l'environnement utilisateur, mais il est préférable de garder cet environnement uniquement pour ce serveur en évitant d'imposer ces valeurs pour d'autres instances de serveur (par exemple si vous avez un serveur de test et de pré-prod sur la même machine sous le même nom d'utilisateur...)

Le script contient ensuite cette partie

if [ "$1" = "jpda" ] ; then
  if [ -z "$JPDA_TRANSPORT" ]; then
    JPDA_TRANSPORT="dt_socket"
  fi
  if [ -z "$JPDA_ADDRESS" ]; then
    JPDA_ADDRESS="8000"
  fi
  if [ -z "$JPDA_SUSPEND" ]; then
    JPDA_SUSPEND="n"
  fi
  if [ -z "$JPDA_OPTS" ]; then
    JPDA_OPTS="-Xdebug -Xrunjdwp:transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND"
  fi
  CATALINA_OPTS="$CATALINA_OPTS $JPDA_OPTS"
  shift
fi

Ensuite il suffit de démarrer Tomcat en ajoutant l'argument "jpda" de la façon suivante :
bin/catalina.sh jpda start

On peut vérifier les options réellement passées à la JVM avec :
$ ps -ef | grep java
tomcat 9699 1 6 00:21 pts/0 00:00:04 /opt/java6/bin/java -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file=/srv/tomcat525/conf/logging.properties -Xdebug -Xrunjdwp:transport=dt_socket,address=10088,server=y,suspend=n -Djava.endorsed.dirs=/srv/tomcat525/common/endorsed -classpath :/srv/tomcat525/bin/bootstrap.jar:/srv/tomcat525/bin/commons-logging-api.jar -Dcatalina.base=/srv/tomcat525 -Dcatalina.home=/srv/tomcat525 -Djava.io.tmpdir=/srv/tomcat525/temp org.apache.catalina.startup.Bootstrap start

ou encore avec

$ jps -v

Lorsque vous redémarrez votre serveur tomcat vous devriez avoir en entête du fichier de log ceci :

Listening for transport dt_socket at address: 10088


Il est alors possible de s'y connecter avec Eclipse :

  1. Aller dans Run > Open debug dialogue > Remote Java Application
  2. Créer une nouvelle configuration (clic sur l'icône avec un + en haut à gauche)
  3. Configuration : nom de la configuration
  4. Project : choisir le projet concerné
  5. Connection type : standard socket (par défaut et seul choix)
  6. Connection properties : le nom d'hôte du serveur exécutant tomcat et le port 10088
  7. Les autres onglets ont généralement les bonnes valeurs par défaut
  8. Valider avec "Apply"
  9. cliquer sur "Debug" pour lancer une session de debug

Dans la perspective Debug il y a dans une fenêtre à gauche une description des processus et à droite les variables et les breakpoints. Sur la fenêtre des breakpoints, il peut être utile d'indiquer au debugger de s'arrêter en plus de certaines lignes (double cliquer dans la marge d'une ligne de code pour placer un breakpoint) sur certaines exceptions : cliquer sur l'icône "J!" et ajouter par exemple l'exception NullPointerException

Le debugger s'arrêtera sur l'exception et vous montrera à quelle ligne dans votre code! Un très bon lien qui m'a permis de mettre en place ce remote debugging
et qui présente aussi d'autre conteneurs et d'autres méthodes de débogage. Mais attention! ce lien est bogué car il met JDPA or c'est bien JPDA qu'il faut utiliser! Sinon un autre lien un peu vieillissant car sur Java 1.4 : Debugging J2EE applications mais les exemples ci-dessus ont été réalisé sur java 6...

L'autre fonction intéressante du debugger est l'arrêt sur condition (conditional breakpoint) qu'il est possible d'activer avec un clic droit sur le breakpoint -> breakpoint properties. A partir de là il suffit d'écrire la condition et l'activer, puis relancer le cours de l'exécution.