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)
+ }
+ }
+}