Search code examples
scaladropwizardmetrics

Where is this mysterious Scala object coming from?


Please note: Although this question has to do with the popular Dropwizard Metrics library and its Scala API analog, Metrics Scala, this is -- at its core -- strictly a Scala question. As such, I believe any knowledgeable Scala dev can answer this!


I am fairly new to Scala and am trying to build a simple app that will leverage this Metrics-Scala library (which again is the Scala API for DW Metrics). I found a very useful GitHub project showing how to setup Metrics-Scala in the real world, and the source file I'm referencing below can be found here.

I cut and diced that source file into a much smaller, simpler version to illustrate my question:

object Metrics extends App {
  val metricRegistry = new com.codahale.metrics.MetricRegistry()
  val healthCheckRegistry = new com.codahale.metrics.health.HealthCheckRegistry()

  ConsoleReporter.forRegistry(metricRegistry)
    .convertRatesTo(TimeUnit.SECONDS)
    .convertDurationsTo(TimeUnit.MILLISECONDS)
    .build().start(10, TimeUnit.SECONDS)

  run()

  while(true){}

  def run() {
    new TimerExample().longRunningInstrumentedMethod()

    spawn {
      val gaugeExample = new RandomNumberGaugeExample()

      while (true) {
        Thread.sleep(500)
        gaugeExample.fetchingRandomNumber()
      }
    }
  }
}

trait Instrumented extends InstrumentedBuilder {
  val metricRegistry = Metrics.metricRegistry
}

class RandomNumberGaugeExample() extends Instrumented {
  def fetchingRandomNumber(): Int = {
    metrics.gauge("random-number") {
      Math.abs(new Random().nextInt() % 1000)
    }.value
  }
}

My concerns are with this mysterious metrics object and its usage.

I understand that RandomNumberGaugeExample inherits a metricsRegistry instance because it extends Instrumented. But I'm not seeing where that metrics instance is defined, what type it is, and how RandomNumberGaugeExample gets asscess to it. Wouldn't RandomNumberGaugeExample just have access to a metricsRegistry?!

Also what is this devilry:

metrics.gauge("random-number") {
  Math.abs(new Random().nextInt() % 1000)
}.value

How does metrics.guage return an integral value?


Solution

  • Instrumented extends InstrumentedBuilder, which is where we find metrics. metrics is a MetricsBuilder.

    As for metrics.gauge, let's look at the gauge method:

    def gauge[A](name: String, scope: String = null)(f: => A): Gauge[A] = {
      wrapDwGauge(metricNameFor(name, scope), new DropwizardGauge[A] { def getValue: A = f })
    }
    

    This method has two parameter lists. The second parameter list, (f: => A) has a call-by-name argument named f that is of type A. A new DropwizardGauge is created with f and passed to wrapDwGauge, which creates a new Gauge instance. So the following devilry...

    metrics.gauge("random-number") {
      Math.abs(new Random().nextInt() % 1000)
    }.value
    

    ...is basically calling the gauge method, passing it two arguments (the String "random-number" and the Int result of Math.abs(new Random().nextInt() % 1000)), then calling .value on the result. The .value returns an Int, because as we can see here, .value just calls the getValue method on the created DropwizardGauge.