diff options
author | vlad <vlad@drivergrp.com> | 2016-10-12 13:00:29 -0700 |
---|---|---|
committer | vlad <vlad@drivergrp.com> | 2016-10-12 13:00:29 -0700 |
commit | 008283e63e01d67cfdaee6976474a5272a0b1e91 (patch) | |
tree | 254b00ef485573cacb4e9ee7761cf53205c0021f /src | |
parent | 461d08d2caefac4798eb5ac3fa3c0c421603de60 (diff) | |
download | driver-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
Diffstat (limited to 'src')
-rw-r--r-- | src/main/scala/com/drivergrp/core/app.scala | 35 | ||||
-rw-r--r-- | src/main/scala/com/drivergrp/core/stats.scala | 54 |
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 + } + } } |