From a98ac16d26421561110a679edb765d64996a675e Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Fri, 12 Oct 2018 14:29:10 +0200 Subject: reorganize the HttpMessage abstractions --- .../HttpServerInstrumentationSpec.scala | 10 +-- .../scala/kamon/instrumentation/HttpMessage.scala | 71 +++++++++++++++++----- .../scala/kamon/instrumentation/HttpServer.scala | 12 ++-- 3 files changed, 66 insertions(+), 27 deletions(-) diff --git a/kamon-core-tests/src/test/scala/kamon/instrumentation/HttpServerInstrumentationSpec.scala b/kamon-core-tests/src/test/scala/kamon/instrumentation/HttpServerInstrumentationSpec.scala index d334184d..c3c5f131 100644 --- a/kamon-core-tests/src/test/scala/kamon/instrumentation/HttpServerInstrumentationSpec.scala +++ b/kamon-core-tests/src/test/scala/kamon/instrumentation/HttpServerInstrumentationSpec.scala @@ -267,8 +267,8 @@ class HttpServerInstrumentationSpec extends WordSpec with Matchers with SpanInsp def noSpanMetricsHttpServer(): HttpServer = HttpServer.from("no-span-metrics", component = TestComponent, interface = TestInterface, port = 8082) def noopHttpServer(): HttpServer = HttpServer.from("noop", component = TestComponent, interface = TestInterface, port = 8083) - def fakeRequest(requestUrl: String, requestPath: String, requestMethod: String, headers: Map[String, String]): HttpRequest = - new HttpRequest { + def fakeRequest(requestUrl: String, requestPath: String, requestMethod: String, headers: Map[String, String]): HttpMessage.Request = + new HttpMessage.Request { override def url: String = requestUrl override def path: String = requestPath override def method: String = requestMethod @@ -276,11 +276,11 @@ class HttpServerInstrumentationSpec extends WordSpec with Matchers with SpanInsp override def readAll(): Map[String, String] = headers } - def fakeResponse(responseStatusCode: Int, headers: mutable.Map[String, String]): HttpResponse.Writable[HttpResponse] = - new HttpResponse.Writable[HttpResponse] { + def fakeResponse(responseStatusCode: Int, headers: mutable.Map[String, String]): HttpMessage.ResponseBuilder[HttpMessage.Response] = + new HttpMessage.ResponseBuilder[HttpMessage.Response] { override def statusCode: Int = responseStatusCode override def write(header: String, value: String): Unit = headers.put(header, value) - override def build(): HttpResponse = this + override def build(): HttpMessage.Response = this } def completedRequests(port: Int, statusCode: Int): Counter = { diff --git a/kamon-core/src/main/scala/kamon/instrumentation/HttpMessage.scala b/kamon-core/src/main/scala/kamon/instrumentation/HttpMessage.scala index b0300546..b141331b 100644 --- a/kamon-core/src/main/scala/kamon/instrumentation/HttpMessage.scala +++ b/kamon-core/src/main/scala/kamon/instrumentation/HttpMessage.scala @@ -2,26 +2,65 @@ package kamon.instrumentation import kamon.context.HttpPropagation.{HeaderReader, HeaderWriter} +/** + * Base abstractions over HTTP messages. + */ +object HttpMessage { -trait HttpRequest extends HeaderReader { - def url: String - def path: String - def method: String -} + /** + * Wrapper for HTTP Request messages. + */ + trait Request extends HeaderReader { + + /** + * Request URL. + */ + def url: String + + /** + * Full request path. Does not include the query. + */ + def path: String -object HttpRequest { - trait Writable[T] extends HttpRequest with HeaderWriter { - def build(): T + /** + * HTTP Method. + */ + def method: String } -} -trait HttpResponse { - def statusCode: Int -} + /** + * Wrapper for HTTP response messages. + */ + trait Response { -object HttpResponse { - trait Writable[T] extends HttpResponse with HeaderWriter { - def build(): T + /** + * Status code on the response message. + */ + def statusCode: Int } -} + /** + * A HTTP message builder on which header values can be written and a complete HTTP message can be build from. + * Implementations will typically wrap a HTTP message model from an instrumented framework and either accumulate + * all header writes until a call to to .build() is made and a new HTTP message is constructed merging the previous + * and accumulated headers (on immutable HTTP models) or directly write the headers on the underlying HTTP message + * (on mutable HTTP models). + */ + trait Builder[Message] extends HeaderWriter { + + /** + * Returns a version a version of the HTTP message container all headers that have been written to the builder. + */ + def build(): Message + } + + /** + * Builder for HTTP Request messages. + */ + trait RequestBuilder[Message] extends Request with Builder[Message] + + /** + * Builder for HTTP Response messages. + */ + trait ResponseBuilder[Message] extends Response with Builder[Message] +} diff --git a/kamon-core/src/main/scala/kamon/instrumentation/HttpServer.scala b/kamon-core/src/main/scala/kamon/instrumentation/HttpServer.scala index 99b330f7..72828424 100644 --- a/kamon-core/src/main/scala/kamon/instrumentation/HttpServer.scala +++ b/kamon-core/src/main/scala/kamon/instrumentation/HttpServer.scala @@ -41,7 +41,7 @@ trait HttpServer { * @param request A HttpRequest wrapper on the original incoming HTTP request. * @return The RequestHandler that will follow the lifecycle of the incoming request. */ - def receive(request: HttpRequest): HttpServer.RequestHandler + def receive(request: HttpMessage.Request): HttpServer.RequestHandler /** @@ -104,7 +104,7 @@ object HttpServer { * @param context Context that should be used for writing returning keys into the response. * @return The modified HTTP response that should be sent to clients. */ - def send[HttpResponse](response: HttpResponse.Writable[HttpResponse], context: Context): HttpResponse + def send[HttpResponse](response: HttpMessage.ResponseBuilder[HttpResponse], context: Context): HttpResponse /** * Signals that the entire response (headers and body) has been sent to the client. @@ -255,7 +255,7 @@ object HttpServer { contextPropagation.defaultHttpPropagation() } - override def receive(request: HttpRequest): RequestHandler = { + override def receive(request: HttpMessage.Request): RequestHandler = { val incomingContext = if(settings.enableContextPropagation) _propagation.read(request) @@ -287,7 +287,7 @@ object HttpServer { } } - override def send[HttpResponse](response: HttpResponse.Writable[HttpResponse], context: Context): HttpResponse = { + override def send[HttpResponse](response: HttpMessage.ResponseBuilder[HttpResponse], context: Context): HttpResponse = { def addResponseTag(tag: String, value: String, mode: TagMode): Unit = mode match { case TagMode.Metric => span.tagMetric(tag, value) case TagMode.Span => span.tag(tag, value) @@ -338,7 +338,7 @@ object HttpServer { } - private def buildServerSpan(context: Context, request: HttpRequest): Span = { + private def buildServerSpan(context: Context, request: HttpMessage.Request): Span = { val span = Kamon.buildSpan(operationName(request)) .withMetricTag("span.kind", "server") .withMetricTag("component", component) @@ -368,7 +368,7 @@ object HttpServer { span.start() } - private def operationName(request: HttpRequest): String = { + private def operationName(request: HttpMessage.Request): String = { val requestPath = request.path val customMapping = settings.operationMappings.collectFirst { case (pattern, operationName) if pattern.accept(requestPath) => operationName -- cgit v1.2.3