Skip to content

Commit c9464f2

Browse files
authored
add basic support for typed actors (#136)
1 parent 9fa571f commit c9464f2

File tree

7 files changed

+78
-3
lines changed

7 files changed

+78
-3
lines changed

build.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ libraryDependencies ++= Seq(
3636
"org.apache.pekko" %% "pekko-slf4j" % pekkoVersion,
3737
"com.typesafe" % "config" % "1.4.3",
3838
"org.aspectj" % "aspectjweaver" % aspectjweaverVersion,
39+
"org.apache.pekko" %% "pekko-actor-typed" % pekkoVersion % Test,
3940
"org.apache.pekko" %% "pekko-testkit" % pekkoVersion % Test,
4041
"org.scalatest" %% "scalatest" % "3.2.19" % Test,
4142
"ch.qos.logback" % "logback-classic" % "1.3.15" % Test

src/main/scala/com/github/pjfanning/micrometer/pekko/ActorMetrics.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ object ActorMetrics {
3535
}
3636
}
3737
def hasMetricsFor(e: Entity): Boolean = map.contains(e)
38+
39+
private[pekko] def getMap(): Map[Entity, ActorMetrics] = map.toMap
40+
private[pekko] def clear(): Unit = map.clear()
3841
}
3942

4043
class ActorMetrics(entity: Entity) {

src/main/scala/org/apache/pekko/monitor/instrumentation/CellInfo.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.apache.pekko.monitor.instrumentation
1818

1919
import com.github.pjfanning.micrometer.pekko.{Entity, MetricsConfig}
20-
2120
import org.apache.pekko.actor.{ActorRef, ActorSystem, Cell}
2221
import org.apache.pekko.routing.{NoRouter, RoutedActorRef}
2322

@@ -26,14 +25,21 @@ case class CellInfo(entity: Entity, actorSystemName: String, isRouter: Boolean,
2625

2726
object CellInfo {
2827

28+
// use String instead of Class[_] to avoid requiring a runtime dependency on the pekko-actor-typed jar
29+
val TypedActorAdapterClassName = "org.apache.pekko.actor.typed.internal.adapter.ActorAdapter"
30+
2931
def cellName(system: ActorSystem, ref: ActorRef): String =
3032
s"""${system.name}/${ref.path.elements.mkString("/")}"""
3133

3234
def cellInfoFor(cell: Cell, system: ActorSystem, ref: ActorRef, parent: ActorRef, actorCellCreation: Boolean): CellInfo = {
3335
def hasRouterProps(cell: Cell): Boolean = cell.props.deploy.routerConfig != NoRouter
3436

3537
val pathString = ref.path.elements.mkString("/")
36-
val isRootSupervisor = pathString.isEmpty || pathString == "user" || pathString == "system"
38+
val isTyped = cell.props.actorClass().getName == TypedActorAdapterClassName
39+
val isRootSupervisor = if (isTyped)
40+
pathString != "user"
41+
else
42+
pathString.isEmpty || pathString == "user" || pathString == "system"
3743
val isRouter = hasRouterProps(cell)
3844
val isRoutee = parent.isInstanceOf[RoutedActorRef]
3945

src/test/resources/application.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pekko {
77
micrometer.pekko {
88
metric.filters {
99
pekko-actor {
10-
includes = [ "**/user/tracked-**", "*/user/measuring-**", "*/user/stop-**" ]
10+
includes = [ "**/user/tracked-**", "*/user/measuring-**", "*/user/stop-**", "greet-service/**" ]
1111
excludes = [ "*/system/**", "*/user/IO-**", "**/user/tracked-explicitly-excluded-**" ]
1212
}
1313

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.github.pjfanning.micrometer.pekko
2+
3+
import org.apache.pekko.actor.typed.{ActorRef, Behavior}
4+
import org.apache.pekko.actor.typed.scaladsl.Behaviors
5+
6+
object TypedActor {
7+
final case class Greet(whom: String, replyTo: ActorRef[Greeted])
8+
final case class Greeted(whom: String, from: ActorRef[Greet])
9+
10+
def apply(): Behavior[Greet] = Behaviors.receive { (context, message) =>
11+
context.log.info("Hello {}!", message.whom)
12+
message.replyTo ! Greeted(message.whom, context.self)
13+
Behaviors.same
14+
}
15+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.github.pjfanning.micrometer.pekko
2+
3+
import com.github.pjfanning.micrometer.pekko.TypedActor.{Greet, Greeted}
4+
import org.apache.pekko.actor.typed.ActorSystem
5+
import org.apache.pekko.actor.typed.scaladsl.AskPattern.Askable
6+
import org.apache.pekko.util.Timeout
7+
8+
import scala.concurrent.duration.DurationInt
9+
import scala.concurrent.Await
10+
11+
class TypedActorMetricsSpec extends BaseSpec {
12+
13+
private val system: ActorSystem[Greet] = ActorSystem(TypedActor(), "greet-service")
14+
15+
override def afterAll(): Unit = {
16+
super.afterAll()
17+
system.terminate()
18+
ActorMetrics.clear()
19+
}
20+
21+
"the typed actor metrics" should {
22+
"respect the configured include and exclude filters" in {
23+
sendMessage("world")
24+
val map = ActorMetrics.getMap()
25+
map should not be empty
26+
val entity = Entity("greet-service/user", MetricsConfig.Actor)
27+
val metrics = map(entity)
28+
metrics.messages.count() shouldEqual 2.0
29+
}
30+
}
31+
32+
def sendMessage(name: String): Unit = {
33+
val fut = system.ask[Greeted](Greet(name, _))(Timeout(10.seconds), system.scheduler)
34+
Await.result(fut, 10.seconds)
35+
}
36+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.apache.pekko.actor.typed.instrumentation
2+
3+
import com.github.pjfanning.micrometer.pekko.BaseSpec
4+
import org.apache.pekko.actor.typed.internal.adapter.ActorAdapter
5+
import org.apache.pekko.monitor.instrumentation.CellInfo
6+
7+
class ClassSpec extends BaseSpec {
8+
9+
"Classloading" should {
10+
"match TypedActorAdapterClassName" in {
11+
Class.forName(CellInfo.TypedActorAdapterClassName) shouldEqual classOf[ActorAdapter[_]]
12+
}
13+
}
14+
}

0 commit comments

Comments
 (0)