27 votes

connexion à scala

En Java, l'idiome standard pour l'enregistrement est de créer une variable statique pour un enregistreur de l'objet et de l'utiliser dans les diverses méthodes.

En Scala, il ressemble à l'idiome est de créer un enregistrement trait avec un enregistreur de membre et mixin le trait dans les classes de béton. Cela signifie que chaque fois qu'un objet est créé, il appelle la journalisation pour obtenir un enregistreur et également l'objet est plus en raison de la référence supplémentaire.

Est-il une alternative qui permet la facilité d'utilisation de la "Journalisation", tout en utilisant une par classe logger exemple?

EDIT: Ma question n'est pas comment on peut écrire une journalisation dans Scala, mais plutôt d'en utiliser un existant (log4j) sans encourir de frais généraux de performance (obtenir une référence pour chaque instance) ou de la complexité du code. Aussi, oui, je veux utiliser log4j, tout simplement parce que je vais utiliser la 3ème partie des bibliothèques écrites en Java qui sont susceptibles d'utiliser log4j.

17voto

Kevin Wright Points 31665

Je venais tout juste de coller à la "Journalisation" approche. Nettoyer le design gagne à chaque fois - si vous obtenez le passe-partout de la route, alors les chances sont que vous pouvez trouver beaucoup plus utile gains réalisables dans d'autres domaines.

Gardez à l'esprit que l'enregistrement cadre de la mise en cache sera bûcherons, donc vous avez encore un par classe, même si chaque instance de cette classe qui arrive à tenir une (peu coûteux) de référence.

Sans avoir la preuve que l'enregistreur de références sont de nuire à votre tas, cela sent un peu comme l'optimisation prématurée... détendez-vous et ne vous inquiétez pas à ce sujet, à moins qu'un profiler vous dit le contraire.

Sur une autre note, vous pouvez aussi rechercher dans l'aide de slf4j et logback au lieu de log4j. slf4j a un nettoyeur de design qui s'intègre mieux avec idiomatiques scala.

9voto

davetron5000 Points 9622

J'ai utilisé log4j avec Scala par la création d'un trait et d'avoir l'enregistreur de par des par des instances non par classe. Avec quelques Scala de la magie, et elle se manifeste, vous pourriez être en mesure de modifier l'enregistreur à être statique (objet interne), mais je ne suis pas sûr à 100%. Personnellement, je suis d'accord avec @KevinWright que faire de l'enregistreur de données statique est une optimisation prématurée.

Notez également que le code ci-dessous contient le journal de messages que de nom, ce qui signifie que votre enregistreur d'appels n'ont pas besoin d'être enveloppé dans `si (log.isDebugEnabled()); complexe des messages de journal créé par la concaténation de chaîne ne sera pas évalué à moins que le niveau de journalisation est approprié. Voir ce lien pour plus d'info: http://www.naildrivin5.com/scalatour/wiki_pages/TypeDependentClosures

http://github.com/davetron5000/shorty/blob/master/src/main/scala/shorty/Logs.scala

package shorty

import org.apache.log4j._

trait Logs {
  private[this] val logger = Logger.getLogger(getClass().getName());

  import org.apache.log4j.Level._

  def debug(message: => String) = if (logger.isEnabledFor(DEBUG)) logger.debug(message)
  def debug(message: => String, ex:Throwable) = if (logger.isEnabledFor(DEBUG)) logger.debug(message,ex)
  def debugValue[T](valueName: String, value: => T):T = {
    val result:T = value
    debug(valueName + " == " + result.toString)
    result
  }

  def info(message: => String) = if (logger.isEnabledFor(INFO)) logger.info(message)
  def info(message: => String, ex:Throwable) = if (logger.isEnabledFor(INFO)) logger.info(message,ex)

  def warn(message: => String) = if (logger.isEnabledFor(WARN)) logger.warn(message)
  def warn(message: => String, ex:Throwable) = if (logger.isEnabledFor(WARN)) logger.warn(message,ex)

