Last active
December 4, 2019 20:06
-
-
Save ssledz/88fa72013912a238367b76e65128a291 to your computer and use it in GitHub Desktop.
MetricsService driven by io.dropwizard.metrics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val dropwizardMetrics = Seq( | |
"metrics-graphite", | |
"metrics-core", | |
"metrics-jvm" | |
).map("io.dropwizard.metrics" % _ % "4.0.5") | |
val logging = "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2" | |
val logback = "ch.qos.logback" % "logback-classic" % "1.2.3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.net.{InetAddress, InetSocketAddress} | |
import java.util.concurrent.TimeUnit | |
import cats.effect.{IO, Resource} | |
import cats.implicits._ | |
import com.codahale.metrics.graphite.{Graphite, GraphiteReporter} | |
import com.codahale.metrics.jvm.{GarbageCollectorMetricSet, MemoryUsageGaugeSet} | |
import com.codahale.metrics.{MetricFilter, MetricRegistry, ScheduledReporter, Slf4jReporter} | |
import com.typesafe.scalalogging.LazyLogging | |
import io.github.ssledz.MetricsService.MetricsConfig.GraphiteConfig | |
import org.slf4j.LoggerFactory | |
trait MetricsService { | |
def measureAndLog[A](timerName: String)(op: => A): A | |
def measureAndLogF[A](timerName: String)(fa: IO[A]): IO[A] | |
def meter(name: String, n: Long = 1): Unit | |
def close(): Unit | |
} | |
object MetricsService extends LazyLogging { | |
val Nop: MetricsService = new MetricsService { | |
def measureAndLog[A](timerName: String)(op: => A): A = op | |
def meter(name: String, n: Long): Unit = () | |
def measureAndLogF[A](timerName: String)(fa: IO[A]): IO[A] = fa | |
def close(): Unit = () | |
} | |
val NopIO: Resource[IO, MetricsService] = Resource.make(IO(Nop))(_ => IO.unit) | |
def resource(cfg: MetricsConfig): Resource[IO, MetricsService] = { | |
val registry: MetricRegistry = new MetricRegistry | |
val slf4j = IO(slf4jReporter(registry, cfg)) | |
val start: ScheduledReporter => IO[ScheduledReporter] = r => | |
IO { | |
r.start(cfg.schedule.toLong, TimeUnit.SECONDS) | |
r | |
} | |
val reporter = cfg.graphite match { | |
case Some(c) => | |
IO(graphiteReporter(registry, c)) | |
.handleErrorWith { ex => | |
IO(logger.error("Error during initialization of metrics service, fallback to slf4j reporter", ex)) >> slf4j | |
} | |
case None => IO(logger.info("Using slf4j metrics reporter")) >> slf4j | |
} | |
registry.register("jvm.gc", new GarbageCollectorMetricSet) | |
registry.register("jvm.mem", new MemoryUsageGaugeSet) | |
Resource.make[IO, MetricsService](reporter >>= start >>= (r => IO(new DefaultMetricsService(registry, r))))(r => IO(r.close())) | |
} | |
private def graphiteReporter(registry: MetricRegistry, cfg: GraphiteConfig): GraphiteReporter = { | |
val graphite = new Graphite(new InetSocketAddress(cfg.host, cfg.port)) | |
GraphiteReporter | |
.forRegistry(registry) | |
.prefixedWith(cfg.resolvePrefix) | |
.convertRatesTo(TimeUnit.SECONDS) | |
.convertDurationsTo(TimeUnit.MILLISECONDS) | |
.filter(MetricFilter.ALL) | |
.build(graphite) | |
} | |
private def slf4jReporter(registry: MetricRegistry, cfg: MetricsConfig): Slf4jReporter = | |
Slf4jReporter | |
.forRegistry(registry) | |
.outputTo(LoggerFactory.getLogger(cfg.slf4jLoggerName)) | |
.convertRatesTo(TimeUnit.SECONDS) | |
.convertDurationsTo(TimeUnit.MILLISECONDS) | |
.build | |
private class DefaultMetricsService(registry: MetricRegistry, reporter: ScheduledReporter) extends MetricsService { | |
def measureAndLog[A](timerName: String)(op: => A): A = registry.timer(timerName).time(() => op) | |
def meter(name: String, n: Long): Unit = registry.meter(name).mark(n) | |
def close(): Unit = reporter.close() | |
def measureAndLogF[A](timerName: String)(fa: IO[A]): IO[A] = | |
for { | |
t <- IO(registry.timer(timerName).time()) | |
a <- fa | |
_ <- IO(t.stop) | |
} yield a | |
} | |
case class MetricsConfig(graphite: Option[GraphiteConfig], slf4jLoggerName: String, schedule: Int = 60) | |
object MetricsConfig { | |
case class GraphiteConfig(port: Int, host: String, prefix: String) { | |
def resolvePrefix: String = prefix.replace("[ip]", InetAddress.getLocalHost.getHostName) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment