diff --git a/build.sbt b/build.sbt index b8ca0b110..e17116179 100644 --- a/build.sbt +++ b/build.sbt @@ -525,7 +525,8 @@ lazy val `kamon-pekko` = (project in file("instrumentation/kamon-pekko")) .settings(Seq( crossScalaVersions := Seq(`scala_2.12_version`, `scala_2.13_version`, scala_3_version), libraryDependencies ++= Seq( - "org.apache.pekko" %% "pekko-actor" % "1.0.1" % "provided" + "org.apache.pekko" %% "pekko-actor" % "1.0.1" % "provided", + "org.apache.pekko" %% "pekko-actor-typed" % "1.0.1" % "test" ) )) .dependsOn( diff --git a/instrumentation/kamon-pekko/build.sbt b/instrumentation/kamon-pekko/build.sbt index 4a0c78a63..8c7c99a80 100644 --- a/instrumentation/kamon-pekko/build.sbt +++ b/instrumentation/kamon-pekko/build.sbt @@ -12,11 +12,13 @@ libraryDependencies ++= { scalatest % Test, logbackClassic % Test, "org.apache.pekko" %% "pekko-actor" % pekkoVersion % "provided,test", + "org.apache.pekko" %% "pekko-actor-typed" % pekkoVersion % "provided,test", "org.apache.pekko" %% "pekko-testkit" % pekkoVersion % "provided,test", "org.apache.pekko" %% "pekko-slf4j" % pekkoVersion % "provided,test", "org.apache.pekko" %% "pekko-remote" % pekkoVersion % "provided,test", "org.apache.pekko" %% "pekko-cluster" % pekkoVersion % "provided,test", "org.apache.pekko" %% "pekko-cluster-sharding" % pekkoVersion % "provided,test", + "org.apache.pekko" %% "pekko-cluster-typed" % pekkoVersion % "provided,test", "org.apache.pekko" %% "pekko-protobuf" % pekkoVersion % "provided,test", "org.apache.pekko" %% "pekko-testkit" % pekkoVersion % Test ) diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorCellInfo.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorCellInfo.scala index cee8cef56..194c13412 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorCellInfo.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorCellInfo.scala @@ -35,7 +35,6 @@ object ActorCellInfo { val actorName = ref.path.name val pathString = ref.path.elements.mkString("/") - val isRootSupervisor = pathString.length == 0 || pathString == "user" || pathString == "system" val isRouter = hasRouterProps(props) val isRoutee = PekkoPrivateAccess.isRoutedActorRef(parent) val isTemporary = PekkoPrivateAccess.isUnstartedActorCell(cell) @@ -48,6 +47,11 @@ object ActorCellInfo { else (props.actorClass(), None) + val isRootSupervisor = if (!isRouter && !isRoutee && isTyped(actorOrRouterClass)) + pathString != "user" + else + pathString.isEmpty || pathString == "user" || pathString == "system" + val fullPath = if (isRoutee) cellName(system, parent) else cellName(system, ref) val dispatcherName = if (isRouter) { if (props.routerConfig.isInstanceOf[BalancingPool]) { diff --git a/instrumentation/kamon-pekko/src/test/resources/application.conf b/instrumentation/kamon-pekko/src/test/resources/application.conf index ca685c1f3..f278cde78 100644 --- a/instrumentation/kamon-pekko/src/test/resources/application.conf +++ b/instrumentation/kamon-pekko/src/test/resources/application.conf @@ -44,7 +44,7 @@ kamon { actors { track { - includes = [ "*/user/tracked-*", "*/user/measuring-*", "*/user/clean-after-collect", "*/user/stop", "*/user/repointable*", "*/" ] + includes = [ "*/user/tracked-*", "*/user/measuring-*", "*/user/clean-after-collect", "*/user/stop", "*/user/repointable*", "*/", "greet-service/*" ] excludes = [ "*/system/**", "*/user/tracked-explicitly-excluded", "*/user/non-tracked-actor" ] } diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TypedActor.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TypedActor.scala new file mode 100644 index 000000000..5ae40dc76 --- /dev/null +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TypedActor.scala @@ -0,0 +1,30 @@ +/* ========================================================================================= + * Copyright © 2013-2017 the kamon project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + * ========================================================================================= + */ + +package kamon.instrumentation.pekko + +import org.apache.pekko.actor.typed.{ActorRef, Behavior} +import org.apache.pekko.actor.typed.scaladsl.Behaviors + +object TypedActor { + final case class Greet(whom: String, replyTo: ActorRef[Greeted]) + final case class Greeted(whom: String, from: ActorRef[Greet]) + + def apply(): Behavior[Greet] = Behaviors.receive { (context, message) => + context.log.info("Hello {}!", message.whom) + message.replyTo ! Greeted(message.whom, context.self) + Behaviors.same + } +} diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TypedActorMetricsSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TypedActorMetricsSpec.scala new file mode 100644 index 000000000..53de2a0c5 --- /dev/null +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TypedActorMetricsSpec.scala @@ -0,0 +1,62 @@ +/* ========================================================================================= + * Copyright © 2013 the kamon project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + * ========================================================================================= + */ + +package kamon.instrumentation.pekko + +import org.apache.pekko.actor.typed.ActorSystem +import org.apache.pekko.actor.typed.scaladsl.AskPattern.Askable +import org.apache.pekko.util.Timeout +import kamon.instrumentation.pekko.ActorMetricsTestActor._ +import kamon.instrumentation.pekko.PekkoMetrics._ +import kamon.instrumentation.pekko.TypedActor._ +import kamon.tag.TagSet +import kamon.testkit.{InitAndStopKamonAfterAll, InstrumentInspection, MetricInspection} +import org.scalactic.TimesOnInt._ +import org.scalatest.BeforeAndAfterAll +import org.scalatest.matchers.should.Matchers +import org.scalatest.wordspec.AnyWordSpec + +import scala.concurrent.Await +import scala.concurrent.duration._ + +class TypedActorMetricsSpec extends AnyWordSpec + with MetricInspection.Syntax with InstrumentInspection.Syntax with Matchers + with InitAndStopKamonAfterAll { + + private val system: ActorSystem[Greet] = ActorSystem(TypedActor(), "greet-service") + + "the Kamon typed actor metrics" should { + "respect the configured include and exclude filters" in new ActorMetricsFixtures { + sendMessage("world") + val pathValues = ActorProcessingTime.tagValues("path") + pathValues should not contain ("greet-service/") + pathValues should contain("greet-service/user") + + } + } + + override protected def afterAll(): Unit = { + system.terminate() + super.afterAll() + } + + trait ActorMetricsFixtures { + + def sendMessage(name: String): Unit = { + val fut = system.ask[Greeted](Greet(name, _))(Timeout(10.seconds), system.scheduler) + Await.result(fut, 10.seconds) + } + } +}