web-dev-qa-db-fra.com

Se connecter Scala

Quel est un bon moyen de vous connecter à une application Scala?)? Quelque chose qui est cohérent avec la philosophie de la langue, n'encombre pas le code, et nécessite peu de maintenance et est discret. Voici une liste d'exigences de base :

  • simple
  • n'encombre pas le code. Scala est excellent pour sa brièveté. Je ne veux pas que la moitié de mon code soit une instruction de journalisation
  • le format de journal peut être modifié pour s’adapter au reste des journaux de mon entreprise et du logiciel de surveillance
  • prend en charge les niveaux de journalisation (débogage, trace, erreur)
  • peut se connecter au disque ainsi qu’à d’autres destinations (socle, console, etc.)
  • configuration minimale, le cas échéant
  • fonctionne dans des conteneurs (serveur Web, par exemple)
  • (facultatif, mais agréable à avoir) vient soit dans le cadre du langage, soit en tant qu'artéfact maven, je n'ai donc pas à pirater mes versions pour l'utiliser.

Je sais que je peux utiliser les solutions de journalisation Java existantes), mais elles échouent sur au moins deux des solutions ci-dessus, à savoir l'encombrement et la configuration.

Merci pour vos réponses.

160
George

emballages slf4j

La plupart des bibliothèques de journalisation de Scala ont été intégrées à un (= $) cadre de journalisation Java (slf4j, log4j, etc.)), mais depuis mars 2015, les bibliothèques de journaux restantes sont toutes slf4j. Ces bibliothèques de journaux fournissent une sorte de log objet auquel vous pouvez appeler info(...), debug(...), etc. Je ne suis pas un grand fan de slf4j, mais il semble maintenant que ce soit la journalisation prédominante Voici la description de SLF4J :

La façade de journalisation simple pour Java ou (SLF4J) sert de façade simple ou d’abstraction pour divers structure de journalisation souhaitée au moment du déploiement.

La possibilité de modifier la bibliothèque de journaux sous-jacente au moment du déploiement confère une caractéristique unique à la famille des enregistreurs slf4j, que vous devez connaître:

  1. classpath comme approche de configuration . Slf4j sait quelle bibliothèque de journalisation sous-jacente vous utilisez en chargeant une classe par un nom. J'ai eu des problèmes dans lesquels slf4j ne reconnaissait pas mon enregistreur lorsque classloader était personnalisé.
  2. Étant donné que la façade simple essaie d’être le dénominateur commun, elle est limitée aux seuls appels de journaux. En d'autres termes, la configuration ne peut pas être effectuée via le code.

Dans un grand projet, il pourrait être pratique de pouvoir contrôler le comportement de journalisation des dépendances transitives si tout le monde utilisait slf4j.

Scala Logging

Scala Logging est écrit par Heiko Seeberger comme successeur de son slf4s . Il utilise la macro pour développer les appels dans if si pour éviter les appels de journal potentiellement coûteux.

La journalisation Scala est une bibliothèque de journalisation commode et performante qui encapsule des bibliothèques de journalisation telles que SLF4J et éventuellement d’autres.

Enregistreurs historiques

  • Logula , un wrapper Log4J écrit par Coda Hale. Utilisé pour aimer celui-ci, mais maintenant il est abandonné.
  • configgy , un wrapper Java.util.logging qui était populaire dans les premiers jours de Scala. Maintenant abandonné.
117
Eugene Yokota

With Scala 2.10+ Envisagez ScalaLogging by Typesafe. Utilise des macros pour fournir une API très propre.

https://github.com/typesafehub/scala-logging

Citant de leur wiki:

Heureusement, des macros Scala peuvent être utilisées pour nous simplifier la vie: ScalaLogging offre à la classe Logger des méthodes de journalisation allégées qui seront étendues à l'idiome précédent. Tout ce que nous avons à écrire est:

logger.debug(s"Some ${expensiveExpression} message!")

Une fois la macro appliquée, le code aura été transformé en idiome décrit ci-dessus.

