diff options
Diffstat (limited to 'src/main/scala/xyz/driver/core/app.scala')
-rw-r--r-- | src/main/scala/xyz/driver/core/app.scala | 105 |
1 files changed, 83 insertions, 22 deletions
diff --git a/src/main/scala/xyz/driver/core/app.scala b/src/main/scala/xyz/driver/core/app.scala index 1977d6a..eb9f7ee 100644 --- a/src/main/scala/xyz/driver/core/app.scala +++ b/src/main/scala/xyz/driver/core/app.scala @@ -12,13 +12,14 @@ import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.RouteResult._ import akka.http.scaladsl.server.{ExceptionHandler, Route, RouteConcatenation} import akka.stream.ActorMaterializer +import com.github.swagger.akka.SwaggerHttpService._ import com.typesafe.config.Config import com.typesafe.scalalogging.Logger import io.swagger.models.Scheme +import io.swagger.util.Json import org.slf4j.{LoggerFactory, MDC} -import spray.json.DefaultJsonProtocol import xyz.driver.core -import xyz.driver.core.rest.{ContextHeaders, Swagger} +import xyz.driver.core.rest._ import xyz.driver.core.stats.SystemStats import xyz.driver.core.time.Time import xyz.driver.core.time.provider.{SystemTimeProvider, TimeProvider} @@ -26,12 +27,16 @@ import xyz.driver.core.time.provider.{SystemTimeProvider, TimeProvider} import scala.compat.Platform.ConcurrentModificationException import scala.concurrent.duration._ import scala.concurrent.{Await, ExecutionContext, Future} +import scala.reflect.runtime.universe._ +import scala.util.control.NonFatal +import scala.util.Try import scalaz.Scalaz.stringInstance import scalaz.syntax.equal._ object app { - class DriverApp(version: String, + class DriverApp(appName: String, + version: String, gitHash: String, modules: Seq[Module], time: TimeProvider = new SystemTimeProvider(), @@ -66,7 +71,7 @@ object app { protected def bindHttp(modules: Seq[Module]): Unit = { val serviceTypes = modules.flatMap(_.routeTypes) - val swaggerService = new Swagger(baseUrl, Scheme.forValue(scheme), version, actorSystem, serviceTypes, config) + val swaggerService = swaggerOverride(serviceTypes) val swaggerRoutes = swaggerService.routes ~ swaggerService.swaggerUI val versionRt = versionRoute(version, gitHash, time.currentTime()) @@ -78,14 +83,11 @@ object app { { ctx => val trackingId = rest.extractTrackingId(ctx.request) MDC.put("trackingId", trackingId) - MDC.put("origin", origin) - MDC.put("xForwardedFor", - extractHeader(ctx.request)("x-forwarded-for") - .orElse(extractHeader(ctx.request)("x_forwarded_for")) - .getOrElse("unknown")) - MDC.put("remoteAddress", extractHeader(ctx.request)("remote-address").getOrElse("unknown")) - MDC.put("userAgent", extractHeader(ctx.request)("user-agent").getOrElse("unknown")) - MDC.put("ip", ip.toOption.map(_.getHostAddress).getOrElse("unknown")) + + val updatedStacktrace = (rest.extractStacktrace(ctx.request) ++ Array(appName)).mkString("->") + MDC.put("stack", updatedStacktrace) + + storeRequestContextToMdc(ctx.request, origin, ip) def requestLogging: Future[Unit] = Future { log.info( @@ -93,7 +95,10 @@ object app { } val contextWithTrackingId = - ctx.withRequest(ctx.request.addHeader(RawHeader(ContextHeaders.TrackingIdHeader, trackingId))) + ctx.withRequest( + ctx.request + .addHeader(RawHeader(ContextHeaders.TrackingIdHeader, trackingId)) + .addHeader(RawHeader(ContextHeaders.StacktraceHeader, updatedStacktrace))) handleExceptions(ExceptionHandler(exceptionHandler))({ c => requestLogging.flatMap { _ => @@ -114,6 +119,51 @@ object app { } } + private def storeRequestContextToMdc(request: HttpRequest, origin: String, ip: RemoteAddress) = { + + MDC.put("origin", origin) + MDC.put("ip", ip.toOption.map(_.getHostAddress).getOrElse("unknown")) + MDC.put("remoteHost", ip.toOption.map(_.getHostName).getOrElse("unknown")) + + MDC.put("xForwardedFor", + extractHeader(request)("x-forwarded-for") + .orElse(extractHeader(request)("x_forwarded_for")) + .getOrElse("unknown")) + MDC.put("remoteAddress", extractHeader(request)("remote-address").getOrElse("unknown")) + MDC.put("userAgent", extractHeader(request)("user-agent").getOrElse("unknown")) + } + + protected def swaggerOverride(apiTypes: Seq[Type]) = { + new Swagger(baseUrl, Scheme.forValue(scheme), version, actorSystem, apiTypes, config) { + override def generateSwaggerJson: String = { + import io.swagger.models.Swagger + + import scala.collection.JavaConverters._ + + try { + val swagger: Swagger = reader.read(toJavaTypeSet(apiTypes).asJava) + + // Removing trailing spaces + swagger.setPaths( + swagger.getPaths.asScala + .map { + case (key, path) => + key.trim -> path + } + .toMap + .asJava) + + Json.pretty().writeValueAsString(swagger) + } catch { + case NonFatal(t) => { + logger.error("Issue with creating swagger.json", t) + throw t + } + } + } + } + } + /** * Override me for custom exception handling * @@ -148,6 +198,7 @@ object app { } protected def versionRoute(version: String, gitHash: String, startupTime: Time): Route = { + import spray.json._ import DefaultJsonProtocol._ import SprayJsonSupport._ @@ -155,17 +206,27 @@ object app { val currentTime = time.currentTime().millis complete( Map( - "version" -> version, - "gitHash" -> gitHash, - "modules" -> modules.map(_.name).mkString(", "), - "startupTime" -> startupTime.millis.toString, - "serverTime" -> currentTime.toString, - "uptime" -> (currentTime - startupTime.millis).toString - )) + "version" -> version.toJson, + "gitHash" -> gitHash.toJson, + "modules" -> modules.map(_.name).toJson, + "dependencies" -> collectAppDependencies().toJson, + "startupTime" -> startupTime.millis.toString.toJson, + "serverTime" -> currentTime.toString.toJson, + "uptime" -> (currentTime - startupTime.millis).toString.toJson + ).toJson) } } + protected def collectAppDependencies(): Map[String, String] = { + + def serviceWithLocation(serviceName: String): (String, String) = + serviceName -> Try(config.getString(s"services.$serviceName.baseUrl")).getOrElse("not-detected") + + modules.flatMap(module => module.serviceDiscovery.getUsedServices.map(serviceWithLocation).toSeq).toMap + } + protected def healthRoute: Route = { + import spray.json._ import DefaultJsonProtocol._ import SprayJsonSupport._ import spray.json._ @@ -236,13 +297,13 @@ object app { } } - import scala.reflect.runtime.universe._ - trait Module { val name: String def route: Route def routeTypes: Seq[Type] + val serviceDiscovery: ServiceDiscovery with SavingUsedServiceDiscovery = new NoServiceDiscovery() + def activate(): Unit = {} def deactivate(): Unit = {} } |