Skip to content

Commit

Permalink
366 path attribute updated (#402)
Browse files Browse the repository at this point in the history
366 add http route
  • Loading branch information
lgajowy authored May 18, 2022
1 parent e943780 commit 0b2334b
Show file tree
Hide file tree
Showing 26 changed files with 792 additions and 49 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/scala.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ on:
types:
- published

env:
SBT_NATIVE_CLIENT: true

jobs:
lint:
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ lazy val otelExtension = (project in file("otel-extension"))
libraryDependencies ++= {
openTelemetryExtension.map(_ % "provided") ++
openTelemetryMuzzle.map(_ % "provided") ++
openTelemetryInstrumentation.map(_ % "provided") ++
openTelemetryInstrumentationApiSemanticConventions ++
byteBuddy.map(_ % "provided") ++
akkaTestkit.map(_ % "it,test") ++
scalatest.map(_ % "it,test") ++
Expand Down
58 changes: 30 additions & 28 deletions example/src/main/scala/example/api/AccountRoutes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,39 +35,41 @@ class AccountRoutes(
}

val routes: Route = Route.seal(
pathPrefix("api" / "v1" / "account" / JavaUUID) { uuid =>
(pathPrefix("balance") & pathEndOrSingleSlash & get) {
import AccountStateActor.Command._
import AccountStateActor.Reply._
onComplete(
shardedRef.ask[AccountStateActor.Reply](ref => ShardingEnvelope(uuid.toString, GetBalance(ref)))
) map { case CurrentBalance(balance) =>
complete(StatusCodes.OK, Account(uuid, balance))
}
} ~
(pathPrefix("withdraw" / DoubleNumber) & pathEndOrSingleSlash) { amount =>
(put | post) {
pathPrefix("api" / "v1" / "account") {
pathPrefix(JavaUUID) { uuid =>
(pathPrefix("balance") & pathEndOrSingleSlash & get) {
import AccountStateActor.Command._
import AccountStateActor.Reply._
onComplete(
shardedRef.ask[AccountStateActor.Reply](ref => ShardingEnvelope(uuid.toString, Withdraw(ref, amount)))
) map {
case CurrentBalance(balance) =>
complete(StatusCodes.Created, Account(uuid, balance))
case InsufficientFunds =>
complete(StatusCodes.Conflict, ApplicationError("insufficient funds"))
shardedRef.ask[AccountStateActor.Reply](ref => ShardingEnvelope(uuid.toString, GetBalance(ref)))
) map { case CurrentBalance(balance) =>
complete(StatusCodes.OK, Account(uuid, balance))
}
}
} ~
(pathPrefix("deposit" / DoubleNumber) & pathEndOrSingleSlash) { amount =>
(put | post) {
import AccountStateActor.Command._
import AccountStateActor.Reply._
} ~
(pathPrefix("withdraw" / DoubleNumber) & pathEndOrSingleSlash) { amount =>
(put | post) {
import AccountStateActor.Command._
import AccountStateActor.Reply._
onComplete(
shardedRef.ask[AccountStateActor.Reply](ref => ShardingEnvelope(uuid.toString, Withdraw(ref, amount)))
) map {
case CurrentBalance(balance) =>
complete(StatusCodes.Created, Account(uuid, balance))
case InsufficientFunds =>
complete(StatusCodes.Conflict, ApplicationError("insufficient funds"))
}
}
} ~
(pathPrefix("deposit" / DoubleNumber) & pathEndOrSingleSlash) { amount =>
(put | post) {
import AccountStateActor.Command._
import AccountStateActor.Reply._

onComplete(
shardedRef.ask[AccountStateActor.Reply](ref => ShardingEnvelope(uuid.toString, Deposit(ref, amount)))
) map { case CurrentBalance(balance) =>
complete(StatusCodes.Created, Account(uuid, balance))
onComplete(
shardedRef.ask[AccountStateActor.Reply](ref => ShardingEnvelope(uuid.toString, Deposit(ref, amount)))
) map { case CurrentBalance(balance) =>
complete(StatusCodes.Created, Account(uuid, balance))
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions extension/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ akka {
io.scalac.mesmer.actor.rules {
"/user" = group
"/user/*" = instance
"/user/" = instance
"/system" = group
"/system/sharding/accounts" = group
"/system/sharding/accounts/*" = instance
}

io {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,25 @@ object OpenTelemetryActorMetricsMonitor {
.getOrElse(defaultConfig.droppedMessages)
)

val defaultConfig: MetricNames = MetricNames(
mailboxSize = "akka_actor_mailbox_size",
mailboxTimeMin = "akka_actor_mailbox_time_min",
mailboxTimeMax = "akka_actor_mailbox_time_max",
mailboxTimeSum = "akka_actor_mailbox_time_sum",
mailboxTimeCount = "akka_actor_mailbox_time_count",
stashedMessages = "akka_actor_stashed_total",
receivedMessages = "akka_actor_received_messages_total",
processedMessages = "akka_actor_processed_messages_total",
failedMessages = "akka_actor_failed_messages",
processingTimeMin = "akka_actor_processing_time_min",
processingTimeMax = "akka_actor_processing_time_max",
processingTimeSum = "akka_actor_processing_time_sum",
processingTimeCount = "akka_actor_processing_time_count",
sentMessages = "akka_actor_sent_messages_total",
droppedMessages = "akka_actor_dropped_messages_total"
)
val defaultConfig: MetricNames =
MetricNames(
mailboxSize = "akka_actor_mailbox_size",
mailboxTimeMin = "akka_actor_mailbox_time_min",
mailboxTimeMax = "akka_actor_mailbox_time_max",
mailboxTimeSum = "akka_actor_mailbox_time_sum",
mailboxTimeCount = "akka_actor_mailbox_time_count",
stashedMessages = "akka_actor_stashed_total",
receivedMessages = "akka_actor_received_messages_total",
processedMessages = "akka_actor_processed_messages_total",
failedMessages = "akka_actor_failed_messages",
processingTimeMin = "akka_actor_processing_time_min",
processingTimeMax = "akka_actor_processing_time_max",
processingTimeSum = "akka_actor_processing_time_sum",
processingTimeCount = "akka_actor_processing_time_count",
sentMessages = "akka_actor_sent_messages_total",
droppedMessages = "akka_actor_dropped_messages_total"
)

}

def apply(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package io.scalac.mesmer.instrumentation.akka.http

import akka.http.scaladsl.model.StatusCodes
import io.scalac.mesmer.agent.utils.{ OtelAgentTest, SafeLoadSystem }
import io.scalac.mesmer.core.util.ReceptionistOps
import org.scalatest.OptionValues
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.flatspec.AnyFlatSpecLike
import org.scalatest.matchers.should.Matchers
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server._
import akka.http.scaladsl.testkit.ScalatestRouteTest
import akka.util.Timeout
import scala.util.Try
import io.opentelemetry.context.{ Context, ContextKey }
import io.scalac.mesmer.otelextension.instrumentations.akka.http.{ RouteContext, RouteTemplateHolder }

import scala.concurrent.Promise
import scala.concurrent.duration._

class HttpRouteTest
extends OtelAgentTest
with AnyFlatSpecLike
with Matchers
with ScalaFutures
with ScalatestRouteTest
with OptionValues
with ReceptionistOps {

implicit val timeout: Timeout = 5.seconds

it should ("add a uuid template") in {
val promise = Promise[String]()

val route: Route = (pathPrefix("api" / "v1" / JavaUUID) & pathEndOrSingleSlash) { _ =>
val template = RouteContext.retrieveFromCurrent.get()
promise.success(template)
complete(StatusCodes.OK)

}

Get("/api/v1/84a5c573-4643-4bb5-a50d-776a8fca0a5b") ~!> route ~> check {
status should be(StatusCodes.OK)
}

whenReady(promise.future) { template =>
template should be("/api/v1/<uuid>")
}
}

it should ("add a number template") in {
val promise = Promise[String]()

val route: Route = (pathPrefix("api" / "v1" / IntNumber) & pathEndOrSingleSlash) { _ =>
val template = RouteContext.retrieveFromCurrent.get()
promise.success(template)
complete(StatusCodes.OK)

}

Get("/api/v1/100") ~!> route ~> check {
status should be(StatusCodes.OK)
}

whenReady(promise.future) { template =>
template should be("/api/v1/<number>")
}
}

it should ("add a wildcard for segment template") in {
val promise = Promise[String]()

val route: Route = (pathPrefix("api" / "v1" / Segment) & pathEndOrSingleSlash) { _ =>
val template = RouteContext.retrieveFromCurrent.get()
promise.success(template)
complete(StatusCodes.OK)

}

Get("/api/v1/anu-thing") ~!> route ~> check {
status should be(StatusCodes.OK)
}

whenReady(promise.future) { template =>
template should be("/api/v1/*")
}
}

it should ("add a uuid template for or matcher") in {
val promise = Promise[String]()

val route: Route = (pathPrefix("api" / "v1" / (JavaUUID | IntNumber)) & pathEndOrSingleSlash) { _ =>
val template = RouteContext.retrieveFromCurrent.get()
promise.success(template)
complete(StatusCodes.OK)

}

Get("/api/v1/84a5c573-4643-4bb5-a50d-776a8fca0a5b") ~!> route ~> check {
status should be(StatusCodes.OK)
}

whenReady(promise.future) { template =>
template should be("/api/v1/<uuid>")
}
}

it should ("add a number template for or matcher") in {
val promise = Promise[String]()

val route: Route = (pathPrefix("api" / "v1" / (JavaUUID | LongNumber)) & pathEndOrSingleSlash) { _ =>
val template = RouteContext.retrieveFromCurrent.get()
promise.success(template)
complete(StatusCodes.OK)

}

Get("/api/v1/100") ~!> route ~> check {
status should be(StatusCodes.OK)
}

whenReady(promise.future) { template =>
template should be("/api/v1/<number>")
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.scalac.mesmer.instrumentation.http.impl;

import akka.http.scaladsl.server.PathMatcher;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import net.bytebuddy.asm.Advice;

public class AndThenMatchedMatchingAdvice {

@Advice.OnMethodExit
public static void onExit(
@Advice.This PathMatcher.Matching<?> self, @Advice.Return PathMatcher.Matching<?> result) {

String value = VirtualField.find(PathMatcher.Matching.class, String.class).get(self);

if (value != null) {

String innerValue = VirtualField.find(PathMatcher.Matching.class, String.class).get(result);
if (innerValue != null) {

VirtualField.find(PathMatcher.Matching.class, String.class).set(result, value + innerValue);
} else {
VirtualField.find(PathMatcher.Matching.class, String.class).set(result, value);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.scalac.mesmer.instrumentation.http.impl;

import akka.http.scaladsl.model.HttpRequest;
import akka.http.scaladsl.model.HttpResponse;
import akka.stream.Materializer;
import io.scalac.mesmer.otelextension.instrumentations.akka.http.UpdateHttpRouteWrapper;
import net.bytebuddy.asm.Advice;
import scala.Function1;
import scala.concurrent.Future;

public class AsyncHandlerAdvice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void wrapHandler(
@Advice.Argument(value = 0, readOnly = false)
Function1<HttpRequest, Future<HttpResponse>> handler,
@Advice.Argument(7) Materializer materialzier) {
handler = new UpdateHttpRouteWrapper(handler, materialzier.executionContext());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.scalac.mesmer.instrumentation.http.impl;

import akka.http.scaladsl.server.PathMatcher;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import net.bytebuddy.asm.Advice;

public class DoubleTemplateAdvice {

@Advice.OnMethodEnter
public static void onEnter(@Advice.Argument(value = 0) PathMatcher<?> result) {

VirtualField.find(PathMatcher.class, String.class).set(result, "<double>");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.scalac.mesmer.instrumentation.http.impl;

import akka.http.scaladsl.server.PathMatcher;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import net.bytebuddy.asm.Advice;

public class EmptyTemplateAdvice {

@Advice.OnMethodExit
public static void onExit(@Advice.This PathMatcher<?> self) {
VirtualField.find(PathMatcher.class, String.class).set(self, "");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.scalac.mesmer.instrumentation.http.impl;

import akka.http.scaladsl.server.PathMatcher;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import net.bytebuddy.asm.Advice;

public class MapMatchedMatchingAdvice {

@Advice.OnMethodExit
public static void onExit(
@Advice.This PathMatcher.Matching<?> self, @Advice.Return PathMatcher.Matching<?> result) {

String value = VirtualField.find(PathMatcher.Matching.class, String.class).get(self);
if (value != null) {

VirtualField.find(PathMatcher.Matching.class, String.class).set(result, value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.scalac.mesmer.instrumentation.http.impl;

import akka.http.scaladsl.server.PathMatcher;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import net.bytebuddy.asm.Advice;

public class NeutralTemplateAdvice {

@Advice.OnMethodEnter
public static void onEnter(@Advice.Argument(value = 0) PathMatcher<?> result) {

VirtualField.find(PathMatcher.class, String.class).set(result, "");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.scalac.mesmer.instrumentation.http.impl;

import akka.http.scaladsl.server.PathMatcher;
import io.opentelemetry.instrumentation.api.field.VirtualField;
import net.bytebuddy.asm.Advice;

public class NumberTemplateAdvice {

@Advice.OnMethodExit
public static void onExit(@Advice.This PathMatcher<?> self) {
VirtualField.find(PathMatcher.class, String.class).set(self, "<number>");
}
}
Loading

0 comments on commit 0b2334b

Please sign in to comment.