De plus, ScalaLogging offre le trait Logging qui fournit commodément une instance de Logger initialisée avec le nom de la classe mélangée dans:

import com.typesafe.scalalogging.slf4j.LazyLogging

class MyClass extends LazyLogging {
  logger.debug("This is very convenient ;-)")
}
62
fracca

Utiliser slf4j et un wrapper est agréable, mais l'utilisation de son interpolation intégrée s'interrompt lorsque vous avez plus de deux valeurs à interpoler, car vous devez alors créer un tableau de valeurs à interpoler.

Une solution similaire = Scala) consiste à utiliser un thunk ou un cluster pour retarder la concaténation du message d'erreur. Un bon exemple en est le journal de Lift.

Log.scalaSlf4jLog.scala

Qui ressemble à ceci:

class Log4JLogger(val logger: Logger) extends LiftLogger {
  override def trace(msg: => AnyRef) = if (isTraceEnabled) logger.trace(msg)
}

Notez que msg est un appel par nom et qu'il ne sera pas évalué à moins que isTraceEnabled soit à true, il est donc inutile de générer une chaîne de message Nice. Cela fonctionne autour du mécanisme d'interpolation de slf4j qui nécessite l'analyse du message d'erreur. Avec ce modèle, vous pouvez interpoler un nombre quelconque de valeurs dans le message d'erreur.

Si vous avez un trait distinct qui mélange ce Log4JLogger à votre classe, alors vous pouvez faire

