How to Monitor Your Scala Play Framework Application with Vigilmon
Play Framework is a reactive web framework for Scala (and Java) — built on Akka and used in high-traffic production systems. This guide shows how to add external uptime monitoring to any Play application with Vigilmon.
Step 1: Add a Health Endpoint to Play
Play uses a controller + route file pattern:
1. Create the health controller (app/controllers/HealthController.scala):
package controllers
import play.api.mvc._
import play.api.libs.json._
import javax.inject._
import scala.concurrent.{ExecutionContext, Future}
@Singleton
class HealthController @Inject()(
cc: ControllerComponents
)(implicit ec: ExecutionContext) extends AbstractController(cc) {
def check: Action[AnyContent] = Action.async { implicit request =>
Future.successful(
Ok(Json.obj("status" -> "ok"))
)
}
}
2. Add the route (conf/routes):
GET /health controllers.HealthController.check
3. Test it:
curl http://localhost:9000/health
# {"status":"ok"}
Step 2: Check Real Dependencies
For a health check that reflects actual service state:
package controllers
import play.api.mvc._
import play.api.libs.json._
import play.api.db.slick.DatabaseConfigProvider
import slick.jdbc.JdbcProfile
import javax.inject._
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Success, Failure}
@Singleton
class HealthController @Inject()(
cc: ControllerComponents,
dbConfigProvider: DatabaseConfigProvider
)(implicit ec: ExecutionContext) extends AbstractController(cc) {
private val dbConfig = dbConfigProvider.get[JdbcProfile]
import dbConfig._
import profile.api._
def check: Action[AnyContent] = Action.async {
val dbCheck = db.run(sql"SELECT 1".as[Int]).transform {
case Success(_) => Success(true)
case Failure(_) => Success(false)
}
dbCheck.map { dbOk =>
if (dbOk) {
Ok(Json.obj("status" -> "ok", "database" -> "ok"))
} else {
ServiceUnavailable(Json.obj("status" -> "error", "database" -> "unreachable"))
}
}
}
}
Step 3: Exclude Health from Authentication Filters
Play uses filters that apply to all routes. If you have an auth filter, exclude the health route:
// app/filters/AuthFilter.scala
class AuthFilter @Inject()(implicit val mat: Materializer, ec: ExecutionContext) extends Filter {
def apply(nextFilter: RequestHeader => Future[Result])
(requestHeader: RequestHeader): Future[Result] = {
// Skip auth for health endpoint
if (requestHeader.path.startsWith("/health")) {
nextFilter(requestHeader)
} else {
// Apply auth logic
validateToken(requestHeader).flatMap {
case true => nextFilter(requestHeader)
case false => Future.successful(Unauthorized("Not authorized"))
}
}
}
}
Step 4: Play Configuration
Make sure your Play app binds to the right port in production:
# conf/application.conf
play.http.port=9000
play.server.http.port=9000
# Allow health endpoint without CSRF
play.filters.disabled += play.filters.csrf.CSRFFilter
# Or configure CSRF to exclude health
Step 5: Connect to Vigilmon
- Sign up at vigilmon.online
- Add Monitor → HTTP Monitor
- URL:
https://your-play-app.com/health - Expected status: 200
- Optional content check:
"status":"ok" - Check interval: 60 seconds
- Alert channels: email or Slack
Play Framework with Docker
FROM eclipse-temurin:21-jdk AS builder
WORKDIR /app
COPY . .
RUN sbt dist
RUN unzip target/universal/*.zip -d target/universal/dist
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=builder /app/target/universal/dist .
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \n CMD curl -f http://localhost:9000/health || exit 1
CMD ["./bin/your-app", "-Dplay.http.secret.key=${APP_SECRET}"]
Summary
- Create a
HealthControllerwith acheckaction that returnsOk(200) - Add
GET /health controllers.HealthController.checkto your routes - Optionally check database/dependencies and return
ServiceUnavailable(503) when unhealthy - Exclude the health route from auth filters
- Connect to Vigilmon for external, multi-region monitoring
Play's reactive architecture handles high concurrency. Make sure you know the moment it stops handling requests.
Top comments (0)