Configuration. Log4j Scala API uses Log4j configuration by default. This supports XML, properties files, and Java-based builders, as well as JSON and YAML with additional dependencies.
Short answer: yes, it decreases application performance as it uses some CPU cycles and other resources (memory, etc). Show activity on this post.
Most of Scala's logging libraries have been some wrappers around a Java logging framework (slf4j, log4j etc), but as of March 2015, the surviving log libraries are all slf4j. These log libraries provide some sort of log
object to which you can call info(...)
, debug(...)
, etc. I'm not a big fan of slf4j, but it now seems to be the predominant logging framework. Here's the description of SLF4J:
The Simple Logging Facade for Java or (SLF4J) serves as a simple facade or abstraction for various logging frameworks, e.g. java.util.logging, log4j and logback, allowing the end user to plug in the desired logging framework at deployment time.
The ability to change underlying log library at deployment time brings in unique characteristic to the entire slf4j family of loggers, which you need to be aware of:
In a large project, it could actually be convenient to be able to control the logging behavior of transitive dependencies if everyone used slf4j.
Scala Logging is written by Heiko Seeberger as a successor to his slf4s. It uses macro to expand calls into if expression to avoid potentially expensive log call.
Scala Logging is a convenient and performant logging library wrapping logging libraries like SLF4J and potentially others.
With Scala 2.10+ Consider ScalaLogging by Typesafe. Uses macros to deliver a very clean API
https://github.com/typesafehub/scala-logging
Quoting from their wiki:
Fortunately Scala macros can be used to make our lives easier: ScalaLogging offers the class
Logger
with lightweight logging methods that will be expanded to the above idiom. So all we have to write is:
logger.debug(s"Some ${expensiveExpression} message!")
After the macro has been applied, the code will have been transformed into the above described idiom.
In addition ScalaLogging offers the trait Logging
which conveniently provides a Logger
instance initialized with the name of the class mixed into:
import com.typesafe.scalalogging.slf4j.LazyLogging
class MyClass extends LazyLogging {
logger.debug("This is very convenient ;-)")
}
Using slf4j and a wrapper is nice but the use of it's built in interpolation breaks down when you have more than two values to interpolate, since then you need to create an Array of values to interpolate.
A more Scala like solution is to use a thunk or cluster to delay the concatenation of the error message. A good example of this is Lift's logger
Log.scala Slf4jLog.scala
Which looks like this:
class Log4JLogger(val logger: Logger) extends LiftLogger {
override def trace(msg: => AnyRef) = if (isTraceEnabled) logger.trace(msg)
}
Note that msg is a call-by-name and won't be evaluated unless isTraceEnabled is true so there's no cost in generating a nice message string. This works around the slf4j's interpolation mechanism which requires parsing the error message. With this model, you can interpolate any number of values into the error message.
If you have a separate trait that mixes this Log4JLogger into your class, then you can do
trace("The foobar from " + a + " doesn't match the foobar from " +
b + " and you should reset the baz from " + c")
instead of
info("The foobar from {0} doesn't match the foobar from {1} and you should reset the baz from {c},
Array(a, b, c))
I've actually followed the recommendation of Eugene and tried it and found out that it has a clumsy configuration and is subjected to bugs, which don't get fixed (such as this one). It doesn't look to be well maintained and it doesn't support Scala 2.10.
-Dorg.slf4j.simplelogger.defaultlog=trace
to execution command or hardcode in your script: System.setProperty("org.slf4j.simplelogger.defaultlog", "trace")
. No need to manage trashy config files!Run/Debug Configurations
and add -Dorg.slf4j.simplelogger.defaultlog=trace
to VM options
.Here's what you need to be running it with 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>
This is how I got Scala Logging working for me:
Put this in your build.sbt
:
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.7.2",
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3"
Then, after doing an sbt update
, this prints out a friendly log message:
import com.typesafe.scalalogging._
object MyApp extends App with LazyLogging {
logger.info("Hello there")
}
If you are using Play, you can of course simply import play.api.Logger
for writing log messages: Logger.debug("Hi")
.
See the docs for more info.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With