trace("The foobar from " + a + " doesn't match the foobar from " +
      b + " and you should reset the baz from " + c")

au lieu de

info("The foobar from {0} doesn't match the foobar from {1} and you should reset the baz from {c},
     Array(a, b, c))
14
Blair Zajac

Ne pas utiliser Logula

En fait, j'ai suivi la recommandation d'Eugene et l'ai essayée et découvert qu'elle avait une configuration maladroite et qu'elle était sujette à des bogues non corrigés (comme celui-ci ). Il ne semble pas être bien entretenu et il ne supporte pas Scala 2.10 .

Utilisez slf4s + slf4j-simple

Avantages clés:

  • Prend en charge les derniers Scala 2.10 (à ce jour, c'est M7)
  • La configuration est polyvalente, mais ne pourrait être plus simple. C'est fait avec propriétés système , que vous pouvez définir en ajoutant quelque chose comme -Dorg.slf4j.simplelogger.defaultlog=trace À la commande d'exécution ou au code fixe dans votre script: System.setProperty("org.slf4j.simplelogger.defaultlog", "trace"). Pas besoin de gérer les fichiers de configuration Trashy!
  • S'adapte bien aux IDE. Par exemple, pour définir le niveau de consignation sur "trace" dans une configuration d'exécution spécifique dans IDEA, accédez simplement à Run/Debug Configurations Et ajoutez -Dorg.slf4j.simplelogger.defaultlog=trace À VM options.
  • Configuration facile: il suffit de déposer les dépendances à partir du bas de cette réponse

Voici ce que vous devez exécuter avec Maven:

<dependency>
  <groupId>com.weiglewilczek.slf4s</groupId>
  <artifactId>slf4s_2.9.1</artifactId>
  <version>1.0.7</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
  <version>1.6.6</version>
</dependency>
12
Nikita Volkov

Voici comment j'ai obtenu Scala Logging pour moi:

Mettez ceci dans votre build.sbt:

libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2",
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"

Ensuite, après avoir effectué un sbt update, Ceci affiche un message de journal convivial:

import com.typesafe.scalalogging._
object MyApp extends App with LazyLogging {
  logger.info("Hello there")
}

Si vous utilisez Play, vous pouvez bien sûr simplement import play.api.Logger Pour écrire les messages du journal: Logger.debug("Hi").

Voir le docs pour plus d'informations.

11
Matthias Braun

J'ai tiré un peu de travail du trait Logging de scalax et créé un trait intégrant également un MessageFormat-based bibliothèque.

Alors ça ressemble un peu à ça:

class Foo extends Loggable {
    info( "Dude, I'm an {0} with {1,number,#}", "Log message", 1234 )
}

Nous aimons l'approche jusqu'à présent.

La mise en oeuvre:

trait Loggable {

    val logger:Logger = Logging.getLogger(this)

    def checkFormat(msg:String, refs:Seq[Any]):String =
        if (refs.size > 0) msgfmtSeq(msg, refs) else msg 

    def trace(msg:String, refs:Any*) = logger trace checkFormat(msg, refs)

    def trace(t:Throwable, msg:String, refs:Any*) = logger trace (checkFormat(msg, refs), t)

    def info(msg:String, refs:Any*) = logger info checkFormat(msg, refs)

    def info(t:Throwable, msg:String, refs:Any*) = logger info (checkFormat(msg, refs), t)

    def warn(msg:String, refs:Any*) = logger warn checkFormat(msg, refs)

    def warn(t:Throwable, msg:String, refs:Any*) = logger warn (checkFormat(msg, refs), t)

    def critical(msg:String, refs:Any*) = logger error checkFormat(msg, refs)

    def critical(t:Throwable, msg:String, refs:Any*) = logger error (checkFormat(msg, refs), t)

}

/**
 * Note: implementation taken from scalax.logging API
 */
object Logging {  

    def loggerNameForClass(className: String) = {  
        if (className endsWith "$") className.substring(0, className.length - 1)  
        else className  
    }  

    def getLogger(logging: AnyRef) = LoggerFactory.getLogger(loggerNameForClass(logging.getClass.getName))  
}
7
Tristan Juricek

J'utilise SLF4J + Logback classic et l'applique comme ceci:

trait Logging {
  lazy val logger = LoggerFactory.getLogger(getClass)

  implicit def logging2Logger(anything: Logging): Logger = anything.logger
}

Ensuite, vous pourrez l’utiliser selon votre style:

class X with Logging {
    logger.debug("foo")
    debug("bar")
}

mais cette approche utilise bien sûr une instance de consignateur par instance de classe.

6
Kristof Jozsa

Vous devriez jeter un coup d'œil à la bibliothèque scalax: http://scalax.scalaforge.org/ Dans cette bibliothèque, il existe un trait de journalisation, utilisant sl4j en tant que backend. En utilisant ce trait, vous pouvez vous connecter assez facilement (utilisez simplement le champ logger de la classe héritant du trait).

4
Gilles

Writer, Monoid et une implémentation de Monad.

4
Tony Morris

Je n'ai pas encore essayé, mais Configgy semble prometteur pour la configuration et la journalisation:

http://github.com/robey/configgy/tree/master

3
dberesford

Formulaires rapides et faciles.

Scala 2.10 et plus vieux:

import com.typesafe.scalalogging.slf4j.Logger
import org.slf4j.LoggerFactory
val logger = Logger(LoggerFactory.getLogger("TheLoggerName"))
logger.debug("Useful message....")

Et build.sbt:

libraryDependencies += "com.typesafe" %% "scalalogging-slf4j" % "1.1.0"

Scala 2.11+ et plus récent:

import import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
val logger = Logger(LoggerFactory.getLogger("TheLoggerName"))
logger.debug("Useful message....")

Et build.sbt:

libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.1.0"
2
xgMz

Je trouve très pratique d’utiliser une sorte de Java enregistreur, sl4j par exemple, avec un simple scala wrapper, qui m'apporte une telle syntaxe

val #! = new Logger(..) // somewhere deep in dsl.logging.

object User with dsl.logging {

  #! ! "info message"
  #! dbg "debug message"
  #! trace "var a=true"

}

À mon avis, très utile mélange de Java infrastructures de journalisation éprouvées et de la syntaxe sophistiquée de scala.

2
Alex Povar

Après avoir utilisé slf4s et logula pendant un certain temps, j’ai écrit loglady, un trait de journalisation simple enveloppant slf4j.

Il offre une API similaire à celle de la bibliothèque de journalisation de Python, ce qui rend les cas courants (chaîne de base, formatage simple) triviaux et évite le formatage passe-partout.

http://github.com/dln/loglady/

2
dln