All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zalando.markscheider.MetricsPlugin.scala Maven / Gradle / Ivy

package org.zalando.markscheider

import java.util.concurrent.TimeUnit
import javax.inject.Inject

import com.codahale.metrics.json.MetricsModule
import com.codahale.metrics.jvm.{ GarbageCollectorMetricSet, MemoryUsageGaugeSet, ThreadStatesGaugeSet }
import com.codahale.metrics.logback.InstrumentedAppender
import com.codahale.metrics.{ MetricRegistry, SharedMetricRegistries }
import com.fasterxml.jackson.databind.ObjectMapper
import play.api._
import play.api.inject.{ ApplicationLifecycle, Module }
import javax.inject._

import ch.qos.logback.classic.LoggerContext
import org.slf4j.LoggerFactory

import scala.concurrent.Future
import scala.language.implicitConversions

@Singleton
class MetricsPlugin @Inject() (
    configuration: Configuration,
    lifecycle:     ApplicationLifecycle,
    registries:    MetricRegistries,
    stopper:       RegistryStopper
) {

  val validUnits = Set("NANOSECONDS", "MICROSECONDS", "MILLISECONDS", "SECONDS", "MINUTES", "HOURS", "DAYS")

  val mapper: ObjectMapper = new ObjectMapper()

  implicit def stringToTimeUnit(s: String): TimeUnit = TimeUnit.valueOf(s)

  val registry = registries.getOrCreate

  lifecycle.addStopHook(() => Future.successful(stopper.stop()))
  onStart()

  def onStart(): Any = {
      def setupJvmMetrics(registry: MetricRegistry): Unit = {
        val jvmMetricsEnabled = configuration.getOptional[Boolean]("org.zalando.markscheider.jvm").getOrElse(true)
        if (jvmMetricsEnabled) {
          registry.registerAll(new GarbageCollectorMetricSet())
          registry.registerAll(new MemoryUsageGaugeSet())
          registry.registerAll(new ThreadStatesGaugeSet())
        }
      }

      def setupLogbackMetrics(registry: MetricRegistry): Unit = {
        val logbackEnabled = configuration.getOptional[Boolean]("org.zalando.markscheider.logback").getOrElse(true)
        if (logbackEnabled) {
          val appender: InstrumentedAppender = new InstrumentedAppender(registry)

          val factory = LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext]
          val rootLogger = factory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME)

          appender.setContext(rootLogger.getLoggerContext)
          appender.start()
          rootLogger.addAppender(appender)
        }
      }

      def setupReporting(conf: Configuration, registry: MetricRegistry): Unit =
        Map(
          "console" -> Reporter.console _,
          "csv" -> Reporter.csv _
        ).foreach {
            case (name, fun) =>
              conf.getOptional[Configuration](name).foreach {
                conf =>
                  if (conf.getOptional[Boolean]("enabled").getOrElse(false)) {
                    fun(conf, registry)()
                  }
              }
          }

    if (enabled) {
      val rateUnit = configuration.getOptional[String]("org.zalando.markscheider.rateUnit").filter(validUnits.contains).getOrElse("SECONDS")
      val durationUnit = configuration.getOptional[String]("org.zalando.markscheider.durationUnit").filter(validUnits.contains).getOrElse("MILLISECONDS")
      val showSamples = configuration.getOptional[Boolean]("org.zalando.markscheider.showSamples").getOrElse(false)

      setupJvmMetrics(registry)
      setupLogbackMetrics(registry)
      setupReporting(configuration.getOptional[Configuration]("org.zalando.markscheider.reporting").getOrElse(Configuration.empty), registry)

      val module = new MetricsModule(rateUnit, durationUnit, showSamples)
      mapper.registerModule(module)
    }
  }

  def enabled: Boolean = configuration.getOptional[Boolean]("org.zalando.markscheider.enabled").getOrElse(true)
}

class RegistryStopper @Inject() (configuration: Configuration) {
  def stop(): Unit = SharedMetricRegistries.remove(configuration.getOptional[String]("org.zalando.markscheider.name").getOrElse("default"))
}

class MetricRegistries @Inject() (configuration: Configuration) {
  def getOrCreate: MetricRegistry =
    SharedMetricRegistries.getOrCreate(configuration.getOptional[String]("org.zalando.markscheider.name").getOrElse("default"))
}

class PlayMetricsModule extends Module {
  def bindings(
    environment:   Environment,
    configuration: Configuration
  ): Seq[play.api.inject.Binding[_]] = Seq(
    bind[MetricsPlugin].toSelf.eagerly(),
    bind[RegistryStopper].toSelf.eagerly(),
    bind[MetricRegistries].toSelf.eagerly(),
    bind[MetricsFilter].toSelf.eagerly()
  )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy