Timed
Use Case
You want to check how long some portion of your code takes to complete.
You can either keep this information as a number, or automatically log it if it’s too high.
Note
Duration is available in both Akka and Scala 2.10, but sadly not before, so for now ScalaWords uses a copied version of the Scala 2.10 implementaiton. It will be removed once more projects are using Scala 2.10.
timed
The simplest version of timed returns a tuple, with both the time (a Stopwatch instance) the code took to execute, and the computed value. Exceptions are not eaten, they’ll be thrown up as you’d expect.
val (time, value) = timed {
Thread.sleep(100)
2 + 2
}
println("Exection took: " + time)
assert value == 4
timedAndLogged
One of many examples you might want to use this Verb is to log an information message if some block of code is taking too long to complete. You could do this on a method level using AOP, but just using this verb is way easier, and code weaving is something you have to think twice before using anyway ;-)
import com.weiglewilczek.sfl4s.Logger
object Test extends Logger with TimedVerb {
val hardMathProblemSolution = timedAndLogger(logger, "Hard math problem") {
// DEBUG: Starting execution of timed block: [Hard math problem]
Thread.sleep(100)
2 + 2
// INFO: Timed [Hard math problem] took: 100ms
}
assert 4 == hardMathProblemSolution
}
Note
ScalaWords currently supports the com.weiglewilczek.slf4s.Logger, I’m thinking about a way to allow any logger to work with this API (without the use of slow Structural Types).
Log when certain conditions are met
Sometimes you have a LOT of log messages like the above, which you don’t really care about. Let’s say most requests are handled within 5ms, but sometimes you get a spike and they take 100ms to process, that’s something worth logging as WARN.
timedAndLoggedIf(_.elapsedMillis > 100)(logger, "Long Operation") { doThings() }
Testing with TimedVerb
As with anything that’s Time related, you’re probably already thinking “how would I test such code?”. Timed is smart enough to allow you to mock out the ticker it’s using, like this:
import com.google.common.base.Ticker
trait TestTimedVerb extends TimedVerb {
override lazy val ticker = new Ticker {
def read() = 0L
}
}
Override the messages
You can override the messages being created by this trait.
Setting loglevels manualy is not yet supported, but I’ll work on a way to use any logger - and then via callbacks you’ll be able to log on any level and any message.
Contents