aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlad <vlad@drivergrp.com>2016-10-12 13:00:29 -0700
committervlad <vlad@drivergrp.com>2016-10-12 13:00:29 -0700
commit008283e63e01d67cfdaee6976474a5272a0b1e91 (patch)
tree254b00ef485573cacb4e9ee7761cf53205c0021f
parent461d08d2caefac4798eb5ac3fa3c0c421603de60 (diff)
downloaddriver-core-008283e63e01d67cfdaee6976474a5272a0b1e91.tar.gz
driver-core-008283e63e01d67cfdaee6976474a5272a0b1e91.tar.bz2
driver-core-008283e63e01d67cfdaee6976474a5272a0b1e91.zip
App /health endpoint with info related to OS, memory, file system and GCv0.9.2
-rw-r--r--src/main/scala/com/drivergrp/core/app.scala35
-rw-r--r--src/main/scala/com/drivergrp/core/stats.scala54
2 files changed, 88 insertions, 1 deletions
diff --git a/src/main/scala/com/drivergrp/core/app.scala b/src/main/scala/com/drivergrp/core/app.scala
index a1e1082..f6100f0 100644
--- a/src/main/scala/com/drivergrp/core/app.scala
+++ b/src/main/scala/com/drivergrp/core/app.scala
@@ -11,6 +11,7 @@ import akka.http.scaladsl.server.{ExceptionHandler, Route, RouteConcatenation}
import akka.stream.ActorMaterializer
import com.drivergrp.core.logging.{Logger, TypesafeScalaLogger}
import com.drivergrp.core.rest.Swagger
+import com.drivergrp.core.stats.SystemStats
import com.drivergrp.core.time.Time
import com.drivergrp.core.time.provider.{SystemTimeProvider, TimeProvider}
import com.typesafe.config.Config
@@ -99,7 +100,7 @@ object app {
val _ = Future {
http.bindAndHandle(route2HandlerFlow(handleExceptions(generalExceptionHandler) {
- logRequestResult("log")(modules.map(_.route).foldLeft(versionRt ~ swaggerRoutes)(_ ~ _))
+ logRequestResult("log")(modules.map(_.route).foldLeft(versionRt ~ healthRoute ~ swaggerRoutes)(_ ~ _))
}), interface, port)(materializer)
}
}
@@ -122,6 +123,38 @@ object app {
}
}
+ protected def healthRoute: Route = {
+ import DefaultJsonProtocol._
+ import SprayJsonSupport._
+ import spray.json._
+
+ val memoryUsage = SystemStats.memoryUsage
+ val gcStats = SystemStats.garbageCollectorStats
+
+ path("health") {
+ complete(
+ Map(
+ "availableProcessors" -> SystemStats.availableProcessors.toJson,
+ "memoryUsage" -> Map(
+ "free" -> memoryUsage.free.toJson,
+ "total" -> memoryUsage.total.toJson,
+ "max" -> memoryUsage.max.toJson
+ ).toJson,
+ "gcStats" -> Map(
+ "garbageCollectionTime" -> gcStats.garbageCollectionTime.toJson,
+ "totalGarbageCollections" -> gcStats.totalGarbageCollections.toJson
+ ).toJson,
+ "fileSystemSpace" -> SystemStats.fileSystemSpace.map { f =>
+ Map("path" -> f.path.toJson,
+ "freeSpace" -> f.freeSpace.toJson,
+ "totalSpace" -> f.totalSpace.toJson,
+ "usableSpace" -> f.usableSpace.toJson)
+ }.toJson,
+ "operatingSystem" -> SystemStats.operatingSystemStats.toJson
+ ))
+ }
+ }
+
/**
* Initializes services
*/
diff --git a/src/main/scala/com/drivergrp/core/stats.scala b/src/main/scala/com/drivergrp/core/stats.scala
index cd77f7a..963e4ea 100644
--- a/src/main/scala/com/drivergrp/core/stats.scala
+++ b/src/main/scala/com/drivergrp/core/stats.scala
@@ -1,5 +1,9 @@
package com.drivergrp.core
+import java.io.File
+import java.lang.management.ManagementFactory
+import java.lang.reflect.Modifier
+
import com.drivergrp.core.logging.Logger
import com.drivergrp.core.time.{Time, TimeRange}
@@ -40,4 +44,54 @@ object stats {
log.audit(s"${keys.mkString(".")}(${interval.start.millis}-${interval.end.millis})=$valueString")
}
}
+
+ final case class MemoryStats(free: Long, total: Long, max: Long)
+
+ final case class GarbageCollectorStats(totalGarbageCollections: Long, garbageCollectionTime: Long)
+
+ final case class FileRootSpace(path: String, totalSpace: Long, freeSpace: Long, usableSpace: Long)
+
+ object SystemStats {
+
+ def memoryUsage: MemoryStats = {
+ val runtime = Runtime.getRuntime
+ MemoryStats(runtime.freeMemory, runtime.totalMemory, runtime.maxMemory)
+ }
+
+ def availableProcessors: Int = {
+ Runtime.getRuntime.availableProcessors()
+ }
+
+ def garbageCollectorStats: GarbageCollectorStats = {
+ import scala.collection.JavaConverters._
+
+ val (totalGarbageCollections, garbageCollectionTime) =
+ ManagementFactory.getGarbageCollectorMXBeans.asScala.foldLeft(0L -> 0L) {
+ case ((total, collectionTime), gc) =>
+ (total + math.min(0L, gc.getCollectionCount)) -> (collectionTime + math.min(0L, gc.getCollectionTime))
+ }
+
+ GarbageCollectorStats(totalGarbageCollections, garbageCollectionTime)
+ }
+
+ def fileSystemSpace: Array[FileRootSpace] = {
+ File.listRoots() map { root =>
+ FileRootSpace(root.getAbsolutePath, root.getTotalSpace, root.getFreeSpace, root.getUsableSpace)
+ }
+ }
+
+ def operatingSystemStats: Map[String, String] = {
+ val operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean
+ operatingSystemMXBean.getClass.getDeclaredMethods
+ .map(method => { method.setAccessible(true); method })
+ .filter(method => method.getName.startsWith("get") && Modifier.isPublic(method.getModifiers))
+ .map { method =>
+ try {
+ method.getName -> String.valueOf(method.invoke(operatingSystemMXBean))
+ } catch {
+ case t: Throwable => method.getName -> t.getMessage
+ }
+ } toMap
+ }
+ }
}