5 votes

L'utilisation de this.getClass dans les traits Scala

Est-ce que quelqu'un peut expliquer pourquoi ce code fonctionne de cette manière? Je voulais créer ma propre preuve de concept de trait Loggable. Le plan était d'instancier une instance de logger afin que les classes héritées n'aient pas à faire ce travail. Mais apparemment ce n'est pas ce que je voulais.

Voici le code :

package hu.jonas.simple

trait Loggable {
  val logger = java.util.logging.Logger.getLogger(this.getClass.getName)

  def whoAmI = {
    logger.info(this.getClass.getName)
  }
}

class Service extends Loggable {
  def answer = {
    whoAmI
  }
}

object Main extends App {
  new Service().answer
}

Cela a produit le message suivant dans le journal :

25 janv. 2013 14:02:07 hu.jonas.simple.Loggable$class whoAmI
INFO: hu.jonas.simple.Service

Pourquoi les deux this.getClass.getName sont-ils différents? Et de plus que devrais-je écrire lorsque j'instancie le logger afin d'obtenir ceci :

25 janv. 2013 14:02:07 hu.jonas.simple.Service whoAmI
INFO: hu.jonas.simple.Service

4voto

Régis Jean-Gilles Points 14463

Dans votre code, les deux occurrences de getClass.getName renvoient la même valeur. Mais le logger, lors de la mise en forme du message de sortie, utilise simplement la classe source (qu'il peut connaître en inspectant la pile) au lieu du nom du logger (qui, dans votre cas, correspond à getClass.getName). Ainsi, le logger utilise le nom de la classe où l'appel à log est effectué pour émettre l'en-tête de l'enregistrement de journal, tandis que le contenu du message de journal est le nom de la classe d'exécution de l'instance. Il s'agit donc d'une question de type statique par rapport à d'exécution. Si vous vous demandez d'où vient Loggable$class, il se trouve simplement que les implémentations de méthode dans un trait nommé T sont situées dans une classe JVM nommée T$class.

Et maintenant, pour une illustration. Dans le code ci-dessous, je change le gestionnaire de journalisation afin d'effacer les informations de la classe source. Cela oblige le logger à utiliser le nom du logger au lieu du nom de la classe source, et vous retrouvez le comportement que vous attendiez.

import java.util.logging._
trait Loggable {
  val logger = Logger.getLogger(this.getClass.getName)

  logger.getParent.getHandlers.foreach{ handler => 
    val formatter = handler.getFormatter
    handler.setFormatter( new java.util.logging.Formatter {
      def format( record: LogRecord ) = {
        record.setSourceClassName( null )
        formatter.format( record )
      }
    })
  }

  def whoAmI = {
    logger.info(this.getClass.getName)
  }
}

class Service extends Loggable {
  def answer = {
    whoAmI
  }
}

object Main extends App {
  new Service().answer
}

Maintenant, pour résoudre correctement votre problème, il existe une propriété nommée java.util.logging.SimpleFormatter.format que vous pouvez définir pour modifier la mise en forme de journal par défaut. Utilisez-la pour que le journal utilise le nom du logger au lieu de la classe source. Voir http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/SimpleFormatter.html. Notez que cela nécessite Java 7.

0voto

jcern Points 7599

Ce que vous regardez ici est la méthode qui a appelé le journal, pas nécessairement la classe du journal. Dans votre cas, il s'agit de Loggable.whoAmI. La classe instanciée est de type hu.jonas.simple.Service, mais comme la méthode est sur Loggable, c'est ce qui s'affiche. Ces informations sont généralement récupérées en parcourant la pile d'appels.

Dans l'exemple ci-dessous, vous obtiendrez les mêmes résultats en extrayant la pile d'appels vous-même :

trait Loggable { 
  val logger = java.util.logging.Logger.getLogger(this.getClass.getName)

  def whoAmI = {
    val stackTrace = Thread.currentThread.getStackTrace();
    logger.info("Classe: %s, Méthode: %s".format(stackTrace(1).getClassName, 
      stackTrace(1).getMethodName))
    logger.info(this.getClass.getName)
  }
}

Cela donnera le résultat suivant :

Jan 25, 2013 9:39:28 AM $line99.$read$$iw$$iw$Loggable$class whoAmI
INFO: Classe: $line99.$read$$iw$$iw$Loggable$class, Méthode: whoAmI

Jan 25, 2013 9:39:28 AM $line99.$read$$iw$$iw$Loggable$class whoAmI
INFO: $line100.$read$$iw$$iw$Service

Comme vous pouvez le voir, cela correspond à ce que le Logger affiche. Si vous continuez à descendre dans la pile d'appels, vous verrez que vous pouvez accéder à la hiérarchie des appels avec stackTrace(3), ce qui finira par donner :

Jan 25, 2013 9:43:58 AM $line107.$read$$iw$$iw$Loggable$class whoAmI
INFO: Classe: $line108.$read$$iw$$iw$Service, Méthode: answer

Je ne suis pas sûr exactement comment modifier cela avec java.util.Logger mais comme indiqué dans une autre réponse - peut-être l'utilisation d'un formateur peut vous donner le résultat souhaité. Sinon, vous pourriez essayer un autre moteur de journalisation ou créer le vôtre avec les informations ci-dessus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X