From ad33ff15ff642b29e21a82c3e8625feb12567aa7 Mon Sep 17 00:00:00 2001 From: vlad Date: Fri, 19 May 2017 17:26:33 -0700 Subject: Http stacktracing using headers to see which hosts this request was passing --- src/main/scala/xyz/driver/core/app.scala | 35 +++++++++++++++------- .../scala/xyz/driver/core/file/S3Storage.scala | 12 ++++---- src/main/scala/xyz/driver/core/rest.scala | 21 ++++++++++--- 3 files changed, 49 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/app.scala b/src/main/scala/xyz/driver/core/app.scala index e35c300..5a6dbbc 100644 --- a/src/main/scala/xyz/driver/core/app.scala +++ b/src/main/scala/xyz/driver/core/app.scala @@ -31,7 +31,8 @@ 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(), @@ -78,14 +79,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 +91,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 { _ => @@ -111,6 +112,20 @@ 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")) + } + /** * Override me for custom exception handling * diff --git a/src/main/scala/xyz/driver/core/file/S3Storage.scala b/src/main/scala/xyz/driver/core/file/S3Storage.scala index 50bfe85..933b01a 100644 --- a/src/main/scala/xyz/driver/core/file/S3Storage.scala +++ b/src/main/scala/xyz/driver/core/file/S3Storage.scala @@ -53,11 +53,13 @@ class S3Storage(s3: AmazonS3, bucket: Name[Bucket], executionContext: ExecutionC result.isTruncated } flatMap { result => result.getObjectSummaries.asScala.toList.map { summary => - FileLink(Name[File](summary.getKey), - Paths.get(path.toString + "/" + summary.getKey), - Revision[File](summary.getETag), - Time(summary.getLastModified.getTime), - summary.getSize) + FileLink( + Name[File](summary.getKey), + Paths.get(path.toString + "/" + summary.getKey), + Revision[File](summary.getETag), + Time(summary.getLastModified.getTime), + summary.getSize + ) } filterNot isInSubFolder(path) } toList }) diff --git a/src/main/scala/xyz/driver/core/rest.scala b/src/main/scala/xyz/driver/core/rest.scala index f1eab45..7e6c800 100644 --- a/src/main/scala/xyz/driver/core/rest.scala +++ b/src/main/scala/xyz/driver/core/rest.scala @@ -18,6 +18,7 @@ import com.typesafe.config.Config import io.swagger.models.Scheme import xyz.driver.core.auth._ import xyz.driver.core.time.provider.TimeProvider +import org.slf4j.MDC import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success} @@ -41,9 +42,14 @@ package rest { .fold(java.util.UUID.randomUUID.toString)(_.value()) } + def extractStacktrace(request: HttpRequest): Array[String] = + request.headers.find(_.name == ContextHeaders.StacktraceHeader).fold("")(_.value()).split("->") + def extractContextHeaders(request: HttpRequest): Map[String, String] = { request.headers.filter { h => - h.name === ContextHeaders.AuthenticationTokenHeader || h.name === ContextHeaders.TrackingIdHeader + h.name === ContextHeaders.AuthenticationTokenHeader || + h.name === ContextHeaders.TrackingIdHeader || + h.name === ContextHeaders.StacktraceHeader } map { header => if (header.name === ContextHeaders.AuthenticationTokenHeader) { header.name -> header.value.stripPrefix(ContextHeaders.AuthenticationHeaderPrefix).trim @@ -106,6 +112,7 @@ package rest { val PermissionsTokenHeader = "Permissions" val AuthenticationHeaderPrefix = "Bearer" val TrackingIdHeader = "X-Trace" + val StacktraceHeader = "X-Stacktrace" } object AuthProvider { @@ -265,9 +272,15 @@ package rest { val requestTime = time.currentTime() val request = requestStub - .withHeaders(RawHeader(ContextHeaders.TrackingIdHeader, context.trackingId)) - .withHeaders(context.contextHeaders.toSeq.map { h => - RawHeader(h._1, h._2): HttpHeader + .withHeaders(context.contextHeaders.toSeq.map { + case (ContextHeaders.TrackingIdHeader, headerValue) => + RawHeader(ContextHeaders.TrackingIdHeader, context.trackingId) + case (ContextHeaders.StacktraceHeader, headerValue) => + RawHeader(ContextHeaders.StacktraceHeader, + Option(MDC.get("stack")) + .orElse(context.contextHeaders.get(ContextHeaders.StacktraceHeader)) + .getOrElse("")) + case (header, headerValue) => RawHeader(header, headerValue) }: _*) log.info(s"Sending request to ${request.method} ${request.uri}") -- cgit v1.2.3