uk.co.unclealex.diagnostics.DiagnosticsComponents.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of play-diagnostics_2.13 Show documentation
Show all versions of play-diagnostics_2.13 Show documentation
Diagnostics for Play applications
package uk.co.unclealex.diagnostics
import java.net.InetSocketAddress
import java.time.Clock
import java.util.concurrent.TimeUnit
import com.codahale.metrics.MetricFilter
import com.codahale.metrics.graphite.{Graphite, GraphiteReporter}
import com.codahale.metrics.health.{HealthCheck, HealthCheckRegistry}
import com.kenshoo.play.metrics._
import com.typesafe.scalalogging.StrictLogging
import play.api.http.HttpErrorHandler
import play.api.mvc.EssentialFilter
import play.api.{ApplicationLoader, BuiltInComponents, BuiltInComponentsFromContext}
import play.filters.gzip.GzipFilter
import uk.co.unclealex.diagnostics.ConfigurationExtensions._
import scala.concurrent.duration.FiniteDuration
import scala.concurrent.{Await, Future}
trait DiagnosticsComponents extends BuiltInComponents {
def metricsBearerToken: String = {
configuration.getOrEnv[String]("metrics token", "metrics.token", "METRICS_TOKEN")
}
def healthCheckBearerToken: String = {
configuration.getOrEnv[String]("health check token", "healthcheck.token", "HEALTHCHECK_TOKEN")
}
def clock: Clock
// Provided
def secureMetricsController: SecureMetricsController
}
abstract class DiagnosticsFromContext(
context: ApplicationLoader.Context,
val name: String) extends BuiltInComponentsFromContext(context) with StrictLogging
with DiagnosticsComponents {
private lazy val metrics: Metrics = new MetricsImpl(applicationLifecycle, configuration)
private lazy val healthCheckRegistry: HealthCheckRegistry = new HealthCheckRegistry()
applicationLifecycle.addStopHook(() => Future.successful(healthCheckRegistry.shutdown()))
def registerHealthCheck(healthCheckName: String, healthCheck: HealthCheck): Unit = {
logger.info(s"Registering health check $healthCheckName")
healthCheckRegistry.register(healthCheckName, healthCheck)
}
def registerHealthCheck(healthCheckName: String, healthCheck: () => Future[String], duration: FiniteDuration): Unit = {
val actualHealthCheck: HealthCheck = () => {
try {
HealthCheck.Result.healthy(Await.result(healthCheck(), duration))
}
catch {
case exception: Throwable => HealthCheck.Result.unhealthy(exception)
}
}
registerHealthCheck(healthCheckName, actualHealthCheck)
}
val maybeGraphiteHost: Option[String] =
configuration.getOptional[String]("metrics.graphite.host")
maybeGraphiteHost.foreach { graphiteHost =>
val graphitePort: Int =
configuration.getOptional[Int]("metrics.graphite.port").getOrElse(2003)
logger.info(s"Sending metrics to $graphiteHost:$graphitePort")
val graphite = new Graphite(new InetSocketAddress(graphiteHost, graphitePort))
val reporter: GraphiteReporter = GraphiteReporter.
forRegistry(metrics.defaultRegistry).
prefixedWith(name).
convertRatesTo(TimeUnit.SECONDS).
convertDurationsTo(TimeUnit.MILLISECONDS).
filter(MetricFilter.ALL).
build(graphite)
reporter.start(1, TimeUnit.MINUTES)
applicationLifecycle.addStopHook(() => Future.successful(reporter.stop()))
}
lazy val secureMetricsController: SecureMetricsController = {
val metricsController: MetricsController = new MetricsController(metrics, controllerComponents)
new SecureMetricsController(metricsController, metricsBearerToken, controllerComponents)
}
lazy val healthCheckController =
new HealthCheckController(healthCheckRegistry, healthCheckBearerToken, controllerComponents)
override def httpFilters: Seq[EssentialFilter] = {
val metricsFilter: MetricsFilter = new MetricsFilterImpl(metrics) {
override def labelPrefix: String = DiagnosticsFromContext.this.name
}
val accessLoggingFilter = new AccessLoggingFilter(clock)
Seq(accessLoggingFilter, metricsFilter, new GzipFilter())
}
override lazy val httpErrorHandler: HttpErrorHandler = new JsonErrorHandler(environment)
}