diff options
author | Ivan Topolnjak <ivantopo@gmail.com> | 2015-01-12 01:45:27 +0100 |
---|---|---|
committer | Ivan Topolnjak <ivantopo@gmail.com> | 2015-01-24 23:19:01 +0100 |
commit | 01a34f67ff75419c440f2e69c0a0db888a670a34 (patch) | |
tree | 9c4dee4e9c13c26937356950f9e4927c3f9dfb7d /kamon-spray/src/test/scala/kamon/spray | |
parent | 4a47e92d23af371f1d50b40af6cbe00a5ffc0105 (diff) | |
download | Kamon-01a34f67ff75419c440f2e69c0a0db888a670a34.tar.gz Kamon-01a34f67ff75419c440f2e69c0a0db888a670a34.tar.bz2 Kamon-01a34f67ff75419c440f2e69c0a0db888a670a34.zip |
! all: improve the metric recorders infrastructure
Diffstat (limited to 'kamon-spray/src/test/scala/kamon/spray')
3 files changed, 100 insertions, 165 deletions
diff --git a/kamon-spray/src/test/scala/kamon/spray/ClientRequestInstrumentationSpec.scala b/kamon-spray/src/test/scala/kamon/spray/ClientRequestInstrumentationSpec.scala index b90b0f3b..c5d7d992 100644 --- a/kamon-spray/src/test/scala/kamon/spray/ClientRequestInstrumentationSpec.scala +++ b/kamon-spray/src/test/scala/kamon/spray/ClientRequestInstrumentationSpec.scala @@ -16,50 +16,36 @@ package kamon.spray -import akka.testkit.{ TestKitBase, TestProbe } -import akka.actor.ActorSystem +import akka.testkit.TestProbe +import kamon.testkit.BaseKamonSpec import org.scalatest.concurrent.ScalaFutures import org.scalatest.time.{ Millis, Seconds, Span } -import org.scalatest.{ Matchers, WordSpecLike } import spray.httpx.RequestBuilding import spray.http.{ HttpResponse, HttpRequest } -import kamon.trace.{ SegmentCategory, SegmentMetricIdentity, TraceRecorder } +import kamon.trace.{ TraceContext, SegmentCategory } import com.typesafe.config.ConfigFactory import spray.can.Http import spray.http.HttpHeaders.RawHeader import kamon.Kamon -import kamon.metric.{ TraceMetrics, Metrics } +import kamon.metric.TraceMetricsSpec import spray.client.pipelining.sendReceive -import kamon.metric.Subscriptions.TickMetricSnapshot import scala.concurrent.duration._ -import kamon.metric.TraceMetrics.TraceMetricsSnapshot - -class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike with Matchers with ScalaFutures with RequestBuilding with TestServer { - implicit lazy val system: ActorSystem = ActorSystem("client-request-instrumentation-spec", ConfigFactory.parseString( - """ - |akka { - | loglevel = ERROR - |} - | - |kamon { - | spray { - | name-generator = kamon.spray.TestSprayNameGenerator - | } - | - | metrics { - | tick-interval = 1 hour - | - | filters = [ - | { - | trace { - | includes = [ "*" ] - | excludes = [] - | } - | } - | ] - | } - |} - """.stripMargin)) + +class ClientRequestInstrumentationSpec extends BaseKamonSpec("client-request-instrumentation-spec") with ScalaFutures + with RequestBuilding with TestServer { + + import TraceMetricsSpec.SegmentSyntax + + override lazy val config = + ConfigFactory.parseString( + """ + |kamon { + | metric.tick-interval = 1 hour + | spray.name-generator = kamon.spray.TestSprayNameGenerator + |} + | + |akka.loggers = ["akka.event.slf4j.Slf4jLogger"] + """.stripMargin) implicit def ec = system.dispatcher implicit val defaultPatience = PatienceConfig(timeout = Span(10, Seconds), interval = Span(5, Millis)) @@ -71,12 +57,12 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit val (_, server, bound) = buildSHostConnectorAndServer // Initiate a request within the context of a trace - val (testContext, responseFuture) = TraceRecorder.withNewTraceContext("include-trace-token-header-at-request-level-api") { + val (testContext, responseFuture) = TraceContext.withContext(newContext("include-trace-token-header-at-request-level-api")) { val rF = sendReceive(system, ec) { Get(s"http://${bound.localAddress.getHostName}:${bound.localAddress.getPort}/dummy-path") } - (TraceRecorder.currentContext, rF) + (TraceContext.currentContext, rF) } // Accept the connection at the server side @@ -85,7 +71,7 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit // Receive the request and reply back val request = server.expectMsgType[HttpRequest] - request.headers should contain(RawHeader(Kamon(Spray).traceTokenHeaderName, testContext.token)) + request.headers should contain(traceTokenHeader(testContext.token)) // Finish the request cycle, just to avoid error messages on the logs. server.reply(HttpResponse(entity = "ok")) @@ -98,12 +84,12 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit val (_, server, bound) = buildSHostConnectorAndServer // Initiate a request within the context of a trace - val (testContext, responseFuture) = TraceRecorder.withNewTraceContext("do-not-include-trace-token-header-at-request-level-api") { + val (testContext, responseFuture) = TraceContext.withContext(newContext("do-not-include-trace-token-header-at-request-level-api")) { val rF = sendReceive(system, ec) { Get(s"http://${bound.localAddress.getHostName}:${bound.localAddress.getPort}/dummy-path") } - (TraceRecorder.currentContext, rF) + (TraceContext.currentContext, rF) } // Accept the connection at the server side @@ -112,7 +98,7 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit // Receive the request and reply back val request = server.expectMsgType[HttpRequest] - request.headers should not contain (RawHeader(Kamon(Spray).traceTokenHeaderName, testContext.token)) + request.headers should not contain (traceTokenHeader(testContext.token)) // Finish the request cycle, just to avoid error messages on the logs. server.reply(HttpResponse(entity = "ok")) @@ -128,12 +114,12 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit val (_, _, bound) = buildSHostConnectorAndServer // Initiate a request within the context of a trace - val (testContext, responseFuture) = TraceRecorder.withNewTraceContext("assign-name-to-segment-with-request-level-api") { + val (testContext, responseFuture) = TraceContext.withContext(newContext("assign-name-to-segment-with-request-level-api")) { val rF = sendReceive(transport.ref)(ec, 10.seconds) { Get(s"http://${bound.localAddress.getHostName}:${bound.localAddress.getPort}/request-level-api-segment") } - (TraceRecorder.currentContext, rF) + (TraceContext.currentContext, rF) } // Receive the request and reply back @@ -142,10 +128,10 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit responseFuture.futureValue.entity.asString should be("ok") testContext.finish() - val traceMetricsSnapshot = takeSnapshotOf("assign-name-to-segment-with-request-level-api") - traceMetricsSnapshot.elapsedTime.numberOfMeasurements should be(1) - traceMetricsSnapshot.segments(SegmentMetricIdentity("request-level /request-level-api-segment", - SegmentCategory.HttpClient, Spray.SegmentLibraryName)).numberOfMeasurements should be(1) + val traceMetricsSnapshot = takeSnapshotOf("assign-name-to-segment-with-request-level-api", "trace") + traceMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) + traceMetricsSnapshot.segment("request-level /request-level-api-segment", SegmentCategory.HttpClient, Spray.SegmentLibraryName) + .numberOfMeasurements should be(1) } "rename a request level api segment once it reaches the relevant host connector" in { @@ -155,12 +141,12 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit val (_, server, bound) = buildSHostConnectorAndServer // Initiate a request within the context of a trace - val (testContext, responseFuture) = TraceRecorder.withNewTraceContext("rename-segment-with-request-level-api") { + val (testContext, responseFuture) = TraceContext.withContext(newContext("rename-segment-with-request-level-api")) { val rF = sendReceive(system, ec) { Get(s"http://${bound.localAddress.getHostName}:${bound.localAddress.getPort}/request-level-api-segment") } - (TraceRecorder.currentContext, rF) + (TraceContext.currentContext, rF) } // Accept the connection at the server side @@ -173,10 +159,10 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit responseFuture.futureValue.entity.asString should be("ok") testContext.finish() - val traceMetricsSnapshot = takeSnapshotOf("rename-segment-with-request-level-api") - traceMetricsSnapshot.elapsedTime.numberOfMeasurements should be(1) - traceMetricsSnapshot.segments(SegmentMetricIdentity("host-level /request-level-api-segment", - SegmentCategory.HttpClient, Spray.SegmentLibraryName)).numberOfMeasurements should be(1) + val traceMetricsSnapshot = takeSnapshotOf("rename-segment-with-request-level-api", "trace") + traceMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) + traceMetricsSnapshot.segment("host-level /request-level-api-segment", SegmentCategory.HttpClient, Spray.SegmentLibraryName) + .numberOfMeasurements should be(1) } } @@ -189,9 +175,9 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit val client = TestProbe() // Initiate a request within the context of a trace - val testContext = TraceRecorder.withNewTraceContext("include-trace-token-header-on-http-client-request") { + val testContext = TraceContext.withContext(newContext("include-trace-token-header-on-http-client-request")) { client.send(hostConnector, Get("/dummy-path")) - TraceRecorder.currentContext + TraceContext.currentContext } // Accept the connection at the server side @@ -200,7 +186,7 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit // Receive the request and reply back val request = server.expectMsgType[HttpRequest] - request.headers should contain(RawHeader(Kamon(Spray).traceTokenHeaderName, testContext.token)) + request.headers should contain(traceTokenHeader(testContext.token)) // Finish the request cycle, just to avoid error messages on the logs. server.reply(HttpResponse(entity = "ok")) @@ -216,9 +202,9 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit val client = TestProbe() // Initiate a request within the context of a trace - val testContext = TraceRecorder.withNewTraceContext("not-include-trace-token-header-on-http-client-request") { + val testContext = TraceContext.withContext(newContext("not-include-trace-token-header-on-http-client-request")) { client.send(hostConnector, Get("/dummy-path")) - TraceRecorder.currentContext + TraceContext.currentContext } // Accept the connection at the server side @@ -227,7 +213,7 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit // Receive the request and reply back val request = server.expectMsgType[HttpRequest] - request.headers should not contain (RawHeader(Kamon(Spray).traceTokenHeaderName, testContext.token)) + request.headers should not contain (traceTokenHeader(testContext.token)) // Finish the request cycle, just to avoid error messages on the logs. server.reply(HttpResponse(entity = "ok")) @@ -243,9 +229,9 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit val client = TestProbe() // Initiate a request within the context of a trace - val testContext = TraceRecorder.withNewTraceContext("create-segment-with-host-level-api") { + val testContext = TraceContext.withContext(newContext("create-segment-with-host-level-api")) { client.send(hostConnector, Get("/host-level-api-segment")) - TraceRecorder.currentContext + TraceContext.currentContext } // Accept the connection at the server side @@ -254,52 +240,39 @@ class ClientRequestInstrumentationSpec extends TestKitBase with WordSpecLike wit // Receive the request and reply back val request = server.expectMsgType[HttpRequest] - request.headers should not contain (RawHeader(Kamon(Spray).traceTokenHeaderName, testContext.token)) + request.headers should not contain (traceTokenHeader(testContext.token)) // Finish the request cycle, just to avoid error messages on the logs. server.reply(HttpResponse(entity = "ok")) client.expectMsgType[HttpResponse] testContext.finish() - val traceMetricsSnapshot = takeSnapshotOf("create-segment-with-host-level-api") - traceMetricsSnapshot.elapsedTime.numberOfMeasurements should be(1) - traceMetricsSnapshot.segments(SegmentMetricIdentity("host-level /host-level-api-segment", - SegmentCategory.HttpClient, Spray.SegmentLibraryName)).numberOfMeasurements should be(1) + val traceMetricsSnapshot = takeSnapshotOf("create-segment-with-host-level-api", "trace") + traceMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) + traceMetricsSnapshot.segment("host-level /host-level-api-segment", SegmentCategory.HttpClient, Spray.SegmentLibraryName) + .numberOfMeasurements should be(1) } } } - def expectTraceMetrics(traceName: String, listener: TestProbe, timeout: FiniteDuration): TraceMetricsSnapshot = { - val tickSnapshot = within(timeout) { - listener.expectMsgType[TickMetricSnapshot] - } - - val metricsOption = tickSnapshot.metrics.get(TraceMetrics(traceName)) - metricsOption should not be empty - metricsOption.get.asInstanceOf[TraceMetricsSnapshot] - } - - def takeSnapshotOf(traceName: String): TraceMetricsSnapshot = { - val recorder = Kamon(Metrics).register(TraceMetrics(traceName), TraceMetrics.Factory) - val collectionContext = Kamon(Metrics).buildDefaultCollectionContext - recorder.get.collect(collectionContext) - } + def traceTokenHeader(token: String): RawHeader = + RawHeader(Kamon(Spray).settings.traceTokenHeaderName, token) - def enableInternalSegmentCollectionStrategy(): Unit = setSegmentCollectionStrategy(ClientSegmentCollectionStrategy.Internal) - def enablePipeliningSegmentCollectionStrategy(): Unit = setSegmentCollectionStrategy(ClientSegmentCollectionStrategy.Pipelining) + def enableInternalSegmentCollectionStrategy(): Unit = setSegmentCollectionStrategy(ClientInstrumentationLevel.HostLevelAPI) + def enablePipeliningSegmentCollectionStrategy(): Unit = setSegmentCollectionStrategy(ClientInstrumentationLevel.RequestLevelAPI) def enableAutomaticTraceTokenPropagation(): Unit = setIncludeTraceToken(true) def disableAutomaticTraceTokenPropagation(): Unit = setIncludeTraceToken(false) - def setSegmentCollectionStrategy(strategy: ClientSegmentCollectionStrategy.Strategy): Unit = { - val target = Kamon(Spray)(system) - val field = target.getClass.getDeclaredField("clientSegmentCollectionStrategy") + def setSegmentCollectionStrategy(strategy: ClientInstrumentationLevel.Level): Unit = { + val target = Kamon(Spray)(system).settings + val field = target.getClass.getDeclaredField("clientInstrumentationLevel") field.setAccessible(true) field.set(target, strategy) } def setIncludeTraceToken(include: Boolean): Unit = { - val target = Kamon(Spray)(system) - val field = target.getClass.getDeclaredField("includeTraceToken") + val target = Kamon(Spray)(system).settings + val field = target.getClass.getDeclaredField("includeTraceTokenHeader") field.setAccessible(true) field.set(target, include) } diff --git a/kamon-spray/src/test/scala/kamon/spray/SprayServerMetricsSpec.scala b/kamon-spray/src/test/scala/kamon/spray/SprayServerMetricsSpec.scala index c4b370d7..58bb2885 100644 --- a/kamon-spray/src/test/scala/kamon/spray/SprayServerMetricsSpec.scala +++ b/kamon-spray/src/test/scala/kamon/spray/SprayServerMetricsSpec.scala @@ -1,46 +1,27 @@ package kamon.spray -import akka.actor.ActorSystem -import akka.testkit.{ TestProbe, TestKitBase } +import akka.testkit.TestProbe import com.typesafe.config.ConfigFactory -import kamon.Kamon -import kamon.http.HttpServerMetrics -import kamon.metric._ +import kamon.testkit.BaseKamonSpec import org.scalatest.concurrent.{ PatienceConfiguration, ScalaFutures } -import org.scalatest.{ Matchers, WordSpecLike } import spray.http.{ StatusCodes, HttpResponse, HttpRequest } import spray.httpx.RequestBuilding -class SprayServerMetricsSpec extends TestKitBase with WordSpecLike with Matchers with RequestBuilding - with ScalaFutures with PatienceConfiguration with TestServer { +class SprayServerMetricsSpec extends BaseKamonSpec("spray-server-metrics-spec") with RequestBuilding with ScalaFutures + with PatienceConfiguration with TestServer { - val collectionContext = CollectionContext(100) - - implicit lazy val system: ActorSystem = ActorSystem("spray-server-metrics-spec", ConfigFactory.parseString( - """ - |akka { - | loglevel = ERROR - |} - | - |kamon { - | metrics { - | tick-interval = 1 hour - | - | filters = [ - | { - | trace { - | includes = [ "*" ] - | excludes = [] - | } - | } - | ] - | } - |} - """.stripMargin)) + override lazy val config = + ConfigFactory.parseString( + """ + |kamon.metric { + | tick-interval = 1 hour + |} + | + |akka.loggers = ["akka.event.slf4j.Slf4jLogger"] + """.stripMargin) "the Spray Server metrics instrumentation" should { - "record trace metrics for requests received" in { - Kamon(Metrics)(system).register(TraceMetrics("GET: /record-trace-metrics"), TraceMetrics.Factory).get.collect(collectionContext) + "record trace metrics for processed requests" in { val (connection, server) = buildClientConnectionAndServer val client = TestProbe() @@ -58,15 +39,17 @@ class SprayServerMetricsSpec extends TestKitBase with WordSpecLike with Matchers client.expectMsgType[HttpResponse] } - val snapshot = Kamon(Metrics)(system).register(TraceMetrics("GET: /record-trace-metrics"), TraceMetrics.Factory).get.collect(collectionContext) - snapshot.elapsedTime.numberOfMeasurements should be(15) + val snapshot = takeSnapshotOf("GET: /record-trace-metrics", "trace") + snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(15) } - "record http serve metrics for all the requests" in { - Kamon(Metrics)(system).register(HttpServerMetrics, HttpServerMetrics.Factory).get.collect(collectionContext) + "record http server metrics for all the requests" in { val (connection, server) = buildClientConnectionAndServer val client = TestProbe() + // Erase metrics recorder from previous tests. + takeSnapshotOf("spray-server", "http-server") + for (repetition ← 1 to 10) { client.send(connection, Get("/record-http-metrics")) server.expectMsgType[HttpRequest] @@ -81,11 +64,11 @@ class SprayServerMetricsSpec extends TestKitBase with WordSpecLike with Matchers client.expectMsgType[HttpResponse] } - val snapshot = Kamon(Metrics)(system).register(HttpServerMetrics, HttpServerMetrics.Factory).get.collect(collectionContext) - snapshot.countsPerTraceAndStatusCode("GET: /record-http-metrics")("200").count should be(10) - snapshot.countsPerTraceAndStatusCode("GET: /record-http-metrics")("400").count should be(5) - snapshot.countsPerStatusCode("200").count should be(10) - snapshot.countsPerStatusCode("400").count should be(5) + val snapshot = takeSnapshotOf("spray-server", "http-server") + snapshot.counter("GET: /record-http-metrics_200").get.count should be(10) + snapshot.counter("GET: /record-http-metrics_400").get.count should be(5) + snapshot.counter("200").get.count should be(10) + snapshot.counter("400").get.count should be(5) } } } diff --git a/kamon-spray/src/test/scala/kamon/spray/SprayServerTracingSpec.scala b/kamon-spray/src/test/scala/kamon/spray/SprayServerTracingSpec.scala index 30d42eea..1ae0cb98 100644 --- a/kamon-spray/src/test/scala/kamon/spray/SprayServerTracingSpec.scala +++ b/kamon-spray/src/test/scala/kamon/spray/SprayServerTracingSpec.scala @@ -17,39 +17,15 @@ package kamon.spray import _root_.spray.httpx.RequestBuilding -import akka.testkit.{ TestKitBase, TestProbe } -import akka.actor.ActorSystem -import org.scalatest.{ Matchers, WordSpecLike } +import akka.testkit.TestProbe +import kamon.testkit.BaseKamonSpec import kamon.Kamon import org.scalatest.concurrent.{ PatienceConfiguration, ScalaFutures } import spray.http.HttpHeaders.RawHeader import spray.http.{ HttpResponse, HttpRequest } -import com.typesafe.config.ConfigFactory - -class SprayServerTracingSpec extends TestKitBase with WordSpecLike with Matchers with RequestBuilding - with ScalaFutures with PatienceConfiguration with TestServer { - - implicit lazy val system: ActorSystem = ActorSystem("spray-server-tracing-spec", ConfigFactory.parseString( - """ - |akka { - | loglevel = ERROR - |} - | - |kamon { - | metrics { - | tick-interval = 2 seconds - | - | filters = [ - | { - | trace { - | includes = [ "*" ] - | excludes = [] - | } - | } - | ] - | } - |} - """.stripMargin)) + +class SprayServerTracingSpec extends BaseKamonSpec("spray-server-tracing-spec") with RequestBuilding with ScalaFutures + with PatienceConfiguration with TestServer { "the spray server request tracing instrumentation" should { "include the trace-token header in responses when the automatic-trace-token-propagation is enabled" in { @@ -58,12 +34,12 @@ class SprayServerTracingSpec extends TestKitBase with WordSpecLike with Matchers val (connection, server) = buildClientConnectionAndServer val client = TestProbe() - client.send(connection, Get("/").withHeaders(RawHeader(Kamon(Spray).traceTokenHeaderName, "propagation-enabled"))) + client.send(connection, Get("/").withHeaders(traceTokenHeader("propagation-enabled"))) server.expectMsgType[HttpRequest] server.reply(HttpResponse(entity = "ok")) val response = client.expectMsgType[HttpResponse] - response.headers should contain(RawHeader(Kamon(Spray).traceTokenHeaderName, "propagation-enabled")) + response.headers should contain(traceTokenHeader("propagation-enabled")) } "reply back with an automatically assigned trace token if none was provided with the request and automatic-trace-token-propagation is enabled" in { @@ -77,7 +53,7 @@ class SprayServerTracingSpec extends TestKitBase with WordSpecLike with Matchers server.reply(HttpResponse(entity = "ok")) val response = client.expectMsgType[HttpResponse] - response.headers.count(_.name == Kamon(Spray).traceTokenHeaderName) should be(1) + response.headers.count(_.name == Kamon(Spray).settings.traceTokenHeaderName) should be(1) } @@ -87,21 +63,24 @@ class SprayServerTracingSpec extends TestKitBase with WordSpecLike with Matchers val (connection, server) = buildClientConnectionAndServer val client = TestProbe() - client.send(connection, Get("/").withHeaders(RawHeader(Kamon(Spray).traceTokenHeaderName, "propagation-disabled"))) + client.send(connection, Get("/").withHeaders(traceTokenHeader("propagation-disabled"))) server.expectMsgType[HttpRequest] server.reply(HttpResponse(entity = "ok")) val response = client.expectMsgType[HttpResponse] - response.headers should not contain RawHeader(Kamon(Spray).traceTokenHeaderName, "propagation-disabled") + response.headers should not contain traceTokenHeader("propagation-disabled") } } + def traceTokenHeader(token: String): RawHeader = + RawHeader(Kamon(Spray).settings.traceTokenHeaderName, token) + def enableAutomaticTraceTokenPropagation(): Unit = setIncludeTraceToken(true) def disableAutomaticTraceTokenPropagation(): Unit = setIncludeTraceToken(false) def setIncludeTraceToken(include: Boolean): Unit = { - val target = Kamon(Spray)(system) - val field = target.getClass.getDeclaredField("includeTraceToken") + val target = Kamon(Spray)(system).settings + val field = target.getClass.getDeclaredField("includeTraceTokenHeader") field.setAccessible(true) field.set(target, include) } |