  def error(ex:Throwable) = if (logger.isEnabledFor(ERROR)) logger.error(ex.toString,ex)
  def error(message: => String) = if (logger.isEnabledFor(ERROR)) logger.error(message)
  def error(message: => String, ex:Throwable) = if (logger.isEnabledFor(ERROR)) logger.error(message,ex)

  def fatal(ex:Throwable) = if (logger.isEnabledFor(FATAL)) logger.fatal(ex.toString,ex)
  def fatal(message: => String) = if (logger.isEnabledFor(FATAL)) logger.fatal(message)
  def fatal(message: => String, ex:Throwable) = if (logger.isEnabledFor(FATAL)) logger.fatal(message,ex)
}

class Foo extends SomeBaseClass with Logs {
  def doit(s:Option[String]) = {
    debug("Got param " + s)
    s match {
      case Some(string) => info(string)
      case None => error("Expected something!")
    } 
  }
}

4voto

Geoff Reedy Points 16508

Si vous êtes vraiment préoccupé par l'espace généraux et/ou du temps supplémentaire dans les initialiseurs d'objets, une bonne stratégie peut être d'avoir un enregistrement trait de caractère qui laisse l'enregistreur de données abstraites comme dans


trait Logging {
  def logger: Logger
  def debug(message: String) { logger.debug(message) }
  def warn(message: String) { logger.warn(message) }
}

Pour les classes qui doivent être aussi légers que possible, alors vous pouvez le faire


object MustBeLightweight {
  val logger = Logger.getLog(classOf[MustBeLightweight])
}
class MustBeLightWeight extends Logging {
  final def logger = MustBeLightweight.logger
}

L'équipe pourrait même inline debug warn et logger dans ce cas.

Vous pouvez également avoir un trait de mélanger dans les classes où la surcharge d'un champ supplémentaire n'est pas un problème


trait PerInstanceLog {
  val logger = Logger.getLog(this.getClass())
}

Une autre option est de laisser la déconnexion de la classe et le mettre dans un objet que dans


object Foo {
  object log extends Logging {
    override val logger = Logger.getLogger(classOf[Foo])
  } 
}

class Foo {
  import Foo.log._
  def someMethod() = { warn("xyz") }
}

Je suis d'accord avec Kevin, bien que, ne pas ajouter de la complexité à moins que vous en avez besoin.

3voto

F0RR Points 337
 object Log {
    def log(message: String) = {
        .....
    }
}
 

Non?

2voto

Arnold deVos Points 61

Parfois, la journalisation au niveau du package est la bonne réponse. Scala rend cela plus facile que de java, car les objets peuvent être définis directement dans un package. Si vous avez défini un Journal comme ceci:

package example 
object Log extends au.com.langdale.util.PackageLogger 

Ce Journal est disponible partout dans l'exemple de forfait. Pour obtenir plus fine de la journalisation, vous pouvez disperser des significations similaires autour de la hiérarchie des paquets. Ou vous pouvez définir tous les colis enregistreurs ensemble comme ceci:

package example {
  import au.com.langdale.util.PackageLogger

  object Log extends PackageLogger 

  package frobber {
    object Log extends PackageLogger 

    package undulater {
      object Log extends PackageLogger
    } 
  }
}

Le PackageLogger classe peut être définie comme suit (en supposant que SLF4J):

package au.com.langdale.util
import org.slf4j.LoggerFactory

class PackageLogger {
  val name = { val c = getClass.getName; c.substring(0, c.lastIndexOf('.')) }
  val inner = LoggerFactory.getLogger(name)

  // various convenient logging methods follow....
  def apply( mesg: => Any ) = inner.info(mesg.toString)
  def info( mesg: String ) = inner.info(mesg)
  def warn( mesg: String ) = inner.warn(mesg)
  def error( mesg: String ) = inner.error(mesg)
}

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