Non-intrusive native Prometheus collectors for Akka internals, negligible performance overhead, suitable for production use.
-
Are you running (or about to run) Akka in production, full-throttle, and want to see what happens inside? Did your load tests produce some ask timeouts? thread starvation? threads behaving non-reactively? old code doing nasty blocking I/O?
-
Would be nice to use Cinnamon Telemetry, but LightBend subscription is out of reach?
-
Overhead created by Kamon doesn't look acceptable, especially when running full-throttle?
-
Already familiar with Prometheus/Grafana observability stack?
If you answer 'yes' to most of the questions above, Akka Sensors may be the right choice for you:
-
Comprehensive feature set to make internals of your Akka visible, in any environment, including high-load production.
-
It is OSS/free, as in MIT license, and uses explicit, very lightweight instrumentation - yet is a treasure trove for a busy observability engineer.
-
Won't affect CPU costs, when running in public cloud.
- time of runnable waiting in queue (histogram)
- time of runnable run (histogram)
- implementation-specific ForkJoinPool and ThreadPool stats (gauges)
- thread states, as seen from JMX ThreadInfo (histogram, updated once in X seconds)
- active worker threads (histogram, updated on each runnable)
- thread watcher, keeping eye on threads running suspiciously long, and reporting their stacktraces - to help you find blocking code quickly
- number of actors (gauge)
- time of actor 'receive' run (histogram)
- actor activity time (histogram)
- unhandled messages (count)
- exceptions (count)
- recovery time (histogram)
- number of recovery events (histogram)
- persist time (histogram)
- recovery failures (counter)
- persist failures (counter)
- cluster events, per type/member (counter)
- number of instances
- start since / uptime
- JVM version
- memory pools
- garbage collector
libraryDependencies ++= Seq( "nl.pragmasoft.sensors" %% "sensors-core" % "1.0.0" ) Override type and executor with Sensors' instrumented executors. Add akka.sensors.AkkaSensorsExtension to extensions.
akka { actor { # main/global/default dispatcher default-dispatcher { type = "akka.sensors.dispatch.InstrumentedDispatcherConfigurator" executor = "akka.sensors.dispatch.InstrumentedExecutor" instrumented-executor { delegate = "fork-join-executor" measure-runs = true watch-long-runs = true watch-check-interval = 1s watch-too-long-run = 3s } } # some other dispatcher used in your app default-blocking-io-dispatcher { type = "akka.sensors.dispatch.InstrumentedDispatcherConfigurator" executor = "akka.sensors.dispatch.InstrumentedExecutor" instrumented-executor { delegate = "thread-pool-executor" measure-runs = true watch-long-runs = false } } } extensions = [ akka.sensors.AkkaSensorsExtension ] } akka { default-dispatcher { type = "akka.sensors.dispatch.InstrumentedDispatcherConfigurator" executor = "akka.sensors.dispatch.InstrumentedExecutor" instrumented-executor { delegate = "fork-join-executor" measure-runs = true watch-long-runs = false } fork-join-executor { parallelism-min = 6 parallelism-factor = 1 parallelism-max = 6 } } } # Non-persistent actors class MyImportantActor extends Actor with ActorMetrics { # This becomes label 'actor', default is simple class name # but you may segment it further # Just make sure the cardinality is sane (<100) override protected def actorTag: String = ... ... # your implementation } # Persistent actors class MyImportantPersistentActor extends Actor with PersistentActorMetrics { ... val behavior = BehaviorMetrics[Command]("ActorLabel") # basic actor metrics .withReceiveTimeoutMetrics(TimeoutCmd) # provides metric for amount of received timeout commands .withPersistenceMetrics # if inner behavior is event sourced, persistence metrics would be collected .setup { ctx: ActorContext[Command] => ... # your implementation } Some parameters of the Sensors library itself, that you may want to tune:
akka.sensors { thread-state-snapshot-period = 5s cluster-watch-enabled = false } 
