From ea16490ace544a67feb7fa2345cf6fb63cf8213f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Fri, 18 Jun 2021 11:27:00 +0200 Subject: [PATCH 01/31] Add modules --- .../mesmer/core/module/AkkaHttpModule.scala | 30 +++++++++++++++++++ .../io/scalac/mesmer/core/module/Module.scala | 22 ++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala create mode 100644 core/src/main/scala/io/scalac/mesmer/core/module/Module.scala diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala new file mode 100644 index 000000000..27e330430 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -0,0 +1,30 @@ +package io.scalac.mesmer.core.module + +import com.typesafe.config.Config + +/** + * Definition of AkkHttp metric related features + */ +sealed trait AkkaHttpMetricsModule extends MetricModule { + this: Module => + + override type Metrics[T] = AkkaHttpMetricsDef[T] + + protected trait AkkaHttpMetricsDef[T] { + def requestTime: T + def requestCounter: T + } +} + +object AkkaHttpModule extends Module with AkkaHttpMetricsModule { + val name: String = "akka-http" + + override type All[T] = Metrics[T] + + def enabled(config: Config): All[Boolean] = + new AkkaHttpMetricsDef[Boolean] { + + val requestTime: Boolean = true + val requestCounter: Boolean = true + } +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala new file mode 100644 index 000000000..6d5202860 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -0,0 +1,22 @@ +package io.scalac.mesmer.core.module + +import com.typesafe.config.Config + +trait Module { + def name: String + type All[_] + + def enabled(config: Config): All[Boolean] +} + +trait MetricModule { + this: Module => + override type All[T] <: Metrics[T] + type Metrics[T] +} + +trait TracesModule { + this: Module => + override type All[T] <: Traces[T] + type Traces[T] +} From 1b79fa993f425007bbd92e5071ef38b7e967c067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Fri, 18 Jun 2021 12:38:05 +0200 Subject: [PATCH 02/31] Add MasmerConfiguration trait --- .../scala/io/scalac/mesmer/agent/Agent.scala | 4 +- .../scala/io/scalac/mesmer/agent/Boot.scala | 22 ++- .../agent/akka/http/AkkaHttpAgent.scala | 22 ++- .../util/i13n/InstrumentModuleFactory.scala | 15 ++ .../mesmer/agent/akka/AkkaHttpAgentTest.scala | 2 +- .../mesmer/agent/utils/InstallAgent.scala | 4 +- .../core/config/ConfigurationUtils.scala | 59 ++++++ .../mesmer/core/module/AkkaHttpModule.scala | 22 ++- .../io/scalac/mesmer/core/module/Module.scala | 9 + extension/src/main/resources/reference.conf | 7 + .../extension/AkkaStreamMonitoring.scala | 54 ++--- .../ClusterRegionsMonitorActor.scala | 2 +- .../config/AkkaMonitoringConfig.scala | 4 +- .../extension/config/BufferConfig.scala | 2 +- .../extension/config/CachingConfig.scala | 5 +- .../extension/config/ConfigurationUtils.scala | 40 ---- .../service/ActorConfigurationService.scala | 2 +- .../OpenTelemetryActorMetricsMonitor.scala | 184 +++++++++--------- .../OpenTelemetryActorSystemMonitor.scala | 22 +-- .../OpenTelemetryClusterMetricsMonitor.scala | 99 +++++----- ...elemetryHttpConnectionMetricsMonitor.scala | 39 ++-- .../OpenTelemetryHttpMetricsMonitor.scala | 57 +++--- ...enTelemetryPersistenceMetricsMonitor.scala | 63 +++--- .../OpenTelemetryStreamMetricsMonitor.scala | 51 +++-- ...elemetryStreamOperatorMetricsMonitor.scala | 72 ++++--- 25 files changed, 438 insertions(+), 424 deletions(-) create mode 100644 core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala delete mode 100644 extension/src/main/scala/io/scalac/mesmer/extension/config/ConfigurationUtils.scala diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala index e390bdc4c..e84d18fe9 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala @@ -13,7 +13,9 @@ object Agent { private val logger = LoggerFactory.getLogger(classOf[Agent]) - def apply(head: AgentInstrumentation, tail: AgentInstrumentation*): Agent = Agent((head +: tail).toSet) + def apply(head: AgentInstrumentation, tail: AgentInstrumentation*): Agent = new Agent((head +: tail).toSet) + + val empty: Agent = new Agent(Set.empty) class LoadingResult(val fqns: Seq[String]) { import LoadingResult.{ logger => loadingLogger } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala index 806b62cee..bc33a8487 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala @@ -1,24 +1,24 @@ package io.scalac.mesmer.agent -import java.lang.instrument.Instrumentation - +import com.typesafe.config.ConfigFactory +import io.scalac.mesmer.agent.akka.actor.{ AkkaActorAgent, AkkaMailboxAgent } +import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent +import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent +import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent +import io.scalac.mesmer.core.util.ModuleInfo import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.builder.AgentBuilder import net.bytebuddy.dynamic.scaffold.TypeValidation +import java.lang.instrument.Instrumentation import scala.annotation.unused -import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent -import io.scalac.mesmer.agent.akka.actor.AkkaMailboxAgent -import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent -import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent -import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent -import io.scalac.mesmer.core.util.ModuleInfo - object Boot { def premain(@unused arg: String, instrumentation: Instrumentation): Unit = { + val config = ConfigFactory.load() + val agentBuilder = new AgentBuilder.Default() .`with`(new ByteBuddy().`with`(TypeValidation.DISABLED)) .`with`(new AgentBuilder.InitializationStrategy.SelfInjection.Eager()) @@ -28,7 +28,9 @@ object Boot { .`with`(AgentBuilder.InstallationListener.StreamWriting.toSystemOut) val allInstrumentations = - AkkaPersistenceAgent.agent ++ AkkaHttpAgent.agent ++ AkkaStreamAgent.agent ++ AkkaActorAgent.agent ++ AkkaMailboxAgent.agent + AkkaPersistenceAgent.agent ++ AkkaStreamAgent.agent ++ AkkaHttpAgent.agent( + config + ) ++ AkkaActorAgent.agent ++ AkkaMailboxAgent.agent val moduleInfo = ModuleInfo.extractModulesInformation(Thread.currentThread().getContextClassLoader) allInstrumentations diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala index f81097562..e974c5280 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala @@ -1,20 +1,32 @@ package io.scalac.mesmer.agent.akka.http -import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } import io.scalac.mesmer.core.model.SupportedModules +import io.scalac.mesmer.core.module.AkkaHttpModule import io.scalac.mesmer.core.support.ModulesSupport -object AkkaHttpAgent extends InstrumentModuleFactory { +object AkkaHttpAgent + extends InstrumentModuleFactoryTest(AkkaHttpModule) + with AkkaHttpModule.Metrics[AgentInstrumentation] { // @ToDo tests all supported versions - protected final val supportedModules: SupportedModules = + protected val supportedModules: SupportedModules = SupportedModules(ModulesSupport.akkaHttpModule, ModulesSupport.akkaHttp) - private val httpAgent = + def requestTime: AgentInstrumentation = httpAgent + + def requestCounter: AgentInstrumentation = httpAgent + + private val httpAgent: AgentInstrumentation = instrument("akka.http.scaladsl.HttpExt") .visit[HttpExtAdvice]("bindAndHandle") - val agent: Agent = Agent(httpAgent) + def agent(config: AkkaHttpModule.All[Boolean]): Agent = { + + val requestCounterAgent = if (config.requestCounter) Agent(requestCounter) else Agent.empty + val requestTimeAgent = if (config.requestTime) Agent(requestTime) else Agent.empty + requestCounterAgent ++ requestTimeAgent + } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala index 84bbb5ede..c2bf4506c 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala @@ -1,5 +1,8 @@ package io.scalac.mesmer.agent.util.i13n +import com.typesafe.config.Config +import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } import io.scalac.mesmer.core.model.SupportedModules +import io.scalac.mesmer.core.module.Module trait InstrumentModuleFactory { @@ -7,3 +10,15 @@ trait InstrumentModuleFactory { protected def instrument(tpe: Type): TypeInstrumentation = TypeInstrumentation(TypeTarget(tpe, supportedModules)) } + +abstract class InstrumentModuleFactoryTest[M <: Module](val module: M) { + this: M#All[AgentInstrumentation] => + + protected def supportedModules: SupportedModules + + protected def instrument(tpe: Type): TypeInstrumentation = TypeInstrumentation(TypeTarget(tpe, supportedModules)) + + protected def agent(config: M#All[Boolean]): Agent + + final def agent(config: Config): Agent = agent(module.enabled(config)) +} diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala index 611b66639..39494e1d2 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala @@ -31,7 +31,7 @@ import io.scalac.mesmer.core.httpServiceKey class AkkaHttpAgentTest extends InstallAgent with AnyFlatSpecLike with ScalatestRouteTest with Matchers { - override protected val agent = AkkaHttpAgent.agent + override protected val agent = AkkaHttpAgent.agent(ConfigFactory.empty) override def testConfig: Config = ConfigFactory.load("application-test") diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala index 0e3a07b09..d9366eb65 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala @@ -1,12 +1,12 @@ package io.scalac.mesmer.agent.utils +import com.typesafe.config.ConfigFactory import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.ByteBuddyAgent import net.bytebuddy.agent.builder.AgentBuilder import net.bytebuddy.dynamic.scaffold.TypeValidation import org.scalatest.BeforeAndAfterAll import org.scalatest.TestSuite - import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent import io.scalac.mesmer.agent.akka.actor.AkkaMailboxAgent @@ -18,7 +18,7 @@ import io.scalac.mesmer.core.util.ModuleInfo.extractModulesInformation object InstallAgent { def allInstrumentations: Agent = - AkkaActorAgent.agent ++ AkkaHttpAgent.agent ++ AkkaPersistenceAgent.agent ++ AkkaStreamAgent.agent ++ AkkaMailboxAgent.agent + AkkaActorAgent.agent ++ AkkaHttpAgent.agent(ConfigFactory.empty) ++ AkkaPersistenceAgent.agent ++ AkkaStreamAgent.agent ++ AkkaMailboxAgent.agent } abstract class InstallAgent extends TestSuite with BeforeAndAfterAll { diff --git a/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala b/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala new file mode 100644 index 000000000..af1459dd4 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala @@ -0,0 +1,59 @@ +package io.scalac.mesmer.core.config + +import com.typesafe.config.{ Config, ConfigException } +import io.scalac.mesmer.core.config.ConfigurationUtils.ConfigOps + +import scala.language.implicitConversions +import scala.reflect.{ classTag, ClassTag } +import scala.util.Try + +object ConfigurationUtils { + + private[core] class ConfigOps(private val value: Config) extends AnyVal { + def tryValue[T: ClassTag]( + path: String + )(extractor: Config => String => T): Either[String, T] = + Try(Function.uncurried(extractor)(value, path)).toEither.left.map { + case _: ConfigException.Missing => s"Configuration for $path" + case _: ConfigException.WrongType => + s"$path is not type of ${classTag[T].runtimeClass}" + } + } + + implicit def toConfigOps(config: Config): ConfigOps = new ConfigOps(config) + +} + +trait Configuration { + protected implicit def toConfigOps(config: Config): ConfigOps = new ConfigOps(config) + + type Result + + protected def defaultConfig: Result + def fromConfig(config: Config): Result = config + .tryValue(absoluteBase)(_.getConfig) + .map(extractFromConfig) + .getOrElse(defaultConfig) + + protected val absoluteBase: String + protected def extractFromConfig(config: Config): Result +} + +trait MesmerConfigurationBase extends Configuration { + + /** + * Absolute path for mesmer configuration in .conf file + */ + private final val mesmerBase: String = "io.scalac.mesmer" + + protected lazy val absoluteBase = s"$mesmerBase.$mesmerConfig" + + /** + * Name of configuration inside mesmer branch + */ + protected def mesmerConfig: String +} + +trait MesmerConfiguration[T] extends MesmerConfigurationBase { + type Result = T +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala index 27e330430..f9c796566 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -16,15 +16,25 @@ sealed trait AkkaHttpMetricsModule extends MetricModule { } } -object AkkaHttpModule extends Module with AkkaHttpMetricsModule { +object AkkaHttpModule extends MesmerModule with AkkaHttpMetricsModule { + + final case class AkkaHttpModuleConfig(requestTime: Boolean, requestCounter: Boolean) extends All[Boolean] + val name: String = "akka-http" override type All[T] = Metrics[T] - def enabled(config: Config): All[Boolean] = - new AkkaHttpMetricsDef[Boolean] { + val defaultConfig = AkkaHttpModuleConfig(true, true) + + protected def extractFromConfig(config: Config): AkkaHttpModule.AkkaHttpMetricsDef[Boolean] = { + val requestTime = config + .tryValue("request-time")(_.getBoolean) + .getOrElse(defaultConfig.requestTime) - val requestTime: Boolean = true - val requestCounter: Boolean = true - } + val requestCounter = config + .tryValue("request-counter")(_.getBoolean) + .getOrElse(defaultConfig.requestCounter) + + AkkaHttpModuleConfig(requestTime = requestTime, requestCounter = requestCounter) + } } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala index 6d5202860..53ba9b9b4 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -1,6 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.Config +import io.scalac.mesmer.core.config.MesmerConfigurationBase trait Module { def name: String @@ -9,6 +10,14 @@ trait Module { def enabled(config: Config): All[Boolean] } +trait MesmerModule extends Module with MesmerConfigurationBase { + override type Result = All[Boolean] + + final def enabled(config: Config): All[Boolean] = fromConfig(config) + + val mesmerConfig = s"module.$name" +} + trait MetricModule { this: Module => override type All[T] <: Metrics[T] diff --git a/extension/src/main/resources/reference.conf b/extension/src/main/resources/reference.conf index c97467c06..45cf44fb3 100644 --- a/extension/src/main/resources/reference.conf +++ b/extension/src/main/resources/reference.conf @@ -24,6 +24,13 @@ io { akka-cluster = true } + enabled { + akka-http { + request-time = true + request-counter = true + } + } + #flush configs cleaning { max-staleness = 20 seconds diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala index b232ea911..9d0446942 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala @@ -1,54 +1,40 @@ package io.scalac.mesmer.extension -import java.util -import java.util.concurrent.atomic.AtomicReference - -import akka.actor.ActorRef -import akka.actor.typed import akka.actor.typed._ import akka.actor.typed.receptionist.Receptionist.Register -import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.scaladsl.TimerScheduler import akka.actor.typed.scaladsl.adapter._ +import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler} +import akka.actor.{ActorRef, typed} import akka.util.Timeout - -import scala.annotation.tailrec -import scala.collection.mutable -import scala.collection.mutable.ListBuffer -import scala.concurrent.duration.FiniteDuration -import scala.concurrent.duration._ -import scala.jdk.CollectionConverters._ -import scala.jdk.DurationConverters._ -import scala.util.Failure -import scala.util.Success - import io.scalac.mesmer.core.akka.model.PushMetrics +import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.core.event.Service.streamService import io.scalac.mesmer.core.event.StreamEvent -import io.scalac.mesmer.core.event.StreamEvent.LastStreamStats -import io.scalac.mesmer.core.event.StreamEvent.StreamInterpreterStats -import io.scalac.mesmer.core.model.Tag.StageName -import io.scalac.mesmer.core.model.Tag.StreamName +import io.scalac.mesmer.core.event.StreamEvent.{LastStreamStats, StreamInterpreterStats} +import io.scalac.mesmer.core.model.Tag.{StageName, StreamName} import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.model.stream.ConnectionStats -import io.scalac.mesmer.core.model.stream.StageInfo +import io.scalac.mesmer.core.model.stream.{ConnectionStats, StageInfo} import io.scalac.mesmer.core.support.ModulesSupport import io.scalac.mesmer.extension.AkkaStreamMonitoring._ -import io.scalac.mesmer.extension.config.BufferConfig -import io.scalac.mesmer.extension.config.CachingConfig -import io.scalac.mesmer.extension.config.ConfigurationUtils._ +import io.scalac.mesmer.extension.config.{BufferConfig, CachingConfig} import io.scalac.mesmer.extension.metric.MetricObserver.Result -import io.scalac.mesmer.extension.metric.StreamMetricsMonitor -import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.EagerLabels -import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.{ Labels => GlobalLabels } -import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor +import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.{EagerLabels, Labels => GlobalLabels} import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.Labels -import io.scalac.mesmer.extension.service.ActorTreeService +import io.scalac.mesmer.extension.metric.{StreamMetricsMonitor, StreamOperatorMetricsMonitor} import io.scalac.mesmer.extension.service.ActorTreeService.Command.GetActors -import io.scalac.mesmer.extension.service.actorTreeServiceKey +import io.scalac.mesmer.extension.service.{ActorTreeService, actorTreeServiceKey} import io.scalac.mesmer.extension.util.GenericBehaviors +import java.util +import java.util.concurrent.atomic.AtomicReference +import scala.annotation.tailrec +import scala.collection.mutable +import scala.collection.mutable.ListBuffer +import scala.concurrent.duration.{FiniteDuration, _} +import scala.jdk.CollectionConverters._ +import scala.jdk.DurationConverters._ +import scala.util.{Failure, Success} + object AkkaStreamMonitoring { sealed trait Command diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/ClusterRegionsMonitorActor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/ClusterRegionsMonitorActor.scala index cab1c882f..f4c60725c 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/ClusterRegionsMonitorActor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/ClusterRegionsMonitorActor.scala @@ -20,7 +20,7 @@ import scala.jdk.DurationConverters.JavaDurationOps import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.CachedQueryResult -import io.scalac.mesmer.extension.config.ConfigurationUtils._ +import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.extension.metric.ClusterMetricsMonitor import io.scalac.mesmer.extension.metric.ClusterMetricsMonitor.Labels diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala index fabdbbe33..4d63adeb9 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala @@ -5,7 +5,7 @@ import com.typesafe.config.Config import scala.concurrent.duration._ import scala.jdk.DurationConverters._ -import io.scalac.mesmer.extension.config +import io.scalac.mesmer.core.config.ConfigurationUtils._ case class AkkaMonitoringConfig( autoStart: AutoStartSettings, @@ -16,7 +16,7 @@ case class AutoStartSettings(akkaActor: Boolean, akkaHttp: Boolean, akkaPersiste object AkkaMonitoringConfig { - import config.ConfigurationUtils._ + private val autoStartDefaults = AutoStartSettings(akkaActor = false, akkaHttp = false, akkaCluster = false, akkaPersistence = false) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala index f5d163c3f..67d58cc94 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala @@ -3,7 +3,7 @@ package io.scalac.mesmer.extension.config import com.typesafe.config.Config import io.scalac.mesmer.core.model.Module -import io.scalac.mesmer.extension.config.ConfigurationUtils._ +import io.scalac.mesmer.core.config.ConfigurationUtils._ object BufferConfig { private val DefaultSize = 1024 diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala index 69a6c1dad..fcfdcd94b 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala @@ -1,9 +1,8 @@ package io.scalac.mesmer.extension.config import com.typesafe.config.Config - +import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.core.model.Module -import io.scalac.mesmer.extension.config.ConfigurationUtils._ case class CachingConfig(maxEntries: Int) @@ -18,5 +17,5 @@ object CachingConfig { } yield CachingConfig(maxEntries) ).getOrElse(CachingConfig.empty) - def empty: CachingConfig = CachingConfig(DefaultSize) + val empty: CachingConfig = CachingConfig(DefaultSize) } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/ConfigurationUtils.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/ConfigurationUtils.scala deleted file mode 100644 index 948c71efe..000000000 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/ConfigurationUtils.scala +++ /dev/null @@ -1,40 +0,0 @@ -package io.scalac.mesmer.extension.config - -import com.typesafe.config.Config -import com.typesafe.config.ConfigException - -import scala.language.implicitConversions -import scala.reflect.ClassTag -import scala.reflect.classTag -import scala.util.Try - -import io.scalac.mesmer.extension.config.ConfigurationUtils.ConfigOps - -object ConfigurationUtils { - - private[extension] class ConfigOps(private val value: Config) extends AnyVal { - def tryValue[T: ClassTag]( - path: String - )(extractor: Config => String => T): Either[String, T] = - Try(Function.uncurried(extractor)(value, path)).toEither.left.map { - case _: ConfigException.Missing => s"Configuration for $path" - case _: ConfigException.WrongType => - s"$path is not type of ${classTag[T].runtimeClass}" - } - } - - implicit def toConfigOps(config: Config): ConfigOps = new ConfigOps(config) -} - -trait Configuration[T] { - protected implicit def toConfigOps(config: Config): ConfigOps = new ConfigOps(config) - - def default: T - def fromConfig(config: Config): T = config - .tryValue(configurationBase)(_.getConfig) - .map(extractFromConfig) - .getOrElse(default) - - protected val configurationBase: String - protected def extractFromConfig(config: Config): T -} diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/service/ActorConfigurationService.scala b/extension/src/main/scala/io/scalac/mesmer/extension/service/ActorConfigurationService.scala index c57fde6f7..12fb177c7 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/service/ActorConfigurationService.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/service/ActorConfigurationService.scala @@ -9,7 +9,7 @@ import scala.jdk.CollectionConverters._ import io.scalac.mesmer.core.PathMatcher import io.scalac.mesmer.core.model.ActorConfiguration -import io.scalac.mesmer.extension.config.ConfigurationUtils._ +import io.scalac.mesmer.core.config.ConfigurationUtils._ trait ActorConfigurationService { def forActorPath(ref: classic.ActorPath): ActorConfiguration diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala index 5c758f58b..cf03c008d 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala @@ -2,16 +2,14 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter - -import io.scalac.mesmer.extension.metric.ActorMetricsMonitor -import io.scalac.mesmer.extension.metric.MetricObserver -import io.scalac.mesmer.extension.metric.RegisterRoot +import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.extension.metric.{ ActorMetricsMonitor, MetricObserver, RegisterRoot } import io.scalac.mesmer.extension.upstream.OpenTelemetryActorMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ object OpenTelemetryActorMetricsMonitor { - case class MetricNames( + final case class MetricNames( mailboxSize: String, mailboxTimeAvg: String, mailboxTimeMin: String, @@ -28,9 +26,91 @@ object OpenTelemetryActorMetricsMonitor { sentMessages: String, droppedMessages: String ) - object MetricNames { + object MetricNames extends MesmerConfiguration[MetricNames] { + + protected val mesmerConfig: String = "mesmer.metrics.actor-metrics" + + protected def extractFromConfig(config: Config): MetricNames = { + val mailboxSize = config + .tryValue("mailbox-size")(_.getString) + .getOrElse(defaultConfig.mailboxSize) + + val mailboxTimeAvg = config + .tryValue("mailbox-time-avg")(_.getString) + .getOrElse(defaultConfig.mailboxTimeAvg) + + val mailboxTimeMin = config + .tryValue("mailbox-time-min")(_.getString) + .getOrElse(defaultConfig.mailboxTimeMin) + + val mailboxTimeMax = config + .tryValue("mailbox-time-max")(_.getString) + .getOrElse(defaultConfig.mailboxTimeMax) + + val mailboxTimeSum = config + .tryValue("mailbox-time-sum")(_.getString) + .getOrElse(defaultConfig.mailboxTimeSum) + + val stashSize = config + .tryValue("stash-size")(_.getString) + .getOrElse(defaultConfig.stashedMessages) + + val receivedMessages = config + .tryValue("received-messages")(_.getString) + .getOrElse(defaultConfig.receivedMessages) + + val processedMessages = config + .tryValue("processed-messages")(_.getString) + .getOrElse(defaultConfig.processedMessages) + + val failedMessages = config + .tryValue("failed-messages")(_.getString) + .getOrElse(defaultConfig.failedMessages) + + val processingTimeAvg = config + .tryValue("processing-time-avg")(_.getString) + .getOrElse(defaultConfig.processingTimeAvg) + + val processingTimeMin = config + .tryValue("processing-time-min")(_.getString) + .getOrElse(defaultConfig.processingTimeMin) + + val processingTimeMax = config + .tryValue("processing-time-max")(_.getString) + .getOrElse(defaultConfig.processingTimeMax) + + val processingTimeSum = config + .tryValue("processing-time-sum")(_.getString) + .getOrElse(defaultConfig.processingTimeSum) + + val sentMessages = config + .tryValue("sent-messages")(_.getString) + .getOrElse(defaultConfig.sentMessages) + + val droppedMessages = config + .tryValue("dropped-messages")(_.getString) + .getOrElse(defaultConfig.droppedMessages) - def default: MetricNames = + MetricNames( + mailboxSize, + mailboxTimeAvg, + mailboxTimeMin, + mailboxTimeMax, + mailboxTimeSum, + stashSize, + receivedMessages, + processedMessages, + failedMessages, + processingTimeAvg, + processingTimeMin, + processingTimeMax, + processingTimeSum, + sentMessages, + droppedMessages + ) + } + + protected val defaultConfig: MetricNames = MetricNames( "akka_actor_mailbox_size", "akka_actor_mailbox_time_avg", @@ -49,96 +129,6 @@ object OpenTelemetryActorMetricsMonitor { "akka_actor_dropped_messages_total" ) - def fromConfig(config: Config): MetricNames = { - import io.scalac.mesmer.extension.config.ConfigurationUtils._ - val defaultCached = default - - config - .tryValue("io.scalac.akka-monitoring.metrics.actor-metrics")( - _.getConfig - ) - .map { clusterMetricsConfig => - val mailboxSize = clusterMetricsConfig - .tryValue("mailbox-size")(_.getString) - .getOrElse(defaultCached.mailboxSize) - - val mailboxTimeAvg = clusterMetricsConfig - .tryValue("mailbox-time-avg")(_.getString) - .getOrElse(defaultCached.mailboxTimeAvg) - - val mailboxTimeMin = clusterMetricsConfig - .tryValue("mailbox-time-min")(_.getString) - .getOrElse(defaultCached.mailboxTimeMin) - - val mailboxTimeMax = clusterMetricsConfig - .tryValue("mailbox-time-max")(_.getString) - .getOrElse(defaultCached.mailboxTimeMax) - - val mailboxTimeSum = clusterMetricsConfig - .tryValue("mailbox-time-sum")(_.getString) - .getOrElse(defaultCached.mailboxTimeSum) - - val stashSize = clusterMetricsConfig - .tryValue("stash-size")(_.getString) - .getOrElse(defaultCached.stashedMessages) - - val receivedMessages = clusterMetricsConfig - .tryValue("received-messages")(_.getString) - .getOrElse(defaultCached.receivedMessages) - - val processedMessages = clusterMetricsConfig - .tryValue("processed-messages")(_.getString) - .getOrElse(defaultCached.processedMessages) - - val failedMessages = clusterMetricsConfig - .tryValue("failed-messages")(_.getString) - .getOrElse(defaultCached.failedMessages) - - val processingTimeAvg = clusterMetricsConfig - .tryValue("processing-time-avg")(_.getString) - .getOrElse(defaultCached.processingTimeAvg) - - val processingTimeMin = clusterMetricsConfig - .tryValue("processing-time-min")(_.getString) - .getOrElse(defaultCached.processingTimeMin) - - val processingTimeMax = clusterMetricsConfig - .tryValue("processing-time-max")(_.getString) - .getOrElse(defaultCached.processingTimeMax) - - val processingTimeSum = clusterMetricsConfig - .tryValue("processing-time-sum")(_.getString) - .getOrElse(defaultCached.processingTimeSum) - - val sentMessages = clusterMetricsConfig - .tryValue("sent-messages")(_.getString) - .getOrElse(defaultCached.sentMessages) - - val droppedMessages = clusterMetricsConfig - .tryValue("dropped-messages")(_.getString) - .getOrElse(defaultCached.droppedMessages) - - MetricNames( - mailboxSize, - mailboxTimeAvg, - mailboxTimeMin, - mailboxTimeMax, - mailboxTimeSum, - stashSize, - receivedMessages, - processedMessages, - failedMessages, - processingTimeAvg, - processingTimeMin, - processingTimeMax, - processingTimeSum, - sentMessages, - droppedMessages - ) - } - .getOrElse(defaultCached) - } - } def apply(meter: Meter, config: Config): OpenTelemetryActorMetricsMonitor = diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala index ee8fd4e0c..603c56544 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala @@ -2,29 +2,27 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter - -import io.scalac.mesmer.extension.config.Configuration -import io.scalac.mesmer.extension.metric.ActorSystemMonitor +import io.scalac.mesmer.core.config.MesmerConfiguration import io.scalac.mesmer.extension.metric.ActorSystemMonitor.BoundMonitor -import io.scalac.mesmer.extension.metric.RegisterRoot +import io.scalac.mesmer.extension.metric.{ ActorSystemMonitor, RegisterRoot } import io.scalac.mesmer.extension.upstream.OpenTelemetryActorSystemMonitor.MetricNames -import io.scalac.mesmer.extension.upstream.opentelemetry.SynchronousInstrumentFactory -import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedCounter +import io.scalac.mesmer.extension.upstream.opentelemetry.{ SynchronousInstrumentFactory, WrappedCounter } object OpenTelemetryActorSystemMonitor { - case class MetricNames( + final case class MetricNames( createdActors: String, terminatedActors: String ) - object MetricNames extends Configuration[MetricNames] { - def default: MetricNames = MetricNames("akka_system_created_actors_total", "akka_system_terminated_actors_total") + object MetricNames extends MesmerConfiguration[MetricNames] { + protected val defaultConfig: MetricNames = + MetricNames("akka_system_created_actors_total", "akka_system_terminated_actors_total") - override protected val configurationBase: String = "io.scalac.akka-monitoring.metrics.actor-system-metrics" + protected val mesmerConfig: String = "metrics.actor-system-metrics" - override protected def extractFromConfig(config: Config): MetricNames = { - lazy val defaultCached = default + protected def extractFromConfig(config: Config): MetricNames = { + lazy val defaultCached = defaultConfig val createdActors = config.tryValue("created-actors")(_.getString).getOrElse(defaultCached.createdActors) val terminatedActors = config.tryValue("terminated-actors")(_.getString).getOrElse(defaultCached.createdActors) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala index 019ed002d..5557fecba 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala @@ -2,14 +2,13 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter - -import io.scalac.mesmer.extension.metric.ClusterMetricsMonitor -import io.scalac.mesmer.extension.metric._ +import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.extension.metric.{ ClusterMetricsMonitor, _ } import io.scalac.mesmer.extension.upstream.OpenTelemetryClusterMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ object OpenTelemetryClusterMetricsMonitor { - case class MetricNames( + final case class MetricNames( shardPerEntity: String, entityPerRegion: String, shardRegionsOnNode: String, @@ -19,8 +18,8 @@ object OpenTelemetryClusterMetricsMonitor { nodeDown: String ) - object MetricNames { - def default: MetricNames = + object MetricNames extends MesmerConfiguration[MetricNames] { + protected val defaultConfig: MetricNames = MetricNames( "akka_cluster_shards_per_region", "akka_cluster_entities_per_region", @@ -31,54 +30,46 @@ object OpenTelemetryClusterMetricsMonitor { "akka_cluster_node_down_total" ) - def fromConfig(config: Config): MetricNames = { - import io.scalac.mesmer.extension.config.ConfigurationUtils._ - lazy val defaultCached = default - - config - .tryValue("io.scalac.akka-monitoring.metrics.cluster-metrics")( - _.getConfig - ) - .map { clusterMetricsConfig => - val shardsPerRegion = clusterMetricsConfig - .tryValue("shards-per-region")(_.getString) - .getOrElse(defaultCached.shardPerEntity) - - val entitiesPerRegion = clusterMetricsConfig - .tryValue("entities-per-region")(_.getString) - .getOrElse(defaultCached.entityPerRegion) - - val shardRegionsOnNode = clusterMetricsConfig - .tryValue("shard-regions-on-node")(_.getString) - .getOrElse(defaultCached.shardRegionsOnNode) - - val entitiesOnNode = clusterMetricsConfig - .tryValue("entities-on-node")(_.getString) - .getOrElse(defaultCached.entitiesOnNode) - - val reachableNodes = clusterMetricsConfig - .tryValue("reachable-nodes")(_.getString) - .getOrElse(defaultCached.reachableNodes) - - val unreachableNodes = clusterMetricsConfig - .tryValue("unreachable-nodes")(_.getString) - .getOrElse(defaultCached.unreachableNodes) - - val nodesDown = clusterMetricsConfig - .tryValue("node-down")(_.getString) - .getOrElse(defaultCached.nodeDown) - - MetricNames( - shardsPerRegion, - entitiesPerRegion, - shardRegionsOnNode, - entitiesOnNode, - reachableNodes, - unreachableNodes, - nodesDown - ) - } - .getOrElse(defaultCached) + protected val mesmerConfig: String = "metrics.cluster-metrics" + + protected def extractFromConfig(config: Config): MetricNames = { + val shardsPerRegion = config + .tryValue("shards-per-region")(_.getString) + .getOrElse(defaultConfig.shardPerEntity) + + val entitiesPerRegion = config + .tryValue("entities-per-region")(_.getString) + .getOrElse(defaultConfig.entityPerRegion) + + val shardRegionsOnNode = config + .tryValue("shard-regions-on-node")(_.getString) + .getOrElse(defaultConfig.shardRegionsOnNode) + + val entitiesOnNode = config + .tryValue("entities-on-node")(_.getString) + .getOrElse(defaultConfig.entitiesOnNode) + + val reachableNodes = config + .tryValue("reachable-nodes")(_.getString) + .getOrElse(defaultConfig.reachableNodes) + + val unreachableNodes = config + .tryValue("unreachable-nodes")(_.getString) + .getOrElse(defaultConfig.unreachableNodes) + + val nodesDown = config + .tryValue("node-down")(_.getString) + .getOrElse(defaultConfig.nodeDown) + + MetricNames( + shardsPerRegion, + entitiesPerRegion, + shardRegionsOnNode, + entitiesOnNode, + reachableNodes, + unreachableNodes, + nodesDown + ) } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala index 598469ecd..96eb9dbf6 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala @@ -2,38 +2,35 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter - import io.scalac.mesmer.extension.metric.HttpConnectionMetricsMonitor import io.scalac.mesmer.extension.metric.RegisterRoot import io.scalac.mesmer.extension.metric.UpDownCounter import io.scalac.mesmer.extension.upstream.opentelemetry._ - import OpenTelemetryHttpConnectionMetricsMonitor.MetricNames +import io.scalac.mesmer.core.config.MesmerConfiguration object OpenTelemetryHttpConnectionMetricsMonitor { - case class MetricNames(connectionTotal: String) + final case class MetricNames(connectionTotal: String) - object MetricNames { - def default: MetricNames = + object MetricNames extends MesmerConfiguration[MetricNames] { + protected val defaultConfig: MetricNames = MetricNames("akka_http_connections") - def fromConfig(config: Config): MetricNames = { - import io.scalac.mesmer.extension.config.ConfigurationUtils._ - val defaultCached = default - - config - .tryValue("io.scalac.akka-monitoring.metrics.http-metrics")( - _.getConfig - ) - .map { clusterMetricsConfig => - val connectionTotal = clusterMetricsConfig - .tryValue("connections")(_.getString) - .getOrElse(defaultCached.connectionTotal) - MetricNames(connectionTotal) - } - .getOrElse(defaultCached) - } + protected val mesmerConfig: String = "metrics.http-metrics" + + + protected def extractFromConfig(config: Config): MetricNames = { + + val connectionTotal = config + .tryValue("connections")(_.getString) + .getOrElse(defaultConfig.connectionTotal) + + MetricNames(connectionTotal) + } + + } + def apply(meter: Meter, config: Config): OpenTelemetryHttpConnectionMetricsMonitor = new OpenTelemetryHttpConnectionMetricsMonitor(meter, MetricNames.fromConfig(config)) } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala index 2ee8a778f..7c0ea8d52 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala @@ -2,47 +2,38 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter - -import io.scalac.mesmer.extension.metric.HttpMetricsMonitor -import io.scalac.mesmer.extension.metric.RegisterRoot +import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.extension.metric.{ HttpMetricsMonitor, RegisterRoot } +import io.scalac.mesmer.extension.upstream.OpenTelemetryHttpMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ -import OpenTelemetryHttpMetricsMonitor.MetricNames - object OpenTelemetryHttpMetricsMonitor { - case class MetricNames( + final case class MetricNames( requestDuration: String, requestTotal: String ) - object MetricNames { - def default: MetricNames = - MetricNames( - "akka_http_request_duration", - "akka_http_request_total" - ) - - def fromConfig(config: Config): MetricNames = { - import io.scalac.mesmer.extension.config.ConfigurationUtils._ - val defaultCached = default - - config - .tryValue("io.scalac.akka-monitoring.metrics.http-metrics")( - _.getConfig - ) - .map { clusterMetricsConfig => - val requestDuration = clusterMetricsConfig - .tryValue("request-duration")(_.getString) - .getOrElse(defaultCached.requestDuration) - - val requestTotal = clusterMetricsConfig - .tryValue("request-total")(_.getString) - .getOrElse(defaultCached.requestTotal) - - MetricNames(requestDuration, requestTotal) - } - .getOrElse(defaultCached) + object MetricNames extends MesmerConfiguration[MetricNames] { + + protected val mesmerConfig: String = "metrics.http-metrics" + + protected val defaultConfig: MetricNames = MetricNames( + "akka_http_request_duration", + "akka_http_request_total" + ) + + protected def extractFromConfig(config: Config): MetricNames = { + val requestDuration = config + .tryValue("request-duration")(_.getString) + .getOrElse(defaultConfig.requestDuration) + + val requestTotal = config + .tryValue("request-total")(_.getString) + .getOrElse(defaultConfig.requestTotal) + + MetricNames(requestDuration, requestTotal) } + } def apply(meter: Meter, config: Config): OpenTelemetryHttpMetricsMonitor = new OpenTelemetryHttpMetricsMonitor(meter, MetricNames.fromConfig(config)) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala index d4918ae1c..9c6400ebe 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala @@ -2,16 +2,13 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter - -import io.scalac.mesmer.extension.metric.Counter -import io.scalac.mesmer.extension.metric.MetricRecorder -import io.scalac.mesmer.extension.metric.PersistenceMetricsMonitor -import io.scalac.mesmer.extension.metric.RegisterRoot +import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.extension.metric.{ Counter, MetricRecorder, PersistenceMetricsMonitor, RegisterRoot } import io.scalac.mesmer.extension.upstream.OpenTelemetryPersistenceMetricsMonitor._ import io.scalac.mesmer.extension.upstream.opentelemetry._ object OpenTelemetryPersistenceMetricsMonitor { - case class MetricNames( + final case class MetricNames( recoveryTime: String, recoveryTotal: String, persistentEvent: String, @@ -19,8 +16,8 @@ object OpenTelemetryPersistenceMetricsMonitor { snapshotTotal: String ) - object MetricNames { - def default: MetricNames = + object MetricNames extends MesmerConfiguration[MetricNames] { + protected val defaultConfig: MetricNames = MetricNames( "akka_persistence_recovery_time", "akka_persistence_recovery_total", @@ -29,35 +26,29 @@ object OpenTelemetryPersistenceMetricsMonitor { "akka_persistence_snapshot_total" ) - def fromConfig(config: Config): MetricNames = { - import io.scalac.mesmer.extension.config.ConfigurationUtils._ - val defaultCached = default - - config - .tryValue("io.scalac.akka-monitoring.metrics.cluster-metrics")( - _.getConfig - ) - .map { clusterMetricsConfig => - val recoveryTime = clusterMetricsConfig - .tryValue("recovery-time")(_.getString) - .getOrElse(defaultCached.recoveryTime) - val recoveryTotal = clusterMetricsConfig - .tryValue("recovery-total")(_.getString) - .getOrElse(defaultCached.recoveryTotal) - val persistentEvent = clusterMetricsConfig - .tryValue("persistent-event")(_.getString) - .getOrElse(defaultCached.persistentEvent) - val persistentEventTotal = clusterMetricsConfig - .tryValue("persistent-event-total")(_.getString) - .getOrElse(defaultCached.persistentEventTotal) - val snapshotTotal = clusterMetricsConfig - .tryValue("snapshot")(_.getString) - .getOrElse(defaultCached.snapshotTotal) - - MetricNames(recoveryTime, recoveryTotal, persistentEvent, persistentEventTotal, snapshotTotal) - } - .getOrElse(defaultCached) + protected val mesmerConfig: String = "metrics.persistence-metrics" + + protected def extractFromConfig(config: Config): MetricNames = { + val recoveryTime = config + .tryValue("recovery-time")(_.getString) + .getOrElse(defaultConfig.recoveryTime) + val recoveryTotal = config + .tryValue("recovery-total")(_.getString) + .getOrElse(defaultConfig.recoveryTotal) + val persistentEvent = config + .tryValue("persistent-event")(_.getString) + .getOrElse(defaultConfig.persistentEvent) + val persistentEventTotal = config + .tryValue("persistent-event-total")(_.getString) + .getOrElse(defaultConfig.persistentEventTotal) + val snapshotTotal = config + .tryValue("snapshot")(_.getString) + .getOrElse(defaultConfig.snapshotTotal) + + MetricNames(recoveryTime, recoveryTotal, persistentEvent, persistentEventTotal, snapshotTotal) + } + } def apply(meter: Meter, config: Config): OpenTelemetryPersistenceMetricsMonitor = new OpenTelemetryPersistenceMetricsMonitor(meter, MetricNames.fromConfig(config)) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitor.scala index f760b8938..219130870 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitor.scala @@ -2,41 +2,40 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter - -import io.scalac.mesmer.extension.metric.MetricObserver -import io.scalac.mesmer.extension.metric.RegisterRoot -import io.scalac.mesmer.extension.metric.StreamMetricsMonitor +import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.extension.metric.{ MetricObserver, RegisterRoot, StreamMetricsMonitor } import io.scalac.mesmer.extension.upstream.OpenTelemetryStreamMetricsMonitor.MetricNames -import io.scalac.mesmer.extension.upstream.opentelemetry.LongSumObserverBuilderAdapter -import io.scalac.mesmer.extension.upstream.opentelemetry.SynchronousInstrumentFactory -import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedLongValueRecorder +import io.scalac.mesmer.extension.upstream.opentelemetry.{ + LongSumObserverBuilderAdapter, + SynchronousInstrumentFactory, + WrappedLongValueRecorder +} object OpenTelemetryStreamMetricsMonitor { - case class MetricNames(runningStreams: String, streamActors: String, streamProcessed: String) + final case class MetricNames(runningStreams: String, streamActors: String, streamProcessed: String) - object MetricNames { - private val defaults: MetricNames = - MetricNames("akka_streams_running_streams", "akka_streams_actors", "akka_stream_processed_messages") + object MetricNames extends MesmerConfiguration[MetricNames] { - def fromConfig(config: Config): MetricNames = { - import io.scalac.mesmer.extension.config.ConfigurationUtils._ + protected val mesmerConfig: String = "metrics.stream-metrics" + + protected val defaultConfig: MetricNames = + MetricNames("akka_streams_running_streams", "akka_streams_actors", "akka_stream_processed_messages") - config.tryValue("io.scalac.akka-monitoring.metrics.stream-metrics")(_.getConfig).map { streamMetricsConfig => - val runningStreams = streamMetricsConfig - .tryValue("running-streams")(_.getString) - .getOrElse(defaults.runningStreams) + protected def extractFromConfig(config: Config): MetricNames = { + val runningStreams = config + .tryValue("running-streams")(_.getString) + .getOrElse(defaultConfig.runningStreams) - val streamActors = streamMetricsConfig - .tryValue("stream-actors")(_.getString) - .getOrElse(defaults.streamActors) + val streamActors = config + .tryValue("stream-actors")(_.getString) + .getOrElse(defaultConfig.streamActors) - val streamProcessed = streamMetricsConfig - .tryValue("stream-processed")(_.getString) - .getOrElse(defaults.streamProcessed) + val streamProcessed = config + .tryValue("stream-processed")(_.getString) + .getOrElse(defaultConfig.streamProcessed) - MetricNames(runningStreams, streamActors, streamProcessed) - } - }.getOrElse(defaults) + MetricNames(runningStreams, streamActors, streamProcessed) + } } def apply(meter: Meter, config: Config): OpenTelemetryStreamMetricsMonitor = diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitor.scala index cae4119d8..ba870fd0e 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitor.scala @@ -2,50 +2,46 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter - -import io.scalac.mesmer.extension.metric.MetricObserver -import io.scalac.mesmer.extension.metric.RegisterRoot -import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor -import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.BoundMonitor -import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.Labels +import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.{ BoundMonitor, Labels } +import io.scalac.mesmer.extension.metric.{ MetricObserver, RegisterRoot, StreamOperatorMetricsMonitor } import io.scalac.mesmer.extension.upstream.OpenTelemetryStreamOperatorMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ object OpenTelemetryStreamOperatorMetricsMonitor { case class MetricNames(operatorProcessed: String, connections: String, runningOperators: String, demand: String) - object MetricNames { - private val defaults: MetricNames = - MetricNames( - "akka_streams_operator_processed_total", - "akka_streams_operator_connections", - "akka_streams_running_operators", - "akka_streams_operator_demand" - ) - - def fromConfig(config: Config): MetricNames = { - import io.scalac.mesmer.extension.config.ConfigurationUtils._ - - config.tryValue("io.scalac.akka-monitoring.metrics.stream-metrics")(_.getConfig).map { streamMetricsConfig => - val operatorProcessed = streamMetricsConfig - .tryValue("operator-processed")(_.getString) - .getOrElse(defaults.operatorProcessed) - - val operatorConnections = streamMetricsConfig - .tryValue("operator-connections")(_.getString) - .getOrElse(defaults.connections) - - val runningOperators = streamMetricsConfig - .tryValue("running-operators")(_.getString) - .getOrElse(defaults.runningOperators) - - val demand = streamMetricsConfig - .tryValue("operator-demand")(_.getString) - .getOrElse(defaults.demand) - - MetricNames(operatorProcessed, operatorConnections, runningOperators, demand) - } - }.getOrElse(defaults) + object MetricNames extends MesmerConfiguration[MetricNames] { + + protected val mesmerConfig: String = "metrics.stream-metrics" + + protected val defaultConfig: MetricNames = MetricNames( + "akka_streams_operator_processed_total", + "akka_streams_operator_connections", + "akka_streams_running_operators", + "akka_streams_operator_demand" + ) + + protected def extractFromConfig(config: Config): MetricNames = { + val operatorProcessed = config + .tryValue("operator-processed")(_.getString) + .getOrElse(defaultConfig.operatorProcessed) + + val operatorConnections = config + .tryValue("operator-connections")(_.getString) + .getOrElse(defaultConfig.connections) + + val runningOperators = config + .tryValue("running-operators")(_.getString) + .getOrElse(defaultConfig.runningOperators) + + val demand = config + .tryValue("operator-demand")(_.getString) + .getOrElse(defaultConfig.demand) + + MetricNames(operatorProcessed, operatorConnections, runningOperators, demand) + } + } def apply(meter: Meter, config: Config): OpenTelemetryStreamOperatorMetricsMonitor = From 97059d95d89e78436b7494508c482c569fefb3c7 Mon Sep 17 00:00:00 2001 From: jczuchnowski Date: Mon, 21 Jun 2021 13:55:12 +0200 Subject: [PATCH 03/31] Remove OpenTelemetry SDK from dependencies --- build.sbt | 4 ++-- project/Dependencies.scala | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index 45bbddb16..64f032f91 100644 --- a/build.sbt +++ b/build.sbt @@ -48,7 +48,7 @@ lazy val core = (project in file("core")) libraryDependencies ++= { akka ++ openTelemetryApi ++ - openTelemetryMetrics ++ + openTelemetryApiMetrics ++ scalatest ++ akkaTestkit } @@ -64,7 +64,7 @@ lazy val extension = (project in file("extension")) libraryDependencies ++= { akka ++ openTelemetryApi ++ - openTelemetryMetrics ++ + openTelemetryApiMetrics ++ akkaTestkit ++ scalatest ++ akkaMultiNodeTestKit ++ diff --git a/project/Dependencies.scala b/project/Dependencies.scala index e95697d66..6b194cbc8 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -42,9 +42,8 @@ object Dependencies { "io.opentelemetry" % "opentelemetry-api" % OpentelemetryVersion ) - val openTelemetryMetrics = Seq( - "io.opentelemetry" % "opentelemetry-api-metrics" % OpentelemetryMetricsVersion, - "io.opentelemetry" % "opentelemetry-sdk-metrics" % OpentelemetryMetricsVersion + val openTelemetryApiMetrics = Seq( + "io.opentelemetry" % "opentelemetry-api-metrics" % OpentelemetryMetricsVersion ) val akkaTestkit = Seq( From 08064d7b42f0a779eb9a059a8839efef1835abda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Tue, 22 Jun 2021 10:52:26 +0200 Subject: [PATCH 04/31] Add noop instuments --- ...ice.java => HttpExtConnectionsAdvice.java} | 5 +- .../akka/http/HttpExtRequestsAdvice.java | 15 +++ .../scala/io/scalac/mesmer/agent/Agent.scala | 31 +++-- .../agent/akka/http/AkkaHttpAgent.scala | 22 ++-- .../agent/akka/http/HttpInstrumentation.scala | 39 ++++--- .../util/i13n/InstrumentModuleFactory.scala | 2 +- .../mesmer/agent/util/i13n/package.scala | 1 + .../mesmer/agent/akka/AkkaHttpAgentTest.scala | 109 +++++++++++------- .../agent/akka/AkkaPersistenceAgentSpec.scala | 2 +- .../agent/akka/impl/AkkaHttpTestImpl.scala | 33 ++++++ .../mesmer/agent/utils/InstallAgent.scala | 92 +++++++++++---- build.sbt | 6 +- .../mesmer/core/module/AkkaHttpModule.scala | 36 ++++-- .../mesmer/extension/AkkaMonitoring.scala | 37 +++--- .../mesmer/extension/HttpEventsActor.scala | 19 ++- .../metric/HttpConnectionMetricsMonitor.scala | 10 +- .../extension/metric/HttpMetricsMonitor.scala | 3 +- .../mesmer/extension/metric/Metric.scala | 33 ++++-- .../OpenTelemetryClusterMetricsMonitor.scala | 2 +- ...elemetryHttpConnectionMetricsMonitor.scala | 15 +-- .../OpenTelemetryHttpMetricsMonitor.scala | 32 +++-- .../upstream/opentelemetry/Synchronized.scala | 13 ++- .../opentelemetry/WrappedInstument.scala | 2 +- .../WrappedSynchronousInstrument.scala | 48 ++++++-- .../HttpConnectionMetricsTestProbe.scala | 2 +- 25 files changed, 414 insertions(+), 195 deletions(-) rename agent/src/main/java/io/scalac/mesmer/agent/akka/http/{HttpExtAdvice.java => HttpExtConnectionsAdvice.java} (80%) create mode 100644 agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtRequestsAdvice.java create mode 100644 agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala diff --git a/agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtAdvice.java b/agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtConnectionsAdvice.java similarity index 80% rename from agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtAdvice.java rename to agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtConnectionsAdvice.java index a0406490c..2d7bf0926 100644 --- a/agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtAdvice.java +++ b/agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtConnectionsAdvice.java @@ -6,12 +6,13 @@ import akka.stream.scaladsl.Flow; import net.bytebuddy.asm.Advice; -public class HttpExtAdvice { +public class HttpExtConnectionsAdvice { + @Advice.OnMethodEnter public static void bindAndHandle(@Advice.Argument(value = 0, readOnly = false) Flow handler, @Advice.Argument(1) String _interface, @Advice.Argument(2) Integer port, @Advice.This Object self) { - handler = HttpInstrumentation.bindAndHandleImpl(handler, _interface, port, (HttpExt) self); + handler = HttpInstrumentation.bindAndHandleConnectionsImpl(handler, _interface, port, (HttpExt) self); } } diff --git a/agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtRequestsAdvice.java b/agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtRequestsAdvice.java new file mode 100644 index 000000000..f543bcaea --- /dev/null +++ b/agent/src/main/java/io/scalac/mesmer/agent/akka/http/HttpExtRequestsAdvice.java @@ -0,0 +1,15 @@ +package io.scalac.mesmer.agent.akka.http; + +import akka.http.scaladsl.HttpExt; +import akka.http.scaladsl.model.HttpRequest; +import akka.http.scaladsl.model.HttpResponse; +import akka.stream.scaladsl.Flow; +import net.bytebuddy.asm.Advice; + +public class HttpExtRequestsAdvice { + @Advice.OnMethodEnter + public static void bindAndHandle(@Advice.Argument(value = 0, readOnly = false) Flow handler, + @Advice.This Object self) { + handler = HttpInstrumentation.bindAndHandleRequestImpl(handler, (HttpExt) self); + } +} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala index e84d18fe9..c680da6aa 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala @@ -1,13 +1,12 @@ package io.scalac.mesmer.agent -import java.lang.instrument.Instrumentation - -import net.bytebuddy.agent.builder.AgentBuilder -import org.slf4j.LoggerFactory - import io.scalac.mesmer.agent.Agent.LoadingResult import io.scalac.mesmer.core.model.SupportedModules import io.scalac.mesmer.core.util.ModuleInfo.Modules +import net.bytebuddy.agent.builder.AgentBuilder +import org.slf4j.LoggerFactory + +import java.lang.instrument.Instrumentation object Agent { @@ -60,21 +59,29 @@ object AgentInstrumentation { } sealed abstract case class AgentInstrumentation(name: String, instrumentingModules: SupportedModules) - extends ((AgentBuilder, Instrumentation, Modules) => LoadingResult) { + extends ((AgentBuilder, Instrumentation, Modules) => LoadingResult) + with Equals { - override def hashCode(): Int = name.hashCode() - override def equals(obj: Any): Boolean = name.equals(obj) // instrumentations should be equal when name is the same + override def hashCode(): Int = name.hashCode() + + override def canEqual(that: Any): Boolean = that.isInstanceOf[AgentInstrumentation] + + override def equals(obj: Any): Boolean = obj match { + case that: AgentInstrumentation if that.canEqual(this) => + that.name == this.name // instrumentations should be equal when name is the same + case _ => false + } } -final case class Agent private (private val set: Set[AgentInstrumentation]) extends { +final case class Agent private (private[agent] val instrumentations: Set[AgentInstrumentation]) extends { import Agent._ - def ++(other: Agent): Agent = Agent(set ++ other.set) + def ++(other: Agent): Agent = Agent(instrumentations ++ other.instrumentations) - def ++(other: AgentInstrumentation): Agent = Agent(set + other) + def ++(other: AgentInstrumentation): Agent = Agent(instrumentations + other) def installOn(builder: AgentBuilder, instrumentation: Instrumentation, modules: Modules): LoadingResult = - set.flatMap { agentInstrumentation => + instrumentations.flatMap { agentInstrumentation => val dependencies = agentInstrumentation.instrumentingModules val allModulesSupported = dependencies.modules.forall { module => diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala index e974c5280..eb3c733b7 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala @@ -8,25 +8,33 @@ import io.scalac.mesmer.core.support.ModulesSupport object AkkaHttpAgent extends InstrumentModuleFactoryTest(AkkaHttpModule) - with AkkaHttpModule.Metrics[AgentInstrumentation] { + with AkkaHttpModule.AkkaHttpConnectionsMetricsDef[AgentInstrumentation] + with AkkaHttpModule.AkkaHttpRequestMetricsDef[AgentInstrumentation] { // @ToDo tests all supported versions protected val supportedModules: SupportedModules = SupportedModules(ModulesSupport.akkaHttpModule, ModulesSupport.akkaHttp) - def requestTime: AgentInstrumentation = httpAgent + def requestTime: AgentInstrumentation = requestEvents - def requestCounter: AgentInstrumentation = httpAgent + def requestCounter: AgentInstrumentation = requestEvents - private val httpAgent: AgentInstrumentation = - instrument("akka.http.scaladsl.HttpExt") - .visit[HttpExtAdvice]("bindAndHandle") + def connections: AgentInstrumentation = connectionEvents + + private lazy val requestEvents = + instrument(`type`("akka.http.scaladsl.HttpExt?requests", "akka.http.scaladsl.HttpExt")) + .visit[HttpExtRequestsAdvice]("bindAndHandle") + + private lazy val connectionEvents = + instrument(`type`("akka.http.scaladsl.HttpExt?connections", "akka.http.scaladsl.HttpExt")) + .visit[HttpExtConnectionsAdvice]("bindAndHandle") def agent(config: AkkaHttpModule.All[Boolean]): Agent = { val requestCounterAgent = if (config.requestCounter) Agent(requestCounter) else Agent.empty val requestTimeAgent = if (config.requestTime) Agent(requestTime) else Agent.empty + val connectionsAgent = if (config.connections) Agent(connections) else Agent.empty - requestCounterAgent ++ requestTimeAgent + requestCounterAgent ++ requestTimeAgent ++ connectionsAgent } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/HttpInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/HttpInstrumentation.scala index d8836846a..91bfc4f0d 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/HttpInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/HttpInstrumentation.scala @@ -1,17 +1,10 @@ package io.scalac.mesmer.agent.akka.http -import _root_.akka.http.scaladsl.model.HttpRequest -import _root_.akka.http.scaladsl.model.HttpResponse +import _root_.akka.http.scaladsl.model.{HttpRequest, HttpResponse} import _root_.akka.stream.BidiShape import akka.actor.typed.scaladsl.adapter._ import akka.http.scaladsl.HttpExt -import akka.stream.scaladsl.BidiFlow -import akka.stream.scaladsl.Broadcast -import akka.stream.scaladsl.Flow -import akka.stream.scaladsl.GraphDSL -import akka.stream.scaladsl.Source -import akka.stream.scaladsl.Zip - +import akka.stream.scaladsl.{BidiFlow, Broadcast, Flow, GraphDSL, Source, Zip} import io.scalac.mesmer.core.akka.stream.BidiFlowForward import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.HttpEvent._ @@ -34,19 +27,13 @@ object HttpInstrumentation { } } - def bindAndHandleImpl( + def bindAndHandleRequestImpl( handler: Flow[HttpRequest, HttpResponse, Any], - interface: String, - port: java.lang.Integer, self: HttpExt ): Flow[HttpRequest, HttpResponse, Any] = { val system = self.asInstanceOf[HttpExt].system.toTyped - val connectionsCountFlow = BidiFlowForward[HttpRequest, HttpResponse]( - onPreStart = () => EventBus(system).publishEvent(ConnectionStarted(interface, port)), - onPostStop = () => EventBus(system).publishEvent(ConnectionCompleted(interface, port)) - ) val requestIdFlow = BidiFlow.fromGraph[HttpRequest, HttpRequest, HttpResponse, HttpResponse, Any](GraphDSL.create() { @@ -93,9 +80,25 @@ object HttpInstrumentation { BidiShape(outerRequest.in, outerRequestOut.outlet, zipRespone.in0, outerResponse.out) }) - connectionsCountFlow - .atop(requestIdFlow) + requestIdFlow .join(handler) } + + def bindAndHandleConnectionsImpl( + handler: Flow[HttpRequest, HttpResponse, Any], + interface: String, + port: java.lang.Integer, + self: HttpExt + ): Flow[HttpRequest, HttpResponse, Any] = { + + val system = self.asInstanceOf[HttpExt].system.toTyped + + val connectionsCountFlow = BidiFlowForward[HttpRequest, HttpResponse]( + onPreStart = () => EventBus(system).publishEvent(ConnectionStarted(interface, port)), + onPostStop = () => EventBus(system).publishEvent(ConnectionCompleted(interface, port)) + ) + + connectionsCountFlow.join(handler) + } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala index c2bf4506c..b2c28e896 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala @@ -18,7 +18,7 @@ abstract class InstrumentModuleFactoryTest[M <: Module](val module: M) { protected def instrument(tpe: Type): TypeInstrumentation = TypeInstrumentation(TypeTarget(tpe, supportedModules)) - protected def agent(config: M#All[Boolean]): Agent + def agent(config: M#All[Boolean]): Agent final def agent(config: Config): Agent = agent(module.enabled(config)) } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index c195e15da..c2834cf83 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -122,6 +122,7 @@ package object i13n { // implicit conversion implicit def methodNameToMethodDesc(methodName: String): MethodDesc = method(methodName) + implicit def classNameToTypeDesc(className: String): TypeDesc = EM.named[TypeDescription](className) implicit def typeNameToType(typeName: String): Type = `type`(typeName) implicit def typeToAgentInstrumentation(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = AgentInstrumentationFactory(typeInstrumentation) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala index 39494e1d2..243e74a79 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala @@ -1,66 +1,91 @@ package io.scalac.mesmer.agent.akka -import akka.actor.testkit.typed.scaladsl.TestProbe -import akka.actor.typed -import akka.actor.typed.receptionist.Receptionist -import akka.actor.typed.receptionist.Receptionist.Deregister -import akka.actor.typed.receptionist.Receptionist.Register -import akka.actor.typed.scaladsl.adapter._ -import akka.http.scaladsl.model.StatusCodes +import akka.http.scaladsl.Http +import akka.http.scaladsl.model.Uri.Path +import akka.http.scaladsl.model.{HttpMethods, HttpRequest, StatusCodes, Uri} import akka.http.scaladsl.model.headers.Connection import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route -import akka.http.scaladsl.testkit.RouteTestTimeout -import akka.http.scaladsl.testkit.ScalatestRouteTest -import com.typesafe.config.Config -import com.typesafe.config.ConfigFactory +import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent +import io.scalac.mesmer.agent.akka.impl.AkkaHttpTestImpl +import io.scalac.mesmer.agent.utils.InstallModule +import io.scalac.mesmer.core.event.HttpEvent.{ConnectionCompleted, ConnectionStarted, RequestCompleted, RequestStarted} +import io.scalac.mesmer.core.module.AkkaHttpModule +import io.scalac.mesmer.core.util.TestOps +import org.scalatest.OptionValues import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import scala.concurrent.Await import scala.concurrent.duration._ import scala.language.postfixOps -import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent -import io.scalac.mesmer.agent.utils.InstallAgent -import io.scalac.mesmer.core.event.HttpEvent -import io.scalac.mesmer.core.event.HttpEvent.ConnectionCompleted -import io.scalac.mesmer.core.event.HttpEvent.ConnectionStarted -import io.scalac.mesmer.core.event.HttpEvent.RequestCompleted -import io.scalac.mesmer.core.event.HttpEvent.RequestStarted -import io.scalac.mesmer.core.httpServiceKey - -class AkkaHttpAgentTest extends InstallAgent with AnyFlatSpecLike with ScalatestRouteTest with Matchers { +class AkkaHttpAgentTest + extends InstallModule(AkkaHttpAgent) + with AnyFlatSpecLike + with Matchers + with OptionValues + with TestOps { - override protected val agent = AkkaHttpAgent.agent(ConfigFactory.empty) +// override var agent = Some(AkkaHttpAgent.agent(AkkaHttpModule.defaultConfig)) - override def testConfig: Config = ConfigFactory.load("application-test") + behavior of "AkkaHttpAgent" - type Fixture = TestProbe[HttpEvent] - - val testRoute: Route = path("test") { - get { - complete((StatusCodes.OK, collection.immutable.Seq(Connection("close")))) + it should behave like withVersion( +// AkkaHttpModule.AkkaHttpModuleConfig(true, true, true), +// AkkaHttpModule.AkkaHttpModuleConfig(false, true, true), + AkkaHttpModule.AkkaHttpModuleConfig(true, false, true) + )( + "instrument routes to generate events on http requests" + )(AkkaHttpTestImpl.systemWithHttpService { implicit system => monitor => + val testRoute: Route = path("test") { + get { + complete((StatusCodes.OK, collection.immutable.Seq(Connection("close")))) + } } - } - - def test(body: Fixture => Any): Any = { - implicit val typedSystem: typed.ActorSystem[Nothing] = system.toTyped - val monitor = TestProbe[HttpEvent]("http-test-probe") - Receptionist(typedSystem).ref ! Register(httpServiceKey, monitor.ref) - body(monitor) - Receptionist(typedSystem).ref ! Deregister(httpServiceKey, monitor.ref) - } +// implicit val timeout = RouteTestTimeout(5 seconds) + import system.executionContext - "AkkaHttpAgent" should "instrument routes to generate events on http requests" in test { monitor => - implicit val timeout = RouteTestTimeout(5 seconds) - Get("/test") ~!> testRoute ~> check { - status should be(StatusCodes.OK) + val response = for { + binding <- Http().newServerAt("127.0.0.1", 0).bind(testRoute) + port = binding.localAddress.getPort + targetUri = Uri.Empty.withPath(Path("/test")).withHost("127.0.0.1").withPort(port).withScheme("http") + response <- Http().singleRequest(HttpRequest(HttpMethods.GET, targetUri)) + } yield { + binding.unbind() + response } + Await.result(response, 5.seconds) + monitor.expectMessageType[ConnectionStarted] monitor.expectMessageType[RequestStarted] monitor.expectMessageType[RequestCompleted] monitor.expectMessageType[ConnectionCompleted] - } + }) + +// "AkkaHttpAgent" should "instrument routes to generate events on http requests" in withVersion( +// AkkaHttpModule.defaultConfig +// )(test { monitor => +// implicit val timeout = RouteTestTimeout(5 seconds) +// +// Get("/test") ~!> testRoute ~> check { +// status should be(StatusCodes.OK) +// } +// monitor.expectMessageType[ConnectionStarted] +// monitor.expectMessageType[RequestStarted] +// monitor.expectMessageType[RequestCompleted] +// monitor.expectMessageType[ConnectionCompleted] +// }) + +// it should "contain 2 transformations" in test { _ => +// agent.value.instrumentations should have size (2) +// } + + it should behave like withVersion(AkkaHttpModule.defaultConfig)("contain 2 transformations")(AkkaHttpTestImpl.systemWithHttpService { + _ => _ => + agent.value.instrumentations should have size (2) + + }) } diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentSpec.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentSpec.scala index 61c399071..802055931 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentSpec.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentSpec.scala @@ -34,7 +34,7 @@ class AkkaPersistenceAgentSpec with ReceptionistOps with SafeLoadSystem { - override protected val agent = AkkaPersistenceAgent.agent +// override protected val agent = AkkaPersistenceAgent.agent implicit val askTimeout: Timeout = Timeout(1.minute) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala new file mode 100644 index 000000000..87f385289 --- /dev/null +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala @@ -0,0 +1,33 @@ +package io.scalac.mesmer.agent.akka.impl + +import akka.actor.testkit.typed.scaladsl.TestProbe +import akka.actor.typed.ActorSystem +import akka.actor.typed.receptionist.Receptionist +import akka.actor.typed.receptionist.Receptionist.{ Deregister, Register } +import akka.actor.typed.scaladsl.adapter._ +import akka.{ actor => classic } +import com.typesafe.config.{ Config, ConfigFactory } +import io.scalac.mesmer.core.event.HttpEvent +import io.scalac.mesmer.core.httpServiceKey + +import java.util.UUID + +object AkkaHttpTestImpl { + + private val testConfig: Config = ConfigFactory.load("application-test") + + def systemWithHttpService(body: ActorSystem[Nothing] => TestProbe[HttpEvent] => Any): Any = { + val cl = Thread.currentThread().getContextClassLoader + println(s"Initializing ActorSystem with classLoader ${cl}") + implicit val typedSystem: ActorSystem[Nothing] = + classic.ActorSystem(UUID.randomUUID().toString, testConfig, cl).toTyped + val monitor = TestProbe[HttpEvent]("http-test-probe") + + Receptionist(typedSystem).ref ! Register(httpServiceKey, monitor.ref) + + body(typedSystem)(monitor) + + Receptionist(typedSystem).ref ! Deregister(httpServiceKey, monitor.ref) + } + +} diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala index d9366eb65..f9be50672 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala @@ -1,33 +1,35 @@ package io.scalac.mesmer.agent.utils -import com.typesafe.config.ConfigFactory +import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.akka.actor.{ AkkaActorAgent, AkkaMailboxAgent } +import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent +import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent +import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent +import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactoryTest +import io.scalac.mesmer.core.module.{ AkkaHttpModule, Module } +import io.scalac.mesmer.core.util.ModuleInfo.{ extractModulesInformation, Modules } import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.ByteBuddyAgent import net.bytebuddy.agent.builder.AgentBuilder import net.bytebuddy.dynamic.scaffold.TypeValidation -import org.scalatest.BeforeAndAfterAll import org.scalatest.TestSuite -import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent -import io.scalac.mesmer.agent.akka.actor.AkkaMailboxAgent -import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent -import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent -import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent -import io.scalac.mesmer.core.util.ModuleInfo.Modules -import io.scalac.mesmer.core.util.ModuleInfo.extractModulesInformation +import org.scalatest.flatspec.AnyFlatSpecLike + +import java.net.{ URL, URLClassLoader } +import scala.util.Try object InstallAgent { def allInstrumentations: Agent = - AkkaActorAgent.agent ++ AkkaHttpAgent.agent(ConfigFactory.empty) ++ AkkaPersistenceAgent.agent ++ AkkaStreamAgent.agent ++ AkkaMailboxAgent.agent + AkkaActorAgent.agent ++ AkkaHttpAgent.agent( + AkkaHttpModule.defaultConfig + ) ++ AkkaPersistenceAgent.agent ++ AkkaStreamAgent.agent ++ AkkaMailboxAgent.agent } -abstract class InstallAgent extends TestSuite with BeforeAndAfterAll { - - import InstallAgent._ +abstract class InstallAgent extends TestSuite { def modules: Modules = extractModulesInformation(Thread.currentThread().getContextClassLoader) - protected def agent: Agent = allInstrumentations + protected var agent: Option[Agent] = None private val builder = new AgentBuilder.Default( new ByteBuddy() @@ -39,13 +41,61 @@ abstract class InstallAgent extends TestSuite with BeforeAndAfterAll { AgentBuilder.Listener.StreamWriting.toSystemOut.withTransformationsOnly() ) - override protected def beforeAll(): Unit = { - super.beforeAll() - + private def installAgent(): Unit = { val instrumentation = ByteBuddyAgent.install() - agent - .installOn(builder, instrumentation, modules) - .eagerLoad() + agent.fold[Unit](throw new AssertionError("Agent must be set")) { + _.installOn(builder, instrumentation, modules) + .eagerLoad() + } + } + + def withAgent(setup: () => Unit)(test: () => Any): Any = { + val context = Thread.currentThread().getContextClassLoader.asInstanceOf[URLClassLoader] + val prefixClassLoader = new PrefixChildFirstClassLoader(Vector("akka.http.scaladsl.HttpExt"), context.getURLs, context) + Thread.currentThread().setContextClassLoader(prefixClassLoader) + + setup() + installAgent() + Class.forName("akka.http.scaladsl.HttpExt", true, prefixClassLoader) + test() + Thread.currentThread().setContextClassLoader(context) } + +} + +final class PrefixChildFirstClassLoader(prefix: Vector[String], urls: Array[URL], parent: ClassLoader) + extends URLClassLoader(urls, parent) { + override def loadClass(name: String, resolve: Boolean): Class[_] = { + + val loaded = Option(findLoadedClass(name)).orElse { + if (prefix.exists(p => name.startsWith(p))) { + println(s"Loading class: $name") + + Try(findClass(name)).toOption + } else None + }.orElse(Try(super.loadClass(name, resolve)).toOption).getOrElse(throw new ClassNotFoundException(name)) + + if (resolve) { + resolveClass(loaded) + } + loaded + } + +} + +abstract class InstallModule[M <: Module](moduleFactory: InstrumentModuleFactoryTest[M]) extends InstallAgent { + this: AnyFlatSpecLike => + + def withVersion(versions: M#All[Boolean]*)(name: String)(test: => Any): Any = + versions.foreach { version => + it should s"$name with $version" in withAgent { () => + agent = Some(moduleFactory.agent(version)) + println(s"Class loader: ${Thread.currentThread().getContextClassLoader}") + println(s"Class loader parent: ${Thread.currentThread().getContextClassLoader.getParent}") + println(s"Class loader 2xparent: ${Thread.currentThread().getContextClassLoader.getParent.getParent}") + }(() => test) + + } + } diff --git a/build.sbt b/build.sbt index bc15faaa3..11f1cc850 100644 --- a/build.sbt +++ b/build.sbt @@ -99,11 +99,15 @@ lazy val agent = (project in file("agent")) assembly / assemblyOption ~= { _.copy(includeScala = false) }, assemblyMergeStrategySettings, Test / fork := true, + Test / parallelExecution := true, + Test / testOnly / fork := (Test / fork).value, Test / testGrouping := ((Test / testGrouping).value flatMap { group => group.tests.map { test => + println(test) Tests.Group(name = test.name, tests = Seq(test), runPolicy = group.runPolicy) } - }) + }), + Test / testOnly / testGrouping := (Test/ testGrouping).value ) .dependsOn( core % "provided->compile;test->test" diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala index f9c796566..259390f5d 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -3,30 +3,44 @@ package io.scalac.mesmer.core.module import com.typesafe.config.Config /** - * Definition of AkkHttp metric related features + * Definition of AkkHttp request related metrics */ -sealed trait AkkaHttpMetricsModule extends MetricModule { +sealed trait AkkaHttpRequestMetricsModule extends MetricModule { this: Module => - override type Metrics[T] = AkkaHttpMetricsDef[T] + override type Metrics[T] <: AkkaHttpRequestMetricsDef[T] - protected trait AkkaHttpMetricsDef[T] { + trait AkkaHttpRequestMetricsDef[T] { def requestTime: T def requestCounter: T } } -object AkkaHttpModule extends MesmerModule with AkkaHttpMetricsModule { +sealed trait AkkaHttpConnectionMetricsModule extends MetricModule { + this: Module => + + override type Metrics[T] <: AkkaHttpConnectionsMetricsDef[T] + + trait AkkaHttpConnectionsMetricsDef[T] { + def connections: T + } +} + +object AkkaHttpModule extends MesmerModule with AkkaHttpRequestMetricsModule with AkkaHttpConnectionMetricsModule { - final case class AkkaHttpModuleConfig(requestTime: Boolean, requestCounter: Boolean) extends All[Boolean] + final case class AkkaHttpModuleConfig(requestTime: Boolean, requestCounter: Boolean, connections: Boolean) + extends AkkaHttpRequestMetricsDef[Boolean] + with AkkaHttpConnectionsMetricsDef[Boolean] val name: String = "akka-http" + override type Metrics[T] = AkkaHttpRequestMetricsDef[T] with AkkaHttpConnectionsMetricsDef[T] + override type All[T] = Metrics[T] - val defaultConfig = AkkaHttpModuleConfig(true, true) + val defaultConfig = AkkaHttpModuleConfig(true, true, true) - protected def extractFromConfig(config: Config): AkkaHttpModule.AkkaHttpMetricsDef[Boolean] = { + protected def extractFromConfig(config: Config): AkkaHttpModule.All[Boolean] = { val requestTime = config .tryValue("request-time")(_.getBoolean) .getOrElse(defaultConfig.requestTime) @@ -35,6 +49,10 @@ object AkkaHttpModule extends MesmerModule with AkkaHttpMetricsModule { .tryValue("request-counter")(_.getBoolean) .getOrElse(defaultConfig.requestCounter) - AkkaHttpModuleConfig(requestTime = requestTime, requestCounter = requestCounter) + val connections = config + .tryValue("connections")(_.getBoolean) + .getOrElse(defaultConfig.connections) + + AkkaHttpModuleConfig(requestTime = requestTime, requestCounter = requestCounter, connections = connections) } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala index 1a0af67d0..2b1a758bc 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala @@ -5,33 +5,28 @@ import akka.actor.typed.receptionist.Receptionist.Register import akka.actor.typed.scaladsl.Behaviors import akka.cluster.Cluster import akka.util.Timeout - -import scala.concurrent.duration._ -import scala.language.postfixOps -import scala.reflect.ClassTag -import scala.util.Try - -import io.scalac.mesmer.core.model.Module -import io.scalac.mesmer.core.model.SupportedVersion -import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.model.{ Module, SupportedVersion, _ } import io.scalac.mesmer.core.support.ModulesSupport -import io.scalac.mesmer.core.util.ModuleInfo import io.scalac.mesmer.core.util.ModuleInfo.Modules -import io.scalac.mesmer.core.util.Timestamp +import io.scalac.mesmer.core.util.{ ModuleInfo, Timestamp } import io.scalac.mesmer.extension.ActorEventsMonitorActor.ReflectiveActorMetricsReader import io.scalac.mesmer.extension.actor.MutableActorMetricStorageFactory -import io.scalac.mesmer.extension.config.AkkaMonitoringConfig -import io.scalac.mesmer.extension.config.CachingConfig -import io.scalac.mesmer.extension.config.InstrumentationLibrary +import io.scalac.mesmer.extension.config.{ AkkaMonitoringConfig, CachingConfig, InstrumentationLibrary } import io.scalac.mesmer.extension.http.CleanableRequestStorage import io.scalac.mesmer.extension.metric.CachingMonitor -import io.scalac.mesmer.extension.persistence.CleanablePersistingStorage -import io.scalac.mesmer.extension.persistence.CleanableRecoveryStorage +import io.scalac.mesmer.extension.persistence.{ CleanablePersistingStorage, CleanableRecoveryStorage } import io.scalac.mesmer.extension.service._ -import io.scalac.mesmer.extension.upstream.OpenTelemetryClusterMetricsMonitor -import io.scalac.mesmer.extension.upstream.OpenTelemetryHttpMetricsMonitor -import io.scalac.mesmer.extension.upstream.OpenTelemetryPersistenceMetricsMonitor -import io.scalac.mesmer.extension.upstream._ +import io.scalac.mesmer.extension.upstream.{ + OpenTelemetryClusterMetricsMonitor, + OpenTelemetryHttpMetricsMonitor, + OpenTelemetryPersistenceMetricsMonitor, + _ +} + +import scala.concurrent.duration._ +import scala.language.postfixOps +import scala.reflect.ClassTag +import scala.util.Try object AkkaMonitoring extends ExtensionId[AkkaMonitoring] { @@ -276,7 +271,7 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM val cachingConfig = CachingConfig.fromConfig(actorSystemConfig, ModulesSupport.akkaHttpModule) val openTelemetryHttpMonitor = - CachingMonitor(OpenTelemetryHttpMetricsMonitor(meter, actorSystemConfig), cachingConfig) + CachingMonitor(OpenTelemetryHttpMetricsMonitor(meter, null, actorSystemConfig), cachingConfig) val openTelemetryHttpConnectionMonitor = CachingMonitor(OpenTelemetryHttpConnectionMetricsMonitor(meter, actorSystemConfig), cachingConfig) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/HttpEventsActor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/HttpEventsActor.scala index ff152aa23..08a8d2be0 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/HttpEventsActor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/HttpEventsActor.scala @@ -1,22 +1,17 @@ package io.scalac.mesmer.extension -import akka.actor.typed.Behavior -import akka.actor.typed.PostStop import akka.actor.typed.receptionist.Receptionist -import akka.actor.typed.receptionist.Receptionist.Deregister -import akka.actor.typed.receptionist.Receptionist.Register +import akka.actor.typed.receptionist.Receptionist.{ Deregister, Register } import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.{ Behavior, PostStop } import akka.util.Timeout - import io.scalac.mesmer.core._ import io.scalac.mesmer.core.event.HttpEvent import io.scalac.mesmer.core.event.HttpEvent._ -import io.scalac.mesmer.core.model.Method -import io.scalac.mesmer.core.model.Path -import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.model.{ Method, Path, _ } +import io.scalac.mesmer.core.module.AkkaHttpModule import io.scalac.mesmer.extension.http.RequestStorage -import io.scalac.mesmer.extension.metric.HttpConnectionMetricsMonitor -import io.scalac.mesmer.extension.metric.HttpMetricsMonitor +import io.scalac.mesmer.extension.metric.{ HttpConnectionMetricsMonitor, HttpMetricsMonitor } import io.scalac.mesmer.extension.service.PathService class HttpEventsActor @@ -52,10 +47,10 @@ object HttpEventsActor { requestStorage: RequestStorage ): Behavior[Event] = Behaviors - .receiveMessage[Event] { + .receiveMessagePartial[Event] { case HttpEventWrapper(connectionEvent: ConnectionEvent) => - val counter = httpConnectionMetricMonitor.bind(createConnectionLabels(connectionEvent)).connectionCounter + val counter = httpConnectionMetricMonitor.bind(createConnectionLabels(connectionEvent)).connections connectionEvent match { case _: ConnectionStarted => counter.incValue(1L) case _: ConnectionCompleted => counter.decValue(1L) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpConnectionMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpConnectionMetricsMonitor.scala index f0064d62b..1c9fd3220 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpConnectionMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpConnectionMetricsMonitor.scala @@ -1,10 +1,8 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable -import io.scalac.mesmer.core.model.Interface -import io.scalac.mesmer.core.model.Node -import io.scalac.mesmer.core.model.Port -import io.scalac.mesmer.core.model.RawLabels +import io.scalac.mesmer.core.model.{ Interface, Node, Port, RawLabels } +import io.scalac.mesmer.core.module.AkkaHttpModule._ object HttpConnectionMetricsMonitor { @@ -12,8 +10,8 @@ object HttpConnectionMetricsMonitor { val serialize: RawLabels = node.serialize ++ interface.serialize ++ port.serialize } - trait BoundMonitor extends Synchronized with Bound { - def connectionCounter: UpDownCounter[Long] with Instrument[Long] + trait BoundMonitor extends AkkaHttpConnectionsMetricsDef[Metric[Long]] with Synchronized with Bound { + def connections: UpDownCounter[Long] with Instrument[Long] } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpMetricsMonitor.scala index 3b6a0eb1e..3d16bae7d 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpMetricsMonitor.scala @@ -2,6 +2,7 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaHttpModule._ object HttpMetricsMonitor { @@ -9,7 +10,7 @@ object HttpMetricsMonitor { val serialize: RawLabels = node.serialize ++ path.serialize ++ method.serialize ++ status.serialize } - trait BoundMonitor extends Synchronized with Bound { + trait BoundMonitor extends AkkaHttpRequestMetricsDef[Metric[Long]] with Synchronized with Bound { def requestTime: MetricRecorder[Long] with Instrument[Long] def requestCounter: Counter[Long] with Instrument[Long] } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala index 813def14e..a911b2008 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala @@ -1,25 +1,44 @@ package io.scalac.mesmer.extension.metric -import java.util.concurrent.atomic.AtomicInteger +import io.scalac.mesmer.extension.metric.SyncWith.UpdaterPair +import java.util.concurrent.atomic.AtomicInteger import scala.annotation.tailrec -import io.scalac.mesmer.extension.metric.SyncWith.UpdaterPair +sealed trait Metric[-T] -sealed trait Metric[T] - -trait MetricRecorder[T] extends Metric[T] { +trait MetricRecorder[-T] extends Metric[T] { def setValue(value: T): Unit } -trait Counter[T] extends Metric[T] { +trait Counter[-T] extends Metric[T] { def incValue(value: T): Unit } -trait UpDownCounter[T] extends Counter[T] { +trait UpDownCounter[-T] extends Counter[T] { def decValue(value: T): Unit } +object Metric { +// private case object NoopMetricRecorder extends MetricRecorder[Any] { +// def setValue(value: Any): Unit = () +// } +// +// private case object NoopCounter extends Counter[Any] { +// def incValue(value: Any): Unit = () +// } +// +// private case object NoopUpDownCounter extends UpDownCounter[Any] { +// def decValue(value: Any): Unit = () +// +// def incValue(value: Any): Unit = () +// } +// +// def noopRecorder[T]: MetricRecorder[T] = NoopMetricRecorder +// def noopCounter[T]: Counter[T] = NoopCounter +// def noopUpDownCounter[T]: UpDownCounter[T] = NoopUpDownCounter +} + final class SyncWith private ( private val amount: Int, private val updaters: List[ diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala index 5557fecba..c4a25211f 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala @@ -127,7 +127,7 @@ final class OpenTelemetryClusterMetricsMonitor(meter: Meter, metricNames: Metric with RegisterRoot with SynchronousInstrumentFactory { - private val otLabels = LabelsFactory.of(labels.serialize) + protected val otLabels = LabelsFactory.of(labels.serialize) val shardPerRegions: MetricObserver[Long, ClusterMetricsMonitor.Labels] = shardsPerRegionRecorder.createObserver(this) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala index 96eb9dbf6..585f093b9 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala @@ -1,10 +1,8 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config -import io.opentelemetry.api.metrics.Meter -import io.scalac.mesmer.extension.metric.HttpConnectionMetricsMonitor -import io.scalac.mesmer.extension.metric.RegisterRoot -import io.scalac.mesmer.extension.metric.UpDownCounter +import io.opentelemetry.api.metrics.{Meter, common} +import io.scalac.mesmer.extension.metric.{HttpConnectionMetricsMonitor, Metric, RegisterRoot, UpDownCounter} import io.scalac.mesmer.extension.upstream.opentelemetry._ import OpenTelemetryHttpConnectionMetricsMonitor.MetricNames import io.scalac.mesmer.core.config.MesmerConfiguration @@ -52,10 +50,13 @@ class OpenTelemetryHttpConnectionMetricsMonitor(meter: Meter, metricNames: Metri with BoundMonitor with SynchronousInstrumentFactory with RegisterRoot { - private val openTelemetryLabels = LabelsFactory.of(labels.serialize) - val connectionCounter: UpDownCounter[Long] with Instrument[Long] = - upDownCounter(connectionTotalCounter, openTelemetryLabels).register(this) + protected val otLabels = LabelsFactory.of(labels.serialize) + val connections: UpDownCounter[Long] with Instrument[Long] = + upDownCounter(connectionTotalCounter, otLabels).register(this) + + +// override def connections: Metric[Long] = ??? } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala index 7c0ea8d52..91a088a4b 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala @@ -3,6 +3,7 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.core.module.AkkaHttpModule import io.scalac.mesmer.extension.metric.{ HttpMetricsMonitor, RegisterRoot } import io.scalac.mesmer.extension.upstream.OpenTelemetryHttpMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ @@ -35,37 +36,48 @@ object OpenTelemetryHttpMetricsMonitor { } } - def apply(meter: Meter, config: Config): OpenTelemetryHttpMetricsMonitor = - new OpenTelemetryHttpMetricsMonitor(meter, MetricNames.fromConfig(config)) + def apply( + meter: Meter, + moduleConfig: AkkaHttpModule.AkkaHttpRequestMetricsDef[Boolean], + config: Config + ): OpenTelemetryHttpMetricsMonitor = + new OpenTelemetryHttpMetricsMonitor(meter, moduleConfig, MetricNames.fromConfig(config)) } -class OpenTelemetryHttpMetricsMonitor(meter: Meter, metricNames: MetricNames) extends HttpMetricsMonitor { +final class OpenTelemetryHttpMetricsMonitor( + meter: Meter, + moduleConfig: AkkaHttpModule.AkkaHttpRequestMetricsDef[Boolean], + metricNames: MetricNames +) extends HttpMetricsMonitor { import HttpMetricsMonitor._ - private val requestTimeRequest = meter + private lazy val requestTimeRequest = meter .longValueRecorderBuilder(metricNames.requestDuration) .setDescription("Amount of ms request took to complete") .build() - private val requestTotalCounter = meter + private lazy val requestTotalCounter = meter .longCounterBuilder(metricNames.requestTotal) .setDescription("Amount of requests") .build() def bind(labels: Labels): BoundMonitor = new HttpMetricsBoundMonitor(labels) - class HttpMetricsBoundMonitor(labels: Labels) + final class HttpMetricsBoundMonitor(labels: Labels) extends opentelemetry.Synchronized(meter) with BoundMonitor with SynchronousInstrumentFactory with RegisterRoot { - private val openTelemetryLabels = LabelsFactory.of(labels.serialize) - val requestTime: WrappedLongValueRecorder = - metricRecorder(requestTimeRequest, openTelemetryLabels).register(this) + protected val otLabels = LabelsFactory.of(labels.serialize) - val requestCounter: WrappedCounter = counter(requestTotalCounter, openTelemetryLabels).register(this) + val requestTime = + if (moduleConfig.requestTime) metricRecorder(requestTimeRequest, otLabels).register(this) + else noopMetricRecorder[Long] + + val requestCounter: WrappedCounter = + if (moduleConfig.requestCounter) counter(requestTotalCounter, otLabels).register(this) else noopCounter[Long] } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/Synchronized.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/Synchronized.scala index 5ddd0541b..1ed08c4fb 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/Synchronized.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/Synchronized.scala @@ -1,21 +1,21 @@ package io.scalac.mesmer.extension.upstream.opentelemetry -import io.opentelemetry.api.metrics.BatchRecorder -import io.opentelemetry.api.metrics.Meter import io.opentelemetry.api.metrics.common.Labels +import io.opentelemetry.api.metrics.{BatchRecorder, Meter} +import io.scalac.mesmer.extension.metric.{Synchronized => BaseSynchronized} import scala.collection.mutable.ListBuffer -import io.scalac.mesmer.extension.metric.{ Synchronized => BaseSynchronized } - abstract class Synchronized(private val meter: Meter) extends BaseSynchronized { import Synchronized._ - type Instrument[X] = WrappedSynchronousInstrument[X] // TODO check if this type is sound + type Instrument[X] = WrappedSynchronousInstrument[X] + + protected val otLabels: Labels def atomically[A, B](first: Instrument[A], second: Instrument[B]): (A, B) => Unit = { (a, b) => meter - .newBatchRecorder(extractLabels(first.labels): _*) + .newBatchRecorder(extractLabels(otLabels): _*) .putValue(first, a) .putValue(second, b) .record() @@ -37,6 +37,7 @@ object Synchronized { case WrappedLongValueRecorder(underlying, _) => recorder.put(underlying, value) case WrappedCounter(underlying, _) => recorder.put(underlying, value) case WrappedUpDownCounter(underlying, _) => recorder.put(underlying, value) + case _: WrappedNoOp => // skip any noop monitor } recorder } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedInstument.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedInstument.scala index 206af4e6b..e202c81b1 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedInstument.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedInstument.scala @@ -14,5 +14,5 @@ trait UnregisteredInstrument[T <: WrappedInstrument] extends (RegisterRoot => T# * Common base trait for both synchronous and asynchronous instruments */ trait WrappedInstrument { self => - type Self >: self.type <: WrappedInstrument + type Self <: WrappedInstrument } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedSynchronousInstrument.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedSynchronousInstrument.scala index 52271668c..316eb65f5 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedSynchronousInstrument.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedSynchronousInstrument.scala @@ -1,16 +1,11 @@ package io.scalac.mesmer.extension.upstream.opentelemetry -import io.opentelemetry.api.metrics.LongCounter -import io.opentelemetry.api.metrics.LongUpDownCounter -import io.opentelemetry.api.metrics.LongValueRecorder -import io.opentelemetry.api.metrics.SynchronousInstrument import io.opentelemetry.api.metrics.common.Labels - +import io.opentelemetry.api.metrics.{ LongCounter, LongUpDownCounter, LongValueRecorder, SynchronousInstrument } import io.scalac.mesmer.extension.metric._ trait SynchronousInstrumentFactory { -// private def wrappedLongValueFactor() private[upstream] def metricRecorder( underlying: LongValueRecorder, labels: Labels @@ -37,12 +32,49 @@ trait SynchronousInstrumentFactory { root.registerUnbind(instrument) instrument } + + private[upstream] def noopMetricRecorder[T]: WrappedSynchronousInstrument[T] with MetricRecorder[T] = + NoopLongValueRecorder + private[upstream] def noopCounter[T]: WrappedSynchronousInstrument[T] with Counter[T] = NoopCounter + private[upstream] def noopUpDownCounter[T]: WrappedSynchronousInstrument[T] with UpDownCounter[T] = NoopUpDownCounter } -sealed trait WrappedSynchronousInstrument[L] extends Unbind with WrappedInstrument { +sealed trait WrappedSynchronousInstrument[-L] extends Unbind with WrappedInstrument { private[extension] def underlying: SynchronousInstrument[_] - private[extension] def labels: Labels +} + +sealed trait WrappedNoOp extends WrappedSynchronousInstrument[Any] { + final private[extension] def underlying: SynchronousInstrument[_] = throw new UnsupportedOperationException( + "Cannot get underlying instrument from noop" + ) +} + +case object NoopLongValueRecorder extends WrappedNoOp with MetricRecorder[Any] { + + private[scalac] def unbind(): Unit = () + + def setValue(value: Any): Unit = () + + override type Self = Nothing +} + +case object NoopCounter extends WrappedNoOp with Counter[Any] { + def incValue(value: Any): Unit = () + + private[scalac] def unbind(): Unit = () + + override type Self = Nothing +} + +case object NoopUpDownCounter extends WrappedNoOp with UpDownCounter[Any] { + def decValue(value: Any): Unit = () + + private[scalac] def unbind(): Unit = () + + def incValue(value: Any): Unit = () + + override type Self = Nothing } final case class WrappedLongValueRecorder private[opentelemetry] (underlying: LongValueRecorder, labels: Labels) diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/util/probe/HttpConnectionMetricsTestProbe.scala b/extension/src/test/scala/io/scalac/mesmer/extension/util/probe/HttpConnectionMetricsTestProbe.scala index 446cd7cc1..130f5b545 100644 --- a/extension/src/test/scala/io/scalac/mesmer/extension/util/probe/HttpConnectionMetricsTestProbe.scala +++ b/extension/src/test/scala/io/scalac/mesmer/extension/util/probe/HttpConnectionMetricsTestProbe.scala @@ -39,7 +39,7 @@ class HttpConnectionMetricsTestProbe(implicit val system: ActorSystem[_]) extend ) extends BoundMonitor with TestProbeSynchronized { - val connectionCounter: UpDownCounter[Long] with SyncTestProbeWrapper = + val connections: UpDownCounter[Long] with SyncTestProbeWrapper = UpDownCounterTestProbeWrapper(connectionCounterProbe, Some(globalConnectionCounter)) def unbind(): Unit = () From fe84f5e967a5728faa7c15369395f840a6f62505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Tue, 22 Jun 2021 11:57:00 +0200 Subject: [PATCH 05/31] Configure config for http module --- .../mesmer/core/module/AkkaHttpModule.scala | 35 ++++++++----- .../io/scalac/mesmer/core/module/Module.scala | 13 +++-- extension/src/main/resources/reference.conf | 5 +- .../mesmer/extension/AkkaMonitoring.scala | 51 +++++++++++-------- 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala index 259390f5d..e2896eceb 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -1,6 +1,6 @@ package io.scalac.mesmer.core.module -import com.typesafe.config.Config +import com.typesafe.config.{ Config => TypesafeConfig } /** * Definition of AkkHttp request related metrics @@ -31,6 +31,10 @@ object AkkaHttpModule extends MesmerModule with AkkaHttpRequestMetricsModule wit final case class AkkaHttpModuleConfig(requestTime: Boolean, requestCounter: Boolean, connections: Boolean) extends AkkaHttpRequestMetricsDef[Boolean] with AkkaHttpConnectionsMetricsDef[Boolean] + with ModuleConfig { + lazy val enabled: Boolean = + requestTime || requestCounter || connections // module is considered enabled if any metric is collected + } val name: String = "akka-http" @@ -40,19 +44,26 @@ object AkkaHttpModule extends MesmerModule with AkkaHttpRequestMetricsModule wit val defaultConfig = AkkaHttpModuleConfig(true, true, true) - protected def extractFromConfig(config: Config): AkkaHttpModule.All[Boolean] = { - val requestTime = config - .tryValue("request-time")(_.getBoolean) - .getOrElse(defaultConfig.requestTime) + protected def extractFromConfig(config: TypesafeConfig): Config = { + + val moduleEnabled = config + .tryValue("enabled")(_.getBoolean) + .getOrElse(true) + + if (moduleEnabled) { + val requestTime = config + .tryValue("request-time")(_.getBoolean) + .getOrElse(defaultConfig.requestTime) - val requestCounter = config - .tryValue("request-counter")(_.getBoolean) - .getOrElse(defaultConfig.requestCounter) + val requestCounter = config + .tryValue("request-counter")(_.getBoolean) + .getOrElse(defaultConfig.requestCounter) - val connections = config - .tryValue("connections")(_.getBoolean) - .getOrElse(defaultConfig.connections) + val connections = config + .tryValue("connections")(_.getBoolean) + .getOrElse(defaultConfig.connections) + AkkaHttpModuleConfig(requestTime = requestTime, requestCounter = requestCounter, connections = connections) + } else AkkaHttpModuleConfig(false, false, false) - AkkaHttpModuleConfig(requestTime = requestTime, requestCounter = requestCounter, connections = connections) } } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala index 53ba9b9b4..8f85a6572 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -1,19 +1,24 @@ package io.scalac.mesmer.core.module -import com.typesafe.config.Config +import com.typesafe.config.{ Config => TypesafeConfig } import io.scalac.mesmer.core.config.MesmerConfigurationBase trait Module { def name: String type All[_] + type Config = All[Boolean] with ModuleConfig - def enabled(config: Config): All[Boolean] + def enabled(config: TypesafeConfig): Config +} + +trait ModuleConfig { + def enabled: Boolean } trait MesmerModule extends Module with MesmerConfigurationBase { - override type Result = All[Boolean] + override type Result = Config - final def enabled(config: Config): All[Boolean] = fromConfig(config) + final def enabled(config: TypesafeConfig): Config = fromConfig(config) val mesmerConfig = s"module.$name" } diff --git a/extension/src/main/resources/reference.conf b/extension/src/main/resources/reference.conf index 45cf44fb3..f99648a39 100644 --- a/extension/src/main/resources/reference.conf +++ b/extension/src/main/resources/reference.conf @@ -14,7 +14,7 @@ io.scalac.mesmer.actor.rules { io { scalac { - akka-monitoring { + mesmer { #flags which module monitoring should be automatically started on extension initilization auto-start { @@ -24,8 +24,9 @@ io { akka-cluster = true } - enabled { + module { akka-http { + enabled = true request-time = true request-counter = true } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala index 2b1a758bc..3d1803abe 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala @@ -6,6 +6,7 @@ import akka.actor.typed.scaladsl.Behaviors import akka.cluster.Cluster import akka.util.Timeout import io.scalac.mesmer.core.model.{ Module, SupportedVersion, _ } +import io.scalac.mesmer.core.module.AkkaHttpModule import io.scalac.mesmer.core.support.ModulesSupport import io.scalac.mesmer.core.util.ModuleInfo.Modules import io.scalac.mesmer.core.util.{ ModuleInfo, Timestamp } @@ -266,32 +267,40 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM } def startHttpEventListener(): Unit = { - log.info("Starting local http event listener") - val cachingConfig = CachingConfig.fromConfig(actorSystemConfig, ModulesSupport.akkaHttpModule) + val httpModuleConfig = AkkaHttpModule.fromConfig(actorSystemConfig) - val openTelemetryHttpMonitor = - CachingMonitor(OpenTelemetryHttpMetricsMonitor(meter, null, actorSystemConfig), cachingConfig) + if (httpModuleConfig.enabled) { + log.info("Starting local http event listener") - val openTelemetryHttpConnectionMonitor = - CachingMonitor(OpenTelemetryHttpConnectionMetricsMonitor(meter, actorSystemConfig), cachingConfig) + val cachingConfig = CachingConfig.fromConfig(actorSystemConfig, ModulesSupport.akkaHttpModule) - val pathService = new CachingPathService(cachingConfig) + val openTelemetryHttpMonitor = + CachingMonitor(OpenTelemetryHttpMetricsMonitor(meter, httpModuleConfig, actorSystemConfig), cachingConfig) - system.systemActorOf( - Behaviors - .supervise( - WithSelfCleaningState - .clean(CleanableRequestStorage.withConfig(config.cleaning)) - .every(config.cleaning.every)(rs => - HttpEventsActor - .apply(openTelemetryHttpMonitor, openTelemetryHttpConnectionMonitor, rs, pathService, clusterNodeName) - ) - ) - .onFailure[Exception](SupervisorStrategy.restart), - "httpEventMonitor", - dispatcherSelector - ) + val openTelemetryHttpConnectionMonitor = + CachingMonitor(OpenTelemetryHttpConnectionMetricsMonitor(meter, actorSystemConfig), cachingConfig) + + val pathService = new CachingPathService(cachingConfig) + + system.systemActorOf( + Behaviors + .supervise( + WithSelfCleaningState + .clean(CleanableRequestStorage.withConfig(config.cleaning)) + .every(config.cleaning.every)(rs => + HttpEventsActor + .apply(openTelemetryHttpMonitor, openTelemetryHttpConnectionMonitor, rs, pathService, clusterNodeName) + ) + ) + .onFailure[Exception](SupervisorStrategy.restart), + "httpEventMonitor", + dispatcherSelector + ) + } else { + log.warn(s"Module ${AkkaHttpModule.name} set to auto-start but it's disabled") + } + } } From 6f4413515a3c381660acb2ac44f349efc760fa0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Wed, 23 Jun 2021 13:41:42 +0200 Subject: [PATCH 06/31] Create all modules --- .../scala/io/scalac/mesmer/agent/Agent.scala | 8 +- .../scala/io/scalac/mesmer/agent/Boot.scala | 2 +- .../ActorCellConstructorInstrumentation.scala | 2 - ...torCellReceiveMessageInstrumentation.scala | 1 - ...ellSendMessageMetricInstrumentation.scala} | 18 +- .../actor/ActorUnhandledInstrumentation.scala | 1 - .../agent/akka/actor/AkkaActorAgent.scala | 171 +++++++++++++----- .../agent/akka/actor/AkkaMailboxAgent.scala | 2 +- .../ClassicStashInstrumentationStash.scala | 1 - .../actor/LocalActorRefProviderAdvice.scala | 1 - .../actor/MailboxDequeueInstrumentation.scala | 1 - .../agent/akka/actor/StashBufferAdvice.scala | 1 - ...andleReceiveExceptionInstrumentation.scala | 1 - .../agent/akka/http/AkkaHttpAgent.scala | 30 +-- .../i13n/AgentInstrumentationFactory.scala | 10 +- .../util/i13n/InstrumentModuleFactory.scala | 2 +- .../mesmer/agent/util/i13n/package.scala | 44 +++-- .../mesmer/core/module/AkkaActorModule.scala | 160 ++++++++++++++++ .../core/module/AkkaActorSystemModule.scala | 37 ++++ .../core/module/AkkaClusterModule.scala | 88 +++++++++ .../mesmer/core/module/AkkaHttpModule.scala | 4 +- .../core/module/AkkaPersistenceModule.scala | 62 +++++++ .../mesmer/core/module/AkkaStreamModule.scala | 93 ++++++++++ .../io/scalac/mesmer/core/module/Module.scala | 2 +- extension/src/main/resources/reference.conf | 3 + .../metric/ActorMetricsMonitor.scala | 21 +-- .../extension/metric/ActorSystemMonitor.scala | 2 +- .../mesmer/extension/metric/Metric.scala | 30 +-- .../OpenTelemetryActorMetricsMonitor.scala | 82 +++++---- .../OpenTelemetryActorSystemMonitor.scala | 9 +- .../OpenTelemetryHttpMetricsMonitor.scala | 2 +- ...enTelemetryPersistenceMetricsMonitor.scala | 4 +- 32 files changed, 714 insertions(+), 181 deletions(-) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ActorCellSendMessageInstrumentation.scala => ActorCellSendMessageMetricInstrumentation.scala} (63%) create mode 100644 core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala create mode 100644 core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala create mode 100644 core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala create mode 100644 core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala create mode 100644 core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala index c680da6aa..5703bb480 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala @@ -56,10 +56,14 @@ object AgentInstrumentation { def apply(builder: AgentBuilder, instrumentation: Instrumentation, modules: Modules): LoadingResult = installation(builder, instrumentation, modules) } + } -sealed abstract case class AgentInstrumentation(name: String, instrumentingModules: SupportedModules) - extends ((AgentBuilder, Instrumentation, Modules) => LoadingResult) +sealed abstract case class AgentInstrumentation( + name: String, + instrumentingModules: SupportedModules, + fqcn: Boolean = false +) extends ((AgentBuilder, Instrumentation, Modules) => LoadingResult) with Equals { override def hashCode(): Int = name.hashCode() diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala index bc33a8487..9d96e9de5 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala @@ -30,7 +30,7 @@ object Boot { val allInstrumentations = AkkaPersistenceAgent.agent ++ AkkaStreamAgent.agent ++ AkkaHttpAgent.agent( config - ) ++ AkkaActorAgent.agent ++ AkkaMailboxAgent.agent + ) ++ AkkaActorAgent.agent(config) ++ AkkaMailboxAgent.agent val moduleInfo = ModuleInfo.extractModulesInformation(Thread.currentThread().getContextClassLoader) allInstrumentations diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellConstructorInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellConstructorInstrumentation.scala index 7459c3a43..d3c91ef5a 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellConstructorInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellConstructorInstrumentation.scala @@ -7,7 +7,6 @@ import net.bytebuddy.asm.Advice.This import io.scalac.mesmer.extension.actor.ActorCellDecorator -class ActorCellConstructorInstrumentation object ActorCellConstructorInstrumentation { @OnMethodExit @@ -15,4 +14,3 @@ object ActorCellConstructorInstrumentation { ActorCellDecorator.initialize(actorCell, mailboxType) } -object ActorCellDispatcherInit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellReceiveMessageInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellReceiveMessageInstrumentation.scala index 5f7123b2f..81dbaf5c0 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellReceiveMessageInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellReceiveMessageInstrumentation.scala @@ -4,7 +4,6 @@ import net.bytebuddy.asm.Advice._ import io.scalac.mesmer.extension.actor.ActorCellDecorator -class ActorCellReceiveMessageInstrumentation object ActorCellReceiveMessageInstrumentation { @OnMethodEnter diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageMetricInstrumentation.scala similarity index 63% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageInstrumentation.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageMetricInstrumentation.scala index ed0fb5f30..27f746b82 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageMetricInstrumentation.scala @@ -1,24 +1,28 @@ package io.scalac.mesmer.agent.akka.actor import akka.actor.Actor -import net.bytebuddy.asm.Advice._ - import io.scalac.mesmer.core.util.ActorRefOps import io.scalac.mesmer.extension.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice._ -class ActorCellSendMessageInstrumentation -object ActorCellSendMessageInstrumentation { +object ActorCellSendMessageMetricInstrumentation { @OnMethodEnter def onEnter(@Argument(0) envelope: Object): Unit = if (envelope != null) { - EnvelopeDecorator.setTimestamp(envelope) val sender = EnvelopeOps.getSender(envelope) if (sender != Actor.noSender) for { cell <- ActorRefOps.Local.cell(sender) - spy <- ActorCellDecorator.get(cell) - } spy.sentMessages.inc() + metrics <- ActorCellDecorator.get(cell) + } metrics.sentMessages.inc() } +} +object ActorCellSendMessageTimestampInstrumentation { + @OnMethodEnter + def onEnter(@Argument(0) envelope: Object): Unit = + if (envelope != null) { + EnvelopeDecorator.setTimestamp(envelope) + } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorUnhandledInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorUnhandledInstrumentation.scala index 489470b61..d9c884d68 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorUnhandledInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorUnhandledInstrumentation.scala @@ -5,7 +5,6 @@ import net.bytebuddy.asm.Advice.This import io.scalac.mesmer.extension.actor.ActorCellDecorator -class ActorUnhandledInstrumentation object ActorUnhandledInstrumentation { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala index 7ee8d51a0..d3a5457c7 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala @@ -1,80 +1,169 @@ package io.scalac.mesmer.agent.akka.actor -import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaActorModule import io.scalac.mesmer.core.support.ModulesSupport import io.scalac.mesmer.core.util.Timestamp -import io.scalac.mesmer.extension.actor.ActorCellDecorator -import io.scalac.mesmer.extension.actor.ActorCellMetrics +import io.scalac.mesmer.extension.actor.{ ActorCellDecorator, ActorCellMetrics } -object AkkaActorAgent extends InstrumentModuleFactory { +object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with AkkaActorModule.All[Agent] { + + def agent(config: AkkaActorModule.AkkaActorMetricsDef[Boolean]): Agent = + Agent.empty ++ + (if (config.mailboxSize) mailboxSize else Agent.empty) ++ + (if (config.mailboxTimeAvg) mailboxTimeAvg else Agent.empty) ++ + (if (config.mailboxTimeMin) mailboxTimeMin else Agent.empty) ++ + (if (config.mailboxTimeMax) mailboxTimeMax else Agent.empty) ++ + (if (config.mailboxTimeSum) mailboxTimeSum else Agent.empty) ++ + (if (config.stashSize) stashSize else Agent.empty) ++ + (if (config.receivedMessages) receivedMessages else Agent.empty) ++ + (if (config.processedMessages) processedMessages else Agent.empty) ++ + (if (config.failedMessages) failedMessages else Agent.empty) ++ + (if (config.processingTimeAvg) processingTimeAvg else Agent.empty) ++ + (if (config.processingTimeMin) processingTimeMin else Agent.empty) ++ + (if (config.processingTimeMax) processingTimeMax else Agent.empty) ++ + (if (config.processingTimeSum) processingTimeSum else Agent.empty) ++ + (if (config.sentMessages) sentMessages else Agent.empty) ++ + (if (config.droppedMessages) droppedMessages else Agent.empty) + + lazy val mailboxSize: Agent = sharedInstrumentation + + lazy val mailboxTimeAvg: Agent = sharedInstrumentation ++ mailboxInstrumentation + + lazy val mailboxTimeMin: Agent = sharedInstrumentation ++ mailboxInstrumentation + + lazy val mailboxTimeMax: Agent = sharedInstrumentation ++ mailboxInstrumentation + + lazy val mailboxTimeSum: Agent = sharedInstrumentation ++ mailboxInstrumentation + + lazy val stashSize: Agent = sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation + + lazy val receivedMessages: Agent = sharedInstrumentation + + lazy val processedMessages: Agent = sharedInstrumentation + + lazy val failedMessages: Agent = sharedInstrumentation ++ abstractSupervisionInstrumentation + + lazy val processingTimeAvg: Agent = sharedInstrumentation + + lazy val processingTimeMin: Agent = sharedInstrumentation + + lazy val processingTimeMax: Agent = sharedInstrumentation + + lazy val processingTimeSum: Agent = sharedInstrumentation + + lazy val sentMessages: Agent = sharedInstrumentation ++ mailboxTimeSendMessageIncInstrumentation + + lazy val droppedMessages: Agent = sharedInstrumentation protected final val supportedModules: SupportedModules = SupportedModules(ModulesSupport.akkaActorModule, ModulesSupport.akkaActor) + /** + * Instrumentation for classic stash + */ private val classicStashInstrumentationAgent = { val stashLogic = instrument("akka.actor.StashSupport") - .visit[ClassicStashInstrumentationStash]("stash") - .visit[ClassicStashInstrumentationPrepend]("prepend") + .visit(ClassicStashInstrumentationStash, "stash") + .visit(ClassicStashInstrumentationPrepend, "prepend") val stashConstructor = instrument(hierarchy("akka.actor.StashSupport").concreteOnly) - .visit[StashConstructorAdvice](constructor) + .visit(StashConstructorAdvice, constructor) Agent(stashLogic, stashConstructor) } - private val mailboxTimeTimestampInstrumentation = - instrument("akka.dispatch.Envelope") - .defineField[Timestamp](EnvelopeDecorator.TimestampVarName) - .defineField[Boolean](EnvelopeDecorator.TimestampVarName) + private val mailboxInstrumentation = { + + /** + * Instrumentation that enrich [[ akka.dispatch.Envelope ]] with additional timestamp field + */ + val mailboxTimeTimestampInstrumentation = + instrument("akka.dispatch.Envelope") + .defineField[Timestamp](EnvelopeDecorator.TimestampVarName) + // .defineField[Boolean](EnvelopeDecorator.TimestampVarName) + + /** + * Instrumentation that sets envelope timestamp to current time on each dispatch + */ + val mailboxTimeSendMessageInstrumentation = + instrument("akka.actor.dungeon.Dispatch".withId("set envelope timestamp")) + .visit( + ActorCellSendMessageTimestampInstrumentation, + method("sendMessage").takesArgument(0, "akka.dispatch.Envelope") + ) + + /** + * Instrumentation that computes time in mailbox + */ + val mailboxTimeDequeueInstrumentation = + instrument("akka.dispatch.Mailbox") + .visit(MailboxDequeueInstrumentation, "dequeue") + + Agent(mailboxTimeTimestampInstrumentation, mailboxTimeSendMessageInstrumentation, mailboxTimeDequeueInstrumentation) + + } - private val mailboxTimeSendMessageInstrumentation = - instrument("akka.actor.dungeon.Dispatch") - .visit[ActorCellSendMessageInstrumentation]( + /** + * Instrumentation that increase send messages on each dispatch + */ + private val mailboxTimeSendMessageIncInstrumentation = + instrument("akka.actor.dungeon.Dispatch".withId("sent message inc")) + .visit( + ActorCellSendMessageMetricInstrumentation, method("sendMessage").takesArgument(0, "akka.dispatch.Envelope") ) - private val mailboxTimeDequeueInstrumentation = - instrument("akka.dispatch.Mailbox") - .visit[MailboxDequeueInstrumentation]("dequeue") - - private val actorCellInstrumentation = - instrument("akka.actor.ActorCell") - .defineField[ActorCellMetrics](ActorCellDecorator.fieldName) - .visit[ActorCellConstructorInstrumentation]("init") - .visit[ActorCellReceiveMessageInstrumentation]("receiveMessage") - - private val actorInstrumentation = + /** + * Instrumentation that add [[ ActorCellMetrics ]] field to [[ akka.actor.ActorCell ]] + * and initialize it in {@code init} method + */ + private val actorCellInstrumentation = instrument("akka.actor.ActorCell") + .defineField[ActorCellMetrics](ActorCellDecorator.fieldName) + .visit(ActorCellConstructorInstrumentation, "init") + .visit(ActorCellReceiveMessageInstrumentation, "receiveMessage") + + private lazy val sharedInstrumentation: Agent = + Agent( + actorCellInstrumentation, + localActorRefProviderInstrumentation, + receiveUnhandledInstrumentation + ) + + /** + * Instrumentation for unhandled metric + */ + private val receiveUnhandledInstrumentation = instrument("akka.actor.Actor") - .visit[ActorUnhandledInstrumentation]("unhandled") + .visit(ActorUnhandledInstrumentation, "unhandled") + /** + * Instrumentation for supervision + */ private val abstractSupervisionInstrumentation = instrument( hierarchy("akka.actor.typed.internal.AbstractSupervisor") .overrides("handleReceiveException") - ).visit[SupervisorHandleReceiveExceptionInstrumentation]("handleReceiveException") + ).visit(SupervisorHandleReceiveExceptionInstrumentation, "handleReceiveException") + /** + * Instrumentation for [[ akka.actor.typed.internal.StashBufferImpl ]] - collection used for typed stash implementation + */ private val stashBufferImplementation = instrument(hierarchy("akka.actor.typed.internal.StashBufferImpl")) - .visit[StashBufferAdvice]("stash") + .visit(StashBufferAdvice, "stash") - private val localActorRefProviderInstrumentation = + /** + * Instrumentation to publish events when new actor is created. This must be enabled + * for any other instrumentation here to work. + */ + private val localActorRefProviderInstrumentation: AgentInstrumentation = instrument("akka.actor.LocalActorRefProvider") - .visit[LocalActorRefProviderAdvice]("actorOf") - - val agent: Agent = Agent( - mailboxTimeTimestampInstrumentation, - mailboxTimeSendMessageInstrumentation, - mailboxTimeDequeueInstrumentation, - actorCellInstrumentation, - actorInstrumentation, - abstractSupervisionInstrumentation, - stashBufferImplementation, - localActorRefProviderInstrumentation - ) ++ classicStashInstrumentationAgent + .visit(LocalActorRefProviderAdvice, "actorOf") } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxAgent.scala index 335a75b80..a302eb6ef 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxAgent.scala @@ -104,7 +104,7 @@ object AkkaMailboxAgent extends InstrumentModuleFactory { ) private val boundedQueueBasedMailboxes: TypeInstrumentation = instrument( `type`( - "akka.dispatch.BoundedQueueBasedMessageQueue", + "akka.dispatch.BoundedQueueBasedMessageQueue".fqcn, ElementMatchers .hasSuperType[TypeDescription]( ElementMatchers.named[TypeDescription]("akka.dispatch.BoundedQueueBasedMessageQueue") diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicStashInstrumentationStash.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicStashInstrumentationStash.scala index 1138bd745..717c9fdeb 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicStashInstrumentationStash.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicStashInstrumentationStash.scala @@ -11,7 +11,6 @@ import net.bytebuddy.asm.Advice.This import io.scalac.mesmer.extension.actor.ActorCellDecorator -class StashConstructorAdvice object StashConstructorAdvice { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/LocalActorRefProviderAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/LocalActorRefProviderAdvice.scala index 88d4684fd..eb71b93a9 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/LocalActorRefProviderAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/LocalActorRefProviderAdvice.scala @@ -8,7 +8,6 @@ import io.scalac.mesmer.core.event.ActorEvent.ActorCreated import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.model.ActorRefTags -class LocalActorRefProviderAdvice object LocalActorRefProviderAdvice { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxDequeueInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxDequeueInstrumentation.scala index b00585b19..02cf4270c 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxDequeueInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxDequeueInstrumentation.scala @@ -5,7 +5,6 @@ import net.bytebuddy.asm.Advice._ import io.scalac.mesmer.core.util.Interval import io.scalac.mesmer.extension.actor.ActorCellDecorator -class MailboxDequeueInstrumentation object MailboxDequeueInstrumentation { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/StashBufferAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/StashBufferAdvice.scala index d1c65f0c9..bad4c3946 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/StashBufferAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/StashBufferAdvice.scala @@ -5,7 +5,6 @@ import net.bytebuddy.asm.Advice import io.scalac.mesmer.extension.actor.ActorCellDecorator -class StashBufferAdvice object StashBufferAdvice { @Advice.OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/SupervisorHandleReceiveExceptionInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/SupervisorHandleReceiveExceptionInstrumentation.scala index b3b575d89..b1c0b038b 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/SupervisorHandleReceiveExceptionInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/SupervisorHandleReceiveExceptionInstrumentation.scala @@ -6,7 +6,6 @@ import net.bytebuddy.asm.Advice.OnMethodExit import io.scalac.mesmer.extension.actor.ActorCellDecorator -class SupervisorHandleReceiveExceptionInstrumentation object SupervisorHandleReceiveExceptionInstrumentation { @OnMethodExit(onThrowable = classOf[Throwable]) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala index eb3c733b7..261749955 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala @@ -1,39 +1,43 @@ package io.scalac.mesmer.agent.akka.http +import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } import io.scalac.mesmer.core.model.SupportedModules import io.scalac.mesmer.core.module.AkkaHttpModule import io.scalac.mesmer.core.support.ModulesSupport object AkkaHttpAgent extends InstrumentModuleFactoryTest(AkkaHttpModule) - with AkkaHttpModule.AkkaHttpConnectionsMetricsDef[AgentInstrumentation] - with AkkaHttpModule.AkkaHttpRequestMetricsDef[AgentInstrumentation] { + with AkkaHttpModule.AkkaHttpConnectionsMetricsDef[Agent] + with AkkaHttpModule.AkkaHttpRequestMetricsDef[Agent] { // @ToDo tests all supported versions protected val supportedModules: SupportedModules = SupportedModules(ModulesSupport.akkaHttpModule, ModulesSupport.akkaHttp) - def requestTime: AgentInstrumentation = requestEvents + def requestTime: Agent = requestEvents - def requestCounter: AgentInstrumentation = requestEvents + def requestCounter: Agent = requestEvents - def connections: AgentInstrumentation = connectionEvents + def connections: Agent = connectionEvents private lazy val requestEvents = - instrument(`type`("akka.http.scaladsl.HttpExt?requests", "akka.http.scaladsl.HttpExt")) - .visit[HttpExtRequestsAdvice]("bindAndHandle") + Agent( + instrument(`type`("http_requests".id, "akka.http.scaladsl.HttpExt")) + .visit[HttpExtRequestsAdvice]("bindAndHandle") + ) private lazy val connectionEvents = - instrument(`type`("akka.http.scaladsl.HttpExt?connections", "akka.http.scaladsl.HttpExt")) - .visit[HttpExtConnectionsAdvice]("bindAndHandle") + Agent( + instrument(`type`("http_connections".id, "akka.http.scaladsl.HttpExt")) + .visit[HttpExtConnectionsAdvice]("bindAndHandle") + ) def agent(config: AkkaHttpModule.All[Boolean]): Agent = { - val requestCounterAgent = if (config.requestCounter) Agent(requestCounter) else Agent.empty - val requestTimeAgent = if (config.requestTime) Agent(requestTime) else Agent.empty - val connectionsAgent = if (config.connections) Agent(connections) else Agent.empty + val requestCounterAgent = if (config.requestCounter) requestCounter else Agent.empty + val requestTimeAgent = if (config.requestTime) requestTime else Agent.empty + val connectionsAgent = if (config.connections) connections else Agent.empty requestCounterAgent ++ requestTimeAgent ++ connectionsAgent } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala index 7b5b3ede8..54919e95d 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala @@ -5,16 +5,18 @@ import io.scalac.mesmer.agent.AgentInstrumentation object AgentInstrumentationFactory { - def apply(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = - AgentInstrumentation(typeInstrumentation.target.tpe.name, typeInstrumentation.target.modules) { + def apply(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = { + val instrumentationName: InstrumentationName = typeInstrumentation.target.`type`.name + AgentInstrumentation(instrumentationName.value, typeInstrumentation.target.modules) { (agentBuilder, instrumentation, _) => agentBuilder - .`type`(typeInstrumentation.target.tpe.desc) + .`type`(typeInstrumentation.target.`type`.desc) .transform { (underlying, _, _, _) => typeInstrumentation.transformBuilder(underlying) } .installOn(instrumentation) - LoadingResult(typeInstrumentation.target.tpe.name) + if (instrumentationName.fqcn) LoadingResult(instrumentationName.value) else LoadingResult.empty } + } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala index b2c28e896..d8bdbcbea 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala @@ -12,7 +12,7 @@ trait InstrumentModuleFactory { } abstract class InstrumentModuleFactoryTest[M <: Module](val module: M) { - this: M#All[AgentInstrumentation] => + this: M#All[Agent] => protected def supportedModules: SupportedModules diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index c2834cf83..4e99888f9 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -1,27 +1,25 @@ package io.scalac.mesmer.agent.util +import io.scalac.mesmer.agent.AgentInstrumentation +import io.scalac.mesmer.core.model.SupportedModules import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription import net.bytebuddy.description.method.MethodDescription import net.bytebuddy.dynamic.DynamicType -import net.bytebuddy.implementation.Implementation -import net.bytebuddy.implementation.MethodDelegation -import net.bytebuddy.matcher.ElementMatcher -import net.bytebuddy.matcher.{ ElementMatchers => EM } +import net.bytebuddy.implementation.{ Implementation, MethodDelegation } +import net.bytebuddy.matcher.{ ElementMatcher, ElementMatchers => EM } import scala.language.implicitConversions -import scala.reflect.ClassTag -import scala.reflect.classTag - -import io.scalac.mesmer.agent.AgentInstrumentation -import io.scalac.mesmer.core.model.SupportedModules +import scala.reflect.{ classTag, ClassTag } package object i13n { final private[i13n] type TypeDesc = ElementMatcher.Junction[TypeDescription] final private[i13n] type MethodDesc = ElementMatcher.Junction[MethodDescription] - final class Type private[i13n] (private[i13n] val name: String, private[i13n] val desc: TypeDesc) { + final case class InstrumentationName(value: String, fqcn: Boolean) + + final class Type private[i13n] (private[i13n] val name: InstrumentationName, private[i13n] val desc: TypeDesc) { def and(addDesc: TypeDesc): Type = new Type(name, desc.and(addDesc)) } @@ -34,13 +32,13 @@ package object i13n { val constructor: MethodDesc = EM.isConstructor def `type`(name: String): Type = - `type`(name, EM.named[TypeDescription](name)) + `type`(name.fqcn, EM.named[TypeDescription](name)) - def `type`(name: String, desc: TypeDesc): Type = new Type(name, desc) + def `type`(name: InstrumentationName, desc: TypeDesc): Type = new Type(name, desc) def hierarchy(name: String): Type = `type`( - name, + name.fqcn, EM.hasSuperType[TypeDescription](EM.named[TypeDescription](name)) ) @@ -56,6 +54,9 @@ package object i13n { def visit[T](method: MethodDesc)(implicit ct: ClassTag[T]): TypeInstrumentation = chain(_.visit(Advice.to(ct.runtimeClass).on(method))) + def visit[A](advice: A, method: MethodDesc)(implicit isObject: A <:< Singleton): TypeInstrumentation = + chain(_.visit(Advice.to(typeFromModule(advice.getClass)).on(method))) + def intercept[T](method: MethodDesc)(implicit ct: ClassTag[T]): TypeInstrumentation = chain(_.method(method).intercept(Advice.to(ct.runtimeClass))) @@ -74,6 +75,11 @@ package object i13n { impl.fold[Builder](implemented)(implemented.intercept) } + private def typeFromModule(clazz: Class[_]): Class[_] = { + val dollarFreeFQCN = clazz.getName.dropRight(1) + Class.forName(dollarFreeFQCN, true, clazz.getClassLoader) + } + private def chain(that: Builder => Builder): TypeInstrumentation = new TypeInstrumentation(target, transformBuilder.andThen(that)) @@ -83,7 +89,7 @@ package object i13n { private[i13n] def apply(target: TypeTarget): TypeInstrumentation = new TypeInstrumentation(target, identity) } - final private[i13n] case class TypeTarget(tpe: Type, modules: SupportedModules) + final private[i13n] case class TypeTarget(`type`: Type, modules: SupportedModules) // extensions @@ -120,10 +126,16 @@ package object i13n { methodDesc.and(EM.isOverriddenFrom(typeDesc)) } + implicit class StringDlsOps(private val value: String) extends AnyVal { + def fqcn: InstrumentationName = InstrumentationName(value, true) + def id: InstrumentationName = InstrumentationName(value, false) + def withId(name: String): Type = `type`(name.id, name) + } + // implicit conversion implicit def methodNameToMethodDesc(methodName: String): MethodDesc = method(methodName) - implicit def classNameToTypeDesc(className: String): TypeDesc = EM.named[TypeDescription](className) - implicit def typeNameToType(typeName: String): Type = `type`(typeName) + implicit def classNameToTypeDesc(className: String): TypeDesc = EM.named[TypeDescription](className) + implicit def typeNameToType(name: String): Type = `type`(name) implicit def typeToAgentInstrumentation(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = AgentInstrumentationFactory(typeInstrumentation) } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala new file mode 100644 index 000000000..2cf8f1058 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala @@ -0,0 +1,160 @@ +package io.scalac.mesmer.core.module +import com.typesafe.config.{ Config => TypesafeConfig } + +sealed trait AkkaActorMetrics extends MetricsModule { + this: Module => + + override type Metrics[T] <: AkkaActorMetricsDef[T] + + trait AkkaActorMetricsDef[T] { + def mailboxSize: T + def mailboxTimeAvg: T + def mailboxTimeMin: T + def mailboxTimeMax: T + def mailboxTimeSum: T + def stashSize: T + def receivedMessages: T + def processedMessages: T + def failedMessages: T + def processingTimeAvg: T + def processingTimeMin: T + def processingTimeMax: T + def processingTimeSum: T + def sentMessages: T + def droppedMessages: T + } +} + +object AkkaActorModule extends MesmerModule with AkkaActorMetrics { + override type Metrics[T] = AkkaActorMetricsDef[T] + + final case class AkkaActorModuleConfig( + mailboxSize: Boolean, + mailboxTimeAvg: Boolean, + mailboxTimeMin: Boolean, + mailboxTimeMax: Boolean, + mailboxTimeSum: Boolean, + stashSize: Boolean, + receivedMessages: Boolean, + processedMessages: Boolean, + failedMessages: Boolean, + processingTimeAvg: Boolean, + processingTimeMin: Boolean, + processingTimeMax: Boolean, + processingTimeSum: Boolean, + sentMessages: Boolean, + droppedMessages: Boolean + ) extends AkkaActorMetricsDef[Boolean] + with ModuleConfig { + lazy val enabled: Boolean = { + mailboxSize || mailboxTimeAvg || mailboxTimeMin || + mailboxTimeMax || + mailboxTimeSum || + stashSize || + receivedMessages || + processedMessages || + failedMessages || + processingTimeAvg || + processingTimeMin || + processingTimeMax || + processingTimeSum || + sentMessages || + droppedMessages + } + } + + val name: String = "akka-actor" + + protected lazy val defaultConfig: Config = + AkkaActorModuleConfig(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + + protected def extractFromConfig(config: TypesafeConfig): Config = { + val moduleEnabled = config + .tryValue("enabled")(_.getBoolean) + .getOrElse(true) + if (moduleEnabled) { + val mailboxSize = config + .tryValue("mailbox-size")(_.getBoolean) + .getOrElse(defaultConfig.mailboxSize) + + val mailboxTimeAvg = config + .tryValue("mailbox-time-avg")(_.getBoolean) + .getOrElse(defaultConfig.mailboxTimeAvg) + + val mailboxTimeMin = config + .tryValue("mailbox-time-min")(_.getBoolean) + .getOrElse(defaultConfig.mailboxTimeMin) + + val mailboxTimeMax = config + .tryValue("mailbox-time-max")(_.getBoolean) + .getOrElse(defaultConfig.mailboxTimeMax) + + val mailboxTimeSum = config + .tryValue("mailbox-time-sum")(_.getBoolean) + .getOrElse(defaultConfig.mailboxTimeSum) + + val stashSize = config + .tryValue("stash-size")(_.getBoolean) + .getOrElse(defaultConfig.stashSize) + + val receivedMessages = config + .tryValue("received-messages")(_.getBoolean) + .getOrElse(defaultConfig.receivedMessages) + + val processedMessages = config + .tryValue("processed-messages")(_.getBoolean) + .getOrElse(defaultConfig.processedMessages) + + val failedMessages = config + .tryValue("failed-messages")(_.getBoolean) + .getOrElse(defaultConfig.failedMessages) + + val processingTimeAvg = config + .tryValue("processing-time-avg")(_.getBoolean) + .getOrElse(defaultConfig.processingTimeAvg) + + val processingTimeMin = config + .tryValue("processing-time-min")(_.getBoolean) + .getOrElse(defaultConfig.processingTimeMin) + + val processingTimeMax = config + .tryValue("processing-time-max")(_.getBoolean) + .getOrElse(defaultConfig.processingTimeMax) + + val processingTimeSum = config + .tryValue("processing-time-sum")(_.getBoolean) + .getOrElse(defaultConfig.processingTimeSum) + + val sentMessages = config + .tryValue("sent-messages")(_.getBoolean) + .getOrElse(defaultConfig.sentMessages) + + val droppedMessages = config + .tryValue("dropped-messages")(_.getBoolean) + .getOrElse(defaultConfig.droppedMessages) + + AkkaActorModuleConfig( + mailboxSize = mailboxSize, + mailboxTimeAvg = mailboxTimeAvg, + mailboxTimeMin = mailboxTimeMin, + mailboxTimeMax = mailboxTimeMax, + mailboxTimeSum = mailboxTimeSum, + stashSize = stashSize, + receivedMessages = receivedMessages, + processedMessages = processedMessages, + failedMessages = failedMessages, + processingTimeAvg = processingTimeAvg, + processingTimeMin = processingTimeMin, + processingTimeMax = processingTimeMax, + processingTimeSum = processingTimeSum, + sentMessages = sentMessages, + droppedMessages = droppedMessages + ) + } else + AkkaActorModuleConfig(false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false) + + } + + override type All[T] = Metrics[T] +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala new file mode 100644 index 000000000..4c7ff50f0 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala @@ -0,0 +1,37 @@ +package io.scalac.mesmer.core.module +import com.typesafe.config.{ Config => TypesafeConfig } + +sealed trait AkkaActorSystemMetricsModule extends MetricsModule { + this: Module => + override type Metrics[T] <: ActorSystemMetricsDef[T] + + trait ActorSystemMetricsDef[T] { + def createdActors: T + def terminatedActors: T + } +} + +object AkkaActorSystemModule extends MesmerModule with AkkaActorSystemMetricsModule { + val name: String = "akka-system" + + override type Metrics[T] = ActorSystemMetricsDef[T] + override type All[T] = Metrics[T] + + final case class ActorSystemModuleConfig( + createdActors: Boolean, + terminatedActors: Boolean + ) extends ActorSystemMetricsDef[Boolean] + with ModuleConfig { + lazy val enabled: Boolean = createdActors || terminatedActors + } + + protected val defaultConfig: Config = ActorSystemModuleConfig(true, true) + + protected def extractFromConfig(config: TypesafeConfig): Config = { + val createdActors = config.tryValue("created-actors")(_.getBoolean).getOrElse(defaultConfig.createdActors) + + val terminatedActors = config.tryValue("terminated-actors")(_.getBoolean).getOrElse(defaultConfig.createdActors) + + ActorSystemModuleConfig(createdActors, terminatedActors) + } +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala new file mode 100644 index 000000000..bbb20e783 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala @@ -0,0 +1,88 @@ +package io.scalac.mesmer.core.module +import com.typesafe.config.{ Config => TypesafeConfig } + +sealed trait AkkaClusterMetricsModule extends MetricsModule { + this: Module => + override type Metrics[T] <: AkkaClusterMetricsDef[T] + + trait AkkaClusterMetricsDef[T] { + def shardPerRegions: T + def entityPerRegion: T + def shardRegionsOnNode: T + def entitiesOnNode: T + def reachableNodes: T + def unreachableNodes: T + def nodeDown: T + } +} + +object AkkaClusterModule extends MesmerModule with AkkaClusterMetricsModule { + + val name: String = "akka-cluster" + + final case class AkkaClusterModuleMetrics( + shardPerRegions: Boolean, + entityPerRegion: Boolean, + shardRegionsOnNode: Boolean, + entitiesOnNode: Boolean, + reachableNodes: Boolean, + unreachableNodes: Boolean, + nodeDown: Boolean + ) extends AkkaClusterMetricsDef[Boolean] + with ModuleConfig { + lazy val enabled: Boolean = shardPerRegions || + entityPerRegion || + shardRegionsOnNode || + entitiesOnNode || + reachableNodes || + unreachableNodes || + nodeDown + } + + override type Metrics[T] = AkkaClusterMetricsDef[T] + + protected val defaultConfig: AkkaClusterModule.Result = + AkkaClusterModuleMetrics(true, true, true, true, true, true, true) + + protected def extractFromConfig(config: TypesafeConfig): AkkaClusterModule.Result = { + val shardsPerRegion = config + .tryValue("shards-per-region")(_.getBoolean) + .getOrElse(defaultConfig.shardPerRegions) + + val entitiesPerRegion = config + .tryValue("entities-per-region")(_.getBoolean) + .getOrElse(defaultConfig.entityPerRegion) + + val shardRegionsOnNode = config + .tryValue("shard-regions-on-node")(_.getBoolean) + .getOrElse(defaultConfig.shardRegionsOnNode) + + val entitiesOnNode = config + .tryValue("entities-on-node")(_.getBoolean) + .getOrElse(defaultConfig.entitiesOnNode) + + val reachableNodes = config + .tryValue("reachable-nodes")(_.getBoolean) + .getOrElse(defaultConfig.reachableNodes) + + val unreachableNodes = config + .tryValue("unreachable-nodes")(_.getBoolean) + .getOrElse(defaultConfig.unreachableNodes) + + val nodesDown = config + .tryValue("node-down")(_.getBoolean) + .getOrElse(defaultConfig.nodeDown) + + AkkaClusterModuleMetrics( + shardPerRegions = shardsPerRegion, + entityPerRegion = entitiesPerRegion, + shardRegionsOnNode = shardRegionsOnNode, + entitiesOnNode = entitiesOnNode, + reachableNodes = reachableNodes, + unreachableNodes = unreachableNodes, + nodeDown = nodesDown + ) + } + + override type All[T] = Metrics[T] +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala index e2896eceb..db87e5f03 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -5,7 +5,7 @@ import com.typesafe.config.{ Config => TypesafeConfig } /** * Definition of AkkHttp request related metrics */ -sealed trait AkkaHttpRequestMetricsModule extends MetricModule { +sealed trait AkkaHttpRequestMetricsModule extends MetricsModule { this: Module => override type Metrics[T] <: AkkaHttpRequestMetricsDef[T] @@ -16,7 +16,7 @@ sealed trait AkkaHttpRequestMetricsModule extends MetricModule { } } -sealed trait AkkaHttpConnectionMetricsModule extends MetricModule { +sealed trait AkkaHttpConnectionMetricsModule extends MetricsModule { this: Module => override type Metrics[T] <: AkkaHttpConnectionsMetricsDef[T] diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala new file mode 100644 index 000000000..9240f8ff8 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala @@ -0,0 +1,62 @@ +package io.scalac.mesmer.core.module +import com.typesafe.config.{ Config => TypesafeConfig } + +sealed trait AkkaPersistenceMetricsModule extends MetricsModule { + this: Module => + + override type Metrics[T] <: AkkaPersistenceMetricsDef[T] + + trait AkkaPersistenceMetricsDef[T] { + def recoveryTime: T + def recoveryTotal: T + def persistentEvent: T + def persistentEventTotal: T + def snapshot: T + } +} + +object AkkaPersistenceModule extends MesmerModule with AkkaPersistenceMetricsModule { + override type Metrics[T] = AkkaPersistenceMetricsDef[T] + + val name: String = "akka-persistence" + + final case class AkkaPersistenceModuleConfig( + recoveryTime: Boolean, + recoveryTotal: Boolean, + persistentEvent: Boolean, + persistentEventTotal: Boolean, + snapshot: Boolean + ) extends AkkaPersistenceMetricsDef[Boolean] + with ModuleConfig { + + lazy val enabled: Boolean = recoveryTime || + recoveryTotal || + persistentEvent || + persistentEventTotal || + snapshot + } + + protected val defaultConfig: AkkaPersistenceModule.Result = AkkaPersistenceModuleConfig(true, true, true, true, true) + + protected def extractFromConfig(config: TypesafeConfig): Config = { + val recoveryTime = config + .tryValue("recovery-time")(_.getBoolean) + .getOrElse(defaultConfig.recoveryTime) + val recoveryTotal = config + .tryValue("recovery-total")(_.getBoolean) + .getOrElse(defaultConfig.recoveryTotal) + val persistentEvent = config + .tryValue("persistent-event")(_.getBoolean) + .getOrElse(defaultConfig.persistentEvent) + val persistentEventTotal = config + .tryValue("persistent-event-total")(_.getBoolean) + .getOrElse(defaultConfig.persistentEventTotal) + val snapshot = config + .tryValue("snapshot")(_.getBoolean) + .getOrElse(defaultConfig.snapshot) + + AkkaPersistenceModuleConfig(recoveryTime, recoveryTotal, persistentEvent, persistentEventTotal, snapshot) + } + + override type All[T] = Metrics[T] +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala new file mode 100644 index 000000000..6046c5858 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala @@ -0,0 +1,93 @@ +package io.scalac.mesmer.core.module +import com.typesafe.config.{Config => TypesafeConfig} + +sealed trait AkkaStreamMetrics extends MetricsModule { + this: Module => + + override type Metrics[T] <: StreamMetricsDef[T] + + trait StreamMetricsDef[T] { + def runningStreamsTotal: T + def streamActorsTotal: T + def streamProcessedMessages: T + } + +} + +sealed trait AkkaStreamOperatorMetrics extends MetricsModule { + this: Module => + + override type Metrics[T] <: StreamOperatorMetricsDef[T] + + trait StreamOperatorMetricsDef[T] { + def processedMessages: T + def operators: T + def demand: T + } + +} + +object AkkaStreamModule extends MesmerModule with AkkaStreamMetrics with AkkaStreamOperatorMetrics { + + val name: String = "akka-stream" + + override type Metrics[T] = StreamOperatorMetricsDef[T] with StreamMetricsDef[T] + override type All[T] = Metrics[T] + + final case class AkkaStreamModuleConfig( + runningStreamsTotal: Boolean, + streamActorsTotal: Boolean, + streamProcessedMessages: Boolean, + processedMessages: Boolean, + operators: Boolean, + demand: Boolean + ) extends StreamOperatorMetricsDef[Boolean] + with StreamMetricsDef[Boolean] + with ModuleConfig { + lazy val enabled: Boolean = runningStreamsTotal || + streamActorsTotal || + streamProcessedMessages || + processedMessages || + operators || + demand + } + + protected def defaultConfig: Config = AkkaStreamModuleConfig(true, true, true, true, true, true) + + protected def extractFromConfig(config: TypesafeConfig): Config = { + + val runningStreams = config + .tryValue("running-streams")(_.getBoolean) + .getOrElse(defaultConfig.runningStreamsTotal) + + val streamActors = config + .tryValue("stream-actors")(_.getBoolean) + .getOrElse(defaultConfig.streamActorsTotal) + + val streamProcessed = config + .tryValue("stream-processed")(_.getBoolean) + .getOrElse(defaultConfig.streamProcessedMessages) + + val operatorProcessed = config + .tryValue("operator-processed")(_.getBoolean) + .getOrElse(defaultConfig.processedMessages) + + val runningOperators = config + .tryValue("running-operators")(_.getBoolean) + .getOrElse(defaultConfig.operators) + + val demand = config + .tryValue("operator-demand")(_.getBoolean) + .getOrElse(defaultConfig.demand) + + AkkaStreamModuleConfig( + runningStreamsTotal = runningStreams, + streamActorsTotal = streamActors, + streamProcessedMessages = streamProcessed, + processedMessages = operatorProcessed, + operators = runningOperators, + demand = demand + ) + } + +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala index 8f85a6572..b6c7483ee 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -23,7 +23,7 @@ trait MesmerModule extends Module with MesmerConfigurationBase { val mesmerConfig = s"module.$name" } -trait MetricModule { +trait MetricsModule { this: Module => override type All[T] <: Metrics[T] type Metrics[T] diff --git a/extension/src/main/resources/reference.conf b/extension/src/main/resources/reference.conf index f99648a39..6fc40f8c9 100644 --- a/extension/src/main/resources/reference.conf +++ b/extension/src/main/resources/reference.conf @@ -84,6 +84,7 @@ io { stream-actors = "akka_streams_actors" stream-processed = "akka_streams_processed_messages" } + cluster-metrics { shards-per-region = "akka_cluster_shards_per_region" entities-per-region = "akka_cluster_entities_per_region" @@ -93,11 +94,13 @@ io { entities-on-node = "akka_cluster_unreachable_nodes" node-down = "akka_cluster_node_down_total" } + http-metrics { connections = "akka_http_connections" request-duration = "akka_http_request_duration" request-total = "akka_http_request_total" } + persistence-metrics { recovery-time = "akka_persistence_recovery_time" recovery-totall = "akka_persistence_recovery_total" diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorMetricsMonitor.scala index 5470adfaa..f8f68fba8 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorMetricsMonitor.scala @@ -2,6 +2,7 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaActorModule object ActorMetricsMonitor { final case class Labels(actorPath: ActorPath, node: Option[Node] = None, tags: Set[Tag] = Set.empty) @@ -9,23 +10,5 @@ object ActorMetricsMonitor { val serialize: RawLabels = node.serialize ++ actorPath.serialize ++ tags.flatMap(_.serialize) } - trait BoundMonitor extends Bound { - def mailboxSize: MetricObserver[Long, Labels] - // TODO Create an abstraction to aggregate multiple metrics (e.g: mailboxTimeAgg: MetricObserverAgg[Long]) - def mailboxTimeAvg: MetricObserver[Long, Labels] - def mailboxTimeMin: MetricObserver[Long, Labels] - def mailboxTimeMax: MetricObserver[Long, Labels] - def mailboxTimeSum: MetricObserver[Long, Labels] - def stashSize: MetricObserver[Long, Labels] - def receivedMessages: MetricObserver[Long, Labels] - def processedMessages: MetricObserver[Long, Labels] - def failedMessages: MetricObserver[Long, Labels] - def processingTimeAvg: MetricObserver[Long, Labels] - def processingTimeMin: MetricObserver[Long, Labels] - def processingTimeMax: MetricObserver[Long, Labels] - def processingTimeSum: MetricObserver[Long, Labels] - def sentMessages: MetricObserver[Long, Labels] - def droppedMessages: MetricObserver[Long, Labels] - - } + trait BoundMonitor extends Bound with AkkaActorModule.Metrics[MetricObserver[Long, Labels]] {} } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorSystemMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorSystemMonitor.scala index be987e356..7d4737cc6 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorSystemMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorSystemMonitor.scala @@ -4,7 +4,7 @@ import io.scalac.mesmer.core.LabelSerializable import io.scalac.mesmer.core.model._ object ActorSystemMonitor { - case class Labels(node: Option[Node]) extends LabelSerializable { + final case class Labels(node: Option[Node]) extends LabelSerializable { override def serialize: RawLabels = node.serialize } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala index a911b2008..597fc752a 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala @@ -19,26 +19,6 @@ trait UpDownCounter[-T] extends Counter[T] { def decValue(value: T): Unit } -object Metric { -// private case object NoopMetricRecorder extends MetricRecorder[Any] { -// def setValue(value: Any): Unit = () -// } -// -// private case object NoopCounter extends Counter[Any] { -// def incValue(value: Any): Unit = () -// } -// -// private case object NoopUpDownCounter extends UpDownCounter[Any] { -// def decValue(value: Any): Unit = () -// -// def incValue(value: Any): Unit = () -// } -// -// def noopRecorder[T]: MetricRecorder[T] = NoopMetricRecorder -// def noopCounter[T]: Counter[T] = NoopCounter -// def noopUpDownCounter[T]: UpDownCounter[T] = NoopUpDownCounter -} - final class SyncWith private ( private val amount: Int, private val updaters: List[ @@ -84,14 +64,20 @@ object SyncWith { } -trait MetricObserver[T, L] extends Metric[T] { +trait MetricObserver[-T, -L] extends Metric[T] { def setUpdater(updater: MetricObserver.Updater[T, L]): Unit } object MetricObserver { type Updater[T, L] = MetricObserver.Result[T, L] => Unit - trait Result[T, L] { + trait Result[-T, -L] { def observe(value: T, labels: L): Unit } + + case object NoopMetricObserver extends MetricObserver[Any, Any] { + def setUpdater(updater: Updater[Any, Any]): Unit = () + } + + def noop[T, L]: MetricObserver[T, L] = NoopMetricObserver } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala index cf03c008d..a177f5b7b 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala @@ -3,6 +3,7 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.core.module.AkkaActorModule import io.scalac.mesmer.extension.metric.{ ActorMetricsMonitor, MetricObserver, RegisterRoot } import io.scalac.mesmer.extension.upstream.OpenTelemetryActorMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ @@ -26,6 +27,7 @@ object OpenTelemetryActorMetricsMonitor { sentMessages: String, droppedMessages: String ) + object MetricNames extends MesmerConfiguration[MetricNames] { protected val mesmerConfig: String = "mesmer.metrics.actor-metrics" @@ -131,98 +133,106 @@ object OpenTelemetryActorMetricsMonitor { } - def apply(meter: Meter, config: Config): OpenTelemetryActorMetricsMonitor = - new OpenTelemetryActorMetricsMonitor(meter, MetricNames.fromConfig(config)) + def apply( + meter: Meter, + moduleConfig: AkkaActorModule.All[Boolean], + config: Config + ): OpenTelemetryActorMetricsMonitor = + new OpenTelemetryActorMetricsMonitor(meter, moduleConfig, MetricNames.fromConfig(config)) } -class OpenTelemetryActorMetricsMonitor(meter: Meter, metricNames: MetricNames) extends ActorMetricsMonitor { +class OpenTelemetryActorMetricsMonitor( + meter: Meter, + moduleConfig: AkkaActorModule.All[Boolean], + metricNames: MetricNames +) extends ActorMetricsMonitor { - private val mailboxSizeObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val mailboxSizeObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.mailboxSize) .setDescription("Tracks the size of an Actor's mailbox") ) - private val mailboxTimeAvgObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val mailboxTimeAvgObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.mailboxTimeAvg) .setDescription("Tracks the average time of an message in an Actor's mailbox") ) - private val mailboxTimeMinObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val mailboxTimeMinObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.mailboxTimeMin) .setDescription("Tracks the minimum time of an message in an Actor's mailbox") ) - private val mailboxTimeMaxObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val mailboxTimeMaxObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.mailboxTimeMax) .setDescription("Tracks the maximum time of an message in an Actor's mailbox") ) - private val mailboxTimeSumObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val mailboxTimeSumObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.mailboxTimeSum) .setDescription("Tracks the sum time of the messages in an Actor's mailbox") ) - private val stashSizeCounter = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val stashSizeCounter = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longSumObserverBuilder(metricNames.stashedMessages) .setDescription("Tracks stash operations on actors") ) - private val receivedMessagesSumObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val receivedMessagesSumObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longSumObserverBuilder(metricNames.receivedMessages) .setDescription("Tracks the sum of received messages in an Actor") ) - private val processedMessagesSumObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val processedMessagesSumObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longSumObserverBuilder(metricNames.processedMessages) .setDescription("Tracks the sum of processed messages in an Actor") ) - private val failedMessagesSumObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val failedMessagesSumObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longSumObserverBuilder(metricNames.failedMessages) .setDescription("Tracks the sum of failed messages in an Actor") ) - private val processingTimeAvgObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val processingTimeAvgObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.processingTimeAvg) .setDescription("Tracks the average processing time of an message in an Actor's receive handler") ) - private val processingTimeMinObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val processingTimeMinObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.processingTimeMin) .setDescription("Tracks the miminum processing time of an message in an Actor's receive handler") ) - private val processingTimeMaxObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val processingTimeMaxObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.processingTimeMax) .setDescription("Tracks the maximum processing time of an message in an Actor's receive handler") ) - private val processingTimeSumObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val processingTimeSumObserver = new LongMetricObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.processingTimeSum) .setDescription("Tracks the sum processing time of an message in an Actor's receive handler") ) - private val sentMessagesObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val sentMessagesObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longSumObserverBuilder(metricNames.sentMessages) .setDescription("Tracks the sum of sent messages in an Actor") ) - private val droppedMessagesObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( + private lazy val droppedMessagesObserver = new LongSumObserverBuilderAdapter[ActorMetricsMonitor.Labels]( meter .longSumObserverBuilder(metricNames.droppedMessages) .setDescription("Tracks the sum of dropped messages in an Actor") @@ -236,49 +246,53 @@ class OpenTelemetryActorMetricsMonitor(meter: Meter, metricNames: MetricNames) e with RegisterRoot with SynchronousInstrumentFactory { - val mailboxSize: MetricObserver[Long, ActorMetricsMonitor.Labels] = mailboxSizeObserver.createObserver(this) + val mailboxSize: MetricObserver[Long, ActorMetricsMonitor.Labels] = + if (moduleConfig.mailboxSize) mailboxSizeObserver.createObserver(this) else MetricObserver.noop val mailboxTimeAvg: MetricObserver[Long, ActorMetricsMonitor.Labels] = - mailboxTimeAvgObserver.createObserver(this) + if (moduleConfig.mailboxTimeAvg) mailboxTimeAvgObserver.createObserver(this) else MetricObserver.noop val mailboxTimeMin: MetricObserver[Long, ActorMetricsMonitor.Labels] = - mailboxTimeMinObserver.createObserver(this) + if (moduleConfig.mailboxTimeMin) mailboxTimeMinObserver.createObserver(this) else MetricObserver.noop val mailboxTimeMax: MetricObserver[Long, ActorMetricsMonitor.Labels] = - mailboxTimeMaxObserver.createObserver(this) + if (moduleConfig.mailboxTimeMax) mailboxTimeMaxObserver.createObserver(this) else MetricObserver.noop val mailboxTimeSum: MetricObserver[Long, ActorMetricsMonitor.Labels] = - mailboxTimeSumObserver.createObserver(this) + if (moduleConfig.mailboxTimeSum) mailboxTimeSumObserver.createObserver(this) else MetricObserver.noop val stashSize: MetricObserver[Long, ActorMetricsMonitor.Labels] = - stashSizeCounter.createObserver(this) + if (moduleConfig.stashSize) stashSizeCounter.createObserver(this) else MetricObserver.noop val receivedMessages: MetricObserver[Long, ActorMetricsMonitor.Labels] = - receivedMessagesSumObserver.createObserver(this) + if (moduleConfig.receivedMessages) receivedMessagesSumObserver.createObserver(this) else MetricObserver.noop val processedMessages: MetricObserver[Long, ActorMetricsMonitor.Labels] = - processedMessagesSumObserver.createObserver(this) + if (moduleConfig.processedMessages) processedMessagesSumObserver.createObserver(this) else MetricObserver.noop val failedMessages: MetricObserver[Long, ActorMetricsMonitor.Labels] = - failedMessagesSumObserver.createObserver(this) + if (moduleConfig.failedMessages) failedMessagesSumObserver.createObserver(this) else MetricObserver.noop val processingTimeAvg: MetricObserver[Long, ActorMetricsMonitor.Labels] = - processingTimeAvgObserver.createObserver(this) + if (moduleConfig.processingTimeAvg) processingTimeAvgObserver.createObserver(this) else MetricObserver.noop val processingTimeMin: MetricObserver[Long, ActorMetricsMonitor.Labels] = - processingTimeMinObserver.createObserver(this) + if (moduleConfig.processingTimeMin) processingTimeMinObserver.createObserver(this) else MetricObserver.noop val processingTimeMax: MetricObserver[Long, ActorMetricsMonitor.Labels] = - processingTimeMaxObserver.createObserver(this) + if (moduleConfig.processingTimeMax) processingTimeMaxObserver.createObserver(this) else MetricObserver.noop val processingTimeSum: MetricObserver[Long, ActorMetricsMonitor.Labels] = - processingTimeSumObserver.createObserver(this) + if (moduleConfig.processingTimeSum) processingTimeSumObserver.createObserver(this) else MetricObserver.noop val sentMessages: MetricObserver[Long, ActorMetricsMonitor.Labels] = - sentMessagesObserver.createObserver(this) + if (moduleConfig.sentMessages) sentMessagesObserver.createObserver(this) else MetricObserver.noop - val droppedMessages: MetricObserver[Long, ActorMetricsMonitor.Labels] = droppedMessagesObserver - .createObserver(this) + val droppedMessages: MetricObserver[Long, ActorMetricsMonitor.Labels] = + if (moduleConfig.droppedMessages) + droppedMessagesObserver + .createObserver(this) + else MetricObserver.noop } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala index 603c56544..1a05fae01 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala @@ -4,9 +4,9 @@ import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter import io.scalac.mesmer.core.config.MesmerConfiguration import io.scalac.mesmer.extension.metric.ActorSystemMonitor.BoundMonitor -import io.scalac.mesmer.extension.metric.{ ActorSystemMonitor, RegisterRoot } +import io.scalac.mesmer.extension.metric.{ActorSystemMonitor, RegisterRoot} import io.scalac.mesmer.extension.upstream.OpenTelemetryActorSystemMonitor.MetricNames -import io.scalac.mesmer.extension.upstream.opentelemetry.{ SynchronousInstrumentFactory, WrappedCounter } +import io.scalac.mesmer.extension.upstream.opentelemetry.{SynchronousInstrumentFactory, WrappedCounter} object OpenTelemetryActorSystemMonitor { @@ -22,10 +22,9 @@ object OpenTelemetryActorSystemMonitor { protected val mesmerConfig: String = "metrics.actor-system-metrics" protected def extractFromConfig(config: Config): MetricNames = { - lazy val defaultCached = defaultConfig - val createdActors = config.tryValue("created-actors")(_.getString).getOrElse(defaultCached.createdActors) + val createdActors = config.tryValue("created-actors")(_.getString).getOrElse(defaultConfig.createdActors) - val terminatedActors = config.tryValue("terminated-actors")(_.getString).getOrElse(defaultCached.createdActors) + val terminatedActors = config.tryValue("terminated-actors")(_.getString).getOrElse(defaultConfig.createdActors) MetricNames(createdActors, terminatedActors) } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala index 91a088a4b..401b8c32d 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala @@ -76,7 +76,7 @@ final class OpenTelemetryHttpMetricsMonitor( if (moduleConfig.requestTime) metricRecorder(requestTimeRequest, otLabels).register(this) else noopMetricRecorder[Long] - val requestCounter: WrappedCounter = + val requestCounter = if (moduleConfig.requestCounter) counter(requestTotalCounter, otLabels).register(this) else noopCounter[Long] } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala index 9c6400ebe..19ed32308 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala @@ -8,6 +8,8 @@ import io.scalac.mesmer.extension.upstream.OpenTelemetryPersistenceMetricsMonito import io.scalac.mesmer.extension.upstream.opentelemetry._ object OpenTelemetryPersistenceMetricsMonitor { + + //TODO remove DRY final case class MetricNames( recoveryTime: String, recoveryTotal: String, @@ -54,7 +56,7 @@ object OpenTelemetryPersistenceMetricsMonitor { new OpenTelemetryPersistenceMetricsMonitor(meter, MetricNames.fromConfig(config)) } -class OpenTelemetryPersistenceMetricsMonitor(meter: Meter, metricNames: MetricNames) extends PersistenceMetricsMonitor { +final class OpenTelemetryPersistenceMetricsMonitor(meter: Meter, metricNames: MetricNames) extends PersistenceMetricsMonitor { import PersistenceMetricsMonitor._ private val recoveryTimeRecorder = meter From 68dc98345b86759641ef8f852fcf688c7909d9bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Wed, 23 Jun 2021 19:57:25 +0200 Subject: [PATCH 07/31] Add all modules --- .../mesmer/agent/akka/actor/ProxiedQueue.java | 1 - .../stream/ActorGraphInterpreterAdvice.java | 2 +- .../akka/stream/GraphStageIslandAdvice.java | 2 +- .../scala/io/scalac/mesmer/agent/Agent.scala | 15 +-- .../scala/io/scalac/mesmer/agent/Boot.scala | 6 +- .../agent/akka/actor/AkkaActorAgent.scala | 36 +++--- ...cala => AkkaMailboxInstrumentations.scala} | 65 +++++----- .../ActorCellConstructorInstrumentation.scala | 8 +- ...torCellReceiveMessageInstrumentation.scala | 5 +- ...CellSendMessageMetricInstrumentation.scala | 2 +- .../ActorUnhandledInstrumentation.scala | 6 +- .../ClassicActorContextProviderOps.scala | 6 +- .../actor/{ => impl}/ClassicActorOps.scala | 5 +- .../ClassicStashInstrumentationStash.scala | 14 +-- .../actor/{ => impl}/EnvelopeDecorator.scala | 6 +- .../akka/actor/{ => impl}/EnvelopeOps.scala | 2 +- .../LocalActorRefProviderAdvice.scala | 8 +- .../MailboxDequeueInstrumentation.scala | 5 +- .../akka/actor/{ => impl}/MailboxOps.scala | 2 +- .../actor/{ => impl}/StashBufferAdvice.scala | 6 +- ...andleReceiveExceptionInstrumentation.scala | 6 +- .../agent/akka/http/AkkaHttpAgent.scala | 6 +- .../persistence/AkkaPersistenceAgent.scala | 76 ++++++++---- .../JournalInteractionsInterceptor.scala | 7 +- .../PersistingEventSuccessInterceptor.scala | 7 +- .../RecoveryCompletedInterceptor.scala | 10 +- .../RecoveryStartedInterceptor.scala | 10 +- .../StoringSnapshotInterceptor.scala | 14 +-- .../agent/akka/stream/AkkaStreamAgent.scala | 116 +++++++++++++----- .../ActorGraphInterpreterDecorator.scala | 20 +-- ...orGraphInterpreterProcessEventAdvice.scala | 8 +- .../stream/{ => impl}/AkkaMirrorTypes.scala | 3 +- .../stream/{ => impl}/ConnectionOps.scala | 3 +- .../GraphInterpreterPushAdvice.scala | 8 +- .../stream/{ => impl}/GraphLogicOps.scala | 4 +- .../{ => impl}/GraphStageIslandOps.scala | 6 +- ...PhasedFusingActorMaterializerAdvice.scala} | 13 +- .../i13n/AgentInstrumentationFactory.scala | 6 +- .../util/i13n/InstrumentModuleFactory.scala | 43 +++++-- .../mesmer/agent/util/i13n/package.scala | 58 ++++++--- .../io/scalac/mesmer/agent/AgentTest.scala | 10 +- .../mesmer/agent/utils/InstallAgent.scala | 20 +-- .../mesmer/core/module/AkkaActorModule.scala | 2 +- .../core/module/AkkaActorSystemModule.scala | 2 +- .../core/module/AkkaClusterModule.scala | 2 +- .../core/module/AkkaPersistenceModule.scala | 2 +- .../mesmer/core/module/AkkaStreamModule.scala | 2 +- .../io/scalac/mesmer/core/module/Module.scala | 2 + .../mesmer/extension/AkkaMonitoring.scala | 21 ++-- .../mesmer/extension/metric/Metric.scala | 4 +- 50 files changed, 393 insertions(+), 300 deletions(-) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{AkkaMailboxAgent.scala => AkkaMailboxInstrumentations.scala} (67%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/ActorCellConstructorInstrumentation.scala (64%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/ActorCellReceiveMessageInstrumentation.scala (84%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/ActorCellSendMessageMetricInstrumentation.scala (94%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/ActorUnhandledInstrumentation.scala (67%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/ClassicActorContextProviderOps.scala (92%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/ClassicActorOps.scala (57%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/ClassicStashInstrumentationStash.scala (89%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/EnvelopeDecorator.scala (77%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/EnvelopeOps.scala (79%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/LocalActorRefProviderAdvice.scala (72%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/MailboxDequeueInstrumentation.scala (84%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/MailboxOps.scala (85%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/StashBufferAdvice.scala (90%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/{ => impl}/SupervisorHandleReceiveExceptionInstrumentation.scala (79%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/{ => impl}/JournalInteractionsInterceptor.scala (89%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/{ => impl}/PersistingEventSuccessInterceptor.scala (89%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/{ => impl}/RecoveryCompletedInterceptor.scala (92%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/{ => impl}/RecoveryStartedInterceptor.scala (92%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/{ => impl}/StoringSnapshotInterceptor.scala (88%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/{ => impl}/ActorGraphInterpreterDecorator.scala (88%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/{ => impl}/ActorGraphInterpreterProcessEventAdvice.scala (86%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/{ => impl}/AkkaMirrorTypes.scala (82%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/{ => impl}/ConnectionOps.scala (96%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/{ => impl}/GraphInterpreterPushAdvice.scala (69%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/{ => impl}/GraphLogicOps.scala (91%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/{ => impl}/GraphStageIslandOps.scala (80%) rename agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/{PhasedFusingActorMeterializerAdvice.scala => impl/PhasedFusingActorMaterializerAdvice.scala} (54%) diff --git a/agent/src/main/java/io/scalac/mesmer/agent/akka/actor/ProxiedQueue.java b/agent/src/main/java/io/scalac/mesmer/agent/akka/actor/ProxiedQueue.java index 101afe2a8..f3bcf65a3 100644 --- a/agent/src/main/java/io/scalac/mesmer/agent/akka/actor/ProxiedQueue.java +++ b/agent/src/main/java/io/scalac/mesmer/agent/akka/actor/ProxiedQueue.java @@ -1,6 +1,5 @@ package io.scalac.mesmer.agent.akka.actor; -import akka.dispatch.BoundedQueueBasedMessageQueue; import akka.dispatch.Envelope; import java.util.concurrent.BlockingQueue; diff --git a/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterAdvice.java b/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterAdvice.java index cbe6a2593..63140fb39 100644 --- a/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterAdvice.java +++ b/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterAdvice.java @@ -1,7 +1,7 @@ package akka; import akka.actor.Actor; -import io.scalac.mesmer.agent.akka.stream.ActorGraphInterpreterDecorator; +import io.scalac.mesmer.agent.akka.stream.impl.ActorGraphInterpreterDecorator; import net.bytebuddy.asm.Advice; import scala.PartialFunction; import scala.runtime.BoxedUnit; diff --git a/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/GraphStageIslandAdvice.java b/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/GraphStageIslandAdvice.java index 2f335e8fa..4f61959b1 100644 --- a/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/GraphStageIslandAdvice.java +++ b/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/GraphStageIslandAdvice.java @@ -1,7 +1,7 @@ package akka.stream; import akka.stream.impl.StreamLayout; -import io.scalac.mesmer.agent.akka.stream.GraphStageIslandOps; +import io.scalac.mesmer.agent.akka.stream.impl.GraphStageIslandOps; import net.bytebuddy.asm.Advice; import java.util.ArrayList; diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala index 5703bb480..c48ee911e 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala @@ -16,7 +16,7 @@ object Agent { val empty: Agent = new Agent(Set.empty) - class LoadingResult(val fqns: Seq[String]) { + class LoadingResult(val fqns: Set[String]) { import LoadingResult.{ logger => loadingLogger } def eagerLoad(): Unit = fqns.foreach { className => @@ -39,30 +39,31 @@ object Agent { object LoadingResult { private val logger = LoggerFactory.getLogger(classOf[LoadingResult]) - def apply(fqns: Seq[String]): LoadingResult = new LoadingResult(fqns) + def apply(fqns: Seq[String]): LoadingResult = new LoadingResult(fqns.toSet) def apply(fqn: String, fqns: String*): LoadingResult = apply(fqn +: fqns) - def empty: LoadingResult = new LoadingResult(Seq.empty) + def empty: LoadingResult = new LoadingResult(Set.empty) } } object AgentInstrumentation { - def apply(name: String, modules: SupportedModules)( + def apply(name: String, modules: SupportedModules, tags: Set[String])( installation: (AgentBuilder, Instrumentation, Modules) => LoadingResult ): AgentInstrumentation = - new AgentInstrumentation(name, modules) { + new AgentInstrumentation(name, modules, tags) { def apply(builder: AgentBuilder, instrumentation: Instrumentation, modules: Modules): LoadingResult = installation(builder, instrumentation, modules) } } +//TODO add tests sealed abstract case class AgentInstrumentation( name: String, instrumentingModules: SupportedModules, - fqcn: Boolean = false + tags: Set[String] ) extends ((AgentBuilder, Instrumentation, Modules) => LoadingResult) with Equals { @@ -72,7 +73,7 @@ sealed abstract case class AgentInstrumentation( override def equals(obj: Any): Boolean = obj match { case that: AgentInstrumentation if that.canEqual(this) => - that.name == this.name // instrumentations should be equal when name is the same + tags == that.tags && name == that.name case _ => false } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala index 9d96e9de5..fb37f4547 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala @@ -1,7 +1,7 @@ package io.scalac.mesmer.agent import com.typesafe.config.ConfigFactory -import io.scalac.mesmer.agent.akka.actor.{ AkkaActorAgent, AkkaMailboxAgent } +import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent @@ -28,9 +28,9 @@ object Boot { .`with`(AgentBuilder.InstallationListener.StreamWriting.toSystemOut) val allInstrumentations = - AkkaPersistenceAgent.agent ++ AkkaStreamAgent.agent ++ AkkaHttpAgent.agent( + AkkaPersistenceAgent.agent(config) ++ AkkaStreamAgent.agent(config) ++ AkkaHttpAgent.agent( config - ) ++ AkkaActorAgent.agent(config) ++ AkkaMailboxAgent.agent + ) ++ AkkaActorAgent.agent(config) val moduleInfo = ModuleInfo.extractModulesInformation(Thread.currentThread().getContextClassLoader) allInstrumentations diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala index d3a5457c7..1a3500b90 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala @@ -1,5 +1,6 @@ package io.scalac.mesmer.agent.akka.actor +import io.scalac.mesmer.agent.akka.actor.impl._ import io.scalac.mesmer.agent.util.i13n._ import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } import io.scalac.mesmer.core.model._ @@ -8,7 +9,10 @@ import io.scalac.mesmer.core.support.ModulesSupport import io.scalac.mesmer.core.util.Timestamp import io.scalac.mesmer.extension.actor.{ ActorCellDecorator, ActorCellMetrics } -object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with AkkaActorModule.All[Agent] { +object AkkaActorAgent + extends InstrumentModuleFactory(AkkaActorModule) + with AkkaActorModule.All[Agent] + with AkkaMailboxInstrumentations { def agent(config: AkkaActorModule.AkkaActorMetricsDef[Boolean]): Agent = Agent.empty ++ @@ -56,7 +60,7 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with lazy val sentMessages: Agent = sharedInstrumentation ++ mailboxTimeSendMessageIncInstrumentation - lazy val droppedMessages: Agent = sharedInstrumentation + lazy val droppedMessages: Agent = sharedInstrumentation ++ boundedQueueAgent protected final val supportedModules: SupportedModules = SupportedModules(ModulesSupport.akkaActorModule, ModulesSupport.akkaActor) @@ -66,13 +70,15 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with */ private val classicStashInstrumentationAgent = { + val instrumentationPrefix = "classic_stash_instrumentation" + val stashLogic = - instrument("akka.actor.StashSupport") + instrument("akka.actor.StashSupport".fqcnWithTags(s"${instrumentationPrefix}_stash_prepend_operation")) .visit(ClassicStashInstrumentationStash, "stash") .visit(ClassicStashInstrumentationPrepend, "prepend") val stashConstructor = - instrument(hierarchy("akka.actor.StashSupport").concreteOnly) + instrument(hierarchy("akka.actor.StashSupport".fqcnWithTags("stash_support_constructor")).concreteOnly) .visit(StashConstructorAdvice, constructor) Agent(stashLogic, stashConstructor) @@ -80,11 +86,13 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with private val mailboxInstrumentation = { + val mailboxTag = "mailbox_time" + /** * Instrumentation that enrich [[ akka.dispatch.Envelope ]] with additional timestamp field */ val mailboxTimeTimestampInstrumentation = - instrument("akka.dispatch.Envelope") + instrument("akka.dispatch.Envelope".fqcn) .defineField[Timestamp](EnvelopeDecorator.TimestampVarName) // .defineField[Boolean](EnvelopeDecorator.TimestampVarName) @@ -92,7 +100,7 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with * Instrumentation that sets envelope timestamp to current time on each dispatch */ val mailboxTimeSendMessageInstrumentation = - instrument("akka.actor.dungeon.Dispatch".withId("set envelope timestamp")) + instrument("akka.actor.dungeon.Dispatch".fqcnWithTags(mailboxTag)) .visit( ActorCellSendMessageTimestampInstrumentation, method("sendMessage").takesArgument(0, "akka.dispatch.Envelope") @@ -102,7 +110,7 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with * Instrumentation that computes time in mailbox */ val mailboxTimeDequeueInstrumentation = - instrument("akka.dispatch.Mailbox") + instrument("akka.dispatch.Mailbox".fqcnWithTags(mailboxTag)) .visit(MailboxDequeueInstrumentation, "dequeue") Agent(mailboxTimeTimestampInstrumentation, mailboxTimeSendMessageInstrumentation, mailboxTimeDequeueInstrumentation) @@ -113,7 +121,7 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with * Instrumentation that increase send messages on each dispatch */ private val mailboxTimeSendMessageIncInstrumentation = - instrument("akka.actor.dungeon.Dispatch".withId("sent message inc")) + instrument("akka.actor.dungeon.Dispatch".fqcnWithTags("send_message")) .visit( ActorCellSendMessageMetricInstrumentation, method("sendMessage").takesArgument(0, "akka.dispatch.Envelope") @@ -121,9 +129,9 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with /** * Instrumentation that add [[ ActorCellMetrics ]] field to [[ akka.actor.ActorCell ]] - * and initialize it in {@code init} method + * and initialize it in `init` method */ - private val actorCellInstrumentation = instrument("akka.actor.ActorCell") + private val actorCellInstrumentation = instrument("akka.actor.ActorCell".fqcnWithTags("metrics")) .defineField[ActorCellMetrics](ActorCellDecorator.fieldName) .visit(ActorCellConstructorInstrumentation, "init") .visit(ActorCellReceiveMessageInstrumentation, "receiveMessage") @@ -139,7 +147,7 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with * Instrumentation for unhandled metric */ private val receiveUnhandledInstrumentation = - instrument("akka.actor.Actor") + instrument("akka.actor.Actor".fqcnWithTags("unhandled")) .visit(ActorUnhandledInstrumentation, "unhandled") /** @@ -147,7 +155,7 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with */ private val abstractSupervisionInstrumentation = instrument( - hierarchy("akka.actor.typed.internal.AbstractSupervisor") + hierarchy("akka.actor.typed.internal.AbstractSupervisor".fqcnWithTags("supervision")) .overrides("handleReceiveException") ).visit(SupervisorHandleReceiveExceptionInstrumentation, "handleReceiveException") @@ -155,7 +163,7 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with * Instrumentation for [[ akka.actor.typed.internal.StashBufferImpl ]] - collection used for typed stash implementation */ private val stashBufferImplementation = - instrument(hierarchy("akka.actor.typed.internal.StashBufferImpl")) + instrument(hierarchy("akka.actor.typed.internal.StashBufferImpl".fqcnWithTags("typed_stash_buffer"))) .visit(StashBufferAdvice, "stash") /** @@ -163,7 +171,7 @@ object AkkaActorAgent extends InstrumentModuleFactoryTest(AkkaActorModule) with * for any other instrumentation here to work. */ private val localActorRefProviderInstrumentation: AgentInstrumentation = - instrument("akka.actor.LocalActorRefProvider") + instrument("akka.actor.LocalActorRefProvider".fqcnWithTags("create")) .visit(LocalActorRefProviderAdvice, "actorOf") } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala similarity index 67% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxAgent.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala index a302eb6ef..c9a9f577a 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala @@ -1,34 +1,22 @@ package io.scalac.mesmer.agent.akka.actor -import java.util.concurrent.BlockingQueue -import java.util.concurrent.Callable -import java.util.concurrent.LinkedBlockingQueue - -import akka.AkkaMirror.ActorRefWithCell -import akka.AkkaMirror.Cell +import akka.AkkaMirror.{ActorRefWithCell, Cell} import akka.dispatch._ import akka.util.BoundedBlockingQueue -import akka.{ actor => classic } +import akka.{actor => classic} +import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.agent.{Agent, AgentInstrumentation} +import io.scalac.mesmer.core.util.ReflectionFieldUtils +import io.scalac.mesmer.extension.actor.ActorCellDecorator import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription -import net.bytebuddy.implementation.FieldAccessor -import net.bytebuddy.implementation.MethodDelegation -import net.bytebuddy.implementation.bind.annotation.SuperCall -import net.bytebuddy.implementation.bind.annotation.This +import net.bytebuddy.implementation.bind.annotation.{SuperCall, This} +import net.bytebuddy.implementation.{FieldAccessor, MethodDelegation} import net.bytebuddy.matcher.ElementMatchers -import scala.reflect.ClassTag -import scala.reflect.classTag +import java.util.concurrent.{BlockingQueue, Callable, LinkedBlockingQueue} +import scala.reflect.{ClassTag, classTag} -import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory -import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.model.SupportedModules -import io.scalac.mesmer.core.support.ModulesSupport -import io.scalac.mesmer.core.util.ReflectionFieldUtils -import io.scalac.mesmer.extension.actor.ActorCellDecorator - -class BoundedNodeMessageQueueAdvice object BoundedNodeMessageQueueAdvice { @Advice.OnMethodExit @@ -63,10 +51,9 @@ object LastEnqueueResult { } abstract class LastEnqueueResult[T: ClassTag] { - val lastResultFieldName = "_lastEnqueueResult" lazy val (lastResultGetter, lastResultSetter) = - ReflectionFieldUtils.getHandlers(classTag[T].runtimeClass, lastResultFieldName) + ReflectionFieldUtils.getHandlers(classTag[T].runtimeClass, LastEnqueueResult.lastResultFieldName) def setResult(queue: Object, result: Boolean): Unit = lastResultSetter.invoke(queue, result) @@ -89,20 +76,26 @@ class AbstractBoundedNodeQueueAdvice(lastEnqueueResult: => LastEnqueueResult[_]) } -object AkkaMailboxAgent extends InstrumentModuleFactory { - protected val supportedModules: SupportedModules = - SupportedModules(ModulesSupport.akkaActorModule, ModulesSupport.akkaActor) +private[actor] trait AkkaMailboxInstrumentations { + this: InstrumentModuleFactory[_] => - private val boundedQueueBasesMailbox: TypeInstrumentation = + /** + * Instrumentation that add boolean field that will hold if last enqueue was successful or not + */ + private val boundedQueueBasesMailbox: AgentInstrumentation = instrument( - "akka.dispatch.AbstractBoundedNodeQueue" + "akka.dispatch.AbstractBoundedNodeQueue".fqcn ) .defineField[Boolean](LastEnqueueResult.lastResultFieldName) .intercept( "add", MethodDelegation.to(new AbstractBoundedNodeQueueAdvice(AbstractBoundedQueueDecorator)) ) - private val boundedQueueBasedMailboxes: TypeInstrumentation = instrument( + + /** + * Instrumentation that add proxy to mailbox queue + */ + private val boundedQueueBasedMailboxes: AgentInstrumentation = instrument( `type`( "akka.dispatch.BoundedQueueBasedMessageQueue".fqcn, ElementMatchers @@ -122,13 +115,15 @@ object AkkaMailboxAgent extends InstrumentModuleFactory { .visit[ProxiedQueue](constructor) .intercept(ElementMatchers.named("queue"), FieldAccessor.ofField(ProxiedQueue.queueFieldName)) - val boundedMessageQueueSemantics: TypeInstrumentation = instrument( - hierarchy("akka.dispatch.BoundedMessageQueueSemantics") + /** + * Instrumentation that increase dropped messages if enqueue was a failure and bounded queue is in use + */ + private val boundedMessageQueueSemantics: AgentInstrumentation = instrument( + hierarchy("akka.dispatch.BoundedMessageQueueSemantics".fqcn) .and(ElementMatchers.not[TypeDescription](ElementMatchers.isAbstract[TypeDescription])) ) - .visit[BoundedNodeMessageQueueAdvice]("enqueue") + .visit(BoundedNodeMessageQueueAdvice, "enqueue") - def agent: Agent = - Agent(boundedQueueBasesMailbox, boundedQueueBasedMailboxes, boundedMessageQueueSemantics) + protected val boundedQueueAgent = Agent(boundedQueueBasesMailbox, boundedQueueBasedMailboxes, boundedMessageQueueSemantics) } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellConstructorInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala similarity index 64% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellConstructorInstrumentation.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala index d3c91ef5a..c498f826c 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellConstructorInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala @@ -1,11 +1,8 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl import akka.dispatch.MailboxType -import net.bytebuddy.asm.Advice.Argument -import net.bytebuddy.asm.Advice.OnMethodExit -import net.bytebuddy.asm.Advice.This - import io.scalac.mesmer.extension.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit, This } object ActorCellConstructorInstrumentation { @@ -13,4 +10,3 @@ object ActorCellConstructorInstrumentation { def onEnter(@This actorCell: Object, @Argument(1) mailboxType: MailboxType): Unit = ActorCellDecorator.initialize(actorCell, mailboxType) } - diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellReceiveMessageInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala similarity index 84% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellReceiveMessageInstrumentation.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala index 81dbaf5c0..2547ed3ce 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellReceiveMessageInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala @@ -1,8 +1,7 @@ -package io.scalac.mesmer.agent.akka.actor - -import net.bytebuddy.asm.Advice._ +package io.scalac.mesmer.agent.akka.actor.impl import io.scalac.mesmer.extension.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice.{ OnMethodEnter, OnMethodExit, This, Thrown } object ActorCellReceiveMessageInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageMetricInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala similarity index 94% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageMetricInstrumentation.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala index 27f746b82..90d99c550 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorCellSendMessageMetricInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala @@ -1,4 +1,4 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.Actor import io.scalac.mesmer.core.util.ActorRefOps diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorUnhandledInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala similarity index 67% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorUnhandledInstrumentation.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala index d9c884d68..8d36c918c 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ActorUnhandledInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala @@ -1,9 +1,7 @@ -package io.scalac.mesmer.agent.akka.actor - -import net.bytebuddy.asm.Advice.OnMethodExit -import net.bytebuddy.asm.Advice.This +package io.scalac.mesmer.agent.akka.actor.impl import io.scalac.mesmer.extension.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice.{OnMethodExit, This} object ActorUnhandledInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicActorContextProviderOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorContextProviderOps.scala similarity index 92% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicActorContextProviderOps.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorContextProviderOps.scala index 26d4abcc0..862a18038 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicActorContextProviderOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorContextProviderOps.scala @@ -1,10 +1,10 @@ -package io.scalac.mesmer.agent.akka.actor - -import java.lang.invoke.MethodHandles +package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.ActorContext import akka.actor.typed.TypedActorContext +import java.lang.invoke.MethodHandles + object ClassicActorContextProviderOps { private lazy val classicActorContextGetter = { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicActorOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorOps.scala similarity index 57% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicActorOps.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorOps.scala index 81b12d2cb..60bcf01e5 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicActorOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorOps.scala @@ -1,7 +1,6 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl -import akka.actor.Actor -import akka.actor.ActorContext +import akka.actor.{ Actor, ActorContext } object ClassicActorOps { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicStashInstrumentationStash.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala similarity index 89% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicStashInstrumentationStash.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala index 717c9fdeb..31d9a4121 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/ClassicStashInstrumentationStash.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala @@ -1,16 +1,12 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl + +import akka.actor.{Actor, ActorContext} +import io.scalac.mesmer.extension.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice.{Argument, OnMethodExit, This} import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType.methodType -import akka.actor.Actor -import akka.actor.ActorContext -import net.bytebuddy.asm.Advice.Argument -import net.bytebuddy.asm.Advice.OnMethodExit -import net.bytebuddy.asm.Advice.This - -import io.scalac.mesmer.extension.actor.ActorCellDecorator - object StashConstructorAdvice { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/EnvelopeDecorator.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeDecorator.scala similarity index 77% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/EnvelopeDecorator.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeDecorator.scala index 2273a8405..4fc830a56 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/EnvelopeDecorator.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeDecorator.scala @@ -1,9 +1,7 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl import akka.dispatch.Envelope - -import io.scalac.mesmer.core.util.ReflectionFieldUtils -import io.scalac.mesmer.core.util.Timestamp +import io.scalac.mesmer.core.util.{ ReflectionFieldUtils, Timestamp } object EnvelopeDecorator { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/EnvelopeOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeOps.scala similarity index 79% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/EnvelopeOps.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeOps.scala index 103f77e48..3f7fbe407 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/EnvelopeOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeOps.scala @@ -1,4 +1,4 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.ActorRef import akka.dispatch.Envelope diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/LocalActorRefProviderAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/LocalActorRefProviderAdvice.scala similarity index 72% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/LocalActorRefProviderAdvice.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/LocalActorRefProviderAdvice.scala index eb71b93a9..c56607fc5 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/LocalActorRefProviderAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/LocalActorRefProviderAdvice.scala @@ -1,12 +1,12 @@ -package io.scalac.mesmer.agent.akka.actor -import akka.actor.ActorRef -import akka.actor.ActorSystem +package io.scalac.mesmer.agent.akka.actor.impl + +import akka.actor.{ ActorRef, ActorSystem } import akka.actor.typed.scaladsl.adapter._ -import net.bytebuddy.asm.Advice._ import io.scalac.mesmer.core.event.ActorEvent.ActorCreated import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.model.ActorRefTags +import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit, Return } object LocalActorRefProviderAdvice { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxDequeueInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala similarity index 84% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxDequeueInstrumentation.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala index 02cf4270c..8bddd1c8f 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxDequeueInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala @@ -1,9 +1,8 @@ -package io.scalac.mesmer.agent.akka.actor - -import net.bytebuddy.asm.Advice._ +package io.scalac.mesmer.agent.akka.actor.impl import io.scalac.mesmer.core.util.Interval import io.scalac.mesmer.extension.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice.{ OnMethodExit, Return, This } object MailboxDequeueInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxOps.scala similarity index 85% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxOps.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxOps.scala index 05b25ea40..6be577810 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/MailboxOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxOps.scala @@ -1,4 +1,4 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl import io.scalac.mesmer.core.util.ReflectionFieldUtils diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/StashBufferAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala similarity index 90% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/StashBufferAdvice.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala index bad4c3946..9ecf12eed 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/StashBufferAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala @@ -1,9 +1,9 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl + import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.adapter._ -import net.bytebuddy.asm.Advice - import io.scalac.mesmer.extension.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice object StashBufferAdvice { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/SupervisorHandleReceiveExceptionInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala similarity index 79% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/SupervisorHandleReceiveExceptionInstrumentation.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala index b1c0b038b..a76953c9c 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/SupervisorHandleReceiveExceptionInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala @@ -1,10 +1,8 @@ -package io.scalac.mesmer.agent.akka.actor +package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.typed.TypedActorContext -import net.bytebuddy.asm.Advice.Argument -import net.bytebuddy.asm.Advice.OnMethodExit - import io.scalac.mesmer.extension.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit } object SupervisorHandleReceiveExceptionInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala index 261749955..227813b96 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala @@ -7,7 +7,7 @@ import io.scalac.mesmer.core.module.AkkaHttpModule import io.scalac.mesmer.core.support.ModulesSupport object AkkaHttpAgent - extends InstrumentModuleFactoryTest(AkkaHttpModule) + extends InstrumentModuleFactory(AkkaHttpModule) with AkkaHttpModule.AkkaHttpConnectionsMetricsDef[Agent] with AkkaHttpModule.AkkaHttpRequestMetricsDef[Agent] { @@ -23,13 +23,13 @@ object AkkaHttpAgent private lazy val requestEvents = Agent( - instrument(`type`("http_requests".id, "akka.http.scaladsl.HttpExt")) + instrument("akka.http.scaladsl.HttpExt".fqcnWithTags("requests")) .visit[HttpExtRequestsAdvice]("bindAndHandle") ) private lazy val connectionEvents = Agent( - instrument(`type`("http_connections".id, "akka.http.scaladsl.HttpExt")) + instrument("akka.http.scaladsl.HttpExt".fqcnWithTags("connections")) .visit[HttpExtConnectionsAdvice]("bindAndHandle") ) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala index 28af01ec9..3605d1679 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala @@ -1,41 +1,73 @@ package io.scalac.mesmer.agent.akka.persistence -import org.slf4j.LoggerFactory - import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.akka.persistence.impl._ import io.scalac.mesmer.agent.util.i13n._ import io.scalac.mesmer.core.model.SupportedModules +import io.scalac.mesmer.core.module.AkkaPersistenceModule import io.scalac.mesmer.core.support.ModulesSupport +import org.slf4j.LoggerFactory + +object AkkaPersistenceAgent + extends InstrumentModuleFactory(AkkaPersistenceModule) + with AkkaPersistenceModule.All[Agent] { + + override def agent(config: AkkaPersistenceModule.AkkaPersistenceMetricsDef[Boolean]): Agent = + Agent.empty ++ + (if (config.recoveryTime) recoveryTime else Agent.empty) ++ + (if (config.recoveryTotal) recoveryTotal else Agent.empty) ++ + (if (config.persistentEvent) persistentEvent else Agent.empty) ++ + (if (config.persistentEventTotal) persistentEventTotal else Agent.empty) ++ + (if (config.snapshot) snapshot else Agent.empty) + + lazy val recoveryTime: Agent = recoveryAgent -object AkkaPersistenceAgent extends InstrumentModuleFactory { + lazy val recoveryTotal: Agent = recoveryAgent + + lazy val persistentEvent: Agent = Agent(eventWriteSuccessInstrumentation) + + lazy val persistentEventTotal: Agent = Agent(eventWriteSuccessInstrumentation) + + lazy val snapshot: Agent = Agent(snapshotLoadingInstrumentation) private[persistence] val logger = LoggerFactory.getLogger(AkkaPersistenceAgent.getClass) protected val supportedModules: SupportedModules = SupportedModules(ModulesSupport.akkaPersistenceTypedModule, ModulesSupport.akkaPersistenceTyped) - private val recoveryStartedAgent = - instrument("akka.persistence.typed.internal.ReplayingSnapshot") - .intercept[RecoveryStartedInterceptor]("onRecoveryStart") + private val recoveryAgent = { + + val recoveryTag = "recovery" + + /** + * Instrumentation to fire event on persistent actor recovery start + */ + val recoveryStartedAgent = + instrument("akka.persistence.typed.internal.ReplayingSnapshot".fqcnWithTags(recoveryTag)) + .visit(RecoveryStartedInterceptor, "onRecoveryStart") + + /** + * Instrumentation to fire event on persistent actor recovery complete + */ + val recoveryCompletedAgent = + instrument("akka.persistence.typed.internal.ReplayingEvents".fqcnWithTags(recoveryTag)) + .visit(RecoveryCompletedInterceptor, "onRecoveryComplete") - private val recoveryCompletedAgent = - instrument("akka.persistence.typed.internal.ReplayingEvents") - .intercept[RecoveryCompletedInterceptor]("onRecoveryComplete") + Agent(recoveryStartedAgent, recoveryCompletedAgent) + } + /** + * Instrumentation to fire events on persistent event start and stop + */ private val eventWriteSuccessInstrumentation = - instrument("akka.persistence.typed.internal.Running") - .intercept[PersistingEventSuccessInterceptor]("onWriteSuccess") - .intercept[JournalInteractionsInterceptor]("onWriteInitiated") + instrument("akka.persistence.typed.internal.Running".fqcnWithTags("persistent_event")) + .visit(PersistingEventSuccessInterceptor, "onWriteSuccess") + .visit(JournalInteractionsInterceptor, "onWriteInitiated") + /** + * Instrumentation to fire event when snapshot is stored + */ private val snapshotLoadingInstrumentation = - instrument("akka.persistence.typed.internal.Running$StoringSnapshot") - .intercept[StoringSnapshotInterceptor]("onSaveSnapshotResponse") - - val agent: Agent = - Agent( - recoveryStartedAgent, - recoveryCompletedAgent, - eventWriteSuccessInstrumentation, - snapshotLoadingInstrumentation - ) + instrument("akka.persistence.typed.internal.Running$StoringSnapshot".fqcnWithTags("snapshot_created")) + .visit(StoringSnapshotInterceptor, "onSaveSnapshotResponse") } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/JournalInteractionsInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/JournalInteractionsInterceptor.scala similarity index 89% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/JournalInteractionsInterceptor.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/JournalInteractionsInterceptor.scala index 85c2f122d..4c5fcb269 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/JournalInteractionsInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/JournalInteractionsInterceptor.scala @@ -1,14 +1,13 @@ -package io.scalac.mesmer.agent.akka.persistence +package io.scalac.mesmer.agent.akka.persistence.impl + import akka.actor.typed.scaladsl.ActorContext import akka.persistence.PersistentRepr -import net.bytebuddy.asm.Advice._ - import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.PersistingEventStarted import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.Timestamp +import net.bytebuddy.asm.Advice._ -class JournalInteractionsInterceptor object JournalInteractionsInterceptor { @OnMethodEnter diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/PersistingEventSuccessInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala similarity index 89% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/PersistingEventSuccessInterceptor.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala index c2365aa85..c1afcbf94 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/PersistingEventSuccessInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala @@ -1,13 +1,12 @@ -package io.scalac.mesmer.agent.akka.persistence +package io.scalac.mesmer.agent.akka.persistence.impl + import akka.actor.typed.scaladsl.ActorContext import akka.persistence.PersistentRepr -import net.bytebuddy.asm.Advice._ - import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.PersistingEventFinished import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.Timestamp -class PersistingEventSuccessInterceptor +import net.bytebuddy.asm.Advice._ object PersistingEventSuccessInterceptor { @OnMethodEnter diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/RecoveryCompletedInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala similarity index 92% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/RecoveryCompletedInterceptor.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala index 1bce1f982..2f3dab810 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/RecoveryCompletedInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala @@ -1,17 +1,15 @@ -package io.scalac.mesmer.agent.akka.persistence +package io.scalac.mesmer.agent.akka.persistence.impl import _root_.akka.actor.typed.scaladsl.ActorContext import _root_.akka.persistence.typed.PersistenceId -import net.bytebuddy.asm.Advice - -import scala.util.Try - +import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.RecoveryFinished import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.Timestamp +import net.bytebuddy.asm.Advice -class RecoveryCompletedInterceptor +import scala.util.Try object RecoveryCompletedInterceptor { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/RecoveryStartedInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala similarity index 92% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/RecoveryStartedInterceptor.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala index e4f723a44..c3a242923 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/RecoveryStartedInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala @@ -1,17 +1,15 @@ -package io.scalac.mesmer.agent.akka.persistence +package io.scalac.mesmer.agent.akka.persistence.impl import _root_.akka.actor.typed.scaladsl.ActorContext import _root_.akka.persistence.typed.PersistenceId -import net.bytebuddy.asm.Advice - -import scala.util.Try - +import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.RecoveryStarted import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.Timestamp +import net.bytebuddy.asm.Advice -class RecoveryStartedInterceptor +import scala.util.Try object RecoveryStartedInterceptor { import AkkaPersistenceAgent.logger diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/StoringSnapshotInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala similarity index 88% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/StoringSnapshotInterceptor.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala index d8f4125e5..4fb72b999 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/StoringSnapshotInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala @@ -1,18 +1,16 @@ -package io.scalac.mesmer.agent.akka.persistence +package io.scalac.mesmer.agent.akka.persistence.impl -import akka.actor.typed.scaladsl.AbstractBehavior -import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext} import akka.persistence.SaveSnapshotSuccess -import net.bytebuddy.asm.Advice._ - -import scala.util.Try - +import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.SnapshotCreated import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.Timestamp +import net.bytebuddy.asm.Advice._ + +import scala.util.Try -class StoringSnapshotInterceptor object StoringSnapshotInterceptor { import AkkaPersistenceAgent.logger diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala index c74d4e2e3..080128e90 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala @@ -3,53 +3,105 @@ package io.scalac.mesmer.agent.akka.stream import akka.ActorGraphInterpreterAdvice import akka.actor.Props import akka.stream.GraphStageIslandAdvice -import akka.stream.impl.fusing.ActorGraphInterpreterProcessEventAdvice -import akka.stream.impl.fusing.ActorGraphInterpreterTryInitAdvice - +import akka.stream.impl.fusing.{ ActorGraphInterpreterProcessEventAdvice, ActorGraphInterpreterTryInitAdvice } import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.akka.stream.impl.{ + ConnectionOps, + GraphInterpreterPushAdvice, + PhasedFusingActorMaterializerAdvice +} import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.model.Module -import io.scalac.mesmer.core.model.SupportedModules -import io.scalac.mesmer.core.model.SupportedVersion +import io.scalac.mesmer.core.model.{ Module, SupportedModules, SupportedVersion } +import io.scalac.mesmer.core.module.AkkaStreamModule + +object AkkaStreamAgent + extends InstrumentModuleFactory(AkkaStreamModule) + with AkkaStreamModule.StreamMetricsDef[Agent] + with AkkaStreamModule.StreamOperatorMetricsDef[Agent] { + + def agent( + config: AkkaStreamModule.All[Boolean] + ): Agent = Agent.empty ++ + (if (config.runningStreamsTotal) runningStreamsTotal else Agent.empty) ++ + (if (config.streamActorsTotal) streamActorsTotal else Agent.empty) ++ + (if (config.streamProcessedMessages) streamProcessedMessages else Agent.empty) ++ + (if (config.processedMessages) processedMessages else Agent.empty) ++ + (if (config.operators) operators else Agent.empty) ++ + (if (config.demand) demand else Agent.empty) + + lazy val runningStreamsTotal: Agent = sharedImplementations + + lazy val streamActorsTotal: Agent = sharedImplementations -object AkkaStreamAgent extends InstrumentModuleFactory { + lazy val streamProcessedMessages: Agent = sharedImplementations - private[akka] val moduleName = Module("akka-stream") + lazy val processedMessages: Agent = sharedImplementations - protected val supportedModules: SupportedModules = SupportedModules(moduleName, SupportedVersion.any) + lazy val operators: Agent = sharedImplementations + + lazy val demand: Agent = sharedImplementations + + protected val supportedModules: SupportedModules = SupportedModules(Module("akka-stream"), SupportedVersion.any) /** * actorOf methods is called when island decide to materialize itself */ - private val phasedFusingActorMeterializerAgent = - instrument("akka.stream.impl.PhasedFusingActorMaterializer") - .intercept[PhasedFusingActorMeterializerAdvice](method("actorOf").takesArguments[Props, String]) + private val phasedFusingActorMaterializerAgentInstrumentation = + instrument("akka.stream.impl.PhasedFusingActorMaterializer".fqcn) + .visit(PhasedFusingActorMaterializerAdvice, method("actorOf").takesArguments[Props, String]) - private val graphInterpreterAgent = - instrument("akka.stream.impl.fusing.GraphInterpreter") - .intercept[GraphInterpreterPushAdvice]("processPush") - .intercept[GraphInterpreterPullAdvice]("processPull") + private val connectionPushAgent = { - private val graphInterpreterConnectionAgent = - instrument("akka.stream.impl.fusing.GraphInterpreter$Connection") - .defineField[Long](ConnectionOps.PullCounterVarName) + /** + * Add incrementing push counter on push processing + */ + val processPush = instrument("akka.stream.impl.fusing.GraphInterpreter".fqcnWithTags("push")) + .visit(GraphInterpreterPushAdvice, "processPush") + + /** + * Adds push counter to [[ akka.stream.impl.fusing.GraphInterpreter.Connection ]] + */ + val pushField = instrument("akka.stream.impl.fusing.GraphInterpreter$Connection".fqcnWithTags("push")) .defineField[Long](ConnectionOps.PushCounterVarName) - private val actorGraphInterpreterAgent = - instrument("akka.stream.impl.fusing.ActorGraphInterpreter") + Agent(processPush, pushField) + } + + private val connectionPullAgent = { + + /** + * Add incrementing pull counter on pull processing + */ + val processPull = instrument("akka.stream.impl.fusing.GraphInterpreter".fqcnWithTags("pull")) + .visit(GraphInterpreterPushAdvice, "processPush") + + /** + * Adds pull counter to [[ akka.stream.impl.fusing.GraphInterpreter.Connection ]] + */ + val pullField = instrument("akka.stream.impl.fusing.GraphInterpreter$Connection".fqcnWithTags("pull")) + .defineField[Long](ConnectionOps.PullCounterVarName) + + Agent(processPull, pullField) + } + + /** + * Instrumentation for Actor that execute streams - adds another message for it to handle that + * pushes all connection data to EventBus and propagation of short living streams + */ + private val actorGraphInterpreterInstrumentation = + instrument("akka.stream.impl.fusing.ActorGraphInterpreter".fqcn) .visit[ActorGraphInterpreterAdvice]("receive") - .visit[ActorGraphInterpreterProcessEventAdvice]("processEvent") - .visit[ActorGraphInterpreterTryInitAdvice]("tryInit") + .visit(ActorGraphInterpreterProcessEventAdvice, "processEvent") + .visit(ActorGraphInterpreterTryInitAdvice, "tryInit") - private val graphStageIslandAgent = - instrument("akka.stream.impl.GraphStageIsland") + /** + * Instrumentation that add additional tag to terminal Sink + */ + private val graphStageIslandInstrumentation = + instrument("akka.stream.impl.GraphStageIsland".fqcn) .visit[GraphStageIslandAdvice]("materializeAtomic") - val agent: Agent = Agent( - phasedFusingActorMeterializerAgent, - actorGraphInterpreterAgent, - graphInterpreterAgent, - graphInterpreterConnectionAgent, - graphStageIslandAgent - ) + private val sharedImplementations = + connectionPullAgent ++ connectionPushAgent ++ actorGraphInterpreterInstrumentation ++ graphStageIslandInstrumentation ++ phasedFusingActorMaterializerAgentInstrumentation + } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterDecorator.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala similarity index 88% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterDecorator.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala index bcf06421e..b5d28b471 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterDecorator.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala @@ -1,21 +1,21 @@ -package io.scalac.mesmer.agent.akka.stream -import java.lang.invoke.MethodType._ +package io.scalac.mesmer.agent.akka.stream.impl -import akka.AkkaMirrorTypes._ +import akka.AkkaMirrorTypes.GraphInterpreterShellMirror import akka.actor.Actor -import akka.actor.typed.scaladsl.adapter._ import akka.stream.GraphLogicOps._ - import io.scalac.mesmer.core.akka.model.PushMetrics import io.scalac.mesmer.core.event.EventBus -import io.scalac.mesmer.core.event.StreamEvent.LastStreamStats -import io.scalac.mesmer.core.event.StreamEvent.StreamInterpreterStats +import io.scalac.mesmer.core.event.StreamEvent.{ LastStreamStats, StreamInterpreterStats } import io.scalac.mesmer.core.invoke.Lookup +import io.scalac.mesmer.core.model.ShellInfo import io.scalac.mesmer.core.model.Tag.SubStreamName -import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.model.stream.ConnectionStats -import io.scalac.mesmer.core.model.stream.StageInfo +import io.scalac.mesmer.core.model.stream.{ ConnectionStats, StageInfo } +import akka.actor.typed.scaladsl.adapter._ + import io.scalac.mesmer.core.util.stream.subStreamNameFromActorRef + +import java.lang.invoke.MethodType.methodType + object ActorGraphInterpreterDecorator extends Lookup { private lazy val shells = { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterProcessEventAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala similarity index 86% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterProcessEventAdvice.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala index 30297a22d..c5d9c7363 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterProcessEventAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala @@ -1,13 +1,14 @@ package akka.stream.impl.fusing -import akka.AkkaMirrorTypes.GraphInterpreterShellMirror import akka.actor.Actor import akka.stream.impl.fusing.ActorGraphInterpreter.BoundaryEvent + + +import akka.AkkaMirrorTypes.GraphInterpreterShellMirror import net.bytebuddy.asm.Advice -import io.scalac.mesmer.agent.akka.stream.ActorGraphInterpreterDecorator +import io.scalac.mesmer.agent.akka.stream.impl.ActorGraphInterpreterDecorator -class ActorGraphInterpreterProcessEventAdvice object ActorGraphInterpreterProcessEventAdvice { @Advice.OnMethodExit @@ -22,7 +23,6 @@ object ActorGraphInterpreterProcessEventAdvice { * Instrumentation for short living streams - part of shell initialization is it's execution * If shell is terminated after that it's not added to activeInterpreters */ -class ActorGraphInterpreterTryInitAdvice object ActorGraphInterpreterTryInitAdvice { @Advice.OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaMirrorTypes.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala similarity index 82% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaMirrorTypes.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala index 64259d11b..9383e0cbb 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaMirrorTypes.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala @@ -1,8 +1,7 @@ package akka import akka.stream.impl.ExtendedActorMaterializer -import akka.stream.impl.fusing.GraphInterpreter -import akka.stream.impl.fusing.GraphInterpreterShell +import akka.stream.impl.fusing.{ GraphInterpreter, GraphInterpreterShell } import akka.stream.stage.GraphStageLogic import akka.util.{ OptionVal => AkkaOptionVal } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ConnectionOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ConnectionOps.scala similarity index 96% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ConnectionOps.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ConnectionOps.scala index 1abf8f4b5..5a0866ce6 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/ConnectionOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ConnectionOps.scala @@ -1,4 +1,5 @@ -package io.scalac.mesmer.agent.akka.stream +package io.scalac.mesmer.agent.akka.stream.impl + import io.scalac.mesmer.core.invoke.Lookup object ConnectionOps extends Lookup { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphInterpreterPushAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala similarity index 69% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphInterpreterPushAdvice.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala index b2614651f..91bc15f07 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphInterpreterPushAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala @@ -1,9 +1,8 @@ -package io.scalac.mesmer.agent.akka.stream -import net.bytebuddy.asm.Advice._ +package io.scalac.mesmer.agent.akka.stream.impl -import io.scalac.mesmer.agent.akka.stream.ConnectionOps._ +import io.scalac.mesmer.agent.akka.stream.impl.ConnectionOps._ +import net.bytebuddy.asm.Advice._ -class GraphInterpreterPushAdvice object GraphInterpreterPushAdvice { @@ -12,7 +11,6 @@ object GraphInterpreterPushAdvice { ConnectionOps.incrementPushCounter(currentConnection) } -class GraphInterpreterPullAdvice object GraphInterpreterPullAdvice { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphLogicOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphLogicOps.scala similarity index 91% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphLogicOps.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphLogicOps.scala index c042da8b1..cf470fac0 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphLogicOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphLogicOps.scala @@ -1,9 +1,9 @@ package akka.stream + import akka.stream.impl.fusing.GraphInterpreter.Connection import akka.stream.stage.GraphStageLogic - -import io.scalac.mesmer.agent.akka.stream.GraphStageIslandOps.TerminalSink +import io.scalac.mesmer.agent.akka.stream.impl.GraphStageIslandOps.TerminalSink import io.scalac.mesmer.core.model.Tag.StageName import io.scalac.mesmer.core.model.Tag.StageName.StreamUniqueStageName diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphStageIslandOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphStageIslandOps.scala similarity index 80% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphStageIslandOps.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphStageIslandOps.scala index 7ff3b845b..9a606ef3f 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/GraphStageIslandOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphStageIslandOps.scala @@ -1,9 +1,7 @@ -package io.scalac.mesmer.agent.akka.stream +package io.scalac.mesmer.agent.akka.stream.impl -import akka.stream.Attributes import akka.stream.Attributes.Attribute -import akka.stream.Shape -import akka.stream.SinkShape +import akka.stream.{ Attributes, Shape, SinkShape } object GraphStageIslandOps { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/PhasedFusingActorMeterializerAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala similarity index 54% rename from agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/PhasedFusingActorMeterializerAdvice.scala rename to agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala index a7c0bc92e..f9ba843fe 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/PhasedFusingActorMeterializerAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala @@ -1,18 +1,13 @@ -package io.scalac.mesmer.agent.akka.stream +package io.scalac.mesmer.agent.akka.stream.impl import akka.AkkaMirrorTypes import akka.actor.ActorRef import akka.actor.typed.scaladsl.adapter._ +import io.scalac.mesmer.core.event.{ActorEvent, EventBus} +import io.scalac.mesmer.core.model.{ActorRefTags, Tag} import net.bytebuddy.asm.Advice._ -import io.scalac.mesmer.core.event.ActorEvent -import io.scalac.mesmer.core.event.EventBus -import io.scalac.mesmer.core.model.ActorRefTags -import io.scalac.mesmer.core.model.Tag - -class PhasedFusingActorMeterializerAdvice - -object PhasedFusingActorMeterializerAdvice { +object PhasedFusingActorMaterializerAdvice { @OnMethodExit def getPhases(@Return ref: ActorRef, @This self: AkkaMirrorTypes.ExtendedActorMaterializerMirror): Unit = diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala index 54919e95d..088fcd289 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala @@ -6,8 +6,8 @@ import io.scalac.mesmer.agent.AgentInstrumentation object AgentInstrumentationFactory { def apply(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = { - val instrumentationName: InstrumentationName = typeInstrumentation.target.`type`.name - AgentInstrumentation(instrumentationName.value, typeInstrumentation.target.modules) { + val instrumentationDetails: InstrumentationDetails[_] = typeInstrumentation.target.`type`.name + AgentInstrumentation(instrumentationDetails.name, typeInstrumentation.target.modules, instrumentationDetails.tags) { (agentBuilder, instrumentation, _) => agentBuilder .`type`(typeInstrumentation.target.`type`.desc) @@ -15,7 +15,7 @@ object AgentInstrumentationFactory { typeInstrumentation.transformBuilder(underlying) } .installOn(instrumentation) - if (instrumentationName.fqcn) LoadingResult(instrumentationName.value) else LoadingResult.empty + if (instrumentationDetails.isFQCN) LoadingResult(instrumentationDetails.name) else LoadingResult.empty } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala index d8bdbcbea..6b0f79f2d 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala @@ -1,24 +1,47 @@ package io.scalac.mesmer.agent.util.i13n import com.typesafe.config.Config -import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } +import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails.FQCN import io.scalac.mesmer.core.model.SupportedModules -import io.scalac.mesmer.core.module.Module - -trait InstrumentModuleFactory { - - protected def supportedModules: SupportedModules - - protected def instrument(tpe: Type): TypeInstrumentation = TypeInstrumentation(TypeTarget(tpe, supportedModules)) +import io.scalac.mesmer.core.module.{MesmerModule, Module} + +object InstrumentModuleFactory { + protected class StringDlsOps(private val value: (String, Module)) extends AnyVal { + + /** + * Assigns `tags` and module name to tags to distinguish this instrumentation from those from other modules and this one + * and mark it as fully qualified class name + */ + def fqcnWithTags(tags: String*): InstrumentationDetails[FQCN] = + InstrumentationDetails.fqcn(value._1, Set(value._2.name) ++ tags) + + /** + * Assigns module name to tags to distinguish this instrumentation from those from other modules + * and mark it as fully qualified class name + */ + def fqcn: InstrumentationDetails[FQCN] = InstrumentationDetails.fqcn(value._1, Set(value._2.name)) + + } + + implicit class FactoryOps[M <: MesmerModule](private val factory: InstrumentModuleFactory[M]) extends AnyVal { + def defaultAgent: Agent = { + factory.agent(factory.module.defaultConfig) + } + } } -abstract class InstrumentModuleFactoryTest[M <: Module](val module: M) { +abstract class InstrumentModuleFactory[M <: Module](val module: M) { this: M#All[Agent] => protected def supportedModules: SupportedModules protected def instrument(tpe: Type): TypeInstrumentation = TypeInstrumentation(TypeTarget(tpe, supportedModules)) - def agent(config: M#All[Boolean]): Agent + def agent(config: module.All[Boolean]): Agent final def agent(config: Config): Agent = agent(module.enabled(config)) + + implicit def enrichStringDsl(value: String): InstrumentModuleFactory.StringDlsOps = + new InstrumentModuleFactory.StringDlsOps(value -> module) + } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index 4e99888f9..310cd9894 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -1,25 +1,39 @@ package io.scalac.mesmer.agent.util import io.scalac.mesmer.agent.AgentInstrumentation +import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails._ import io.scalac.mesmer.core.model.SupportedModules import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription import net.bytebuddy.description.method.MethodDescription import net.bytebuddy.dynamic.DynamicType -import net.bytebuddy.implementation.{ Implementation, MethodDelegation } -import net.bytebuddy.matcher.{ ElementMatcher, ElementMatchers => EM } +import net.bytebuddy.implementation.{Implementation, MethodDelegation} +import net.bytebuddy.matcher.{ElementMatcher, ElementMatchers => EM} import scala.language.implicitConversions -import scala.reflect.{ classTag, ClassTag } +import scala.reflect.{ClassTag, classTag} package object i13n { final private[i13n] type TypeDesc = ElementMatcher.Junction[TypeDescription] final private[i13n] type MethodDesc = ElementMatcher.Junction[MethodDescription] - final case class InstrumentationName(value: String, fqcn: Boolean) + final case class InstrumentationDetails[S <: Status] private (name: String, tags: Set[String], isFQCN: Boolean) - final class Type private[i13n] (private[i13n] val name: InstrumentationName, private[i13n] val desc: TypeDesc) { + object InstrumentationDetails { + sealed trait Status + + sealed trait FQCN extends Status + + sealed trait NonFQCN extends Status + + def fqcn(name: String, tags: Set[String]): InstrumentationDetails[FQCN] = + InstrumentationDetails[FQCN](name, tags, isFQCN = true) + def nonFQCN(name: String, tags: Set[String]): InstrumentationDetails[NonFQCN] = + InstrumentationDetails[NonFQCN](name, tags, isFQCN = false) + } + + final class Type private[i13n] (private[i13n] val name: InstrumentationDetails[_], private[i13n] val desc: TypeDesc) { def and(addDesc: TypeDesc): Type = new Type(name, desc.and(addDesc)) } @@ -31,15 +45,12 @@ package object i13n { val constructor: MethodDesc = EM.isConstructor - def `type`(name: String): Type = - `type`(name.fqcn, EM.named[TypeDescription](name)) - - def `type`(name: InstrumentationName, desc: TypeDesc): Type = new Type(name, desc) + def `type`(name: InstrumentationDetails[_], desc: TypeDesc): Type = new Type(name, desc) - def hierarchy(name: String): Type = + def hierarchy(details: InstrumentationDetails[FQCN]): Type = `type`( - name.fqcn, - EM.hasSuperType[TypeDescription](EM.named[TypeDescription](name)) + details, + EM.hasSuperType[TypeDescription](EM.named[TypeDescription](details.name)) ) // wrappers @@ -57,6 +68,9 @@ package object i13n { def visit[A](advice: A, method: MethodDesc)(implicit isObject: A <:< Singleton): TypeInstrumentation = chain(_.visit(Advice.to(typeFromModule(advice.getClass)).on(method))) +// def intercept[A](advice: A, method: MethodDesc)(implicit isObject: A <:< Singleton): TypeInstrumentation = +// chain(_.method(method).intercept(Advice.to(typeFromModule(advice.getClass)))) + def intercept[T](method: MethodDesc)(implicit ct: ClassTag[T]): TypeInstrumentation = chain(_.method(method).intercept(Advice.to(ct.runtimeClass))) @@ -126,16 +140,20 @@ package object i13n { methodDesc.and(EM.isOverriddenFrom(typeDesc)) } - implicit class StringDlsOps(private val value: String) extends AnyVal { - def fqcn: InstrumentationName = InstrumentationName(value, true) - def id: InstrumentationName = InstrumentationName(value, false) - def withId(name: String): Type = `type`(name.id, name) - } +// implicit class StringDlsOps(private val value: String) extends AnyVal { +// +// /** +// * Assigns tags to this instrumentation to distinguish it from others and prevent merging +// */ +// def fqcnWithTagsRemove(tags: String*): InstrumentationDetails[FQCN] = +// InstrumentationDetails.fqcn(value, tags.toSet) +// def nonFQCN: InstrumentationDetails[NonFQCN] = InstrumentationDetails.nonFQCN(value, Set.empty) +// } // implicit conversion - implicit def methodNameToMethodDesc(methodName: String): MethodDesc = method(methodName) - implicit def classNameToTypeDesc(className: String): TypeDesc = EM.named[TypeDescription](className) - implicit def typeNameToType(name: String): Type = `type`(name) + implicit def fqcnDetailsToType(details: InstrumentationDetails[FQCN]): Type = `type`(details, details.name) + implicit def methodNameToMethodDesc(methodName: String): MethodDesc = method(methodName) + implicit def classNameToTypeDesc(className: String): TypeDesc = EM.named[TypeDescription](className) implicit def typeToAgentInstrumentation(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = AgentInstrumentationFactory(typeInstrumentation) } diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala index 6cb9f339c..a463db42b 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala @@ -38,7 +38,7 @@ class AgentTest extends AnyFlatSpec with Matchers { supported ++ (module, SupportedVersion(version)) } val expectedResult = LoadingResult("some.class", "other.class") - val sut = Agent(AgentInstrumentation("sut", supportedModules)(returning(expectedResult))) + val sut = Agent(AgentInstrumentation("sut", supportedModules, Set.empty)(returning(expectedResult))) sut.installOn(builder, instrumentation, modules) shouldBe expectedResult } @@ -47,7 +47,7 @@ class AgentTest extends AnyFlatSpec with Matchers { supported ++ (module, SupportedVersion.none) } val expectedResult = LoadingResult("some.class", "other.class") - val sut = Agent(AgentInstrumentation("sut", supportedModules)(returning(expectedResult))) + val sut = Agent(AgentInstrumentation("sut", supportedModules,Set.empty)(returning(expectedResult))) sut.installOn(builder, instrumentation, modules) shouldBe LoadingResult.empty } @@ -56,7 +56,7 @@ class AgentTest extends AnyFlatSpec with Matchers { supported ++ (module, SupportedVersion(version)) } ++ (testModuleOne, SupportedVersion.none) val expectedResult = LoadingResult("some.class", "other.class") - val sut = Agent(AgentInstrumentation("sut", supportedModules)(returning(expectedResult))) + val sut = Agent(AgentInstrumentation("sut", supportedModules, Set.empty)(returning(expectedResult))) sut.installOn(builder, instrumentation, modules) shouldBe LoadingResult.empty } @@ -64,12 +64,12 @@ class AgentTest extends AnyFlatSpec with Matchers { case (instrumentation, builder) => val successfulInstrumentationResult = LoadingResult("some.class") val successfulInstrumentation = - AgentInstrumentation("success", SupportedModules(testModuleOne, SupportedVersion(moduleOneVersion)))( + AgentInstrumentation("success", SupportedModules(testModuleOne, SupportedVersion(moduleOneVersion)), Set.empty)( returning(successfulInstrumentationResult) ) val failingInstrumentationResult = LoadingResult("other.class") val failingInstrumentation = - AgentInstrumentation("success", SupportedModules(testModuleTwo, SupportedVersion.none))( + AgentInstrumentation("success", SupportedModules(testModuleTwo, SupportedVersion.none), Set.empty)( returning(failingInstrumentationResult) ) val sut = Agent(successfulInstrumentation) ++ failingInstrumentation diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala index f9be50672..4602c421d 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala @@ -1,12 +1,13 @@ package io.scalac.mesmer.agent.utils import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.akka.actor.{ AkkaActorAgent, AkkaMailboxAgent } +import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent -import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactoryTest -import io.scalac.mesmer.core.module.{ AkkaHttpModule, Module } +import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory +import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory._ +import io.scalac.mesmer.core.module.Module import io.scalac.mesmer.core.util.ModuleInfo.{ extractModulesInformation, Modules } import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.ByteBuddyAgent @@ -20,9 +21,7 @@ import scala.util.Try object InstallAgent { def allInstrumentations: Agent = - AkkaActorAgent.agent ++ AkkaHttpAgent.agent( - AkkaHttpModule.defaultConfig - ) ++ AkkaPersistenceAgent.agent ++ AkkaStreamAgent.agent ++ AkkaMailboxAgent.agent + AkkaActorAgent.defaultAgent ++ AkkaHttpAgent.defaultAgent ++ AkkaPersistenceAgent.defaultAgent ++ AkkaStreamAgent.defaultAgent } abstract class InstallAgent extends TestSuite { @@ -51,8 +50,9 @@ abstract class InstallAgent extends TestSuite { } def withAgent(setup: () => Unit)(test: () => Any): Any = { - val context = Thread.currentThread().getContextClassLoader.asInstanceOf[URLClassLoader] - val prefixClassLoader = new PrefixChildFirstClassLoader(Vector("akka.http.scaladsl.HttpExt"), context.getURLs, context) + val context = Thread.currentThread().getContextClassLoader.asInstanceOf[URLClassLoader] + val prefixClassLoader = + new PrefixChildFirstClassLoader(Vector("akka.http.scaladsl.HttpExt"), context.getURLs, context) Thread.currentThread().setContextClassLoader(prefixClassLoader) setup() @@ -84,10 +84,10 @@ final class PrefixChildFirstClassLoader(prefix: Vector[String], urls: Array[URL] } -abstract class InstallModule[M <: Module](moduleFactory: InstrumentModuleFactoryTest[M]) extends InstallAgent { +abstract class InstallModule[M <: Module](moduleFactory: InstrumentModuleFactory[M]) extends InstallAgent { this: AnyFlatSpecLike => - def withVersion(versions: M#All[Boolean]*)(name: String)(test: => Any): Any = + def withVersion(versions: moduleFactory.module.All[Boolean]*)(name: String)(test: => Any): Any = versions.foreach { version => it should s"$name with $version" in withAgent { () => agent = Some(moduleFactory.agent(version)) diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala index 2cf8f1058..7524e1cd4 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala @@ -65,7 +65,7 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics { val name: String = "akka-actor" - protected lazy val defaultConfig: Config = + lazy val defaultConfig: Config = AkkaActorModuleConfig(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) protected def extractFromConfig(config: TypesafeConfig): Config = { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala index 4c7ff50f0..594a8ae11 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala @@ -25,7 +25,7 @@ object AkkaActorSystemModule extends MesmerModule with AkkaActorSystemMetricsMod lazy val enabled: Boolean = createdActors || terminatedActors } - protected val defaultConfig: Config = ActorSystemModuleConfig(true, true) + val defaultConfig: Config = ActorSystemModuleConfig(true, true) protected def extractFromConfig(config: TypesafeConfig): Config = { val createdActors = config.tryValue("created-actors")(_.getBoolean).getOrElse(defaultConfig.createdActors) diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala index bbb20e783..5477cc974 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala @@ -41,7 +41,7 @@ object AkkaClusterModule extends MesmerModule with AkkaClusterMetricsModule { override type Metrics[T] = AkkaClusterMetricsDef[T] - protected val defaultConfig: AkkaClusterModule.Result = + val defaultConfig: AkkaClusterModule.Result = AkkaClusterModuleMetrics(true, true, true, true, true, true, true) protected def extractFromConfig(config: TypesafeConfig): AkkaClusterModule.Result = { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala index 9240f8ff8..4647fe70a 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala @@ -36,7 +36,7 @@ object AkkaPersistenceModule extends MesmerModule with AkkaPersistenceMetricsMod snapshot } - protected val defaultConfig: AkkaPersistenceModule.Result = AkkaPersistenceModuleConfig(true, true, true, true, true) + val defaultConfig: AkkaPersistenceModule.Result = AkkaPersistenceModuleConfig(true, true, true, true, true) protected def extractFromConfig(config: TypesafeConfig): Config = { val recoveryTime = config diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala index 6046c5858..b7ea19871 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala @@ -52,7 +52,7 @@ object AkkaStreamModule extends MesmerModule with AkkaStreamMetrics with AkkaStr demand } - protected def defaultConfig: Config = AkkaStreamModuleConfig(true, true, true, true, true, true) + val defaultConfig: Config = AkkaStreamModuleConfig(true, true, true, true, true, true) protected def extractFromConfig(config: TypesafeConfig): Config = { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala index b6c7483ee..9fba1326b 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -20,6 +20,8 @@ trait MesmerModule extends Module with MesmerConfigurationBase { final def enabled(config: TypesafeConfig): Config = fromConfig(config) + def defaultConfig: Result + val mesmerConfig = s"module.$name" } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala index 3d1803abe..4531075f2 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala @@ -5,24 +5,19 @@ import akka.actor.typed.receptionist.Receptionist.Register import akka.actor.typed.scaladsl.Behaviors import akka.cluster.Cluster import akka.util.Timeout -import io.scalac.mesmer.core.model.{ Module, SupportedVersion, _ } -import io.scalac.mesmer.core.module.AkkaHttpModule +import io.scalac.mesmer.core.model.{Module, SupportedVersion, _} +import io.scalac.mesmer.core.module.{AkkaActorModule, AkkaHttpModule} import io.scalac.mesmer.core.support.ModulesSupport import io.scalac.mesmer.core.util.ModuleInfo.Modules -import io.scalac.mesmer.core.util.{ ModuleInfo, Timestamp } +import io.scalac.mesmer.core.util.{ModuleInfo, Timestamp} import io.scalac.mesmer.extension.ActorEventsMonitorActor.ReflectiveActorMetricsReader import io.scalac.mesmer.extension.actor.MutableActorMetricStorageFactory -import io.scalac.mesmer.extension.config.{ AkkaMonitoringConfig, CachingConfig, InstrumentationLibrary } +import io.scalac.mesmer.extension.config.{AkkaMonitoringConfig, CachingConfig, InstrumentationLibrary} import io.scalac.mesmer.extension.http.CleanableRequestStorage import io.scalac.mesmer.extension.metric.CachingMonitor -import io.scalac.mesmer.extension.persistence.{ CleanablePersistingStorage, CleanableRecoveryStorage } +import io.scalac.mesmer.extension.persistence.{CleanablePersistingStorage, CleanableRecoveryStorage} import io.scalac.mesmer.extension.service._ -import io.scalac.mesmer.extension.upstream.{ - OpenTelemetryClusterMetricsMonitor, - OpenTelemetryHttpMetricsMonitor, - OpenTelemetryPersistenceMetricsMonitor, - _ -} +import io.scalac.mesmer.extension.upstream.{OpenTelemetryClusterMetricsMonitor, OpenTelemetryHttpMetricsMonitor, OpenTelemetryPersistenceMetricsMonitor, _} import scala.concurrent.duration._ import scala.language.postfixOps @@ -166,7 +161,7 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM def startActorMonitor(): Unit = { log.debug("Starting actor monitor") - val actorMonitor = OpenTelemetryActorMetricsMonitor(meter, actorSystemConfig) + val actorMonitor = OpenTelemetryActorMetricsMonitor(meter, AkkaActorModule.fromConfig(actorSystemConfig), actorSystemConfig) system.systemActorOf( Behaviors @@ -300,7 +295,7 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM } else { log.warn(s"Module ${AkkaHttpModule.name} set to auto-start but it's disabled") } - + } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala index 597fc752a..3c8642bc4 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala @@ -65,11 +65,13 @@ object SyncWith { } trait MetricObserver[-T, -L] extends Metric[T] { + def setUpdater(updater: MetricObserver.Updater[T, L]): Unit } object MetricObserver { - type Updater[T, L] = MetricObserver.Result[T, L] => Unit + + type Updater[+T, +L] = MetricObserver.Result[T, L] => Unit trait Result[-T, -L] { def observe(value: T, labels: L): Unit From 599a9fe59e582f2e80750a9a101c8466992b3665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Wed, 23 Jun 2021 19:58:02 +0200 Subject: [PATCH 08/31] update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 064464c0c..89403d0f6 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ target/ *.log.* *.sh .vscode/ -.metals/ \ No newline at end of file +.metals/ +.bloop/ From b024d6173bb72c715184e1c093047fe543547271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Fri, 25 Jun 2021 10:21:31 +0200 Subject: [PATCH 09/31] Fix compilation --- .../scala/io/scalac/mesmer/agent/Agent.scala | 37 +- .../scala/io/scalac/mesmer/agent/Boot.scala | 16 +- .../agent/akka/actor/AkkaActorAgent.scala | 121 ++++-- .../agent/akka/http/AkkaHttpAgent.scala | 46 ++- .../persistence/AkkaPersistenceAgent.scala | 60 ++- .../agent/akka/stream/AkkaStreamAgent.scala | 67 +-- .../i13n/AgentInstrumentationFactory.scala | 19 +- .../util/i13n/InstrumentModuleFactory.scala | 51 ++- .../mesmer/agent/util/i13n/package.scala | 25 +- .../agent/AgentInstrumentationTest.scala | 44 ++ .../io/scalac/mesmer/agent/AgentTest.scala | 75 +--- .../mesmer/agent/akka/AkkaHttpAgentTest.scala | 98 ++--- .../mesmer/agent/utils/InstallAgent.scala | 38 +- .../mesmer/core/model/SupportedModules.scala | 2 + .../mesmer/core/model/SupportedVersion.scala | 1 + .../io/scalac/mesmer/core/model/Version.scala | 2 +- .../mesmer/core/module/AkkaActorModule.scala | 121 ++++-- .../core/module/AkkaActorSystemModule.scala | 14 +- .../core/module/AkkaClusterModule.scala | 127 +++--- .../mesmer/core/module/AkkaHttpModule.scala | 52 ++- .../core/module/AkkaPersistenceModule.scala | 104 +++-- .../mesmer/core/module/AkkaStreamModule.scala | 138 ++++--- .../io/scalac/mesmer/core/module/Module.scala | 41 +- .../mesmer/core/support/ModulesSupport.scala | 24 +- .../scalac/mesmer/core/util/LibraryInfo.scala | 48 +++ .../scalac/mesmer/core/util/ModuleInfo.scala | 48 --- .../core/model/SupportedModulesTest.scala | 36 +- .../mesmer/extension/AkkaMonitoring.scala | 381 +++++++++--------- .../extension/AkkaStreamMonitoring.scala | 29 +- .../config/AkkaMonitoringConfig.scala | 9 +- .../extension/config/BufferConfig.scala | 3 +- .../extension/config/CachingConfig.scala | 2 +- 32 files changed, 1113 insertions(+), 766 deletions(-) create mode 100644 agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala create mode 100644 core/src/main/scala/io/scalac/mesmer/core/util/LibraryInfo.scala delete mode 100644 core/src/main/scala/io/scalac/mesmer/core/util/ModuleInfo.scala diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala index c48ee911e..672242163 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala @@ -1,8 +1,6 @@ package io.scalac.mesmer.agent import io.scalac.mesmer.agent.Agent.LoadingResult -import io.scalac.mesmer.core.model.SupportedModules -import io.scalac.mesmer.core.util.ModuleInfo.Modules import net.bytebuddy.agent.builder.AgentBuilder import org.slf4j.LoggerFactory @@ -10,8 +8,6 @@ import java.lang.instrument.Instrumentation object Agent { - private val logger = LoggerFactory.getLogger(classOf[Agent]) - def apply(head: AgentInstrumentation, tail: AgentInstrumentation*): Agent = new Agent((head +: tail).toSet) val empty: Agent = new Agent(Set.empty) @@ -49,22 +45,20 @@ object Agent { object AgentInstrumentation { - def apply(name: String, modules: SupportedModules, tags: Set[String])( - installation: (AgentBuilder, Instrumentation, Modules) => LoadingResult + def apply(name: String, tags: Set[String])( + installation: (AgentBuilder, Instrumentation) => LoadingResult ): AgentInstrumentation = - new AgentInstrumentation(name, modules, tags) { - def apply(builder: AgentBuilder, instrumentation: Instrumentation, modules: Modules): LoadingResult = - installation(builder, instrumentation, modules) + new AgentInstrumentation(name, tags) { + def apply(builder: AgentBuilder, instrumentation: Instrumentation): LoadingResult = + installation(builder, instrumentation) } } -//TODO add tests sealed abstract case class AgentInstrumentation( name: String, - instrumentingModules: SupportedModules, tags: Set[String] -) extends ((AgentBuilder, Instrumentation, Modules) => LoadingResult) +) extends ((AgentBuilder, Instrumentation) => LoadingResult) with Equals { override def hashCode(): Int = name.hashCode() @@ -85,22 +79,9 @@ final case class Agent private (private[agent] val instrumentations: Set[AgentIn def ++(other: AgentInstrumentation): Agent = Agent(instrumentations + other) - def installOn(builder: AgentBuilder, instrumentation: Instrumentation, modules: Modules): LoadingResult = - instrumentations.flatMap { agentInstrumentation => - val dependencies = agentInstrumentation.instrumentingModules - - val allModulesSupported = dependencies.modules.forall { module => - modules - .get(module) - .exists(dependencies.supportedVersion(module).supports) - } + def installOn(builder: AgentBuilder, instrumentation: Instrumentation): LoadingResult = + instrumentations.map { agentInstrumentation => + agentInstrumentation(builder, instrumentation) - if (allModulesSupported) { - val requiredModules = modules.view.filterKeys(dependencies.modules.contains) - Some(agentInstrumentation(builder, instrumentation, requiredModules.toMap)) - } else { - logger.error("Unsupported versions for instrumentation for {}", agentInstrumentation.name) - None - } }.fold(LoadingResult.empty)(_ ++ _) } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala index fb37f4547..35ac1ce4c 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala @@ -5,7 +5,7 @@ import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent -import io.scalac.mesmer.core.util.ModuleInfo +import io.scalac.mesmer.core.util.LibraryInfo import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.builder.AgentBuilder import net.bytebuddy.dynamic.scaffold.TypeValidation @@ -15,6 +15,7 @@ import scala.annotation.unused object Boot { + //TODO better configuration specification def premain(@unused arg: String, instrumentation: Instrumentation): Unit = { val config = ConfigFactory.load() @@ -27,14 +28,15 @@ object Boot { ) .`with`(AgentBuilder.InstallationListener.StreamWriting.toSystemOut) - val allInstrumentations = - AkkaPersistenceAgent.agent(config) ++ AkkaStreamAgent.agent(config) ++ AkkaHttpAgent.agent( - config - ) ++ AkkaActorAgent.agent(config) - val moduleInfo = ModuleInfo.extractModulesInformation(Thread.currentThread().getContextClassLoader) + val info = LibraryInfo.extractModulesInformation(Thread.currentThread().getContextClassLoader) + + val allInstrumentations = AkkaPersistenceAgent.initAgent(info, config).getOrElse(Agent.empty) ++ + AkkaStreamAgent.initAgent(info, config).getOrElse(Agent.empty) ++ + AkkaHttpAgent.initAgent(info, config).getOrElse(Agent.empty) ++ + AkkaActorAgent.initAgent(info, config).getOrElse(Agent.empty) allInstrumentations - .installOn(agentBuilder, instrumentation, moduleInfo) + .installOn(agentBuilder, instrumentation) .eagerLoad() } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala index 1a3500b90..4cc90d8db 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala @@ -5,65 +5,113 @@ import io.scalac.mesmer.agent.util.i13n._ import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.module.AkkaActorModule -import io.scalac.mesmer.core.support.ModulesSupport import io.scalac.mesmer.core.util.Timestamp import io.scalac.mesmer.extension.actor.{ ActorCellDecorator, ActorCellMetrics } object AkkaActorAgent extends InstrumentModuleFactory(AkkaActorModule) - with AkkaActorModule.All[Agent] + with AkkaActorModule.All[AkkaActorModule.AkkaJar[Version] => Option[Agent]] with AkkaMailboxInstrumentations { - def agent(config: AkkaActorModule.AkkaActorMetricsDef[Boolean]): Agent = - Agent.empty ++ - (if (config.mailboxSize) mailboxSize else Agent.empty) ++ - (if (config.mailboxTimeAvg) mailboxTimeAvg else Agent.empty) ++ - (if (config.mailboxTimeMin) mailboxTimeMin else Agent.empty) ++ - (if (config.mailboxTimeMax) mailboxTimeMax else Agent.empty) ++ - (if (config.mailboxTimeSum) mailboxTimeSum else Agent.empty) ++ - (if (config.stashSize) stashSize else Agent.empty) ++ - (if (config.receivedMessages) receivedMessages else Agent.empty) ++ - (if (config.processedMessages) processedMessages else Agent.empty) ++ - (if (config.failedMessages) failedMessages else Agent.empty) ++ - (if (config.processingTimeAvg) processingTimeAvg else Agent.empty) ++ - (if (config.processingTimeMin) processingTimeMin else Agent.empty) ++ - (if (config.processingTimeMax) processingTimeMax else Agent.empty) ++ - (if (config.processingTimeSum) processingTimeSum else Agent.empty) ++ - (if (config.sentMessages) sentMessages else Agent.empty) ++ - (if (config.droppedMessages) droppedMessages else Agent.empty) + /** + * @param config configuration of features that are wanted by the user + * @param jars versions of required jars to deduce which features can be enabled + * @return Resulting agent and resulting configuration based on runtime properties + */ + override protected def agent( + config: AkkaActorModule.All[Boolean], + jars: AkkaActorModule.Jars[Version] + ): (Agent, AkkaActorModule.All[Boolean]) = { + val mailboxSizeAgent = if (config.mailboxSize) mailboxSize(jars) else None + val mailboxTimeAvgAgent = if (config.mailboxTimeAvg) mailboxTimeAvg(jars) else None + val mailboxTimeMinAgent = if (config.mailboxTimeMin) mailboxTimeMin(jars) else None + val mailboxTimeMaxAgent = if (config.mailboxTimeMax) mailboxTimeMax(jars) else None + val mailboxTimeSumAgent = if (config.mailboxTimeSum) mailboxTimeSum(jars) else None + val stashSizeAgent = if (config.stashSize) stashSize(jars) else None + val receivedMessagesAgent = if (config.receivedMessages) receivedMessages(jars) else None + val processedMessagesAgent = if (config.processedMessages) processedMessages(jars) else None + val failedMessagesAgent = if (config.failedMessages) failedMessages(jars) else None + val processingTimeAvgAgent = if (config.processingTimeAvg) processingTimeAvg(jars) else None + val processingTimeMinAgent = if (config.processingTimeMin) processingTimeMin(jars) else None + val processingTimeMaxAgent = if (config.processingTimeMax) processingTimeMax(jars) else None + val processingTimeSumAgent = if (config.processingTimeSum) processingTimeSum(jars) else None + val sentMessagesAgent = if (config.sentMessages) sentMessages(jars) else None + val droppedMessagesAgent = if (config.droppedMessages) droppedMessages(jars) else None + + val resultantAgent = mailboxSizeAgent.getOrElse(Agent.empty) ++ + mailboxTimeAvgAgent.getOrElse(Agent.empty) ++ + mailboxTimeMinAgent.getOrElse(Agent.empty) ++ + mailboxTimeMaxAgent.getOrElse(Agent.empty) ++ + mailboxTimeSumAgent.getOrElse(Agent.empty) ++ + stashSizeAgent.getOrElse(Agent.empty) ++ + receivedMessagesAgent.getOrElse(Agent.empty) ++ + processedMessagesAgent.getOrElse(Agent.empty) ++ + failedMessagesAgent.getOrElse(Agent.empty) ++ + processingTimeAvgAgent.getOrElse(Agent.empty) ++ + processingTimeMinAgent.getOrElse(Agent.empty) ++ + processingTimeMaxAgent.getOrElse(Agent.empty) ++ + processingTimeSumAgent.getOrElse(Agent.empty) ++ + sentMessagesAgent.getOrElse(Agent.empty) ++ + droppedMessagesAgent.getOrElse(Agent.empty) + + val enabled = AkkaActorModule.Impl( + mailboxSize = mailboxSizeAgent.isDefined, + mailboxTimeAvg = mailboxTimeAvgAgent.isDefined, + mailboxTimeMin = mailboxTimeMinAgent.isDefined, + mailboxTimeMax = mailboxTimeMaxAgent.isDefined, + mailboxTimeSum = mailboxTimeSumAgent.isDefined, + stashSize = stashSizeAgent.isDefined, + receivedMessages = receivedMessagesAgent.isDefined, + processedMessages = processedMessagesAgent.isDefined, + failedMessages = failedMessagesAgent.isDefined, + processingTimeAvg = processingTimeAvgAgent.isDefined, + processingTimeMin = processingTimeMinAgent.isDefined, + processingTimeMax = processingTimeMaxAgent.isDefined, + processingTimeSum = processingTimeSumAgent.isDefined, + sentMessages = sentMessagesAgent.isDefined, + droppedMessages = droppedMessagesAgent.isDefined + ) - lazy val mailboxSize: Agent = sharedInstrumentation + (resultantAgent, enabled) + } - lazy val mailboxTimeAvg: Agent = sharedInstrumentation ++ mailboxInstrumentation + lazy val mailboxSize: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) - lazy val mailboxTimeMin: Agent = sharedInstrumentation ++ mailboxInstrumentation + lazy val mailboxTimeAvg: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ mailboxInstrumentation) - lazy val mailboxTimeMax: Agent = sharedInstrumentation ++ mailboxInstrumentation + lazy val mailboxTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ mailboxInstrumentation) - lazy val mailboxTimeSum: Agent = sharedInstrumentation ++ mailboxInstrumentation + lazy val mailboxTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ mailboxInstrumentation) - lazy val stashSize: Agent = sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation + lazy val mailboxTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ mailboxInstrumentation) - lazy val receivedMessages: Agent = sharedInstrumentation + lazy val stashSize: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation) - lazy val processedMessages: Agent = sharedInstrumentation + lazy val receivedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) - lazy val failedMessages: Agent = sharedInstrumentation ++ abstractSupervisionInstrumentation + lazy val processedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) - lazy val processingTimeAvg: Agent = sharedInstrumentation + lazy val failedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ abstractSupervisionInstrumentation) - lazy val processingTimeMin: Agent = sharedInstrumentation + lazy val processingTimeAvg: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) - lazy val processingTimeMax: Agent = sharedInstrumentation + lazy val processingTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) - lazy val processingTimeSum: Agent = sharedInstrumentation + lazy val processingTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) - lazy val sentMessages: Agent = sharedInstrumentation ++ mailboxTimeSendMessageIncInstrumentation + lazy val processingTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) - lazy val droppedMessages: Agent = sharedInstrumentation ++ boundedQueueAgent + lazy val sentMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ mailboxTimeSendMessageIncInstrumentation) - protected final val supportedModules: SupportedModules = - SupportedModules(ModulesSupport.akkaActorModule, ModulesSupport.akkaActor) + lazy val droppedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ boundedQueueAgent) /** * Instrumentation for classic stash @@ -173,5 +221,4 @@ object AkkaActorAgent private val localActorRefProviderInstrumentation: AgentInstrumentation = instrument("akka.actor.LocalActorRefProvider".fqcnWithTags("create")) .visit(LocalActorRefProviderAdvice, "actorOf") - } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala index 227813b96..c0ea297cf 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala @@ -2,24 +2,20 @@ package io.scalac.mesmer.agent.akka.http import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.model.SupportedModules +import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaHttpModule -import io.scalac.mesmer.core.support.ModulesSupport +import io.scalac.mesmer.core.module.AkkaHttpModule._ object AkkaHttpAgent extends InstrumentModuleFactory(AkkaHttpModule) - with AkkaHttpModule.AkkaHttpConnectionsMetricsDef[Agent] - with AkkaHttpModule.AkkaHttpRequestMetricsDef[Agent] { + with AkkaHttpModule.AkkaHttpConnectionsMetricsDef[AkkaHttpModule.AkkaJar[Version] => Option[Agent]] + with AkkaHttpModule.AkkaHttpRequestMetricsDef[AkkaHttpModule.AkkaJar[Version] => Option[Agent]] { - // @ToDo tests all supported versions - protected val supportedModules: SupportedModules = - SupportedModules(ModulesSupport.akkaHttpModule, ModulesSupport.akkaHttp) + def requestTime: AkkaHttpModule.Jars[Version] => Option[Agent] = _ => Some(requestEvents) // Version => Option[Agent] - def requestTime: Agent = requestEvents + def requestCounter: AkkaHttpModule.Jars[Version] => Option[Agent] = _ => Some(requestEvents) - def requestCounter: Agent = requestEvents - - def connections: Agent = connectionEvents + def connections: AkkaHttpModule.Jars[Version] => Option[Agent] = _ => Some(connectionEvents) private lazy val requestEvents = Agent( @@ -33,12 +29,26 @@ object AkkaHttpAgent .visit[HttpExtConnectionsAdvice]("bindAndHandle") ) - def agent(config: AkkaHttpModule.All[Boolean]): Agent = { - - val requestCounterAgent = if (config.requestCounter) requestCounter else Agent.empty - val requestTimeAgent = if (config.requestTime) requestTime else Agent.empty - val connectionsAgent = if (config.connections) connections else Agent.empty - - requestCounterAgent ++ requestTimeAgent ++ connectionsAgent + /** + * @param config configuration of features that are wanted by the user + * @param jars versions of required jars to deduce which features can be enabled + * @return Some if feature can be enabled, None otherwise + */ + override def agent( + config: AkkaHttpModule.All[Boolean], + jars: AkkaHttpModule.Jars[Version] + ): (Agent, AkkaHttpModule.All[Boolean]) = { + val requestCounterAgent = if (config.requestCounter) requestCounter(jars) else None + val requestTimeAgent = if (config.requestTime) requestTime(jars) else None + val connectionsAgent = if (config.connections) connections(jars) else None + + val resultantAgent = requestCounterAgent.getOrElse(Agent.empty) ++ requestTimeAgent.getOrElse( + Agent.empty + ) ++ connectionsAgent.getOrElse(Agent.empty) + + val enabled = Impl[Boolean](requestCounterAgent.isDefined, requestTimeAgent.isDefined, connectionsAgent.isDefined) + + (resultantAgent, enabled) } + } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala index 3605d1679..d84f86dd3 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala @@ -3,38 +3,64 @@ package io.scalac.mesmer.agent.akka.persistence import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.akka.persistence.impl._ import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.model.SupportedModules +import io.scalac.mesmer.core.model.{SupportedModules, Version} import io.scalac.mesmer.core.module.AkkaPersistenceModule import io.scalac.mesmer.core.support.ModulesSupport import org.slf4j.LoggerFactory object AkkaPersistenceAgent extends InstrumentModuleFactory(AkkaPersistenceModule) - with AkkaPersistenceModule.All[Agent] { + with AkkaPersistenceModule.All[AkkaPersistenceModule.AkkaJar[Version] => Option[Agent]] { - override def agent(config: AkkaPersistenceModule.AkkaPersistenceMetricsDef[Boolean]): Agent = - Agent.empty ++ - (if (config.recoveryTime) recoveryTime else Agent.empty) ++ - (if (config.recoveryTotal) recoveryTotal else Agent.empty) ++ - (if (config.persistentEvent) persistentEvent else Agent.empty) ++ - (if (config.persistentEventTotal) persistentEventTotal else Agent.empty) ++ - (if (config.snapshot) snapshot else Agent.empty) + /** + * @param config configuration of features that are wanted by the user + * @param jars versions of required jars to deduce which features can be enabled + * @return Resulting agent and resulting configuration based on runtime properties + */ + override protected def agent( + config: AkkaPersistenceModule.AkkaPersistenceMetricsDef[Boolean], + jars: AkkaPersistenceModule.Jars[Version] + ): (Agent, AkkaPersistenceModule.AkkaPersistenceMetricsDef[Boolean]) = { + + val recoveryTimeAgent = if (config.recoveryTime) recoveryTime(jars) else None + val recoveryTotalAgent = if (config.recoveryTotal) recoveryTime(jars) else None + val persistentEventAgent = if (config.persistentEvent) recoveryTime(jars) else None + val persistentEventTotalAgent = if (config.persistentEventTotal) recoveryTime(jars) else None + val snapshotAgent = if (config.snapshot) recoveryTime(jars) else None + + val resultantAgent = + recoveryTimeAgent.getOrElse(Agent.empty) ++ + recoveryTotalAgent.getOrElse(Agent.empty) ++ + persistentEventAgent.getOrElse(Agent.empty) ++ + persistentEventTotalAgent.getOrElse(Agent.empty) ++ + snapshotAgent.getOrElse(Agent.empty) + + val enabled = AkkaPersistenceModule.Impl( + recoveryTime = recoveryTimeAgent.isDefined, + recoveryTotal = recoveryTotalAgent.isDefined, + persistentEvent = persistentEventAgent.isDefined, + persistentEventTotal = persistentEventTotalAgent.isDefined, + snapshot = snapshotAgent.isDefined + ) + + (resultantAgent, enabled) + } - lazy val recoveryTime: Agent = recoveryAgent + lazy val recoveryTime: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => Some(recoveryAgent) - lazy val recoveryTotal: Agent = recoveryAgent + lazy val recoveryTotal: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => Some(recoveryAgent) - lazy val persistentEvent: Agent = Agent(eventWriteSuccessInstrumentation) + lazy val persistentEvent: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => + Some(Agent(eventWriteSuccessInstrumentation)) - lazy val persistentEventTotal: Agent = Agent(eventWriteSuccessInstrumentation) + lazy val persistentEventTotal: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => + Some(Agent(eventWriteSuccessInstrumentation)) - lazy val snapshot: Agent = Agent(snapshotLoadingInstrumentation) + lazy val snapshot: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => + Some(Agent(snapshotLoadingInstrumentation)) private[persistence] val logger = LoggerFactory.getLogger(AkkaPersistenceAgent.getClass) - protected val supportedModules: SupportedModules = - SupportedModules(ModulesSupport.akkaPersistenceTypedModule, ModulesSupport.akkaPersistenceTyped) - private val recoveryAgent = { val recoveryTag = "recovery" diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala index 080128e90..2876d9883 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala @@ -3,45 +3,62 @@ package io.scalac.mesmer.agent.akka.stream import akka.ActorGraphInterpreterAdvice import akka.actor.Props import akka.stream.GraphStageIslandAdvice -import akka.stream.impl.fusing.{ ActorGraphInterpreterProcessEventAdvice, ActorGraphInterpreterTryInitAdvice } +import akka.stream.impl.fusing.{ActorGraphInterpreterProcessEventAdvice, ActorGraphInterpreterTryInitAdvice} import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.akka.stream.impl.{ - ConnectionOps, - GraphInterpreterPushAdvice, - PhasedFusingActorMaterializerAdvice -} +import io.scalac.mesmer.agent.akka.stream.impl.{ConnectionOps, GraphInterpreterPushAdvice, PhasedFusingActorMaterializerAdvice} import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.model.{ Module, SupportedModules, SupportedVersion } +import io.scalac.mesmer.core.model.{SupportedModules, SupportedVersion, Version} import io.scalac.mesmer.core.module.AkkaStreamModule object AkkaStreamAgent extends InstrumentModuleFactory(AkkaStreamModule) - with AkkaStreamModule.StreamMetricsDef[Agent] - with AkkaStreamModule.StreamOperatorMetricsDef[Agent] { + with AkkaStreamModule.StreamMetricsDef[AkkaStreamModule.AkkaJar[Version] => Option[Agent]] + with AkkaStreamModule.StreamOperatorMetricsDef[AkkaStreamModule.AkkaJar[Version] => Option[Agent]] { - def agent( - config: AkkaStreamModule.All[Boolean] - ): Agent = Agent.empty ++ - (if (config.runningStreamsTotal) runningStreamsTotal else Agent.empty) ++ - (if (config.streamActorsTotal) streamActorsTotal else Agent.empty) ++ - (if (config.streamProcessedMessages) streamProcessedMessages else Agent.empty) ++ - (if (config.processedMessages) processedMessages else Agent.empty) ++ - (if (config.operators) operators else Agent.empty) ++ - (if (config.demand) demand else Agent.empty) - lazy val runningStreamsTotal: Agent = sharedImplementations + /** + * @param config configuration of features that are wanted by the user + * @param jars versions of required jars to deduce which features can be enabled + * @return Resulting agent and resulting configuration based on runtime properties + */ + protected def agent(config: AkkaStreamModule.All[Boolean], jars: AkkaStreamModule.Jars[Version]): (Agent, AkkaStreamModule.All[Boolean]) = { + val runningStreamsTotalAgent = if (config.runningStreamsTotal) runningStreamsTotal(jars) else None + val streamActorsTotalAgent = if (config.runningStreamsTotal) streamActorsTotal(jars) else None + val streamProcessedMessagesAgent = if (config.runningStreamsTotal) streamProcessedMessages(jars) else None + val processedMessagesAgent = if (config.runningStreamsTotal) processedMessages(jars) else None + val operatorsAgent = if (config.runningStreamsTotal) operators(jars) else None + val demandAgent = if (config.runningStreamsTotal) demand(jars) else None + + val resultantAgent = + runningStreamsTotalAgent.getOrElse(Agent.empty) ++ + streamActorsTotalAgent.getOrElse(Agent.empty) ++ + streamProcessedMessagesAgent.getOrElse(Agent.empty) ++ + processedMessagesAgent.getOrElse(Agent.empty) ++ + operatorsAgent.getOrElse(Agent.empty) ++ + demandAgent.getOrElse(Agent.empty) + + val enabled = AkkaStreamModule.Impl( + runningStreamsTotal = runningStreamsTotalAgent.isDefined, + streamActorsTotal = streamActorsTotalAgent.isDefined, + streamProcessedMessages = streamProcessedMessagesAgent.isDefined, + processedMessages = processedMessagesAgent.isDefined, + operators = operatorsAgent.isDefined, + demand = demandAgent.isDefined + ) + (resultantAgent, enabled) + } - lazy val streamActorsTotal: Agent = sharedImplementations + lazy val runningStreamsTotal: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) - lazy val streamProcessedMessages: Agent = sharedImplementations + lazy val streamActorsTotal: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) - lazy val processedMessages: Agent = sharedImplementations + lazy val streamProcessedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) - lazy val operators: Agent = sharedImplementations + lazy val processedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) - lazy val demand: Agent = sharedImplementations + lazy val operators: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) - protected val supportedModules: SupportedModules = SupportedModules(Module("akka-stream"), SupportedVersion.any) + lazy val demand: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) /** * actorOf methods is called when island decide to materialize itself diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala index 088fcd289..cbf58edb7 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala @@ -6,16 +6,15 @@ import io.scalac.mesmer.agent.AgentInstrumentation object AgentInstrumentationFactory { def apply(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = { - val instrumentationDetails: InstrumentationDetails[_] = typeInstrumentation.target.`type`.name - AgentInstrumentation(instrumentationDetails.name, typeInstrumentation.target.modules, instrumentationDetails.tags) { - (agentBuilder, instrumentation, _) => - agentBuilder - .`type`(typeInstrumentation.target.`type`.desc) - .transform { (underlying, _, _, _) => - typeInstrumentation.transformBuilder(underlying) - } - .installOn(instrumentation) - if (instrumentationDetails.isFQCN) LoadingResult(instrumentationDetails.name) else LoadingResult.empty + val instrumentationDetails: InstrumentationDetails[_] = typeInstrumentation.`type`.name + AgentInstrumentation(instrumentationDetails.name, instrumentationDetails.tags) { (agentBuilder, instrumentation) => + agentBuilder + .`type`(typeInstrumentation.`type`.desc) + .transform { (underlying, _, _, _) => + typeInstrumentation.transformBuilder(underlying) + } + .installOn(instrumentation) + if (instrumentationDetails.isFQCN) LoadingResult(instrumentationDetails.name) else LoadingResult.empty } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala index 6b0f79f2d..73637e391 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala @@ -2,8 +2,9 @@ package io.scalac.mesmer.agent.util.i13n import com.typesafe.config.Config import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails.FQCN -import io.scalac.mesmer.core.model.SupportedModules -import io.scalac.mesmer.core.module.{MesmerModule, Module} +import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.module.{ MesmerModule, Module, RegisterGlobalConfiguration } +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo object InstrumentModuleFactory { protected class StringDlsOps(private val value: (String, Module)) extends AnyVal { @@ -23,23 +24,49 @@ object InstrumentModuleFactory { } - implicit class FactoryOps[M <: MesmerModule](private val factory: InstrumentModuleFactory[M]) extends AnyVal { - def defaultAgent: Agent = { - factory.agent(factory.module.defaultConfig) - } + implicit class FactoryOps[M <: MesmerModule with RegisterGlobalConfiguration](private val factory: InstrumentModuleFactory[M]) extends AnyVal { + + def defaultAgent(jarsInfo: LibraryInfo): Agent = + factory + .initAgent(jarsInfo, factory.module.defaultConfig, registerGlobal = false) + .getOrElse(throw new IllegalStateException("Unsupported library version found - cannot install agent")) } } -abstract class InstrumentModuleFactory[M <: Module](val module: M) { - this: M#All[Agent] => +abstract class InstrumentModuleFactory[M <: Module with RegisterGlobalConfiguration](val module: M) { + /* + Requiring all features to be a function from versions to Option[Agent] we allow there to create different instrumentations depending + on runtime version of jars. TODO add information on which versions are supported + */ + this: M#All[M#AkkaJar[Version] => Option[Agent]] => - protected def supportedModules: SupportedModules + protected def instrument(tpe: Type): TypeInstrumentation = TypeInstrumentation(tpe) - protected def instrument(tpe: Type): TypeInstrumentation = TypeInstrumentation(TypeTarget(tpe, supportedModules)) + /** + * @param config configuration of features that are wanted by the user + * @param jars versions of required jars to deduce which features can be enabled + * @return Resulting agent and resulting configuration based on runtime properties + */ + protected def agent(config: module.All[Boolean], jars: module.AkkaJar[Version]): (Agent, module.All[Boolean]) - def agent(config: module.All[Boolean]): Agent + private[i13n] final def agent( + config: module.All[Boolean], + jars: module.AkkaJar[Version], + registerGlobal: Boolean + ): Agent = { + val (agents, enabled) = agent(config, jars) + if (registerGlobal) + module.registerGlobal(enabled) + agents + } - final def agent(config: Config): Agent = agent(module.enabled(config)) + final def initAgent(jarsInfo: LibraryInfo, config: Config): Option[Agent] = + initAgent(jarsInfo, module.enabled(config), registerGlobal = true) + + final def initAgent(jarsInfo: LibraryInfo, config: module.All[Boolean], registerGlobal: Boolean): Option[Agent] = + module.jarsFromLibraryInfo(jarsInfo).map { jars => + agent(config, jars, registerGlobal) + } implicit def enrichStringDsl(value: String): InstrumentModuleFactory.StringDlsOps = new InstrumentModuleFactory.StringDlsOps(value -> module) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index 310cd9894..2ac0b344b 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -2,16 +2,15 @@ package io.scalac.mesmer.agent.util import io.scalac.mesmer.agent.AgentInstrumentation import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails._ -import io.scalac.mesmer.core.model.SupportedModules import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription import net.bytebuddy.description.method.MethodDescription import net.bytebuddy.dynamic.DynamicType -import net.bytebuddy.implementation.{Implementation, MethodDelegation} -import net.bytebuddy.matcher.{ElementMatcher, ElementMatchers => EM} +import net.bytebuddy.implementation.{ Implementation, MethodDelegation } +import net.bytebuddy.matcher.{ ElementMatcher, ElementMatchers => EM } import scala.language.implicitConversions -import scala.reflect.{ClassTag, classTag} +import scala.reflect.{ classTag, ClassTag } package object i13n { @@ -58,7 +57,7 @@ package object i13n { private[i13n] type Builder = DynamicType.Builder[_] final class TypeInstrumentation private ( - private[i13n] val target: TypeTarget, + private[i13n] val `type`: Type, private[i13n] val transformBuilder: Builder => Builder ) { @@ -95,16 +94,14 @@ package object i13n { } private def chain(that: Builder => Builder): TypeInstrumentation = - new TypeInstrumentation(target, transformBuilder.andThen(that)) + new TypeInstrumentation(`type`, transformBuilder.andThen(that)) } private[i13n] object TypeInstrumentation { - private[i13n] def apply(target: TypeTarget): TypeInstrumentation = new TypeInstrumentation(target, identity) + private[i13n] def apply(target: Type): TypeInstrumentation = new TypeInstrumentation(target, identity) } - final private[i13n] case class TypeTarget(`type`: Type, modules: SupportedModules) - // extensions sealed trait TypeDescLike[T] extends Any { @@ -140,16 +137,6 @@ package object i13n { methodDesc.and(EM.isOverriddenFrom(typeDesc)) } -// implicit class StringDlsOps(private val value: String) extends AnyVal { -// -// /** -// * Assigns tags to this instrumentation to distinguish it from others and prevent merging -// */ -// def fqcnWithTagsRemove(tags: String*): InstrumentationDetails[FQCN] = -// InstrumentationDetails.fqcn(value, tags.toSet) -// def nonFQCN: InstrumentationDetails[NonFQCN] = InstrumentationDetails.nonFQCN(value, Set.empty) -// } - // implicit conversion implicit def fqcnDetailsToType(details: InstrumentationDetails[FQCN]): Type = `type`(details, details.name) implicit def methodNameToMethodDesc(methodName: String): MethodDesc = method(methodName) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala new file mode 100644 index 000000000..6bdc6f02a --- /dev/null +++ b/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala @@ -0,0 +1,44 @@ +package io.scalac.mesmer.agent + +import io.scalac.mesmer.agent.Agent.LoadingResult +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class AgentInstrumentationTest extends AnyFlatSpec with Matchers { + + behavior of "AgentInstrumentation" + + private def returning(result: LoadingResult): (Any, Any) => LoadingResult = (_, _) => result + + it should "be equal if tags and name are the same" in { + val name = "some.class" + val tags = Set("tag1", "tag2") + + val agent = AgentInstrumentation(name, tags)(returning(LoadingResult.empty)) + val agent2 = AgentInstrumentation(name, tags)(returning(LoadingResult.empty)) + + agent should be(agent2) + } + + it should "be not be equal if tags are different" in { + val name = "some.class" + val tags1 = Set("tag1", "tag2") + val tags2 = Set("tag2", "tag3") + + val agent = AgentInstrumentation(name, tags1)(returning(LoadingResult.empty)) + val agent2 = AgentInstrumentation(name, tags2)(returning(LoadingResult.empty)) + + agent should not be (agent2) + } + + it should "be not be equal if names are different" in { + val name = "some.class" + val name2 = "other.class" + val tags = Set("tag1", "tag2") + + val agent = AgentInstrumentation(name, tags)(returning(LoadingResult.empty)) + val agent2 = AgentInstrumentation(name2, tags)(returning(LoadingResult.empty)) + + agent should not be (agent2) + } +} diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala index a463db42b..60f13fec5 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala @@ -1,79 +1,40 @@ package io.scalac.mesmer.agent -import java.lang.instrument.Instrumentation - +import io.scalac.mesmer.agent.Agent.LoadingResult import net.bytebuddy.agent.ByteBuddyAgent import net.bytebuddy.agent.builder.AgentBuilder import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import io.scalac.mesmer.agent.Agent.LoadingResult -import io.scalac.mesmer.core.model.Module -import io.scalac.mesmer.core.model.SupportedModules -import io.scalac.mesmer.core.model.SupportedVersion -import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.util.ModuleInfo.Modules +import java.lang.instrument.Instrumentation class AgentTest extends AnyFlatSpec with Matchers { - val testModuleOne: Module = Module("test-module-1") - val testModuleTwo: Module = Module("test-module-2") - val moduleOneVersion: Version = Version(2, 2, 2) - val moduleTwoVersion: Version = Version(3, 3, 3) - val modules: Modules = Map(testModuleOne -> moduleOneVersion, testModuleTwo -> moduleTwoVersion) + def returning(result: LoadingResult): (AgentBuilder, Instrumentation) => LoadingResult = (_, _) => result - type Fixture = (Instrumentation, AgentBuilder) + behavior of "Agent" - def test(body: Fixture => Any): Any = { + it should "keep one copy of equal instrumentation" in { - val instrumentation = ByteBuddyAgent.install() - val builder = new AgentBuilder.Default() - Function.untupled(body)(instrumentation, builder) - } + val agentInstrumentationOne = AgentInstrumentation("name", Set("tag"))(returning(LoadingResult.empty)) + val agentInstrumentationTwo = AgentInstrumentation("name", Set("tag"))(returning(LoadingResult.empty)) - def returning(result: LoadingResult): (AgentBuilder, Instrumentation, Modules) => LoadingResult = (_, _, _) => result + val agent = Agent(agentInstrumentationOne, agentInstrumentationTwo) - "Agent" should "execute instrumenting function when version match" in test { case (instrumentation, builder) => - val supportedModules = modules.foldLeft(SupportedModules.empty) { case (supported, (module, version)) => - supported ++ (module, SupportedVersion(version)) - } - val expectedResult = LoadingResult("some.class", "other.class") - val sut = Agent(AgentInstrumentation("sut", supportedModules, Set.empty)(returning(expectedResult))) - sut.installOn(builder, instrumentation, modules) shouldBe expectedResult + agent.instrumentations should have size (1) } - it should "not execute instrumenting when no version match" in test { case (instrumentation, builder) => - val supportedModules = modules.foldLeft(SupportedModules.empty) { case (supported, (module, _)) => - supported ++ (module, SupportedVersion.none) - } - val expectedResult = LoadingResult("some.class", "other.class") - val sut = Agent(AgentInstrumentation("sut", supportedModules,Set.empty)(returning(expectedResult))) - sut.installOn(builder, instrumentation, modules) shouldBe LoadingResult.empty - } + it should "combine result from different agent instrumentations" in { - it should "not execute instrumenting when any version doesn't match" in test { case (instrumentation, builder) => - val supportedModules = modules.foldLeft(SupportedModules.empty) { case (supported, (module, version)) => - supported ++ (module, SupportedVersion(version)) - } ++ (testModuleOne, SupportedVersion.none) - val expectedResult = LoadingResult("some.class", "other.class") - val sut = Agent(AgentInstrumentation("sut", supportedModules, Set.empty)(returning(expectedResult))) - sut.installOn(builder, instrumentation, modules) shouldBe LoadingResult.empty - } + val agentInstrumentationOne = AgentInstrumentation("test_name_one", Set("tag"))(returning(LoadingResult("one"))) + val agentInstrumentationTwo = AgentInstrumentation("test_name_one", Set.empty)(returning(LoadingResult("two"))) + val agentInstrumentationThree = AgentInstrumentation("test_name_two", Set("tag"))(returning(LoadingResult("three"))) - it should "partially instrument when several agent instrumentations are defined" in test { - case (instrumentation, builder) => - val successfulInstrumentationResult = LoadingResult("some.class") - val successfulInstrumentation = - AgentInstrumentation("success", SupportedModules(testModuleOne, SupportedVersion(moduleOneVersion)), Set.empty)( - returning(successfulInstrumentationResult) - ) - val failingInstrumentationResult = LoadingResult("other.class") - val failingInstrumentation = - AgentInstrumentation("success", SupportedModules(testModuleTwo, SupportedVersion.none), Set.empty)( - returning(failingInstrumentationResult) - ) - val sut = Agent(successfulInstrumentation) ++ failingInstrumentation + val expectedResult = LoadingResult(Seq("one", "two", "three")) - sut.installOn(builder, instrumentation, modules) shouldBe successfulInstrumentationResult + val agent = Agent(agentInstrumentationOne, agentInstrumentationTwo, agentInstrumentationThree) + + agent.installOn(new AgentBuilder.Default(), ByteBuddyAgent.install()) should be(expectedResult) } + } diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala index 243e74a79..5330527d0 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala @@ -31,61 +31,61 @@ class AkkaHttpAgentTest behavior of "AkkaHttpAgent" - it should behave like withVersion( -// AkkaHttpModule.AkkaHttpModuleConfig(true, true, true), -// AkkaHttpModule.AkkaHttpModuleConfig(false, true, true), - AkkaHttpModule.AkkaHttpModuleConfig(true, false, true) - )( - "instrument routes to generate events on http requests" - )(AkkaHttpTestImpl.systemWithHttpService { implicit system => monitor => - val testRoute: Route = path("test") { - get { - complete((StatusCodes.OK, collection.immutable.Seq(Connection("close")))) - } - } -// implicit val timeout = RouteTestTimeout(5 seconds) - import system.executionContext - - - val response = for { - binding <- Http().newServerAt("127.0.0.1", 0).bind(testRoute) - port = binding.localAddress.getPort - targetUri = Uri.Empty.withPath(Path("/test")).withHost("127.0.0.1").withPort(port).withScheme("http") - response <- Http().singleRequest(HttpRequest(HttpMethods.GET, targetUri)) - } yield { - binding.unbind() - response - } - Await.result(response, 5.seconds) - - monitor.expectMessageType[ConnectionStarted] - monitor.expectMessageType[RequestStarted] - monitor.expectMessageType[RequestCompleted] - monitor.expectMessageType[ConnectionCompleted] - }) - -// "AkkaHttpAgent" should "instrument routes to generate events on http requests" in withVersion( -// AkkaHttpModule.defaultConfig -// )(test { monitor => -// implicit val timeout = RouteTestTimeout(5 seconds) +// it should behave like withVersion( +//// AkkaHttpModule.AkkaHttpModuleConfig(true, true, true), +//// AkkaHttpModule.AkkaHttpModuleConfig(false, true, true), +// AkkaHttpModule.Impl(true, false, true) +// )( +// "instrument routes to generate events on http requests" +// )(AkkaHttpTestImpl.systemWithHttpService { implicit system => monitor => +// val testRoute: Route = path("test") { +// get { +// complete((StatusCodes.OK, collection.immutable.Seq(Connection("close")))) +// } +// } +//// implicit val timeout = RouteTestTimeout(5 seconds) +// import system.executionContext +// // -// Get("/test") ~!> testRoute ~> check { -// status should be(StatusCodes.OK) +// val response = for { +// binding <- Http().newServerAt("127.0.0.1", 0).bind(testRoute) +// port = binding.localAddress.getPort +// targetUri = Uri.Empty.withPath(Path("/test")).withHost("127.0.0.1").withPort(port).withScheme("http") +// response <- Http().singleRequest(HttpRequest(HttpMethods.GET, targetUri)) +// } yield { +// binding.unbind() +// response // } +// Await.result(response, 5.seconds) +// // monitor.expectMessageType[ConnectionStarted] // monitor.expectMessageType[RequestStarted] // monitor.expectMessageType[RequestCompleted] // monitor.expectMessageType[ConnectionCompleted] // }) - -// it should "contain 2 transformations" in test { _ => -// agent.value.instrumentations should have size (2) -// } - - it should behave like withVersion(AkkaHttpModule.defaultConfig)("contain 2 transformations")(AkkaHttpTestImpl.systemWithHttpService { - _ => _ => - agent.value.instrumentations should have size (2) - - }) +// +//// "AkkaHttpAgent" should "instrument routes to generate events on http requests" in withVersion( +//// AkkaHttpModule.defaultConfig +//// )(test { monitor => +//// implicit val timeout = RouteTestTimeout(5 seconds) +//// +//// Get("/test") ~!> testRoute ~> check { +//// status should be(StatusCodes.OK) +//// } +//// monitor.expectMessageType[ConnectionStarted] +//// monitor.expectMessageType[RequestStarted] +//// monitor.expectMessageType[RequestCompleted] +//// monitor.expectMessageType[ConnectionCompleted] +//// }) +// +//// it should "contain 2 transformations" in test { _ => +//// agent.value.instrumentations should have size (2) +//// } +// +// it should behave like withVersion(AkkaHttpModule.defaultConfig)("contain 2 transformations")(AkkaHttpTestImpl.systemWithHttpService { +// _ => _ => +// agent.value.instrumentations should have size (2) +// +// }) } diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala index 4602c421d..d4b4c1b63 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala @@ -7,8 +7,8 @@ import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory._ -import io.scalac.mesmer.core.module.Module -import io.scalac.mesmer.core.util.ModuleInfo.{ extractModulesInformation, Modules } +import io.scalac.mesmer.core.module.{Module, RegisterGlobalConfiguration} +import io.scalac.mesmer.core.util.LibraryInfo.{LibraryInfo, extractModulesInformation} import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.ByteBuddyAgent import net.bytebuddy.agent.builder.AgentBuilder @@ -16,17 +16,19 @@ import net.bytebuddy.dynamic.scaffold.TypeValidation import org.scalatest.TestSuite import org.scalatest.flatspec.AnyFlatSpecLike -import java.net.{ URL, URLClassLoader } +import java.net.{URL, URLClassLoader} import scala.util.Try object InstallAgent { - def allInstrumentations: Agent = - AkkaActorAgent.defaultAgent ++ AkkaHttpAgent.defaultAgent ++ AkkaPersistenceAgent.defaultAgent ++ AkkaStreamAgent.defaultAgent + def allInstrumentations(info: LibraryInfo): Agent = AkkaActorAgent.defaultAgent(info) ++ + AkkaHttpAgent.defaultAgent(info) ++ + AkkaPersistenceAgent.defaultAgent(info) ++ + AkkaStreamAgent.defaultAgent(info) } abstract class InstallAgent extends TestSuite { - def modules: Modules = extractModulesInformation(Thread.currentThread().getContextClassLoader) + def modules: LibraryInfo = extractModulesInformation(Thread.currentThread().getContextClassLoader) protected var agent: Option[Agent] = None @@ -44,7 +46,7 @@ abstract class InstallAgent extends TestSuite { val instrumentation = ByteBuddyAgent.install() agent.fold[Unit](throw new AssertionError("Agent must be set")) { - _.installOn(builder, instrumentation, modules) + _.installOn(builder, instrumentation) .eagerLoad() } } @@ -84,18 +86,18 @@ final class PrefixChildFirstClassLoader(prefix: Vector[String], urls: Array[URL] } -abstract class InstallModule[M <: Module](moduleFactory: InstrumentModuleFactory[M]) extends InstallAgent { +abstract class InstallModule[M <: Module with RegisterGlobalConfiguration](moduleFactory: InstrumentModuleFactory[M]) extends InstallAgent { this: AnyFlatSpecLike => - def withVersion(versions: moduleFactory.module.All[Boolean]*)(name: String)(test: => Any): Any = - versions.foreach { version => - it should s"$name with $version" in withAgent { () => - agent = Some(moduleFactory.agent(version)) - println(s"Class loader: ${Thread.currentThread().getContextClassLoader}") - println(s"Class loader parent: ${Thread.currentThread().getContextClassLoader.getParent}") - println(s"Class loader 2xparent: ${Thread.currentThread().getContextClassLoader.getParent.getParent}") - }(() => test) - - } +// def withVersion(versions: moduleFactory.module.All[Boolean]*)(name: String)(test: => Any): Any = +// versions.foreach { version => +// it should s"$name with $version" in withAgent { () => +// agent = Some(moduleFactory.initAgent(version)) +// println(s"Class loader: ${Thread.currentThread().getContextClassLoader}") +// println(s"Class loader parent: ${Thread.currentThread().getContextClassLoader.getParent}") +// println(s"Class loader 2xparent: ${Thread.currentThread().getContextClassLoader.getParent.getParent}") +// }(() => test) +// +// } } diff --git a/core/src/main/scala/io/scalac/mesmer/core/model/SupportedModules.scala b/core/src/main/scala/io/scalac/mesmer/core/model/SupportedModules.scala index e974b188e..5b8320c80 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/model/SupportedModules.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/model/SupportedModules.scala @@ -1,5 +1,7 @@ package io.scalac.mesmer.core.model +import io.scalac.mesmer.core.module.Module + object SupportedModules { def apply(module: Module, supportedVersion: SupportedVersion): SupportedModules = new SupportedModules(Map(module -> supportedVersion)) diff --git a/core/src/main/scala/io/scalac/mesmer/core/model/SupportedVersion.scala b/core/src/main/scala/io/scalac/mesmer/core/model/SupportedVersion.scala index a9cd67635..ece4c9878 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/model/SupportedVersion.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/model/SupportedVersion.scala @@ -1,5 +1,6 @@ package io.scalac.mesmer.core.model +//TODO add descriptive toString sealed trait SupportedVersion { import SupportedVersion._ diff --git a/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala b/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala index 7929659f2..2998aead3 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala @@ -11,4 +11,4 @@ object Version { def apply(major: Int, minor: Int, patch: Int): Version = Version(major.toString, minor.toString, patch.toString) } -final case class Module(name: String) +//final case class Module(name: String) diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala index 7524e1cd4..2f89edbea 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala @@ -1,5 +1,8 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } +import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaActorMetrics extends MetricsModule { this: Module => @@ -25,48 +28,33 @@ sealed trait AkkaActorMetrics extends MetricsModule { } } -object AkkaActorModule extends MesmerModule with AkkaActorMetrics { +object AkkaActorModule extends MesmerModule with AkkaActorMetrics with RegisterGlobalConfiguration { override type Metrics[T] = AkkaActorMetricsDef[T] - - final case class AkkaActorModuleConfig( - mailboxSize: Boolean, - mailboxTimeAvg: Boolean, - mailboxTimeMin: Boolean, - mailboxTimeMax: Boolean, - mailboxTimeSum: Boolean, - stashSize: Boolean, - receivedMessages: Boolean, - processedMessages: Boolean, - failedMessages: Boolean, - processingTimeAvg: Boolean, - processingTimeMin: Boolean, - processingTimeMax: Boolean, - processingTimeSum: Boolean, - sentMessages: Boolean, - droppedMessages: Boolean - ) extends AkkaActorMetricsDef[Boolean] - with ModuleConfig { - lazy val enabled: Boolean = { - mailboxSize || mailboxTimeAvg || mailboxTimeMin || - mailboxTimeMax || - mailboxTimeSum || - stashSize || - receivedMessages || - processedMessages || - failedMessages || - processingTimeAvg || - processingTimeMin || - processingTimeMax || - processingTimeSum || - sentMessages || - droppedMessages - } - } + override type All[T] = Metrics[T] + override type AkkaJar[T] = Jars[T] + + final case class Impl[T]( + mailboxSize: T, + mailboxTimeAvg: T, + mailboxTimeMin: T, + mailboxTimeMax: T, + mailboxTimeSum: T, + stashSize: T, + receivedMessages: T, + processedMessages: T, + failedMessages: T, + processingTimeAvg: T, + processingTimeMin: T, + processingTimeMax: T, + processingTimeSum: T, + sentMessages: T, + droppedMessages: T + ) extends AkkaActorMetricsDef[T] val name: String = "akka-actor" lazy val defaultConfig: Config = - AkkaActorModuleConfig(true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) + Impl[Boolean](true, true, true, true, true, true, true, true, true, true, true, true, true, true, true) protected def extractFromConfig(config: TypesafeConfig): Config = { val moduleEnabled = config @@ -133,7 +121,7 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics { .tryValue("dropped-messages")(_.getBoolean) .getOrElse(defaultConfig.droppedMessages) - AkkaActorModuleConfig( + Impl[Boolean]( mailboxSize = mailboxSize, mailboxTimeAvg = mailboxTimeAvg, mailboxTimeMin = mailboxTimeMin, @@ -151,10 +139,61 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics { droppedMessages = droppedMessages ) } else - AkkaActorModuleConfig(false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false) + Impl[Boolean](false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false) } - override type All[T] = Metrics[T] + final case class Jars[T](akkaActor: T, akkaActorTyped: T) + + def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = + for { + actor <- info.get(requiredAkkaJars.akkaActor) + actorTyped <- info.get(requiredAkkaJars.akkaActorTyped) + } yield Jars(actor, actorTyped) + + val requiredAkkaJars: Jars[String] = Jars("akka-actor", "akka-actor-typed") + + /** + * Combines config that with AND operator + */ + implicit val combineConfig: Combine[All[Boolean]] = (first, second) => { + Impl( + mailboxSize = first.mailboxSize && second.mailboxSize, + mailboxTimeAvg = first.mailboxTimeAvg && second.mailboxTimeAvg, + mailboxTimeMin = first.mailboxTimeMin && second.mailboxTimeMin, + mailboxTimeMax = first.mailboxTimeMax && second.mailboxTimeMax, + mailboxTimeSum = first.mailboxTimeSum && second.mailboxTimeSum, + stashSize = first.stashSize && second.stashSize, + receivedMessages = first.receivedMessages && second.receivedMessages, + processedMessages = first.processedMessages && second.processedMessages, + failedMessages = first.failedMessages && second.failedMessages, + processingTimeAvg = first.processingTimeAvg && second.processingTimeAvg, + processingTimeMin = first.processingTimeMin && second.processingTimeMin, + processingTimeMax = first.processingTimeMax && second.processingTimeMax, + processingTimeSum = first.processingTimeSum && second.processingTimeSum, + sentMessages = first.sentMessages && second.sentMessages, + droppedMessages = first.droppedMessages && second.droppedMessages + ) + } + + implicit val traverseAll: Traverse[All] = new Traverse[All] { + def sequence[T](obj: AkkaActorModule.AkkaActorMetricsDef[T]): Seq[T] = Seq( + obj.mailboxSize, + obj.mailboxTimeAvg, + obj.mailboxTimeMin, + obj.mailboxTimeMax, + obj.mailboxTimeSum, + obj.stashSize, + obj.receivedMessages, + obj.processedMessages, + obj.failedMessages, + obj.processingTimeAvg, + obj.processingTimeMin, + obj.processingTimeMax, + obj.processingTimeSum, + obj.sentMessages, + obj.droppedMessages + ) + } } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala index 594a8ae11..5791057ad 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala @@ -1,5 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } +import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaActorSystemMetricsModule extends MetricsModule { this: Module => @@ -20,8 +22,7 @@ object AkkaActorSystemModule extends MesmerModule with AkkaActorSystemMetricsMod final case class ActorSystemModuleConfig( createdActors: Boolean, terminatedActors: Boolean - ) extends ActorSystemMetricsDef[Boolean] - with ModuleConfig { + ) extends ActorSystemMetricsDef[Boolean] { lazy val enabled: Boolean = createdActors || terminatedActors } @@ -34,4 +35,13 @@ object AkkaActorSystemModule extends MesmerModule with AkkaActorSystemMetricsMod ActorSystemModuleConfig(createdActors, terminatedActors) } + + override type AkkaJar[T] = Jars[T] + + final case class Jars[T](akkaActor: T) + + def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = + info.get(requiredAkkaJars.akkaActor).map(Jars.apply[Version]) + + val requiredAkkaJars: AkkaJar[String] = Jars("akka-actor") } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala index 5477cc974..e2d2f3329 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala @@ -1,5 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } +import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaClusterMetricsModule extends MetricsModule { this: Module => @@ -20,69 +22,78 @@ object AkkaClusterModule extends MesmerModule with AkkaClusterMetricsModule { val name: String = "akka-cluster" - final case class AkkaClusterModuleMetrics( - shardPerRegions: Boolean, - entityPerRegion: Boolean, - shardRegionsOnNode: Boolean, - entitiesOnNode: Boolean, - reachableNodes: Boolean, - unreachableNodes: Boolean, - nodeDown: Boolean - ) extends AkkaClusterMetricsDef[Boolean] - with ModuleConfig { - lazy val enabled: Boolean = shardPerRegions || - entityPerRegion || - shardRegionsOnNode || - entitiesOnNode || - reachableNodes || - unreachableNodes || - nodeDown - } + final case class Impl[T]( + shardPerRegions: T, + entityPerRegion: T, + shardRegionsOnNode: T, + entitiesOnNode: T, + reachableNodes: T, + unreachableNodes: T, + nodeDown: T + ) extends AkkaClusterMetricsDef[T] override type Metrics[T] = AkkaClusterMetricsDef[T] - val defaultConfig: AkkaClusterModule.Result = - AkkaClusterModuleMetrics(true, true, true, true, true, true, true) + val defaultConfig: AkkaClusterModule.Result = + Impl[Boolean](true, true, true, true, true, true, true) protected def extractFromConfig(config: TypesafeConfig): AkkaClusterModule.Result = { - val shardsPerRegion = config - .tryValue("shards-per-region")(_.getBoolean) - .getOrElse(defaultConfig.shardPerRegions) - - val entitiesPerRegion = config - .tryValue("entities-per-region")(_.getBoolean) - .getOrElse(defaultConfig.entityPerRegion) - - val shardRegionsOnNode = config - .tryValue("shard-regions-on-node")(_.getBoolean) - .getOrElse(defaultConfig.shardRegionsOnNode) - - val entitiesOnNode = config - .tryValue("entities-on-node")(_.getBoolean) - .getOrElse(defaultConfig.entitiesOnNode) - - val reachableNodes = config - .tryValue("reachable-nodes")(_.getBoolean) - .getOrElse(defaultConfig.reachableNodes) - - val unreachableNodes = config - .tryValue("unreachable-nodes")(_.getBoolean) - .getOrElse(defaultConfig.unreachableNodes) - - val nodesDown = config - .tryValue("node-down")(_.getBoolean) - .getOrElse(defaultConfig.nodeDown) - - AkkaClusterModuleMetrics( - shardPerRegions = shardsPerRegion, - entityPerRegion = entitiesPerRegion, - shardRegionsOnNode = shardRegionsOnNode, - entitiesOnNode = entitiesOnNode, - reachableNodes = reachableNodes, - unreachableNodes = unreachableNodes, - nodeDown = nodesDown - ) + val moduleEnabled = config + .tryValue("enabled")(_.getBoolean) + .getOrElse(true) + + if (moduleEnabled) { + val shardsPerRegion = config + .tryValue("shards-per-region")(_.getBoolean) + .getOrElse(defaultConfig.shardPerRegions) + + val entitiesPerRegion = config + .tryValue("entities-per-region")(_.getBoolean) + .getOrElse(defaultConfig.entityPerRegion) + + val shardRegionsOnNode = config + .tryValue("shard-regions-on-node")(_.getBoolean) + .getOrElse(defaultConfig.shardRegionsOnNode) + + val entitiesOnNode = config + .tryValue("entities-on-node")(_.getBoolean) + .getOrElse(defaultConfig.entitiesOnNode) + + val reachableNodes = config + .tryValue("reachable-nodes")(_.getBoolean) + .getOrElse(defaultConfig.reachableNodes) + + val unreachableNodes = config + .tryValue("unreachable-nodes")(_.getBoolean) + .getOrElse(defaultConfig.unreachableNodes) + + val nodesDown = config + .tryValue("node-down")(_.getBoolean) + .getOrElse(defaultConfig.nodeDown) + + Impl[Boolean]( + shardPerRegions = shardsPerRegion, + entityPerRegion = entitiesPerRegion, + shardRegionsOnNode = shardRegionsOnNode, + entitiesOnNode = entitiesOnNode, + reachableNodes = reachableNodes, + unreachableNodes = unreachableNodes, + nodeDown = nodesDown + ) + } else Impl[Boolean](false, false, false, false, false, false, false) + } - override type All[T] = Metrics[T] + override type All[T] = Metrics[T] + override type AkkaJar[T] = Jars[T] + + final case class Jars[T](akkaCluster: T, akkaClusterTyped: T) + + override def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = + for { + cluster <- info.get(requiredAkkaJars.akkaCluster) + clusterTyped <- info.get(requiredAkkaJars.akkaClusterTyped) + } yield Jars(cluster, clusterTyped) + + val requiredAkkaJars: AkkaJar[String] = Jars("akka-cluster", "akka-cluster-typed") } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala index db87e5f03..486fab1aa 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -1,6 +1,9 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } +import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo /** * Definition of AkkHttp request related metrics @@ -26,23 +29,23 @@ sealed trait AkkaHttpConnectionMetricsModule extends MetricsModule { } } -object AkkaHttpModule extends MesmerModule with AkkaHttpRequestMetricsModule with AkkaHttpConnectionMetricsModule { +object AkkaHttpModule + extends MesmerModule + with RegisterGlobalConfiguration + with AkkaHttpRequestMetricsModule + with AkkaHttpConnectionMetricsModule { - final case class AkkaHttpModuleConfig(requestTime: Boolean, requestCounter: Boolean, connections: Boolean) - extends AkkaHttpRequestMetricsDef[Boolean] - with AkkaHttpConnectionsMetricsDef[Boolean] - with ModuleConfig { - lazy val enabled: Boolean = - requestTime || requestCounter || connections // module is considered enabled if any metric is collected - } + final case class Impl[T](requestTime: T, requestCounter: T, connections: T) + extends AkkaHttpRequestMetricsDef[T] + with AkkaHttpConnectionsMetricsDef[T] val name: String = "akka-http" - override type Metrics[T] = AkkaHttpRequestMetricsDef[T] with AkkaHttpConnectionsMetricsDef[T] + override type Metrics[T] = AkkaHttpConnectionsMetricsDef[T] with AkkaHttpRequestMetricsDef[T] override type All[T] = Metrics[T] - val defaultConfig = AkkaHttpModuleConfig(true, true, true) + val defaultConfig: Config = Impl[Boolean](true, true, true) protected def extractFromConfig(config: TypesafeConfig): Config = { @@ -62,8 +65,33 @@ object AkkaHttpModule extends MesmerModule with AkkaHttpRequestMetricsModule wit val connections = config .tryValue("connections")(_.getBoolean) .getOrElse(defaultConfig.connections) - AkkaHttpModuleConfig(requestTime = requestTime, requestCounter = requestCounter, connections = connections) - } else AkkaHttpModuleConfig(false, false, false) + Impl[Boolean](requestTime = requestTime, requestCounter = requestCounter, connections = connections) + } else Impl(false, false, false) + + } + + override type AkkaJar[T] = Jars[T] + + final case class Jars[T](akkaHttp: T) + + def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = + info.get(requiredAkkaJars.akkaHttp).map(Jars.apply[Version]) + + val requiredAkkaJars: Jars[String] = Jars("akka-http") + + implicit val combineConfig: Combine[All[Boolean]] = (first, second) => { + Impl( + requestTime = first.requestTime && second.requestTime, + requestCounter = first.requestCounter && second.requestCounter, + connections = first.connections && second.connections + ) + } + implicit val traverseAll: Traverse[All] = new Traverse[All] { + def sequence[T](obj: All[T]): Seq[T] = Seq( + obj.requestTime, + obj.requestCounter, + obj.connections + ) } } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala index 4647fe70a..7eaf42055 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala @@ -1,5 +1,8 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } +import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaPersistenceMetricsModule extends MetricsModule { this: Module => @@ -15,48 +18,79 @@ sealed trait AkkaPersistenceMetricsModule extends MetricsModule { } } -object AkkaPersistenceModule extends MesmerModule with AkkaPersistenceMetricsModule { +object AkkaPersistenceModule extends MesmerModule with AkkaPersistenceMetricsModule with RegisterGlobalConfiguration { override type Metrics[T] = AkkaPersistenceMetricsDef[T] val name: String = "akka-persistence" - final case class AkkaPersistenceModuleConfig( - recoveryTime: Boolean, - recoveryTotal: Boolean, - persistentEvent: Boolean, - persistentEventTotal: Boolean, - snapshot: Boolean - ) extends AkkaPersistenceMetricsDef[Boolean] - with ModuleConfig { - - lazy val enabled: Boolean = recoveryTime || - recoveryTotal || - persistentEvent || - persistentEventTotal || - snapshot - } + final case class Impl[T]( + recoveryTime: T, + recoveryTotal: T, + persistentEvent: T, + persistentEventTotal: T, + snapshot: T + ) extends AkkaPersistenceMetricsDef[T] - val defaultConfig: AkkaPersistenceModule.Result = AkkaPersistenceModuleConfig(true, true, true, true, true) + val defaultConfig: AkkaPersistenceModule.Result = Impl(true, true, true, true, true) protected def extractFromConfig(config: TypesafeConfig): Config = { - val recoveryTime = config - .tryValue("recovery-time")(_.getBoolean) - .getOrElse(defaultConfig.recoveryTime) - val recoveryTotal = config - .tryValue("recovery-total")(_.getBoolean) - .getOrElse(defaultConfig.recoveryTotal) - val persistentEvent = config - .tryValue("persistent-event")(_.getBoolean) - .getOrElse(defaultConfig.persistentEvent) - val persistentEventTotal = config - .tryValue("persistent-event-total")(_.getBoolean) - .getOrElse(defaultConfig.persistentEventTotal) - val snapshot = config - .tryValue("snapshot")(_.getBoolean) - .getOrElse(defaultConfig.snapshot) - - AkkaPersistenceModuleConfig(recoveryTime, recoveryTotal, persistentEvent, persistentEventTotal, snapshot) + + val moduleEnabled = config + .tryValue("enabled")(_.getBoolean) + .getOrElse(true) + if (moduleEnabled) { + val recoveryTime = config + .tryValue("recovery-time")(_.getBoolean) + .getOrElse(defaultConfig.recoveryTime) + val recoveryTotal = config + .tryValue("recovery-total")(_.getBoolean) + .getOrElse(defaultConfig.recoveryTotal) + val persistentEvent = config + .tryValue("persistent-event")(_.getBoolean) + .getOrElse(defaultConfig.persistentEvent) + val persistentEventTotal = config + .tryValue("persistent-event-total")(_.getBoolean) + .getOrElse(defaultConfig.persistentEventTotal) + val snapshot = config + .tryValue("snapshot")(_.getBoolean) + .getOrElse(defaultConfig.snapshot) + + Impl[Boolean](recoveryTime, recoveryTotal, persistentEvent, persistentEventTotal, snapshot) + } else Impl[Boolean](false, false, false, false, false) + + } + + override type All[T] = Metrics[T] + override type AkkaJar[T] = Jars[T] + + final case class Jars[T](akkaPersistence: T, akkaPersistenceTyped: T) + + def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = + for { + persistence <- info.get(requiredAkkaJars.akkaPersistence) + persistenceTyped <- info.get(requiredAkkaJars.akkaPersistenceTyped) + } yield Jars(persistence, persistenceTyped) + + val requiredAkkaJars: AkkaJar[String] = Jars("akka-persistence", "akka-persistence-typed") + + implicit val combineConfig: Combine[All[Boolean]] = (first, second) => { + Impl( + recoveryTime = first.recoveryTime && second.recoveryTime, + recoveryTotal = first.recoveryTotal && second.recoveryTotal, + persistentEvent = first.persistentEvent && second.persistentEvent, + persistentEventTotal = first.persistentEventTotal && second.persistentEventTotal, + snapshot = first.snapshot && second.snapshot + ) + } + + implicit val traverseAll: Traverse[All] = new Traverse[All] { + def sequence[T](obj: All[T]): Seq[T] = Seq( + obj.recoveryTime, + obj.recoveryTotal, + obj.persistentEvent, + obj.persistentEventTotal, + obj.snapshot + ) } - override type All[T] = Metrics[T] } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala index b7ea19871..8f9fd9176 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala @@ -1,5 +1,8 @@ package io.scalac.mesmer.core.module -import com.typesafe.config.{Config => TypesafeConfig} +import com.typesafe.config.{ Config => TypesafeConfig } +import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaStreamMetrics extends MetricsModule { this: Module => @@ -27,67 +30,100 @@ sealed trait AkkaStreamOperatorMetrics extends MetricsModule { } -object AkkaStreamModule extends MesmerModule with AkkaStreamMetrics with AkkaStreamOperatorMetrics { +object AkkaStreamModule + extends MesmerModule + with AkkaStreamMetrics + with AkkaStreamOperatorMetrics + with RegisterGlobalConfiguration { val name: String = "akka-stream" override type Metrics[T] = StreamOperatorMetricsDef[T] with StreamMetricsDef[T] override type All[T] = Metrics[T] - final case class AkkaStreamModuleConfig( - runningStreamsTotal: Boolean, - streamActorsTotal: Boolean, - streamProcessedMessages: Boolean, - processedMessages: Boolean, - operators: Boolean, - demand: Boolean - ) extends StreamOperatorMetricsDef[Boolean] - with StreamMetricsDef[Boolean] - with ModuleConfig { - lazy val enabled: Boolean = runningStreamsTotal || - streamActorsTotal || - streamProcessedMessages || - processedMessages || - operators || - demand - } + final case class Impl[T]( + runningStreamsTotal: T, + streamActorsTotal: T, + streamProcessedMessages: T, + processedMessages: T, + operators: T, + demand: T + ) extends StreamOperatorMetricsDef[T] + with StreamMetricsDef[T] - val defaultConfig: Config = AkkaStreamModuleConfig(true, true, true, true, true, true) + val defaultConfig: Config = Impl(true, true, true, true, true, true) protected def extractFromConfig(config: TypesafeConfig): Config = { - val runningStreams = config - .tryValue("running-streams")(_.getBoolean) - .getOrElse(defaultConfig.runningStreamsTotal) - - val streamActors = config - .tryValue("stream-actors")(_.getBoolean) - .getOrElse(defaultConfig.streamActorsTotal) - - val streamProcessed = config - .tryValue("stream-processed")(_.getBoolean) - .getOrElse(defaultConfig.streamProcessedMessages) - - val operatorProcessed = config - .tryValue("operator-processed")(_.getBoolean) - .getOrElse(defaultConfig.processedMessages) - - val runningOperators = config - .tryValue("running-operators")(_.getBoolean) - .getOrElse(defaultConfig.operators) - - val demand = config - .tryValue("operator-demand")(_.getBoolean) - .getOrElse(defaultConfig.demand) - - AkkaStreamModuleConfig( - runningStreamsTotal = runningStreams, - streamActorsTotal = streamActors, - streamProcessedMessages = streamProcessed, - processedMessages = operatorProcessed, - operators = runningOperators, - demand = demand + val moduleEnabled = config + .tryValue("enabled")(_.getBoolean) + .getOrElse(true) + + if (moduleEnabled) { + val runningStreams = config + .tryValue("running-streams")(_.getBoolean) + .getOrElse(defaultConfig.runningStreamsTotal) + + val streamActors = config + .tryValue("stream-actors")(_.getBoolean) + .getOrElse(defaultConfig.streamActorsTotal) + + val streamProcessed = config + .tryValue("stream-processed")(_.getBoolean) + .getOrElse(defaultConfig.streamProcessedMessages) + + val operatorProcessed = config + .tryValue("operator-processed")(_.getBoolean) + .getOrElse(defaultConfig.processedMessages) + + val runningOperators = config + .tryValue("running-operators")(_.getBoolean) + .getOrElse(defaultConfig.operators) + + val demand = config + .tryValue("operator-demand")(_.getBoolean) + .getOrElse(defaultConfig.demand) + + Impl[Boolean]( + runningStreamsTotal = runningStreams, + streamActorsTotal = streamActors, + streamProcessedMessages = streamProcessed, + processedMessages = operatorProcessed, + operators = runningOperators, + demand = demand + ) + } else Impl[Boolean](false, false, false, false, false, false) + + } + + override type AkkaJar[T] = Jars[T] + + final case class Jars[T](akkaStream: T) + + def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = + info.get(requiredAkkaJars.akkaStream).map(Jars.apply[Version]) + + val requiredAkkaJars: AkkaJar[String] = Jars("akka-stream") + + implicit val combine: Combine[All[Boolean]] = (first, second) => { + Impl( + runningStreamsTotal = first.runningStreamsTotal && second.runningStreamsTotal, + streamActorsTotal = first.streamActorsTotal && second.streamActorsTotal, + streamProcessedMessages = first.streamProcessedMessages && second.streamProcessedMessages, + processedMessages = first.processedMessages && second.processedMessages, + operators = first.operators && second.operators, + demand = first.demand && second.demand ) } + implicit val traverseAll: Traverse[All] = new Traverse[All] { + def sequence[T](obj: All[T]): Seq[T] = Seq( + obj.runningStreamsTotal, + obj.streamActorsTotal, + obj.streamProcessedMessages, + obj.processedMessages, + obj.operators, + obj.demand + ) + } } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala index 9fba1326b..08fad89da 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -2,17 +2,39 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } import io.scalac.mesmer.core.config.MesmerConfigurationBase +import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo trait Module { def name: String - type All[_] - type Config = All[Boolean] with ModuleConfig + type All[T] <: AnyRef + type Config = All[Boolean] def enabled(config: TypesafeConfig): Config + + type AkkaJar[T] + + def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] + + def requiredAkkaJars: AkkaJar[String] } -trait ModuleConfig { - def enabled: Boolean +object Module { + + implicit class AllOps[M[X] <: Module#All[X], T](val value: M[T]) extends AnyVal { + def combine(other: M[T])(implicit combine: Combine[M[T]]): M[T] = combine.combine(value, other) + def exists(check: T => Boolean)(implicit traverse: Traverse[M]): Boolean = traverse.sequence(value).exists(check) + } + + //TODO is there a standard type class? + trait Combine[T] { + def combine(first: T, second: T): T + } + + trait Traverse[F[_]] { + def sequence[T](obj: F[T]): Seq[T] + } + } trait MesmerModule extends Module with MesmerConfigurationBase { @@ -36,3 +58,14 @@ trait TracesModule { override type All[T] <: Traces[T] type Traces[T] } + +trait RegisterGlobalConfiguration extends Module { + + @volatile + private[this] var global: All[Boolean] = _ + + final def registerGlobal(conf: All[Boolean]): Unit = + global = conf + + final def globalConfiguration: Option[All[Boolean]] = if (global ne null) Some(global) else None +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/support/ModulesSupport.scala b/core/src/main/scala/io/scalac/mesmer/core/support/ModulesSupport.scala index 48e953928..7f3680acf 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/support/ModulesSupport.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/support/ModulesSupport.scala @@ -1,8 +1,9 @@ package io.scalac.mesmer.core.support -import io.scalac.mesmer.core.model.Module +//import io.scalac.mesmer.core.model.Module import io.scalac.mesmer.core.model.SupportedVersion import io.scalac.mesmer.core.model.SupportedVersion._ +import io.scalac.mesmer.core.module._ trait ModulesSupport { def akkaActor: SupportedVersion @@ -13,12 +14,21 @@ trait ModulesSupport { } object ModulesSupport extends ModulesSupport { - val akkaHttpModule: Module = Module("akka-http") - val akkaClusterTypedModule: Module = Module("akka-cluster-typed") - val akkaPersistenceTypedModule: Module = Module("akka-persistence-typed") - val akkaActorTypedModule: Module = Module("akka-actor-typed") - val akkaActorModule: Module = Module("akka-actor") - val akkaStreamModule: Module = Module("akka-stream") + + val modules: Set[Module] = Set( + AkkaHttpModule, + AkkaActorModule, + AkkaPersistenceModule, + AkkaStreamModule, + AkkaClusterModule + ) + +// val akkaHttpModule: Module = Module("akka-http") +// val akkaClusterTypedModule: Module = Module("akka-cluster-typed") +// val akkaPersistenceTypedModule: Module = Module("akka-persistence-typed") +// val akkaActorTypedModule: Module = Module("akka-actor-typed") +// val akkaActorModule: Module = Module("akka-actor") +// val akkaStreamModule: Module = Module("akka-stream") private val commonAkkaSupportedVersion: SupportedVersion = majors("2").and(minors("6")).and(patches("8", "9", "10", "11", "12", "13", "14")) diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/LibraryInfo.scala b/core/src/main/scala/io/scalac/mesmer/core/util/LibraryInfo.scala new file mode 100644 index 000000000..6dd5f8ae3 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/util/LibraryInfo.scala @@ -0,0 +1,48 @@ +package io.scalac.mesmer.core.util + +import io.scalac.mesmer.core.model.Version + +import java.util.jar.{ Attributes, Manifest } +import scala.jdk.CollectionConverters._ + +object LibraryInfo { + + /** + * Mapping from library implementation name to found version + */ + type LibraryInfo = Map[String, Version] + + private val ModulePrefix = "module" + + private def matchModules(properties: Map[String, String]): LibraryInfo = + properties.keySet.flatMap { key => + for { + splitted @ Array(ModulePrefix, libraryName) <- Option(key.split('.')) if splitted.length == 2 + versionRaw <- properties.get(key) + version <- Version(versionRaw) + } yield libraryName -> version + }.toMap + + private def fromSystemProperties(): LibraryInfo = + matchModules(System.getProperties.asScala.toMap) + + private def fromJarManifest(classLoader: ClassLoader): LibraryInfo = + classLoader + .getResources("META-INF/MANIFEST.MF") + .asScala + .flatMap { resource => + val manifest = new Manifest(resource.openStream()) + val attributes = manifest.getMainAttributes + + for { + libraryName <- Option(attributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE)) + versionRaw <- Option(attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION)) + version <- Version(versionRaw) + } yield libraryName -> version + } + .toMap + + def extractModulesInformation(classLoader: ClassLoader): LibraryInfo = + fromJarManifest(classLoader) ++ fromSystemProperties() + +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/ModuleInfo.scala b/core/src/main/scala/io/scalac/mesmer/core/util/ModuleInfo.scala deleted file mode 100644 index 9020e8d1e..000000000 --- a/core/src/main/scala/io/scalac/mesmer/core/util/ModuleInfo.scala +++ /dev/null @@ -1,48 +0,0 @@ -package io.scalac.mesmer.core.util - -import java.util.jar.Attributes -import java.util.jar.Manifest - -import scala.jdk.CollectionConverters._ - -import io.scalac.mesmer.core.model.Module -import io.scalac.mesmer.core.model.Version - -object ModuleInfo { - - type Modules = Map[Module, Version] - - private val ModulePrefix = "module" - - private def matchModules(properties: Map[String, String]): Modules = - properties.keySet.flatMap { key => - for { - splitted @ Array(ModulePrefix, module) <- Option(key.split('.')) if splitted.length == 2 - versionRaw <- properties.get(key) - version <- Version(versionRaw) - } yield Module(module) -> version - }.toMap - - private def fromSystemProperties(): Modules = - matchModules(System.getProperties.asScala.toMap) - - private def fromJarManifest(classLoader: ClassLoader): Modules = - classLoader - .getResources("META-INF/MANIFEST.MF") - .asScala - .flatMap { resource => - val manifest = new Manifest(resource.openStream()) - val attributes = manifest.getMainAttributes - - for { - moduleId <- Option(attributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE)) - versionRaw <- Option(attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION)) - version <- Version(versionRaw) - } yield Module(moduleId) -> version - } - .toMap - - def extractModulesInformation(classLoader: ClassLoader): Modules = - fromJarManifest(classLoader) ++ fromSystemProperties() - -} diff --git a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala index 59b65dc66..5eda02348 100644 --- a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala +++ b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala @@ -1,13 +1,47 @@ package io.scalac.mesmer.core.model +import com.typesafe.config.{Config => TypesafeConfig} +import io.scalac.mesmer.core.module.Module +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo import org.scalatest.Inspectors import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import scala.runtime.BoxedUnit + class SupportedModulesTest extends AnyFlatSpec with Matchers with Inspectors { + type Id[T] = T + +// object TestModuleOne extends Module { +// val name: String = "test-module-one" +// +// type All[T] = Any +// +// def enabled(config: TypesafeConfig) = () +// +// override type AkkaJar = Any +// +// def jarsFromLibraryInfo(info: LibraryInfo) = None +// +// val requiredAkkaJars: Any = () +// } + + object TestModuleOne extends Module { + val name: String = "test-module-one" + + override type All[T] = AnyRef + + def enabled(config: TypesafeConfig) = BoxedUnit.UNIT + + override type AkkaJar[T] = Any + + def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = None + + val requiredAkkaJars: Any = () + } "SupportedModules" should "combine required versions" in { - val module = Module("akka.http") + val module = TestModuleOne val firstSupportedVersions = List(Version(2, 6, 8), Version(2, 6, 9)) val secondSupportedVersions = List(Version(2, 6, 9), Version(2, 6, 10)) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala index 4531075f2..97273dda6 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala @@ -5,23 +5,24 @@ import akka.actor.typed.receptionist.Receptionist.Register import akka.actor.typed.scaladsl.Behaviors import akka.cluster.Cluster import akka.util.Timeout -import io.scalac.mesmer.core.model.{Module, SupportedVersion, _} -import io.scalac.mesmer.core.module.{AkkaActorModule, AkkaHttpModule} -import io.scalac.mesmer.core.support.ModulesSupport -import io.scalac.mesmer.core.util.ModuleInfo.Modules -import io.scalac.mesmer.core.util.{ModuleInfo, Timestamp} +import io.scalac.mesmer.core.AkkaDispatcher +import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.Module._ +import io.scalac.mesmer.core.module.{ AkkaHttpModule, AkkaPersistenceModule, _ } +import io.scalac.mesmer.core.util.Timestamp import io.scalac.mesmer.extension.ActorEventsMonitorActor.ReflectiveActorMetricsReader +import io.scalac.mesmer.extension.AkkaMonitoring.ExportInterval import io.scalac.mesmer.extension.actor.MutableActorMetricStorageFactory -import io.scalac.mesmer.extension.config.{AkkaMonitoringConfig, CachingConfig, InstrumentationLibrary} +import io.scalac.mesmer.extension.config.{ AkkaMonitoringConfig, CachingConfig, InstrumentationLibrary } import io.scalac.mesmer.extension.http.CleanableRequestStorage import io.scalac.mesmer.extension.metric.CachingMonitor -import io.scalac.mesmer.extension.persistence.{CleanablePersistingStorage, CleanableRecoveryStorage} +import io.scalac.mesmer.extension.persistence.{ CleanablePersistingStorage, CleanableRecoveryStorage } import io.scalac.mesmer.extension.service._ -import io.scalac.mesmer.extension.upstream.{OpenTelemetryClusterMetricsMonitor, OpenTelemetryHttpMetricsMonitor, OpenTelemetryPersistenceMetricsMonitor, _} +import io.scalac.mesmer.extension.upstream.{ OpenTelemetryClusterMetricsMonitor, _ } import scala.concurrent.duration._ import scala.language.postfixOps -import scala.reflect.ClassTag +import scala.reflect.{ classTag, ClassTag } import scala.util.Try object AkkaMonitoring extends ExtensionId[AkkaMonitoring] { @@ -29,87 +30,17 @@ object AkkaMonitoring extends ExtensionId[AkkaMonitoring] { private val ExportInterval = 5.seconds def createExtension(system: ActorSystem[_]): AkkaMonitoring = { - val config = AkkaMonitoringConfig.apply(system.settings.config) - val monitor = new AkkaMonitoring(system, config) - - val modules: Modules = ModuleInfo.extractModulesInformation(system.dynamicAccess.classLoader) - - modules - .get(ModulesSupport.akkaActorModule) - .fold(system.log.error("No akka version detected"))(_ => startMonitors(monitor, config, modules, ModulesSupport)) - - monitor + val config = AkkaMonitoringConfig(system.settings.config) + new AkkaMonitoring(system, config) } - - private def startMonitors( - monitoring: AkkaMonitoring, - config: AkkaMonitoringConfig, - modules: Modules, - modulesSupport: ModulesSupport - ): Unit = { - import ModulesSupport._ - import monitoring.system - - def initModule( - module: Module, - supportedVersion: SupportedVersion, - autoStart: Boolean, - init: AkkaMonitoring => Unit - ): Unit = - modules - .get(module) - .toRight(s"No version of ${module.name} detected") - .filterOrElse(supportedVersion.supports, s"Unsupported version of ${module.name} detected") - .fold( - err => system.log.error(err), - _ => - if (autoStart) { - system.log.info("Start monitoring module {}", module.name) - init(monitoring) - } else - system.log.info("Supported version of {} detected, but auto-start is set to false", module.name) - ) - - initModule( - akkaActorModule, - modulesSupport.akkaActor, - config.autoStart.akkaActor, - am => { - am.startActorTreeService() - am.startActorMonitor() - am.startStreamMonitor() - } - ) - initModule(akkaHttpModule, modulesSupport.akkaHttp, config.autoStart.akkaHttp, _.startHttpEventListener()) - initModule( - akkaClusterTypedModule, - modulesSupport.akkaClusterTyped, - config.autoStart.akkaCluster, - cm => { - cm.startSelfMemberMonitor() - cm.startClusterEventsMonitor() - cm.startClusterRegionsMonitor() - } - ) - initModule( - akkaPersistenceTypedModule, - modulesSupport.akkaPersistenceTyped, - config.autoStart.akkaPersistence, - cm => cm.startPersistenceMonitoring() - ) - - } - } final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaMonitoringConfig) extends Extension { - import AkkaMonitoring.ExportInterval import system.log private val meter = InstrumentationLibrary.mesmerMeter private val actorSystemConfig = system.settings.config private val openTelemetryClusterMetricsMonitor = OpenTelemetryClusterMetricsMonitor(meter, actorSystemConfig) - import io.scalac.mesmer.core.AkkaDispatcher._ implicit private val timeout: Timeout = 5 seconds @@ -132,75 +63,124 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM nodeName => Some(nodeName.toNode) ) - def startActorTreeService(): Unit = { - val actorSystemMonitor = OpenTelemetryActorSystemMonitor( - meter, - actorSystemConfig - ) + private val dispatcher = AkkaDispatcher.safeDispatcherSelector(system) - val actorConfigurationService = new ConfigBasedConfigurationService(system.settings.config) + /* + We combine global config published by agent with current config to account for actor system having + different config file than agent. We take account only for 4 modules as those are only affected by agent. + */ + private lazy val akkaActorConfig = + AkkaActorModule.globalConfiguration.map { config => + config.combine(AkkaActorModule.enabled(actorSystemConfig)) + } - val serviceRef = system.systemActorOf( - Behaviors - .supervise( - ActorTreeService( - actorSystemMonitor, - clusterNodeName, - ReflectiveActorTreeTraverser, - actorConfigurationService - ) - ) - .onFailure(SupervisorStrategy.restart), - "mesmerActorTreeService" - ) + private lazy val akkaHttpConfig = + AkkaHttpModule.globalConfiguration.map { config => + config.combine(AkkaHttpModule.enabled(actorSystemConfig)) + } - // publish service - system.receptionist ! Register(actorTreeServiceKey, serviceRef.narrow[ActorTreeService.Command]) - } + private lazy val akkaPersistenceConfig = + AkkaPersistenceModule.globalConfiguration.map { config => + config.combine(AkkaPersistenceModule.enabled(actorSystemConfig)) + } - def startActorMonitor(): Unit = { - log.debug("Starting actor monitor") - - val actorMonitor = OpenTelemetryActorMetricsMonitor(meter, AkkaActorModule.fromConfig(actorSystemConfig), actorSystemConfig) - - system.systemActorOf( - Behaviors - .supervise( - ActorEventsMonitorActor( - actorMonitor, - clusterNodeName, - ExportInterval, - new MutableActorMetricStorageFactory, - ReflectiveActorMetricsReader, - () => Timestamp.create() + private lazy val akkaStreamConfig = + AkkaStreamModule.globalConfiguration.map { config => + config.combine(AkkaStreamModule.enabled(actorSystemConfig)) + } + + private def startWithConfig[M <: Module](module: M, config: Option[M#All[Boolean]])(startUp: M#All[Boolean] => Unit)( + implicit traverse: Traverse[M#All] + ): Unit = + config.fold { + log.error("No global configuration found for {} - check if agent is installed.", module.name) + } { moduleConfig => + if (!moduleConfig.exists(_ == true)) { + log.warn(s"Module {} started but no metrics are enabled / supported", module.name) + } else { + log.debug("Starting up module {}", module.name) + startUp(moduleConfig) + } + } + + /** + * Start service that will monitor actor tree structure and publish refs on demand + */ + def startActorTreeService(): Unit = + startWithConfig[AkkaActorModule.type](AkkaActorModule, akkaActorConfig) { _ => + val actorSystemMonitor = OpenTelemetryActorSystemMonitor( + meter, + actorSystemConfig + ) + val actorConfigurationService = new ConfigBasedConfigurationService(system.settings.config) + + val serviceRef = system.systemActorOf( + Behaviors + .supervise( + ActorTreeService( + actorSystemMonitor, + clusterNodeName, + ReflectiveActorTreeTraverser, + actorConfigurationService + ) ) - ) - .onFailure(SupervisorStrategy.restart), - "mesmerActorMonitor", - dispatcherSelector - ) - } + .onFailure(SupervisorStrategy.restart), + "mesmerActorTreeService" + ) - def startStreamMonitor(): Unit = { - log.debug("Start stream monitor") + // publish service + system.receptionist ! Register(actorTreeServiceKey, serviceRef.narrow[ActorTreeService.Command]) + } - val streamOperatorMonitor = OpenTelemetryStreamOperatorMetricsMonitor(meter, actorSystemConfig) + /** + * Start actor that monitor actor metrics + */ + def startActorMonitor(): Unit = + startWithConfig[AkkaActorModule.type](AkkaActorModule, akkaActorConfig) { moduleConfig => + val actorMonitor = + OpenTelemetryActorMetricsMonitor(meter, moduleConfig, actorSystemConfig) - val streamMonitor = CachingMonitor( - OpenTelemetryStreamMetricsMonitor(meter, actorSystemConfig), - CachingConfig.fromConfig(actorSystemConfig, ModulesSupport.akkaStreamModule) - ) + system.systemActorOf( + Behaviors + .supervise( + ActorEventsMonitorActor( + actorMonitor, + clusterNodeName, + ExportInterval, + new MutableActorMetricStorageFactory[ActorKey], + ReflectiveActorMetricsReader, + () => Timestamp.create() + ) + ) + .onFailure(SupervisorStrategy.restart), + "mesmerActorMonitor", + dispatcher + ) + } - system.systemActorOf( - Behaviors - .supervise( - AkkaStreamMonitoring(streamOperatorMonitor, streamMonitor, clusterNodeName) - ) - .onFailure(SupervisorStrategy.restart), - "mesmerStreamMonitor", - dispatcherSelector - ) - } + /** + * Start actor monitoring stream performance + */ + def startStreamMonitor(): Unit = + startWithConfig[AkkaStreamModule.type](AkkaStreamModule, akkaStreamConfig) { moduleConfig => + log.debug("Start stream monitor") + val streamOperatorMonitor = OpenTelemetryStreamOperatorMetricsMonitor(meter, actorSystemConfig) + + val streamMonitor = CachingMonitor( + OpenTelemetryStreamMetricsMonitor(meter, actorSystemConfig), + CachingConfig.fromConfig(actorSystemConfig, AkkaStreamModule) + ) + + system.systemActorOf( + Behaviors + .supervise( + AkkaStreamMonitoring(streamOperatorMonitor, streamMonitor, clusterNodeName) + ) + .onFailure(SupervisorStrategy.restart), + "mesmerStreamMonitor", + dispatcher + ) + } def startSelfMemberMonitor(): Unit = startClusterMonitor(ClusterSelfNodeEventsActor) @@ -211,7 +191,7 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM private def startClusterMonitor[T <: ClusterMonitorActor: ClassTag]( actor: T ): Unit = { - val name = implicitly[ClassTag[T]].runtimeClass.getSimpleName + val name = classTag[T].runtimeClass.getSimpleName clusterNodeName.fold { log.error("ActorSystem is not properly configured to start cluster monitor of type {}", name) } { _ => @@ -221,57 +201,57 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM .supervise(actor(openTelemetryClusterMetricsMonitor)) .onFailure[Exception](SupervisorStrategy.restart), name, - dispatcherSelector + dispatcher ) } } - def startPersistenceMonitoring(): Unit = { - log.debug("Starting PersistenceEventsListener") - - val cachingConfig = CachingConfig.fromConfig(actorSystemConfig, ModulesSupport.akkaPersistenceTypedModule) - val openTelemetryPersistenceMonitor = CachingMonitor( - OpenTelemetryPersistenceMetricsMonitor(meter, actorSystemConfig), - cachingConfig - ) - val pathService = new CachingPathService(cachingConfig) - - system.systemActorOf( - Behaviors - .supervise( - WithSelfCleaningState - .clean(CleanableRecoveryStorage.withConfig(config.cleaning)) - .every(config.cleaning.every)(rs => - WithSelfCleaningState - .clean(CleanablePersistingStorage.withConfig(config.cleaning)) - .every(config.cleaning.every) { ps => - PersistenceEventsActor.apply( - openTelemetryPersistenceMonitor, - rs, - ps, - pathService, - clusterNodeName - ) - } - ) - ) - .onFailure[Exception](SupervisorStrategy.restart), - "persistenceAgentMonitor", - dispatcherSelector - ) - } - - def startHttpEventListener(): Unit = { - - val httpModuleConfig = AkkaHttpModule.fromConfig(actorSystemConfig) + /** + * Start actor responsible for measuring akka persistence metrics + */ + def startPersistenceMonitor(): Unit = + startWithConfig[AkkaPersistenceModule.type](AkkaPersistenceModule, akkaPersistenceConfig) { _ => + val cachingConfig = CachingConfig.fromConfig(actorSystemConfig, AkkaPersistenceModule) + val openTelemetryPersistenceMonitor = CachingMonitor( + OpenTelemetryPersistenceMetricsMonitor(meter, actorSystemConfig), + cachingConfig + ) + val pathService = new CachingPathService(cachingConfig) - if (httpModuleConfig.enabled) { - log.info("Starting local http event listener") + system.systemActorOf( + Behaviors + .supervise( + WithSelfCleaningState + .clean(CleanableRecoveryStorage.withConfig(config.cleaning)) + .every(config.cleaning.every)(rs => + WithSelfCleaningState + .clean(CleanablePersistingStorage.withConfig(config.cleaning)) + .every(config.cleaning.every) { ps => + PersistenceEventsActor.apply( + openTelemetryPersistenceMonitor, + rs, + ps, + pathService, + clusterNodeName + ) + } + ) + ) + .onFailure[Exception](SupervisorStrategy.restart), + "persistenceAgentMonitor", + dispatcher + ) + } - val cachingConfig = CachingConfig.fromConfig(actorSystemConfig, ModulesSupport.akkaHttpModule) + /** + * Start http actor responsible for calculating akka http metrics + */ + def startHttpMonitor(): Unit = + startWithConfig[AkkaHttpModule.type](AkkaHttpModule, akkaHttpConfig) { moduleConfig => + val cachingConfig = CachingConfig.fromConfig(actorSystemConfig, AkkaHttpModule) val openTelemetryHttpMonitor = - CachingMonitor(OpenTelemetryHttpMetricsMonitor(meter, httpModuleConfig, actorSystemConfig), cachingConfig) + CachingMonitor(OpenTelemetryHttpMetricsMonitor(meter, moduleConfig, actorSystemConfig), cachingConfig) val openTelemetryHttpConnectionMonitor = CachingMonitor(OpenTelemetryHttpConnectionMetricsMonitor(meter, actorSystemConfig), cachingConfig) @@ -290,12 +270,37 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM ) .onFailure[Exception](SupervisorStrategy.restart), "httpEventMonitor", - dispatcherSelector + dispatcher ) - } else { - log.warn(s"Module ${AkkaHttpModule.name} set to auto-start but it's disabled") + } + + private def autoStart(): Unit = { + import config.{autoStart => autoStartConfig} + + if (autoStartConfig.akkaActor || autoStartConfig.akkaStream) { + startActorTreeService() + } + if (autoStartConfig.akkaStream) { + startStreamMonitor() + } + if (autoStartConfig.akkaActor) { + startActorMonitor() + } + if (autoStartConfig.akkaHttp) { + startHttpMonitor() + } + if (autoStartConfig.akkaHttp) { + startPersistenceMonitor() + } + + if (autoStartConfig.akkaCluster) { + startClusterEventsMonitor() + startClusterRegionsMonitor() + startSelfMemberMonitor() } } + autoStart() + } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala index 9d0446942..d238e63a2 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala @@ -3,26 +3,26 @@ package io.scalac.mesmer.extension import akka.actor.typed._ import akka.actor.typed.receptionist.Receptionist.Register import akka.actor.typed.scaladsl.adapter._ -import akka.actor.typed.scaladsl.{ActorContext, Behaviors, TimerScheduler} -import akka.actor.{ActorRef, typed} +import akka.actor.typed.scaladsl.{ ActorContext, Behaviors, TimerScheduler } +import akka.actor.{ typed, ActorRef } import akka.util.Timeout import io.scalac.mesmer.core.akka.model.PushMetrics import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.core.event.Service.streamService import io.scalac.mesmer.core.event.StreamEvent -import io.scalac.mesmer.core.event.StreamEvent.{LastStreamStats, StreamInterpreterStats} -import io.scalac.mesmer.core.model.Tag.{StageName, StreamName} +import io.scalac.mesmer.core.event.StreamEvent.{ LastStreamStats, StreamInterpreterStats } +import io.scalac.mesmer.core.model.Tag.{ StageName, StreamName } import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.model.stream.{ConnectionStats, StageInfo} -import io.scalac.mesmer.core.support.ModulesSupport +import io.scalac.mesmer.core.model.stream.{ ConnectionStats, StageInfo } +import io.scalac.mesmer.core.module.AkkaStreamModule import io.scalac.mesmer.extension.AkkaStreamMonitoring._ -import io.scalac.mesmer.extension.config.{BufferConfig, CachingConfig} +import io.scalac.mesmer.extension.config.{ BufferConfig, CachingConfig } import io.scalac.mesmer.extension.metric.MetricObserver.Result -import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.{EagerLabels, Labels => GlobalLabels} +import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.{ EagerLabels, Labels => GlobalLabels } import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.Labels -import io.scalac.mesmer.extension.metric.{StreamMetricsMonitor, StreamOperatorMetricsMonitor} +import io.scalac.mesmer.extension.metric.{ StreamMetricsMonitor, StreamOperatorMetricsMonitor } import io.scalac.mesmer.extension.service.ActorTreeService.Command.GetActors -import io.scalac.mesmer.extension.service.{ActorTreeService, actorTreeServiceKey} +import io.scalac.mesmer.extension.service.{ actorTreeServiceKey, ActorTreeService } import io.scalac.mesmer.extension.util.GenericBehaviors import java.util @@ -30,10 +30,10 @@ import java.util.concurrent.atomic.AtomicReference import scala.annotation.tailrec import scala.collection.mutable import scala.collection.mutable.ListBuffer -import scala.concurrent.duration.{FiniteDuration, _} +import scala.concurrent.duration.{ FiniteDuration, _ } import scala.jdk.CollectionConverters._ import scala.jdk.DurationConverters._ -import scala.util.{Failure, Success} +import scala.util.{ Failure, Success } object AkkaStreamMonitoring { @@ -221,12 +221,11 @@ final class AkkaStreamMonitoring( node: Option[Node], actorTreeService: typed.ActorRef[ActorTreeService.Command] ) { - import ModulesSupport._ private implicit val timeout: Timeout = streamCollectionTimeout - private val cachingConfig = CachingConfig.fromConfig(context.system.settings.config, akkaStreamModule) - private val bufferConfig = BufferConfig.fromConfig(context.system.settings.config, akkaStreamModule) + private val cachingConfig = CachingConfig.fromConfig(context.system.settings.config, AkkaStreamModule) + private val bufferConfig = BufferConfig.fromConfig(context.system.settings.config, AkkaStreamModule) private val indexCache = ConnectionsIndexCache.bounded(cachingConfig.maxEntries) private val operationsBoundMonitor = streamOperatorMonitor.bind() private val boundStreamMonitor = streamMonitor.bind(EagerLabels(node)) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala index 4d63adeb9..332141130 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala @@ -12,14 +12,14 @@ case class AkkaMonitoringConfig( cleaning: CleaningSettings ) -case class AutoStartSettings(akkaActor: Boolean, akkaHttp: Boolean, akkaPersistence: Boolean, akkaCluster: Boolean) +case class AutoStartSettings(akkaActor: Boolean, akkaHttp: Boolean, akkaPersistence: Boolean, akkaCluster: Boolean, akkaStream: Boolean) object AkkaMonitoringConfig { private val autoStartDefaults = - AutoStartSettings(akkaActor = false, akkaHttp = false, akkaCluster = false, akkaPersistence = false) + AutoStartSettings(akkaActor = false, akkaHttp = false, akkaCluster = false, akkaPersistence = false, akkaStream = false) private val cleaningSettingsDefaults = CleaningSettings(20.seconds, 5.second) private val akkaMonitoringDefaults = AkkaMonitoringConfig(autoStartDefaults, cleaningSettingsDefaults) @@ -37,7 +37,10 @@ object AkkaMonitoringConfig { autoStartConfig.tryValue("akka-persistence")(_.getBoolean).getOrElse(autoStartDefaults.akkaPersistence) val akkaCluster = autoStartConfig.tryValue("akka-cluster")(_.getBoolean).getOrElse(autoStartDefaults.akkaCluster) - AutoStartSettings(akkaActor, akkaHttp, akkaPersistence, akkaCluster) + val akkaStream = + autoStartConfig.tryValue("akka-stream")(_.getBoolean).getOrElse(autoStartDefaults.akkaStream) + + AutoStartSettings(akkaActor, akkaHttp, akkaPersistence, akkaCluster, akkaStream) } .getOrElse(autoStartDefaults) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala index 67d58cc94..6a6a1bd06 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala @@ -1,9 +1,8 @@ package io.scalac.mesmer.extension.config import com.typesafe.config.Config - -import io.scalac.mesmer.core.model.Module import io.scalac.mesmer.core.config.ConfigurationUtils._ +import io.scalac.mesmer.core.module.Module object BufferConfig { private val DefaultSize = 1024 diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala index fcfdcd94b..486c75a4b 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala @@ -2,7 +2,7 @@ package io.scalac.mesmer.extension.config import com.typesafe.config.Config import io.scalac.mesmer.core.config.ConfigurationUtils._ -import io.scalac.mesmer.core.model.Module +import io.scalac.mesmer.core.module.Module case class CachingConfig(maxEntries: Int) From 95af6faea753e2dab234ae9f09bbcd4aab04645b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Fri, 25 Jun 2021 16:02:40 +0200 Subject: [PATCH 10/31] Fix agent tests --- .../stream/ActorGraphInterpreterAdvice.java | 4 +- .../scala/io/scalac/mesmer/agent/Agent.scala | 18 +-- .../actor/AkkaMailboxInstrumentations.scala | 19 +-- .../impl/ActorUnhandledInstrumentation.scala | 2 +- .../persistence/AkkaPersistenceAgent.scala | 21 ++-- .../persistence/impl/PersistenceUtils.scala | 19 +++ .../PersistingEventSuccessInterceptor.scala | 1 + .../impl/RecoveryCompletedInterceptor.scala | 38 ++---- .../impl/RecoveryStartedInterceptor.scala | 35 ++---- .../impl/StoringSnapshotInterceptor.scala | 58 ++++------ .../agent/akka/stream/AkkaStreamAgent.scala | 56 +++++---- ...orGraphInterpreterProcessEventAdvice.scala | 8 +- .../impl/GraphInterpreterPushAdvice.scala | 2 - .../PhasedFusingActorMaterializerAdvice.scala | 9 +- .../i13n/AgentInstrumentationFactory.scala | 19 +-- .../util/i13n/InstrumentModuleFactory.scala | 22 +++- .../mesmer/agent/util/i13n/package.scala | 18 ++- agent/src/test/resources/logback-test.xml | 1 + .../agent/AgentInstrumentationTest.scala | 12 +- .../io/scalac/mesmer/agent/AgentTest.scala | 15 ++- .../agent/akka/AkkaActorAgentTest.scala | 28 ++--- .../mesmer/agent/akka/AkkaHttpAgentTest.scala | 109 +++++++----------- ...c.scala => AkkaPersistenceAgentTest.scala} | 15 +-- .../agent/akka/actor/ActorEventTest.scala | 6 +- .../agent/akka/actor/ActorMailboxTest.scala | 39 +++---- .../akka/stream/AkkaStreamAgentTest.scala | 38 +++--- .../mesmer/agent/utils/InstallAgent.scala | 81 +++---------- build.sbt | 1 - .../core/util/ReflectionFieldUtils.scala | 8 +- 29 files changed, 312 insertions(+), 390 deletions(-) create mode 100644 agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistenceUtils.scala rename agent/src/test/scala/io/scalac/mesmer/agent/akka/{AkkaPersistenceAgentSpec.scala => AkkaPersistenceAgentTest.scala} (91%) diff --git a/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterAdvice.java b/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterAdvice.java index 63140fb39..e6a1f8e61 100644 --- a/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterAdvice.java +++ b/agent/src/main/java/io/scalac/mesmer/agent/akka/stream/ActorGraphInterpreterAdvice.java @@ -12,8 +12,8 @@ public class ActorGraphInterpreterAdvice { @Advice.OnMethodExit public static void overrideReceive(@Advice.Return(readOnly = false) PartialFunction result, - @Advice.This Actor self) { - result = ActorGraphInterpreterDecorator.addCollectionReceive(result, self); + @Advice.This Object self) { + result = ActorGraphInterpreterDecorator.addCollectionReceive(result, (Actor) self); } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala index 672242163..a4c9162ff 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala @@ -8,9 +8,9 @@ import java.lang.instrument.Instrumentation object Agent { - def apply(head: AgentInstrumentation, tail: AgentInstrumentation*): Agent = new Agent((head +: tail).toSet) + def apply(head: AgentInstrumentation, tail: AgentInstrumentation*): Agent = new Agent(Set.from(head +: tail)) - val empty: Agent = new Agent(Set.empty) + val empty: Agent = new Agent(Set.empty[AgentInstrumentation]) class LoadingResult(val fqns: Set[String]) { import LoadingResult.{ logger => loadingLogger } @@ -45,10 +45,10 @@ object Agent { object AgentInstrumentation { - def apply(name: String, tags: Set[String])( + def apply(name: String, tags: Set[String], deferred: Boolean)( installation: (AgentBuilder, Instrumentation) => LoadingResult ): AgentInstrumentation = - new AgentInstrumentation(name, tags) { + new AgentInstrumentation(name, tags, deferred) { def apply(builder: AgentBuilder, instrumentation: Instrumentation): LoadingResult = installation(builder, instrumentation) } @@ -57,9 +57,11 @@ object AgentInstrumentation { sealed abstract case class AgentInstrumentation( name: String, - tags: Set[String] + tags: Set[String], + private val deferred: Boolean ) extends ((AgentBuilder, Instrumentation) => LoadingResult) - with Equals { + with Equals + with Ordered[AgentInstrumentation] { override def hashCode(): Int = name.hashCode() @@ -70,6 +72,8 @@ sealed abstract case class AgentInstrumentation( tags == that.tags && name == that.name case _ => false } + + final def compare(that: AgentInstrumentation): Int = Ordering[Boolean].compare(this.deferred, that.deferred) } final case class Agent private (private[agent] val instrumentations: Set[AgentInstrumentation]) extends { @@ -80,7 +84,7 @@ final case class Agent private (private[agent] val instrumentations: Set[AgentIn def ++(other: AgentInstrumentation): Agent = Agent(instrumentations + other) def installOn(builder: AgentBuilder, instrumentation: Instrumentation): LoadingResult = - instrumentations.map { agentInstrumentation => + instrumentations.toSeq.sorted.map { agentInstrumentation => agentInstrumentation(builder, instrumentation) }.fold(LoadingResult.empty)(_ ++ _) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala index c9a9f577a..a96c2fb72 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala @@ -1,21 +1,21 @@ package io.scalac.mesmer.agent.akka.actor -import akka.AkkaMirror.{ActorRefWithCell, Cell} +import akka.AkkaMirror.{ ActorRefWithCell, Cell } import akka.dispatch._ import akka.util.BoundedBlockingQueue -import akka.{actor => classic} +import akka.{ actor => classic } import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.agent.{Agent, AgentInstrumentation} +import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } import io.scalac.mesmer.core.util.ReflectionFieldUtils import io.scalac.mesmer.extension.actor.ActorCellDecorator import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription -import net.bytebuddy.implementation.bind.annotation.{SuperCall, This} -import net.bytebuddy.implementation.{FieldAccessor, MethodDelegation} +import net.bytebuddy.implementation.bind.annotation.{ SuperCall, This } +import net.bytebuddy.implementation.{ FieldAccessor, MethodDelegation } import net.bytebuddy.matcher.ElementMatchers -import java.util.concurrent.{BlockingQueue, Callable, LinkedBlockingQueue} -import scala.reflect.{ClassTag, classTag} +import java.util.concurrent.{ BlockingQueue, Callable, LinkedBlockingQueue } +import scala.reflect.{ classTag, ClassTag } object BoundedNodeMessageQueueAdvice { @@ -113,7 +113,7 @@ private[actor] trait AkkaMailboxInstrumentations { ) .defineField[BlockingQueue[_]](ProxiedQueue.queueFieldName) .visit[ProxiedQueue](constructor) - .intercept(ElementMatchers.named("queue"), FieldAccessor.ofField(ProxiedQueue.queueFieldName)) + .intercept(named("queue").method, FieldAccessor.ofField(ProxiedQueue.queueFieldName)) /** * Instrumentation that increase dropped messages if enqueue was a failure and bounded queue is in use @@ -124,6 +124,7 @@ private[actor] trait AkkaMailboxInstrumentations { ) .visit(BoundedNodeMessageQueueAdvice, "enqueue") - protected val boundedQueueAgent = Agent(boundedQueueBasesMailbox, boundedQueueBasedMailboxes, boundedMessageQueueSemantics) + protected val boundedQueueAgent = + Agent(boundedQueueBasesMailbox, boundedQueueBasedMailboxes, boundedMessageQueueSemantics) } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala index 8d36c918c..dde91fe3d 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala @@ -1,7 +1,7 @@ package io.scalac.mesmer.agent.akka.actor.impl import io.scalac.mesmer.extension.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{OnMethodExit, This} +import net.bytebuddy.asm.Advice.{ OnMethodExit, This } object ActorUnhandledInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala index d84f86dd3..8869cc61a 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala @@ -3,9 +3,8 @@ package io.scalac.mesmer.agent.akka.persistence import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.akka.persistence.impl._ import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.model.{SupportedModules, Version} +import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaPersistenceModule -import io.scalac.mesmer.core.support.ModulesSupport import org.slf4j.LoggerFactory object AkkaPersistenceAgent @@ -23,10 +22,10 @@ object AkkaPersistenceAgent ): (Agent, AkkaPersistenceModule.AkkaPersistenceMetricsDef[Boolean]) = { val recoveryTimeAgent = if (config.recoveryTime) recoveryTime(jars) else None - val recoveryTotalAgent = if (config.recoveryTotal) recoveryTime(jars) else None - val persistentEventAgent = if (config.persistentEvent) recoveryTime(jars) else None - val persistentEventTotalAgent = if (config.persistentEventTotal) recoveryTime(jars) else None - val snapshotAgent = if (config.snapshot) recoveryTime(jars) else None + val recoveryTotalAgent = if (config.recoveryTotal) recoveryTotal(jars) else None + val persistentEventAgent = if (config.persistentEvent) persistentEvent(jars) else None + val persistentEventTotalAgent = if (config.persistentEventTotal) persistentEventTotal(jars) else None + val snapshotAgent = if (config.snapshot) snapshot(jars) else None val resultantAgent = recoveryTimeAgent.getOrElse(Agent.empty) ++ @@ -70,14 +69,14 @@ object AkkaPersistenceAgent */ val recoveryStartedAgent = instrument("akka.persistence.typed.internal.ReplayingSnapshot".fqcnWithTags(recoveryTag)) - .visit(RecoveryStartedInterceptor, "onRecoveryStart") + .intercept(RecoveryStartedInterceptor,"onRecoveryStart") /** * Instrumentation to fire event on persistent actor recovery complete */ val recoveryCompletedAgent = instrument("akka.persistence.typed.internal.ReplayingEvents".fqcnWithTags(recoveryTag)) - .visit(RecoveryCompletedInterceptor, "onRecoveryComplete") + .intercept(RecoveryCompletedInterceptor,"onRecoveryComplete") Agent(recoveryStartedAgent, recoveryCompletedAgent) } @@ -87,13 +86,13 @@ object AkkaPersistenceAgent */ private val eventWriteSuccessInstrumentation = instrument("akka.persistence.typed.internal.Running".fqcnWithTags("persistent_event")) - .visit(PersistingEventSuccessInterceptor, "onWriteSuccess") - .visit(JournalInteractionsInterceptor, "onWriteInitiated") + .intercept(PersistingEventSuccessInterceptor, "onWriteSuccess") + .intercept(JournalInteractionsInterceptor,"onWriteInitiated") /** * Instrumentation to fire event when snapshot is stored */ private val snapshotLoadingInstrumentation = instrument("akka.persistence.typed.internal.Running$StoringSnapshot".fqcnWithTags("snapshot_created")) - .visit(StoringSnapshotInterceptor, "onSaveSnapshotResponse") + .intercept(StoringSnapshotInterceptor,"onSaveSnapshotResponse") } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistenceUtils.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistenceUtils.scala new file mode 100644 index 000000000..47ddd0554 --- /dev/null +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistenceUtils.scala @@ -0,0 +1,19 @@ +package io.scalac.mesmer.agent.akka.persistence.impl + +import io.scalac.mesmer.core.util.ReflectionFieldUtils + +private[impl] trait PersistenceUtils { + +// protected val (elo, melon) = ("String", "elo") + + protected lazy val replayingSnapshotsSetupGetter = + ReflectionFieldUtils.getGetter("akka.persistence.typed.internal.ReplayingSnapshot", "setup") + + protected lazy val replayingEventsSetupGetter = + ReflectionFieldUtils.getGetter("akka.persistence.typed.internal.ReplayingEvents", "setup") + + protected lazy val behaviorSetupPersistenceId = + ReflectionFieldUtils.getGetter("akka.persistence.typed.internal.BehaviorSetup", "persistenceId") + + +} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala index c1afcbf94..97bb1fbaf 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala @@ -7,6 +7,7 @@ import io.scalac.mesmer.core.event.PersistenceEvent.PersistingEventFinished import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.Timestamp import net.bytebuddy.asm.Advice._ + object PersistingEventSuccessInterceptor { @OnMethodEnter diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala index 2f3dab810..3279dec08 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala @@ -6,31 +6,15 @@ import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.RecoveryFinished import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.util.Timestamp +import io.scalac.mesmer.core.util.{ ReflectionFieldUtils, Timestamp } import net.bytebuddy.asm.Advice -import scala.util.Try +object RecoveryCompletedInterceptor extends PersistenceUtils { -object RecoveryCompletedInterceptor { - private lazy val setupField = { - val setup = Class.forName("akka.persistence.typed.internal.ReplayingEvents").getDeclaredField("setup") - setup.setAccessible(true) - setup - } - - private lazy val persistenceIdField = { - val persistenceId = Class.forName("akka.persistence.typed.internal.BehaviorSetup").getDeclaredField("persistenceId") - persistenceId.setAccessible(true) - persistenceId - } + private lazy val persistenceIdHandle = + ReflectionFieldUtils.chain(replayingEventsSetupGetter, behaviorSetupPersistenceId) - val persistenceIdExtractor: Any => Try[PersistenceId] = ref => { - for { - setup <- Try(setupField.get(ref)) - persistenceId <- Try(persistenceIdField.get(setup)) - } yield persistenceId.asInstanceOf[PersistenceId] - } import AkkaPersistenceAgent.logger @Advice.OnMethodEnter def enter( @@ -39,14 +23,12 @@ object RecoveryCompletedInterceptor { ): Unit = { val path = actorContext.self.path.toPath logger.trace("Recovery completed for {}", path) + val persistenceId = persistenceIdHandle.invoke(thiz).asInstanceOf[PersistenceId] + + EventBus(actorContext.system) + .publishEvent( + RecoveryFinished(path, persistenceId.id, Timestamp.create()) + ) - persistenceIdExtractor(thiz).fold( - _.printStackTrace(), - persistenceId => - EventBus(actorContext.system) - .publishEvent( - RecoveryFinished(path, persistenceId.id, Timestamp.create()) - ) - ) } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala index c3a242923..1fe7a07be 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala @@ -6,31 +6,13 @@ import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.RecoveryStarted import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.util.Timestamp +import io.scalac.mesmer.core.util.{ ReflectionFieldUtils, Timestamp } import net.bytebuddy.asm.Advice -import scala.util.Try - -object RecoveryStartedInterceptor { +object RecoveryStartedInterceptor extends PersistenceUtils { import AkkaPersistenceAgent.logger - private val setupField = { - val setup = Class.forName("akka.persistence.typed.internal.ReplayingSnapshot").getDeclaredField("setup") - setup.setAccessible(true) - setup - } - private val persistenceIdField = { - val persistenceId = Class.forName("akka.persistence.typed.internal.BehaviorSetup").getDeclaredField("persistenceId") - persistenceId.setAccessible(true) - persistenceId - } - - val persistenceIdExtractor: Any => Try[PersistenceId] = ref => { - for { - setup <- Try(setupField.get(ref)) - persistenceId <- Try(persistenceIdField.get(setup)) - } yield persistenceId.asInstanceOf[PersistenceId] - } + lazy val persistenceIdHandle = ReflectionFieldUtils.chain(replayingSnapshotsSetupGetter, behaviorSetupPersistenceId) @Advice.OnMethodEnter def enter( @@ -39,11 +21,10 @@ object RecoveryStartedInterceptor { ): Unit = { val path = context.self.path.toPath logger.trace("Started actor {} recovery", path) - persistenceIdExtractor(thiz).fold( - _.printStackTrace(), - persistenceId => - EventBus(context.system) - .publishEvent(RecoveryStarted(path, persistenceId.id, Timestamp.create())) - ) + + val persistenceId = persistenceIdHandle.invoke(thiz).asInstanceOf[PersistenceId] + + EventBus(context.system) + .publishEvent(RecoveryStarted(path, persistenceId.id, Timestamp.create())) } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala index 4fb72b999..a7807d1a9 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala @@ -1,51 +1,39 @@ package io.scalac.mesmer.agent.akka.persistence.impl -import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext} +import akka.actor.typed.scaladsl.{ AbstractBehavior, ActorContext } import akka.persistence.SaveSnapshotSuccess -import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.SnapshotCreated import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.util.Timestamp +import io.scalac.mesmer.core.util.{ ReflectionFieldUtils, Timestamp } import net.bytebuddy.asm.Advice._ -import scala.util.Try +object StoringSnapshotInterceptor extends PersistenceUtils { -object StoringSnapshotInterceptor { - import AkkaPersistenceAgent.logger - - private lazy val contextField = Try { - val context = Class - .forName("akka.actor.typed.scaladsl.AbstractBehavior") - .getDeclaredField("context") - context.setAccessible(true) - context - } + private lazy val contextGetter = + ReflectionFieldUtils.getGetter("akka.actor.typed.scaladsl.AbstractBehavior", "context") @OnMethodEnter def onSaveSnapshotResponse( @Argument(0) response: AnyRef, @This self: AbstractBehavior[_] - ): Unit = - contextField - .map(_.get(self).asInstanceOf[ActorContext[_]]) - .fold( - ex => logger.error("Couldn't find field context", ex), - context => - response match { - case SaveSnapshotSuccess(meta) => - context.log.trace("Snapshot for {} created", meta.persistenceId) - EventBus(context.system) - .publishEvent( - SnapshotCreated( - context.self.path.toPath, - meta.persistenceId, - meta.sequenceNr, - Timestamp.create() - ) - ) - case _ => - } - ) + ): Unit = { + val context = contextGetter.invoke(self).asInstanceOf[ActorContext[_]] + response match { + case SaveSnapshotSuccess(meta) => + context.log.trace("Snapshot for {} created", meta.persistenceId) + EventBus(context.system) + .publishEvent( + SnapshotCreated( + context.self.path.toPath, + meta.persistenceId, + meta.sequenceNr, + Timestamp.create() + ) + ) + case _ => + } + + } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala index 2876d9883..59fb1ac1d 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala @@ -1,13 +1,17 @@ package io.scalac.mesmer.agent.akka.stream import akka.ActorGraphInterpreterAdvice -import akka.actor.Props import akka.stream.GraphStageIslandAdvice -import akka.stream.impl.fusing.{ActorGraphInterpreterProcessEventAdvice, ActorGraphInterpreterTryInitAdvice} +import akka.stream.impl.fusing.{ ActorGraphInterpreterProcessEventAdvice, ActorGraphInterpreterTryInitAdvice } import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.akka.stream.impl.{ConnectionOps, GraphInterpreterPushAdvice, PhasedFusingActorMaterializerAdvice} +import io.scalac.mesmer.agent.akka.stream.impl.{ + ConnectionOps, + GraphInterpreterPullAdvice, + GraphInterpreterPushAdvice, + PhasedFusingActorMaterializerAdvice +} import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.model.{SupportedModules, SupportedVersion, Version} +import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaStreamModule object AkkaStreamAgent @@ -15,19 +19,21 @@ object AkkaStreamAgent with AkkaStreamModule.StreamMetricsDef[AkkaStreamModule.AkkaJar[Version] => Option[Agent]] with AkkaStreamModule.StreamOperatorMetricsDef[AkkaStreamModule.AkkaJar[Version] => Option[Agent]] { - /** * @param config configuration of features that are wanted by the user * @param jars versions of required jars to deduce which features can be enabled * @return Resulting agent and resulting configuration based on runtime properties */ - protected def agent(config: AkkaStreamModule.All[Boolean], jars: AkkaStreamModule.Jars[Version]): (Agent, AkkaStreamModule.All[Boolean]) = { - val runningStreamsTotalAgent = if (config.runningStreamsTotal) runningStreamsTotal(jars) else None - val streamActorsTotalAgent = if (config.runningStreamsTotal) streamActorsTotal(jars) else None + protected def agent( + config: AkkaStreamModule.All[Boolean], + jars: AkkaStreamModule.Jars[Version] + ): (Agent, AkkaStreamModule.All[Boolean]) = { + val runningStreamsTotalAgent = if (config.runningStreamsTotal) runningStreamsTotal(jars) else None + val streamActorsTotalAgent = if (config.runningStreamsTotal) streamActorsTotal(jars) else None val streamProcessedMessagesAgent = if (config.runningStreamsTotal) streamProcessedMessages(jars) else None - val processedMessagesAgent = if (config.runningStreamsTotal) processedMessages(jars) else None - val operatorsAgent = if (config.runningStreamsTotal) operators(jars) else None - val demandAgent = if (config.runningStreamsTotal) demand(jars) else None + val processedMessagesAgent = if (config.runningStreamsTotal) processedMessages(jars) else None + val operatorsAgent = if (config.runningStreamsTotal) operators(jars) else None + val demandAgent = if (config.runningStreamsTotal) demand(jars) else None val resultantAgent = runningStreamsTotalAgent.getOrElse(Agent.empty) ++ @@ -38,12 +44,12 @@ object AkkaStreamAgent demandAgent.getOrElse(Agent.empty) val enabled = AkkaStreamModule.Impl( - runningStreamsTotal = runningStreamsTotalAgent.isDefined, - streamActorsTotal = streamActorsTotalAgent.isDefined, - streamProcessedMessages = streamProcessedMessagesAgent.isDefined, - processedMessages = processedMessagesAgent.isDefined, - operators = operatorsAgent.isDefined, - demand = demandAgent.isDefined + runningStreamsTotal = runningStreamsTotalAgent.isDefined, + streamActorsTotal = streamActorsTotalAgent.isDefined, + streamProcessedMessages = streamProcessedMessagesAgent.isDefined, + processedMessages = processedMessagesAgent.isDefined, + operators = operatorsAgent.isDefined, + demand = demandAgent.isDefined ) (resultantAgent, enabled) } @@ -52,7 +58,8 @@ object AkkaStreamAgent lazy val streamActorsTotal: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) - lazy val streamProcessedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) + lazy val streamProcessedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedImplementations) lazy val processedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) @@ -64,8 +71,9 @@ object AkkaStreamAgent * actorOf methods is called when island decide to materialize itself */ private val phasedFusingActorMaterializerAgentInstrumentation = - instrument("akka.stream.impl.PhasedFusingActorMaterializer".fqcn) - .visit(PhasedFusingActorMaterializerAdvice, method("actorOf").takesArguments[Props, String]) + instrument(hierarchy("akka.stream.impl.ExtendedActorMaterializer".fqcn)) + .visit(PhasedFusingActorMaterializerAdvice, method("actorOf")) + .deferred private val connectionPushAgent = { @@ -74,12 +82,14 @@ object AkkaStreamAgent */ val processPush = instrument("akka.stream.impl.fusing.GraphInterpreter".fqcnWithTags("push")) .visit(GraphInterpreterPushAdvice, "processPush") + .deferred /** * Adds push counter to [[ akka.stream.impl.fusing.GraphInterpreter.Connection ]] */ val pushField = instrument("akka.stream.impl.fusing.GraphInterpreter$Connection".fqcnWithTags("push")) .defineField[Long](ConnectionOps.PushCounterVarName) + .deferred Agent(processPush, pushField) } @@ -90,13 +100,15 @@ object AkkaStreamAgent * Add incrementing pull counter on pull processing */ val processPull = instrument("akka.stream.impl.fusing.GraphInterpreter".fqcnWithTags("pull")) - .visit(GraphInterpreterPushAdvice, "processPush") + .visit(GraphInterpreterPullAdvice, "processPull") + .deferred /** * Adds pull counter to [[ akka.stream.impl.fusing.GraphInterpreter.Connection ]] */ val pullField = instrument("akka.stream.impl.fusing.GraphInterpreter$Connection".fqcnWithTags("pull")) .defineField[Long](ConnectionOps.PullCounterVarName) + .deferred Agent(processPull, pullField) } @@ -110,6 +122,7 @@ object AkkaStreamAgent .visit[ActorGraphInterpreterAdvice]("receive") .visit(ActorGraphInterpreterProcessEventAdvice, "processEvent") .visit(ActorGraphInterpreterTryInitAdvice, "tryInit") + .deferred /** * Instrumentation that add additional tag to terminal Sink @@ -117,6 +130,7 @@ object AkkaStreamAgent private val graphStageIslandInstrumentation = instrument("akka.stream.impl.GraphStageIsland".fqcn) .visit[GraphStageIslandAdvice]("materializeAtomic") + .deferred private val sharedImplementations = connectionPullAgent ++ connectionPushAgent ++ actorGraphInterpreterInstrumentation ++ graphStageIslandInstrumentation ++ phasedFusingActorMaterializerAgentInstrumentation diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala index c5d9c7363..59afa6dbd 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala @@ -12,9 +12,9 @@ import io.scalac.mesmer.agent.akka.stream.impl.ActorGraphInterpreterDecorator object ActorGraphInterpreterProcessEventAdvice { @Advice.OnMethodExit - def processEvent(@Advice.This self: Actor, @Advice.Argument(0) boundaryEvent: BoundaryEvent): Unit = + def processEvent(@Advice.This self: AnyRef , @Advice.Argument(0) boundaryEvent: BoundaryEvent): Unit = if (boundaryEvent.shell.isTerminated) { - ActorGraphInterpreterDecorator.shellFinished(boundaryEvent.shell, self) + ActorGraphInterpreterDecorator.shellFinished(boundaryEvent.shell, self.asInstanceOf[Actor]) } } @@ -27,12 +27,12 @@ object ActorGraphInterpreterTryInitAdvice { @Advice.OnMethodExit def tryInit( - @Advice.This self: Actor, + @Advice.This self: AnyRef, @Advice.Argument(0) shell: GraphInterpreterShellMirror, @Advice.Return initialized: Boolean ): Unit = if (!initialized) { - ActorGraphInterpreterDecorator.shellFinished(shell, self) + ActorGraphInterpreterDecorator.shellFinished(shell, self.asInstanceOf[Actor]) } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala index 91bc15f07..7fb193e51 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala @@ -3,7 +3,6 @@ package io.scalac.mesmer.agent.akka.stream.impl import io.scalac.mesmer.agent.akka.stream.impl.ConnectionOps._ import net.bytebuddy.asm.Advice._ - object GraphInterpreterPushAdvice { @OnMethodEnter @@ -11,7 +10,6 @@ object GraphInterpreterPushAdvice { ConnectionOps.incrementPushCounter(currentConnection) } - object GraphInterpreterPullAdvice { @OnMethodEnter diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala index f9ba843fe..a5cc149ed 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala @@ -3,13 +3,14 @@ package io.scalac.mesmer.agent.akka.stream.impl import akka.AkkaMirrorTypes import akka.actor.ActorRef import akka.actor.typed.scaladsl.adapter._ -import io.scalac.mesmer.core.event.{ActorEvent, EventBus} -import io.scalac.mesmer.core.model.{ActorRefTags, Tag} +import io.scalac.mesmer.core.event.{ ActorEvent, EventBus } +import io.scalac.mesmer.core.model.{ ActorRefTags, Tag } import net.bytebuddy.asm.Advice._ object PhasedFusingActorMaterializerAdvice { @OnMethodExit - def getPhases(@Return ref: ActorRef, @This self: AkkaMirrorTypes.ExtendedActorMaterializerMirror): Unit = - EventBus(self.system.toTyped).publishEvent(ActorEvent.TagsSet(ActorRefTags(ref, Set(Tag.stream)))) + def actorOf(@Return ref: ActorRef, @This self: Object): Unit = + EventBus(self.asInstanceOf[AkkaMirrorTypes.ExtendedActorMaterializerMirror].system.toTyped) + .publishEvent(ActorEvent.TagsSet(ActorRefTags(ref, Set(Tag.stream)))) } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala index cbf58edb7..a955575ee 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/AgentInstrumentationFactory.scala @@ -5,16 +5,17 @@ import io.scalac.mesmer.agent.AgentInstrumentation object AgentInstrumentationFactory { - def apply(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = { + def apply(typeInstrumentation: TypeInstrumentation, load: Seq[String], deferred: Boolean): AgentInstrumentation = { val instrumentationDetails: InstrumentationDetails[_] = typeInstrumentation.`type`.name - AgentInstrumentation(instrumentationDetails.name, instrumentationDetails.tags) { (agentBuilder, instrumentation) => - agentBuilder - .`type`(typeInstrumentation.`type`.desc) - .transform { (underlying, _, _, _) => - typeInstrumentation.transformBuilder(underlying) - } - .installOn(instrumentation) - if (instrumentationDetails.isFQCN) LoadingResult(instrumentationDetails.name) else LoadingResult.empty + AgentInstrumentation(instrumentationDetails.name, instrumentationDetails.tags, deferred) { + (agentBuilder, instrumentation) => + agentBuilder + .`type`(typeInstrumentation.`type`.desc) + .transform { (underlying, _, _, _) => + typeInstrumentation.transformBuilder(underlying) + } + .installOn(instrumentation) + if (instrumentationDetails.isFQCN) LoadingResult(instrumentationDetails.name +: load) else LoadingResult.empty } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala index 73637e391..03e9a6830 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala @@ -1,10 +1,25 @@ package io.scalac.mesmer.agent.util.i13n import com.typesafe.config.Config import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.util.i13n.InstrumentationDSL.NameDSL import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails.FQCN import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.{ MesmerModule, Module, RegisterGlobalConfiguration } import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo +import net.bytebuddy.description.`type`.TypeDescription +import net.bytebuddy.description.method.MethodDescription +import net.bytebuddy.matcher.ElementMatchers +object InstrumentationDSL { + final class NameDSL(private val value: String) extends AnyVal { + def method: MethodDesc = ElementMatchers.named[MethodDescription](value) + def `type`: TypeDesc = ElementMatchers.named[TypeDescription](value) + } +} + +sealed trait InstrumentationDSL { + + protected def named(name: String): NameDSL = new NameDSL(name) +} object InstrumentModuleFactory { protected class StringDlsOps(private val value: (String, Module)) extends AnyVal { @@ -24,7 +39,9 @@ object InstrumentModuleFactory { } - implicit class FactoryOps[M <: MesmerModule with RegisterGlobalConfiguration](private val factory: InstrumentModuleFactory[M]) extends AnyVal { + implicit class FactoryOps[M <: MesmerModule with RegisterGlobalConfiguration]( + private val factory: InstrumentModuleFactory[M] + ) extends AnyVal { def defaultAgent(jarsInfo: LibraryInfo): Agent = factory @@ -33,7 +50,8 @@ object InstrumentModuleFactory { } } -abstract class InstrumentModuleFactory[M <: Module with RegisterGlobalConfiguration](val module: M) { +abstract class InstrumentModuleFactory[M <: Module with RegisterGlobalConfiguration](val module: M) + extends InstrumentationDSL { /* Requiring all features to be a function from versions to Option[Agent] we allow there to create different instrumentations depending on runtime version of jars. TODO add information on which versions are supported diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index 2ac0b344b..b61e9d08f 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -14,8 +14,8 @@ import scala.reflect.{ classTag, ClassTag } package object i13n { - final private[i13n] type TypeDesc = ElementMatcher.Junction[TypeDescription] - final private[i13n] type MethodDesc = ElementMatcher.Junction[MethodDescription] + type TypeDesc = ElementMatcher.Junction[TypeDescription] + type MethodDesc = ElementMatcher.Junction[MethodDescription] final case class InstrumentationDetails[S <: Status] private (name: String, tags: Set[String], isFQCN: Boolean) @@ -67,8 +67,8 @@ package object i13n { def visit[A](advice: A, method: MethodDesc)(implicit isObject: A <:< Singleton): TypeInstrumentation = chain(_.visit(Advice.to(typeFromModule(advice.getClass)).on(method))) -// def intercept[A](advice: A, method: MethodDesc)(implicit isObject: A <:< Singleton): TypeInstrumentation = -// chain(_.method(method).intercept(Advice.to(typeFromModule(advice.getClass)))) + def intercept[A](advice: A, method: MethodDesc)(implicit isObject: A <:< Singleton): TypeInstrumentation = + chain(_.method(method).intercept(Advice.to(typeFromModule(advice.getClass)))) def intercept[T](method: MethodDesc)(implicit ct: ClassTag[T]): TypeInstrumentation = chain(_.method(method).intercept(Advice.to(ct.runtimeClass))) @@ -90,7 +90,7 @@ package object i13n { private def typeFromModule(clazz: Class[_]): Class[_] = { val dollarFreeFQCN = clazz.getName.dropRight(1) - Class.forName(dollarFreeFQCN, true, clazz.getClassLoader) + Class.forName(dollarFreeFQCN, false, clazz.getClassLoader) } private def chain(that: Builder => Builder): TypeInstrumentation = @@ -142,5 +142,11 @@ package object i13n { implicit def methodNameToMethodDesc(methodName: String): MethodDesc = method(methodName) implicit def classNameToTypeDesc(className: String): TypeDesc = EM.named[TypeDescription](className) implicit def typeToAgentInstrumentation(typeInstrumentation: TypeInstrumentation): AgentInstrumentation = - AgentInstrumentationFactory(typeInstrumentation) + AgentInstrumentationFactory(typeInstrumentation, Seq.empty, false) + + implicit final class LoadingOps(private val value: TypeInstrumentation) extends AnyRef { + def withLoad(fqcn: String, fqcns: String*): AgentInstrumentation = + AgentInstrumentationFactory(value, fqcn +: fqcns, false) + def deferred: AgentInstrumentation = AgentInstrumentationFactory(value, Seq.empty, true) + } } diff --git a/agent/src/test/resources/logback-test.xml b/agent/src/test/resources/logback-test.xml index f1f333c60..93f4bb7b9 100644 --- a/agent/src/test/resources/logback-test.xml +++ b/agent/src/test/resources/logback-test.xml @@ -15,6 +15,7 @@ + diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala index 6bdc6f02a..6d2382ec3 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala @@ -14,8 +14,8 @@ class AgentInstrumentationTest extends AnyFlatSpec with Matchers { val name = "some.class" val tags = Set("tag1", "tag2") - val agent = AgentInstrumentation(name, tags)(returning(LoadingResult.empty)) - val agent2 = AgentInstrumentation(name, tags)(returning(LoadingResult.empty)) + val agent = AgentInstrumentation(name, tags, deferred = false)(returning(LoadingResult.empty)) + val agent2 = AgentInstrumentation(name, tags, deferred = false)(returning(LoadingResult.empty)) agent should be(agent2) } @@ -25,8 +25,8 @@ class AgentInstrumentationTest extends AnyFlatSpec with Matchers { val tags1 = Set("tag1", "tag2") val tags2 = Set("tag2", "tag3") - val agent = AgentInstrumentation(name, tags1)(returning(LoadingResult.empty)) - val agent2 = AgentInstrumentation(name, tags2)(returning(LoadingResult.empty)) + val agent = AgentInstrumentation(name, tags1, deferred = false)(returning(LoadingResult.empty)) + val agent2 = AgentInstrumentation(name, tags2, deferred = false)(returning(LoadingResult.empty)) agent should not be (agent2) } @@ -36,8 +36,8 @@ class AgentInstrumentationTest extends AnyFlatSpec with Matchers { val name2 = "other.class" val tags = Set("tag1", "tag2") - val agent = AgentInstrumentation(name, tags)(returning(LoadingResult.empty)) - val agent2 = AgentInstrumentation(name2, tags)(returning(LoadingResult.empty)) + val agent = AgentInstrumentation(name, tags, deferred = false)(returning(LoadingResult.empty)) + val agent2 = AgentInstrumentation(name2, tags, deferred = false)(returning(LoadingResult.empty)) agent should not be (agent2) } diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala index 60f13fec5..4cfe7b026 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala @@ -16,8 +16,10 @@ class AgentTest extends AnyFlatSpec with Matchers { it should "keep one copy of equal instrumentation" in { - val agentInstrumentationOne = AgentInstrumentation("name", Set("tag"))(returning(LoadingResult.empty)) - val agentInstrumentationTwo = AgentInstrumentation("name", Set("tag"))(returning(LoadingResult.empty)) + val agentInstrumentationOne = + AgentInstrumentation("name", Set("tag"), deferred = false)(returning(LoadingResult.empty)) + val agentInstrumentationTwo = + AgentInstrumentation("name", Set("tag"), deferred = false)(returning(LoadingResult.empty)) val agent = Agent(agentInstrumentationOne, agentInstrumentationTwo) @@ -26,9 +28,12 @@ class AgentTest extends AnyFlatSpec with Matchers { it should "combine result from different agent instrumentations" in { - val agentInstrumentationOne = AgentInstrumentation("test_name_one", Set("tag"))(returning(LoadingResult("one"))) - val agentInstrumentationTwo = AgentInstrumentation("test_name_one", Set.empty)(returning(LoadingResult("two"))) - val agentInstrumentationThree = AgentInstrumentation("test_name_two", Set("tag"))(returning(LoadingResult("three"))) + val agentInstrumentationOne = + AgentInstrumentation("test_name_one", Set("tag"), deferred = false)(returning(LoadingResult("one"))) + val agentInstrumentationTwo = + AgentInstrumentation("test_name_one", Set.empty, deferred = false)(returning(LoadingResult("two"))) + val agentInstrumentationThree = + AgentInstrumentation("test_name_two", Set("tag"), deferred = false)(returning(LoadingResult("three"))) val expectedResult = LoadingResult(Seq("one", "two", "three")) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala index 734c7b474..a52df9316 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala @@ -1,16 +1,17 @@ package io.scalac.mesmer.agent.akka -import akka.actor.PoisonPill -import akka.actor.Props import akka.actor.testkit.typed.scaladsl.TestProbe -import akka.actor.typed.ActorRef -import akka.actor.typed.Behavior -import akka.actor.typed.SupervisorStrategy -import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.scaladsl.StashBuffer import akka.actor.typed.scaladsl.adapter._ -import akka.{ actor => classic } +import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer} +import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy} +import akka.actor.{PoisonPill, Props} +import akka.{actor => classic} +import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent +import io.scalac.mesmer.agent.utils.{InstallAgent, InstallModule, SafeLoadSystem} +import io.scalac.mesmer.core.event.ActorEvent +import io.scalac.mesmer.core.util.MetricsToolKit.Counter +import io.scalac.mesmer.core.util.ReceptionistOps +import io.scalac.mesmer.extension.actor.{ActorCellDecorator, ActorCellMetrics} import org.scalatest.OptionValues import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike @@ -19,16 +20,9 @@ import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ import scala.util.control.NoStackTrace -import io.scalac.mesmer.agent.utils.InstallAgent -import io.scalac.mesmer.agent.utils.SafeLoadSystem -import io.scalac.mesmer.core.event.ActorEvent -import io.scalac.mesmer.core.util.MetricsToolKit.Counter -import io.scalac.mesmer.core.util.ReceptionistOps -import io.scalac.mesmer.extension.actor.ActorCellDecorator -import io.scalac.mesmer.extension.actor.ActorCellMetrics - class AkkaActorAgentTest extends InstallAgent +// extends InstallModule(AkkaActorAgent) with AnyFlatSpecLike with ReceptionistOps with OptionValues diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala index 5330527d0..1590a53fe 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala @@ -1,91 +1,70 @@ package io.scalac.mesmer.agent.akka -import akka.http.scaladsl.Http -import akka.http.scaladsl.model.Uri.Path -import akka.http.scaladsl.model.{HttpMethods, HttpRequest, StatusCodes, Uri} +import akka.actor.testkit.typed.scaladsl.TestProbe +import akka.actor.typed +import akka.actor.typed.receptionist.Receptionist +import akka.actor.typed.receptionist.Receptionist.{ Deregister, Register } +import akka.actor.typed.scaladsl.adapter._ +import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.model.headers.Connection import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route +import akka.http.scaladsl.testkit.{ RouteTestTimeout, ScalatestRouteTest } +import com.typesafe.config.{ Config, ConfigFactory } import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent -import io.scalac.mesmer.agent.akka.impl.AkkaHttpTestImpl import io.scalac.mesmer.agent.utils.InstallModule -import io.scalac.mesmer.core.event.HttpEvent.{ConnectionCompleted, ConnectionStarted, RequestCompleted, RequestStarted} -import io.scalac.mesmer.core.module.AkkaHttpModule +import io.scalac.mesmer.core.event.HttpEvent +import io.scalac.mesmer.core.event.HttpEvent.{ + ConnectionCompleted, + ConnectionStarted, + RequestCompleted, + RequestStarted +} +import io.scalac.mesmer.core.httpServiceKey import io.scalac.mesmer.core.util.TestOps import org.scalatest.OptionValues import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import scala.concurrent.Await import scala.concurrent.duration._ import scala.language.postfixOps class AkkaHttpAgentTest extends InstallModule(AkkaHttpAgent) + with ScalatestRouteTest with AnyFlatSpecLike with Matchers with OptionValues with TestOps { -// override var agent = Some(AkkaHttpAgent.agent(AkkaHttpModule.defaultConfig)) + override def testConfig: Config = ConfigFactory.load("application-test") + + type Fixture = TestProbe[HttpEvent] + + val testRoute: Route = path("test") { + get { + complete((StatusCodes.OK, collection.immutable.Seq(Connection("close")))) + } + } + + def test(body: Fixture => Any): Any = { + implicit val typedSystem: typed.ActorSystem[Nothing] = system.toTyped + val monitor = TestProbe[HttpEvent]("http-test-probe") + Receptionist(typedSystem).ref ! Register(httpServiceKey, monitor.ref) + body(monitor) + Receptionist(typedSystem).ref ! Deregister(httpServiceKey, monitor.ref) + } - behavior of "AkkaHttpAgent" + "AkkaHttpAgent" should "instrument routes to generate events on http requests" in test { monitor => + implicit val timeout = RouteTestTimeout(5 seconds) -// it should behave like withVersion( -//// AkkaHttpModule.AkkaHttpModuleConfig(true, true, true), -//// AkkaHttpModule.AkkaHttpModuleConfig(false, true, true), -// AkkaHttpModule.Impl(true, false, true) -// )( -// "instrument routes to generate events on http requests" -// )(AkkaHttpTestImpl.systemWithHttpService { implicit system => monitor => -// val testRoute: Route = path("test") { -// get { -// complete((StatusCodes.OK, collection.immutable.Seq(Connection("close")))) -// } -// } -//// implicit val timeout = RouteTestTimeout(5 seconds) -// import system.executionContext -// -// -// val response = for { -// binding <- Http().newServerAt("127.0.0.1", 0).bind(testRoute) -// port = binding.localAddress.getPort -// targetUri = Uri.Empty.withPath(Path("/test")).withHost("127.0.0.1").withPort(port).withScheme("http") -// response <- Http().singleRequest(HttpRequest(HttpMethods.GET, targetUri)) -// } yield { -// binding.unbind() -// response -// } -// Await.result(response, 5.seconds) -// -// monitor.expectMessageType[ConnectionStarted] -// monitor.expectMessageType[RequestStarted] -// monitor.expectMessageType[RequestCompleted] -// monitor.expectMessageType[ConnectionCompleted] -// }) -// -//// "AkkaHttpAgent" should "instrument routes to generate events on http requests" in withVersion( -//// AkkaHttpModule.defaultConfig -//// )(test { monitor => -//// implicit val timeout = RouteTestTimeout(5 seconds) -//// -//// Get("/test") ~!> testRoute ~> check { -//// status should be(StatusCodes.OK) -//// } -//// monitor.expectMessageType[ConnectionStarted] -//// monitor.expectMessageType[RequestStarted] -//// monitor.expectMessageType[RequestCompleted] -//// monitor.expectMessageType[ConnectionCompleted] -//// }) -// -//// it should "contain 2 transformations" in test { _ => -//// agent.value.instrumentations should have size (2) -//// } -// -// it should behave like withVersion(AkkaHttpModule.defaultConfig)("contain 2 transformations")(AkkaHttpTestImpl.systemWithHttpService { -// _ => _ => -// agent.value.instrumentations should have size (2) -// -// }) + Get("/test") ~!> testRoute ~> check { + status should be(StatusCodes.OK) + } + monitor.expectMessageType[ConnectionStarted] + monitor.expectMessageType[RequestStarted] + monitor.expectMessageType[RequestCompleted] + monitor.expectMessageType[ConnectionCompleted] + } } diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentSpec.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentTest.scala similarity index 91% rename from agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentSpec.scala rename to agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentTest.scala index 802055931..d8e3050c3 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentSpec.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentTest.scala @@ -1,7 +1,6 @@ package io.scalac.mesmer.agent.akka import java.util.UUID - import _root_.akka.actor.testkit.typed.scaladsl.TestProbe import _root_.akka.actor.typed.receptionist.Receptionist import _root_.akka.actor.typed.receptionist.Receptionist.Deregister @@ -13,20 +12,18 @@ import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ - import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent -import io.scalac.mesmer.agent.utils.DummyEventSourcedActor +import io.scalac.mesmer.agent.utils.{DummyEventSourcedActor, InstallAgent, InstallModule, SafeLoadSystem} import io.scalac.mesmer.agent.utils.DummyEventSourcedActor.DoNothing import io.scalac.mesmer.agent.utils.DummyEventSourcedActor.Persist -import io.scalac.mesmer.agent.utils.InstallAgent -import io.scalac.mesmer.agent.utils.SafeLoadSystem import io.scalac.mesmer.core.event.PersistenceEvent import io.scalac.mesmer.core.event.PersistenceEvent._ +import io.scalac.mesmer.core.module.AkkaPersistenceModule import io.scalac.mesmer.core.persistenceServiceKey import io.scalac.mesmer.core.util.ReceptionistOps -class AkkaPersistenceAgentSpec - extends InstallAgent +class AkkaPersistenceAgentTest + extends InstallModule(AkkaPersistenceAgent) with AnyFlatSpecLike with Matchers with ScalaFutures @@ -34,8 +31,6 @@ class AkkaPersistenceAgentSpec with ReceptionistOps with SafeLoadSystem { -// override protected val agent = AkkaPersistenceAgent.agent - implicit val askTimeout: Timeout = Timeout(1.minute) type Fixture = TestProbe[PersistenceEvent] @@ -49,6 +44,8 @@ class AkkaPersistenceAgentSpec } "AkkaPersistenceAgent" should "generate only recovery events" in test { monitor => + + agent.instrumentations should have size(4) val id = UUID.randomUUID() Receptionist(system).ref ! Register(persistenceServiceKey, monitor.ref) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorEventTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorEventTest.scala index 6348e6ed0..d5778d4eb 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorEventTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorEventTest.scala @@ -14,9 +14,7 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.time.Span import scala.concurrent.duration._ - -import io.scalac.mesmer.agent.utils.InstallAgent -import io.scalac.mesmer.agent.utils.SafeLoadSystem +import io.scalac.mesmer.agent.utils.{InstallAgent, InstallModule, SafeLoadSystem} import io.scalac.mesmer.core.event.ActorEvent import io.scalac.mesmer.core.event.ActorEvent.ActorCreated import io.scalac.mesmer.core.event.Service.actorService @@ -26,7 +24,7 @@ import io.scalac.mesmer.core.util.TestBehaviors.Pass import io.scalac.mesmer.core.util.TestCase.CommonMonitorTestFactory class ActorEventTest - extends InstallAgent + extends InstallModule(AkkaActorAgent) with SafeLoadSystem with AnyFlatSpecLike with Matchers diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala index 5fd699897..34cca7f25 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala @@ -1,39 +1,26 @@ package io.scalac.mesmer.agent.akka.actor -import java.util.Comparator - -import akka.actor.ActorSystem -import akka.actor.PoisonPill -import akka.actor.typed.ActorRef -import akka.actor.typed.Behavior -import akka.actor.typed.MailboxSelector -import akka.actor.typed.Props -import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.adapter._ -import akka.dispatch.BoundedPriorityMailbox -import akka.dispatch.BoundedStablePriorityMailbox -import akka.dispatch.Envelope -import akka.{ actor => classic } -import com.typesafe.config.Config -import com.typesafe.config.ConfigFactory +import akka.actor.typed.scaladsl.{ActorContext, Behaviors} +import akka.actor.typed.{ActorRef, Behavior, MailboxSelector, Props} +import akka.actor.{ActorSystem, PoisonPill} +import akka.dispatch.{BoundedPriorityMailbox, BoundedStablePriorityMailbox, Envelope} +import akka.{actor => classic} +import com.typesafe.config.{Config, ConfigFactory} +import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish +import io.scalac.mesmer.agent.utils.{InstallModule, SafeLoadSystem} +import io.scalac.mesmer.core.config.AkkaPatienceConfig +import io.scalac.mesmer.core.util.TestOps +import io.scalac.mesmer.extension.actor.{ActorCellDecorator, ActorCellMetrics, DroppedMessagesCellMetrics} import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import java.util.Comparator import scala.annotation.unused import scala.concurrent.duration.Duration import scala.jdk.DurationConverters._ -import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish -import io.scalac.mesmer.agent.utils.InstallAgent -import io.scalac.mesmer.agent.utils.SafeLoadSystem -import io.scalac.mesmer.core.config.AkkaPatienceConfig -import io.scalac.mesmer.core.util.TestOps -import io.scalac.mesmer.extension.actor.ActorCellDecorator -import io.scalac.mesmer.extension.actor.ActorCellMetrics -import io.scalac.mesmer.extension.actor.DroppedMessagesCellMetrics - final class HashCodePriorityMailbox( capacity: Int, pushTimeOut: Duration @@ -59,7 +46,7 @@ final class StableHashCodePriorityMailbox( } class ActorMailboxTest - extends InstallAgent + extends InstallModule(AkkaActorAgent) with SafeLoadSystem with AnyFlatSpecLike with Matchers diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgentTest.scala index a540b76c0..8d32d85f6 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgentTest.scala @@ -3,43 +3,32 @@ package io.scalac.mesmer.agent.akka.stream import akka.Done import akka.actor.ActorRef import akka.actor.testkit.typed.scaladsl.TestProbe -import akka.actor.typed.ActorSystem -import akka.actor.typed.Behavior +import akka.actor.typed.{ActorSystem, Behavior} import akka.actor.typed.receptionist.Receptionist._ import akka.actor.typed.receptionist.ServiceKey import akka.actor.typed.scaladsl.Behaviors -import akka.stream.Attributes -import akka.stream.BufferOverflowException -import akka.stream.OverflowStrategy -import akka.stream.QueueOfferResult +import akka.stream.{Attributes, BufferOverflowException, OverflowStrategy, QueueOfferResult} import akka.stream.scaladsl._ -import org.scalatest._ -import org.scalatest.concurrent.Futures -import org.scalatest.concurrent.ScalaFutures -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.ExecutionContext -import scala.concurrent.Future -import scala.concurrent.duration._ - -import io.scalac.mesmer.agent.utils.InstallAgent -import io.scalac.mesmer.agent.utils.SafeLoadSystem +import io.scalac.mesmer.agent.utils.{InstallAgent, InstallModule, SafeLoadSystem} import io.scalac.mesmer.core.akka.model.PushMetrics import io.scalac.mesmer.core.config.AkkaPatienceConfig -import io.scalac.mesmer.core.event.ActorEvent import io.scalac.mesmer.core.event.ActorEvent.TagsSet -import io.scalac.mesmer.core.event.Service -import io.scalac.mesmer.core.event.StreamEvent -import io.scalac.mesmer.core.event.StreamEvent.LastStreamStats -import io.scalac.mesmer.core.event.StreamEvent.StreamInterpreterStats +import io.scalac.mesmer.core.event.{ActorEvent, Service, StreamEvent} +import io.scalac.mesmer.core.event.StreamEvent.{LastStreamStats, StreamInterpreterStats} import io.scalac.mesmer.core.model.ActorRefTags import io.scalac.mesmer.core.model.Tag.stream import io.scalac.mesmer.core.util.TestBehaviors.Pass import io.scalac.mesmer.core.util.TestCase.CommonMonitorTestFactory +import org.scalatest._ +import org.scalatest.concurrent.{Futures, ScalaFutures} +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + +import scala.concurrent.{ExecutionContext, Future} +import scala.concurrent.duration._ class AkkaStreamAgentTest - extends InstallAgent + extends InstallModule(AkkaStreamAgent) with AnyFlatSpecLike with Matchers with SafeLoadSystem @@ -153,6 +142,7 @@ class AkkaStreamAgentTest "AkkaStreamAgentTest" should "accurately detect push / demand" in testCase { implicit c => implicit val ec: ExecutionContext = system.executionContext + val Demand = 5L val ExpectedElements = Demand + 1L // somehow sinkQueue demand 1 element in advance diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala index d4b4c1b63..bfdfc1715 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala @@ -7,17 +7,14 @@ import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory._ -import io.scalac.mesmer.core.module.{Module, RegisterGlobalConfiguration} -import io.scalac.mesmer.core.util.LibraryInfo.{LibraryInfo, extractModulesInformation} +import io.scalac.mesmer.agent.utils.InstallAgent.allInstrumentations +import io.scalac.mesmer.core.module.{ MesmerModule, RegisterGlobalConfiguration } +import io.scalac.mesmer.core.util.LibraryInfo.{ extractModulesInformation, LibraryInfo } import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.ByteBuddyAgent import net.bytebuddy.agent.builder.AgentBuilder import net.bytebuddy.dynamic.scaffold.TypeValidation -import org.scalatest.TestSuite -import org.scalatest.flatspec.AnyFlatSpecLike - -import java.net.{URL, URLClassLoader} -import scala.util.Try +import org.scalatest.{ BeforeAndAfterAll, TestSuite } object InstallAgent { def allInstrumentations(info: LibraryInfo): Agent = AkkaActorAgent.defaultAgent(info) ++ @@ -26,11 +23,11 @@ object InstallAgent { AkkaStreamAgent.defaultAgent(info) } -abstract class InstallAgent extends TestSuite { +abstract class InstallAgent extends TestSuite with BeforeAndAfterAll { - def modules: LibraryInfo = extractModulesInformation(Thread.currentThread().getContextClassLoader) + def jars: LibraryInfo = extractModulesInformation(Thread.currentThread().getContextClassLoader) - protected var agent: Option[Agent] = None + protected def agent: Agent = allInstrumentations(jars) private val builder = new AgentBuilder.Default( new ByteBuddy() @@ -39,65 +36,25 @@ abstract class InstallAgent extends TestSuite { .`with`(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) .`with`(new AgentBuilder.InitializationStrategy.SelfInjection.Eager()) .`with`( - AgentBuilder.Listener.StreamWriting.toSystemOut.withTransformationsOnly() + AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly() ) - private def installAgent(): Unit = { - val instrumentation = ByteBuddyAgent.install() - - agent.fold[Unit](throw new AssertionError("Agent must be set")) { - _.installOn(builder, instrumentation) - .eagerLoad() - } - } - - def withAgent(setup: () => Unit)(test: () => Any): Any = { - val context = Thread.currentThread().getContextClassLoader.asInstanceOf[URLClassLoader] - val prefixClassLoader = - new PrefixChildFirstClassLoader(Vector("akka.http.scaladsl.HttpExt"), context.getURLs, context) - Thread.currentThread().setContextClassLoader(prefixClassLoader) - - setup() - installAgent() - Class.forName("akka.http.scaladsl.HttpExt", true, prefixClassLoader) - test() - Thread.currentThread().setContextClassLoader(context) - } + override protected def beforeAll(): Unit = { + super.beforeAll() -} - -final class PrefixChildFirstClassLoader(prefix: Vector[String], urls: Array[URL], parent: ClassLoader) - extends URLClassLoader(urls, parent) { - override def loadClass(name: String, resolve: Boolean): Class[_] = { - - val loaded = Option(findLoadedClass(name)).orElse { - if (prefix.exists(p => name.startsWith(p))) { - println(s"Loading class: $name") - - Try(findClass(name)).toOption - } else None - }.orElse(Try(super.loadClass(name, resolve)).toOption).getOrElse(throw new ClassNotFoundException(name)) + val instrumentation = ByteBuddyAgent.install() - if (resolve) { - resolveClass(loaded) - } - loaded + agent + .installOn(builder, instrumentation) + .eagerLoad() } - } -abstract class InstallModule[M <: Module with RegisterGlobalConfiguration](moduleFactory: InstrumentModuleFactory[M]) extends InstallAgent { - this: AnyFlatSpecLike => +abstract class InstallModule[M <: MesmerModule with RegisterGlobalConfiguration]( + moduleFactory: InstrumentModuleFactory[M] +) extends InstallAgent { + import InstrumentModuleFactory._ -// def withVersion(versions: moduleFactory.module.All[Boolean]*)(name: String)(test: => Any): Any = -// versions.foreach { version => -// it should s"$name with $version" in withAgent { () => -// agent = Some(moduleFactory.initAgent(version)) -// println(s"Class loader: ${Thread.currentThread().getContextClassLoader}") -// println(s"Class loader parent: ${Thread.currentThread().getContextClassLoader.getParent}") -// println(s"Class loader 2xparent: ${Thread.currentThread().getContextClassLoader.getParent.getParent}") -// }(() => test) -// -// } + override protected def agent: Agent = moduleFactory.defaultAgent(jars) } diff --git a/build.sbt b/build.sbt index 11f1cc850..7db02b00f 100644 --- a/build.sbt +++ b/build.sbt @@ -103,7 +103,6 @@ lazy val agent = (project in file("agent")) Test / testOnly / fork := (Test / fork).value, Test / testGrouping := ((Test / testGrouping).value flatMap { group => group.tests.map { test => - println(test) Tests.Group(name = test.name, tests = Seq(test), runPolicy = group.runPolicy) } }), diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/ReflectionFieldUtils.scala b/core/src/main/scala/io/scalac/mesmer/core/util/ReflectionFieldUtils.scala index 243ea3883..0a823cea3 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/ReflectionFieldUtils.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/ReflectionFieldUtils.scala @@ -1,10 +1,10 @@ package io.scalac.mesmer.core.util -import java.lang.invoke.MethodHandle -import java.lang.reflect.Field - import io.scalac.mesmer.core.invoke.Lookup +import java.lang.invoke.{ MethodHandle, MethodHandles } +import java.lang.reflect.Field + object ReflectionFieldUtils extends Lookup { @inline final def getHandlers(className: String, fieldName: String): (MethodHandle, MethodHandle) = @@ -39,4 +39,6 @@ object ReflectionFieldUtils extends Lookup { field } + def chain(first: MethodHandle, second: MethodHandle): MethodHandle = + MethodHandles.collectArguments(second, 0, first) } From 379d624e03282dfdb3e46588481e8b2083bebc0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Mon, 28 Jun 2021 12:04:22 +0200 Subject: [PATCH 11/31] Add OpenTelemetry monitor tests --- .../scala/io/scalac/mesmer/agent/Agent.scala | 5 +- .../scala/io/scalac/mesmer/agent/Boot.scala | 14 +-- .../agent/akka/actor/AkkaActorAgent.scala | 6 +- .../actor/AkkaMailboxInstrumentations.scala | 29 +++-- .../ActorCellConstructorInstrumentation.scala | 5 +- ...torCellReceiveMessageInstrumentation.scala | 6 +- ...CellSendMessageMetricInstrumentation.scala | 7 +- .../impl/ActorUnhandledInstrumentation.scala | 4 +- .../impl/ClassicActorContextProviderOps.scala | 4 +- .../akka/actor/impl/ClassicActorOps.scala | 3 +- .../ClassicStashInstrumentationStash.scala | 12 ++- .../akka/actor/impl/EnvelopeDecorator.scala | 4 +- .../impl/LocalActorRefProviderAdvice.scala | 7 +- .../impl/MailboxDequeueInstrumentation.scala | 5 +- .../akka/actor/impl/StashBufferAdvice.scala | 3 +- ...andleReceiveExceptionInstrumentation.scala | 4 +- .../agent/akka/http/HttpInstrumentation.scala | 12 ++- .../persistence/AkkaPersistenceAgent.scala | 11 +- .../impl/JournalInteractionsInterceptor.scala | 3 +- .../persistence/impl/PersistenceUtils.scala | 8 +- .../PersistingEventSuccessInterceptor.scala | 3 +- .../impl/RecoveryCompletedInterceptor.scala | 7 +- .../impl/RecoveryStartedInterceptor.scala | 9 +- .../impl/StoringSnapshotInterceptor.scala | 9 +- .../agent/akka/stream/AkkaStreamAgent.scala | 14 +-- .../impl/ActorGraphInterpreterDecorator.scala | 14 +-- ...orGraphInterpreterProcessEventAdvice.scala | 6 +- .../akka/stream/impl/AkkaMirrorTypes.scala | 3 +- .../impl/GraphInterpreterPushAdvice.scala | 3 +- .../akka/stream/impl/GraphLogicOps.scala | 2 +- .../stream/impl/GraphStageIslandOps.scala | 4 +- .../PhasedFusingActorMaterializerAdvice.scala | 7 +- .../util/i13n/InstrumentModuleFactory.scala | 11 +- .../mesmer/agent/util/i13n/package.scala | 14 ++- .../agent/AgentInstrumentationTest.scala | 3 +- .../io/scalac/mesmer/agent/AgentTest.scala | 5 +- .../agent/akka/AkkaActorAgentTest.scala | 27 +++-- .../mesmer/agent/akka/AkkaHttpAgentTest.scala | 30 +++--- .../agent/akka/AkkaPersistenceAgentTest.scala | 10 +- .../agent/akka/actor/ActorEventTest.scala | 4 +- .../agent/akka/actor/ActorMailboxTest.scala | 37 ++++--- .../agent/akka/impl/AkkaHttpTestImpl.scala | 11 +- .../akka/stream/AkkaStreamAgentTest.scala | 36 ++++--- .../mesmer/agent/utils/InstallAgent.scala | 18 ++-- .../core/config/ConfigurationUtils.scala | 11 +- .../mesmer/core/module/AkkaActorModule.scala | 4 +- .../core/module/AkkaActorSystemModule.scala | 1 + .../core/module/AkkaClusterModule.scala | 1 + .../mesmer/core/module/AkkaHttpModule.scala | 4 +- .../core/module/AkkaPersistenceModule.scala | 4 +- .../mesmer/core/module/AkkaStreamModule.scala | 4 +- .../io/scalac/mesmer/core/module/Module.scala | 5 +- .../scalac/mesmer/core/util/LibraryInfo.scala | 6 +- .../core/util/ReflectionFieldUtils.scala | 7 +- .../core/model/SupportedModulesTest.scala | 7 +- .../main/resources/common/application.conf | 2 +- .../extension/AkkaStreamMonitoring.scala | 52 +++++---- .../ClusterRegionsMonitorActor.scala | 2 +- .../mesmer/extension/HttpEventsActor.scala | 15 ++- .../{AkkaMonitoring.scala => Mesmer.scala} | 56 ++++++---- .../config/AkkaMonitoringConfig.scala | 18 +++- .../extension/config/BufferConfig.scala | 1 + .../extension/config/CachingConfig.scala | 1 + .../extension/metric/ActorSystemMonitor.scala | 3 +- .../metric/ClusterMetricsMonitor.scala | 3 +- .../metric/HttpConnectionMetricsMonitor.scala | 5 +- .../mesmer/extension/metric/Metric.scala | 5 +- .../metric/PersistenceMetricsMonitor.scala | 3 +- .../metric/StreamMetricsMonitor.scala | 7 +- .../metric/StreamOperatorMetricsMonitor.scala | 3 +- .../service/ActorConfigurationService.scala | 2 +- .../OpenTelemetryActorMetricsMonitor.scala | 9 +- .../OpenTelemetryActorSystemMonitor.scala | 36 +++++-- .../OpenTelemetryClusterMetricsMonitor.scala | 70 +++++++----- ...elemetryHttpConnectionMetricsMonitor.scala | 58 +++++----- .../OpenTelemetryHttpMetricsMonitor.scala | 14 ++- ...enTelemetryPersistenceMetricsMonitor.scala | 48 ++++++--- .../OpenTelemetryStreamMetricsMonitor.scala | 56 ++++++---- ...elemetryStreamOperatorMetricsMonitor.scala | 40 ++++--- .../upstream/opentelemetry/Synchronized.scala | 6 +- .../WrappedSynchronousInstrument.scala | 6 +- ...OpenTelemetryActorMetricsMonitorTest.scala | 101 ++++++++++++++++++ .../OpenTelemetryActorSystemMonitorTest.scala | 49 +++++++++ ...enTelemetryClusterMetricsMonitorTest.scala | 63 +++++++++++ ...etryHttpConnectionMetricsMonitorTest.scala | 47 ++++++++ .../OpenTelemetryHttpMetricsMonitorTest.scala | 50 +++++++++ ...lemetryPersistenceMetricsMonitorTest.scala | 59 ++++++++++ ...penTelemetryStreamMetricsMonitorTest.scala | 56 ++++++++++ ...etryStreamOperatorMetricsMonitorTest.scala | 49 +++++++++ .../util/OpenTelemetryNoopMeter.scala | 6 ++ 90 files changed, 1125 insertions(+), 369 deletions(-) rename extension/src/main/scala/io/scalac/mesmer/extension/{AkkaMonitoring.scala => Mesmer.scala} (85%) create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitorTest.scala create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitorTest.scala create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitorTest.scala create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitorTest.scala create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitorTest.scala create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitorTest.scala create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitorTest.scala create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitorTest.scala create mode 100644 extension/src/test/scala/io/scalac/mesmer/extension/util/OpenTelemetryNoopMeter.scala diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala index a4c9162ff..3c4c6d05a 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Agent.scala @@ -1,10 +1,11 @@ package io.scalac.mesmer.agent -import io.scalac.mesmer.agent.Agent.LoadingResult +import java.lang.instrument.Instrumentation + import net.bytebuddy.agent.builder.AgentBuilder import org.slf4j.LoggerFactory -import java.lang.instrument.Instrumentation +import io.scalac.mesmer.agent.Agent.LoadingResult object Agent { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala index 35ac1ce4c..622e422db 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala @@ -1,18 +1,20 @@ package io.scalac.mesmer.agent +import java.lang.instrument.Instrumentation + import com.typesafe.config.ConfigFactory -import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent -import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent -import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent -import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent -import io.scalac.mesmer.core.util.LibraryInfo import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.builder.AgentBuilder import net.bytebuddy.dynamic.scaffold.TypeValidation -import java.lang.instrument.Instrumentation import scala.annotation.unused +import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent +import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent +import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent +import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent +import io.scalac.mesmer.core.util.LibraryInfo + object Boot { //TODO better configuration specification diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala index 4cc90d8db..560def9eb 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala @@ -1,12 +1,14 @@ package io.scalac.mesmer.agent.akka.actor +import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.AgentInstrumentation import io.scalac.mesmer.agent.akka.actor.impl._ import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.module.AkkaActorModule import io.scalac.mesmer.core.util.Timestamp -import io.scalac.mesmer.extension.actor.{ ActorCellDecorator, ActorCellMetrics } +import io.scalac.mesmer.extension.actor.ActorCellDecorator +import io.scalac.mesmer.extension.actor.ActorCellMetrics object AkkaActorAgent extends InstrumentModuleFactory(AkkaActorModule) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala index a96c2fb72..fba344e6b 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala @@ -1,21 +1,30 @@ package io.scalac.mesmer.agent.akka.actor -import akka.AkkaMirror.{ ActorRefWithCell, Cell } +import java.util.concurrent.BlockingQueue +import java.util.concurrent.Callable +import java.util.concurrent.LinkedBlockingQueue + +import akka.AkkaMirror.ActorRefWithCell +import akka.AkkaMirror.Cell import akka.dispatch._ import akka.util.BoundedBlockingQueue import akka.{ actor => classic } -import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } -import io.scalac.mesmer.core.util.ReflectionFieldUtils -import io.scalac.mesmer.extension.actor.ActorCellDecorator import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription -import net.bytebuddy.implementation.bind.annotation.{ SuperCall, This } -import net.bytebuddy.implementation.{ FieldAccessor, MethodDelegation } +import net.bytebuddy.implementation.FieldAccessor +import net.bytebuddy.implementation.MethodDelegation +import net.bytebuddy.implementation.bind.annotation.SuperCall +import net.bytebuddy.implementation.bind.annotation.This import net.bytebuddy.matcher.ElementMatchers -import java.util.concurrent.{ BlockingQueue, Callable, LinkedBlockingQueue } -import scala.reflect.{ classTag, ClassTag } +import scala.reflect.ClassTag +import scala.reflect.classTag + +import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.AgentInstrumentation +import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.core.util.ReflectionFieldUtils +import io.scalac.mesmer.extension.actor.ActorCellDecorator object BoundedNodeMessageQueueAdvice { @@ -124,7 +133,7 @@ private[actor] trait AkkaMailboxInstrumentations { ) .visit(BoundedNodeMessageQueueAdvice, "enqueue") - protected val boundedQueueAgent = + protected val boundedQueueAgent: Agent = Agent(boundedQueueBasesMailbox, boundedQueueBasedMailboxes, boundedMessageQueueSemantics) } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala index c498f826c..d5e709afc 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala @@ -1,8 +1,11 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.dispatch.MailboxType +import net.bytebuddy.asm.Advice.Argument +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.This + import io.scalac.mesmer.extension.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit, This } object ActorCellConstructorInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala index 2547ed3ce..a198ac2b9 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala @@ -1,7 +1,11 @@ package io.scalac.mesmer.agent.akka.actor.impl +import net.bytebuddy.asm.Advice.OnMethodEnter +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.This +import net.bytebuddy.asm.Advice.Thrown + import io.scalac.mesmer.extension.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ OnMethodEnter, OnMethodExit, This, Thrown } object ActorCellReceiveMessageInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala index 90d99c550..90293b440 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala @@ -1,9 +1,10 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.Actor +import net.bytebuddy.asm.Advice._ + import io.scalac.mesmer.core.util.ActorRefOps import io.scalac.mesmer.extension.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice._ object ActorCellSendMessageMetricInstrumentation { @@ -13,8 +14,8 @@ object ActorCellSendMessageMetricInstrumentation { val sender = EnvelopeOps.getSender(envelope) if (sender != Actor.noSender) for { - cell <- ActorRefOps.Local.cell(sender) - metrics <- ActorCellDecorator.get(cell) + cell <- ActorRefOps.Local.cell(sender) + metrics <- ActorCellDecorator.get(cell) } metrics.sentMessages.inc() } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala index dde91fe3d..262840d4f 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.agent.akka.actor.impl +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.This + import io.scalac.mesmer.extension.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ OnMethodExit, This } object ActorUnhandledInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorContextProviderOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorContextProviderOps.scala index 862a18038..42bb8d029 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorContextProviderOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorContextProviderOps.scala @@ -1,10 +1,10 @@ package io.scalac.mesmer.agent.akka.actor.impl +import java.lang.invoke.MethodHandles + import akka.actor.ActorContext import akka.actor.typed.TypedActorContext -import java.lang.invoke.MethodHandles - object ClassicActorContextProviderOps { private lazy val classicActorContextGetter = { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorOps.scala index 60bcf01e5..629d25a28 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicActorOps.scala @@ -1,6 +1,7 @@ package io.scalac.mesmer.agent.akka.actor.impl -import akka.actor.{ Actor, ActorContext } +import akka.actor.Actor +import akka.actor.ActorContext object ClassicActorOps { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala index 31d9a4121..1398b8e3d 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala @@ -1,12 +1,16 @@ package io.scalac.mesmer.agent.akka.actor.impl -import akka.actor.{Actor, ActorContext} -import io.scalac.mesmer.extension.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{Argument, OnMethodExit, This} - import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType.methodType +import akka.actor.Actor +import akka.actor.ActorContext +import net.bytebuddy.asm.Advice.Argument +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.This + +import io.scalac.mesmer.extension.actor.ActorCellDecorator + object StashConstructorAdvice { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeDecorator.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeDecorator.scala index 4fc830a56..9906ed0db 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeDecorator.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/EnvelopeDecorator.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.dispatch.Envelope -import io.scalac.mesmer.core.util.{ ReflectionFieldUtils, Timestamp } + +import io.scalac.mesmer.core.util.ReflectionFieldUtils +import io.scalac.mesmer.core.util.Timestamp object EnvelopeDecorator { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/LocalActorRefProviderAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/LocalActorRefProviderAdvice.scala index c56607fc5..7793dd426 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/LocalActorRefProviderAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/LocalActorRefProviderAdvice.scala @@ -1,12 +1,15 @@ package io.scalac.mesmer.agent.akka.actor.impl -import akka.actor.{ ActorRef, ActorSystem } +import akka.actor.ActorRef +import akka.actor.ActorSystem import akka.actor.typed.scaladsl.adapter._ +import net.bytebuddy.asm.Advice.Argument +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.Return import io.scalac.mesmer.core.event.ActorEvent.ActorCreated import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.model.ActorRefTags -import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit, Return } object LocalActorRefProviderAdvice { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala index 8bddd1c8f..26cb1b74e 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala @@ -1,8 +1,11 @@ package io.scalac.mesmer.agent.akka.actor.impl +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.Return +import net.bytebuddy.asm.Advice.This + import io.scalac.mesmer.core.util.Interval import io.scalac.mesmer.extension.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ OnMethodExit, Return, This } object MailboxDequeueInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala index 9ecf12eed..00c5a1c56 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala @@ -2,9 +2,10 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.adapter._ -import io.scalac.mesmer.extension.actor.ActorCellDecorator import net.bytebuddy.asm.Advice +import io.scalac.mesmer.extension.actor.ActorCellDecorator + object StashBufferAdvice { @Advice.OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala index a76953c9c..6a5f091c3 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala @@ -1,8 +1,10 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.typed.TypedActorContext +import net.bytebuddy.asm.Advice.Argument +import net.bytebuddy.asm.Advice.OnMethodExit + import io.scalac.mesmer.extension.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit } object SupervisorHandleReceiveExceptionInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/HttpInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/HttpInstrumentation.scala index 91bfc4f0d..59f5665f1 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/HttpInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/HttpInstrumentation.scala @@ -1,10 +1,17 @@ package io.scalac.mesmer.agent.akka.http -import _root_.akka.http.scaladsl.model.{HttpRequest, HttpResponse} +import _root_.akka.http.scaladsl.model.HttpRequest +import _root_.akka.http.scaladsl.model.HttpResponse import _root_.akka.stream.BidiShape import akka.actor.typed.scaladsl.adapter._ import akka.http.scaladsl.HttpExt -import akka.stream.scaladsl.{BidiFlow, Broadcast, Flow, GraphDSL, Source, Zip} +import akka.stream.scaladsl.BidiFlow +import akka.stream.scaladsl.Broadcast +import akka.stream.scaladsl.Flow +import akka.stream.scaladsl.GraphDSL +import akka.stream.scaladsl.Source +import akka.stream.scaladsl.Zip + import io.scalac.mesmer.core.akka.stream.BidiFlowForward import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.HttpEvent._ @@ -34,7 +41,6 @@ object HttpInstrumentation { val system = self.asInstanceOf[HttpExt].system.toTyped - val requestIdFlow = BidiFlow.fromGraph[HttpRequest, HttpRequest, HttpResponse, HttpResponse, Any](GraphDSL.create() { implicit builder => diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala index 8869cc61a..1519b2972 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala @@ -1,11 +1,12 @@ package io.scalac.mesmer.agent.akka.persistence +import org.slf4j.LoggerFactory + import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.akka.persistence.impl._ import io.scalac.mesmer.agent.util.i13n._ import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaPersistenceModule -import org.slf4j.LoggerFactory object AkkaPersistenceAgent extends InstrumentModuleFactory(AkkaPersistenceModule) @@ -69,14 +70,14 @@ object AkkaPersistenceAgent */ val recoveryStartedAgent = instrument("akka.persistence.typed.internal.ReplayingSnapshot".fqcnWithTags(recoveryTag)) - .intercept(RecoveryStartedInterceptor,"onRecoveryStart") + .intercept(RecoveryStartedInterceptor, "onRecoveryStart") /** * Instrumentation to fire event on persistent actor recovery complete */ val recoveryCompletedAgent = instrument("akka.persistence.typed.internal.ReplayingEvents".fqcnWithTags(recoveryTag)) - .intercept(RecoveryCompletedInterceptor,"onRecoveryComplete") + .intercept(RecoveryCompletedInterceptor, "onRecoveryComplete") Agent(recoveryStartedAgent, recoveryCompletedAgent) } @@ -87,12 +88,12 @@ object AkkaPersistenceAgent private val eventWriteSuccessInstrumentation = instrument("akka.persistence.typed.internal.Running".fqcnWithTags("persistent_event")) .intercept(PersistingEventSuccessInterceptor, "onWriteSuccess") - .intercept(JournalInteractionsInterceptor,"onWriteInitiated") + .intercept(JournalInteractionsInterceptor, "onWriteInitiated") /** * Instrumentation to fire event when snapshot is stored */ private val snapshotLoadingInstrumentation = instrument("akka.persistence.typed.internal.Running$StoringSnapshot".fqcnWithTags("snapshot_created")) - .intercept(StoringSnapshotInterceptor,"onSaveSnapshotResponse") + .intercept(StoringSnapshotInterceptor, "onSaveSnapshotResponse") } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/JournalInteractionsInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/JournalInteractionsInterceptor.scala index 4c5fcb269..bae8d3d26 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/JournalInteractionsInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/JournalInteractionsInterceptor.scala @@ -2,11 +2,12 @@ package io.scalac.mesmer.agent.akka.persistence.impl import akka.actor.typed.scaladsl.ActorContext import akka.persistence.PersistentRepr +import net.bytebuddy.asm.Advice._ + import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.PersistingEventStarted import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.Timestamp -import net.bytebuddy.asm.Advice._ object JournalInteractionsInterceptor { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistenceUtils.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistenceUtils.scala index 47ddd0554..b04bb1b27 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistenceUtils.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistenceUtils.scala @@ -1,19 +1,19 @@ package io.scalac.mesmer.agent.akka.persistence.impl import io.scalac.mesmer.core.util.ReflectionFieldUtils +import java.lang.invoke.MethodHandle private[impl] trait PersistenceUtils { // protected val (elo, melon) = ("String", "elo") - protected lazy val replayingSnapshotsSetupGetter = + protected lazy val replayingSnapshotsSetupGetter: MethodHandle = ReflectionFieldUtils.getGetter("akka.persistence.typed.internal.ReplayingSnapshot", "setup") - protected lazy val replayingEventsSetupGetter = + protected lazy val replayingEventsSetupGetter: MethodHandle = ReflectionFieldUtils.getGetter("akka.persistence.typed.internal.ReplayingEvents", "setup") - protected lazy val behaviorSetupPersistenceId = + protected lazy val behaviorSetupPersistenceId: MethodHandle = ReflectionFieldUtils.getGetter("akka.persistence.typed.internal.BehaviorSetup", "persistenceId") - } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala index 97bb1fbaf..7120bd5bf 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/PersistingEventSuccessInterceptor.scala @@ -2,11 +2,12 @@ package io.scalac.mesmer.agent.akka.persistence.impl import akka.actor.typed.scaladsl.ActorContext import akka.persistence.PersistentRepr +import net.bytebuddy.asm.Advice._ + import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.PersistingEventFinished import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.Timestamp -import net.bytebuddy.asm.Advice._ object PersistingEventSuccessInterceptor { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala index 3279dec08..b7446d7ff 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryCompletedInterceptor.scala @@ -2,16 +2,17 @@ package io.scalac.mesmer.agent.akka.persistence.impl import _root_.akka.actor.typed.scaladsl.ActorContext import _root_.akka.persistence.typed.PersistenceId +import net.bytebuddy.asm.Advice + import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.RecoveryFinished import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.util.{ ReflectionFieldUtils, Timestamp } -import net.bytebuddy.asm.Advice +import io.scalac.mesmer.core.util.ReflectionFieldUtils +import io.scalac.mesmer.core.util.Timestamp object RecoveryCompletedInterceptor extends PersistenceUtils { - private lazy val persistenceIdHandle = ReflectionFieldUtils.chain(replayingEventsSetupGetter, behaviorSetupPersistenceId) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala index 1fe7a07be..0bbd1ecab 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/RecoveryStartedInterceptor.scala @@ -2,17 +2,20 @@ package io.scalac.mesmer.agent.akka.persistence.impl import _root_.akka.actor.typed.scaladsl.ActorContext import _root_.akka.persistence.typed.PersistenceId +import net.bytebuddy.asm.Advice + import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.RecoveryStarted import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.util.{ ReflectionFieldUtils, Timestamp } -import net.bytebuddy.asm.Advice +import io.scalac.mesmer.core.util.ReflectionFieldUtils +import io.scalac.mesmer.core.util.Timestamp +import java.lang.invoke.MethodHandle object RecoveryStartedInterceptor extends PersistenceUtils { import AkkaPersistenceAgent.logger - lazy val persistenceIdHandle = ReflectionFieldUtils.chain(replayingSnapshotsSetupGetter, behaviorSetupPersistenceId) + lazy val persistenceIdHandle: MethodHandle = ReflectionFieldUtils.chain(replayingSnapshotsSetupGetter, behaviorSetupPersistenceId) @Advice.OnMethodEnter def enter( diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala index a7807d1a9..dc7f5dcab 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/impl/StoringSnapshotInterceptor.scala @@ -1,12 +1,15 @@ package io.scalac.mesmer.agent.akka.persistence.impl -import akka.actor.typed.scaladsl.{ AbstractBehavior, ActorContext } +import akka.actor.typed.scaladsl.AbstractBehavior +import akka.actor.typed.scaladsl.ActorContext import akka.persistence.SaveSnapshotSuccess +import net.bytebuddy.asm.Advice._ + import io.scalac.mesmer.core.event.EventBus import io.scalac.mesmer.core.event.PersistenceEvent.SnapshotCreated import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.util.{ ReflectionFieldUtils, Timestamp } -import net.bytebuddy.asm.Advice._ +import io.scalac.mesmer.core.util.ReflectionFieldUtils +import io.scalac.mesmer.core.util.Timestamp object StoringSnapshotInterceptor extends PersistenceUtils { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala index 59fb1ac1d..5a9bce88e 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala @@ -2,14 +2,14 @@ package io.scalac.mesmer.agent.akka.stream import akka.ActorGraphInterpreterAdvice import akka.stream.GraphStageIslandAdvice -import akka.stream.impl.fusing.{ ActorGraphInterpreterProcessEventAdvice, ActorGraphInterpreterTryInitAdvice } +import akka.stream.impl.fusing.ActorGraphInterpreterProcessEventAdvice +import akka.stream.impl.fusing.ActorGraphInterpreterTryInitAdvice + import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.akka.stream.impl.{ - ConnectionOps, - GraphInterpreterPullAdvice, - GraphInterpreterPushAdvice, - PhasedFusingActorMaterializerAdvice -} +import io.scalac.mesmer.agent.akka.stream.impl.ConnectionOps +import io.scalac.mesmer.agent.akka.stream.impl.GraphInterpreterPullAdvice +import io.scalac.mesmer.agent.akka.stream.impl.GraphInterpreterPushAdvice +import io.scalac.mesmer.agent.akka.stream.impl.PhasedFusingActorMaterializerAdvice import io.scalac.mesmer.agent.util.i13n._ import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaStreamModule diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala index b5d28b471..a7cb02ac3 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala @@ -1,21 +1,23 @@ package io.scalac.mesmer.agent.akka.stream.impl +import java.lang.invoke.MethodType.methodType + import akka.AkkaMirrorTypes.GraphInterpreterShellMirror import akka.actor.Actor +import akka.actor.typed.scaladsl.adapter._ import akka.stream.GraphLogicOps._ + import io.scalac.mesmer.core.akka.model.PushMetrics import io.scalac.mesmer.core.event.EventBus -import io.scalac.mesmer.core.event.StreamEvent.{ LastStreamStats, StreamInterpreterStats } +import io.scalac.mesmer.core.event.StreamEvent.LastStreamStats +import io.scalac.mesmer.core.event.StreamEvent.StreamInterpreterStats import io.scalac.mesmer.core.invoke.Lookup import io.scalac.mesmer.core.model.ShellInfo import io.scalac.mesmer.core.model.Tag.SubStreamName -import io.scalac.mesmer.core.model.stream.{ ConnectionStats, StageInfo } -import akka.actor.typed.scaladsl.adapter._ - +import io.scalac.mesmer.core.model.stream.ConnectionStats +import io.scalac.mesmer.core.model.stream.StageInfo import io.scalac.mesmer.core.util.stream.subStreamNameFromActorRef -import java.lang.invoke.MethodType.methodType - object ActorGraphInterpreterDecorator extends Lookup { private lazy val shells = { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala index 59afa6dbd..113e63e85 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala @@ -1,10 +1,8 @@ package akka.stream.impl.fusing +import akka.AkkaMirrorTypes.GraphInterpreterShellMirror import akka.actor.Actor import akka.stream.impl.fusing.ActorGraphInterpreter.BoundaryEvent - - -import akka.AkkaMirrorTypes.GraphInterpreterShellMirror import net.bytebuddy.asm.Advice import io.scalac.mesmer.agent.akka.stream.impl.ActorGraphInterpreterDecorator @@ -12,7 +10,7 @@ import io.scalac.mesmer.agent.akka.stream.impl.ActorGraphInterpreterDecorator object ActorGraphInterpreterProcessEventAdvice { @Advice.OnMethodExit - def processEvent(@Advice.This self: AnyRef , @Advice.Argument(0) boundaryEvent: BoundaryEvent): Unit = + def processEvent(@Advice.This self: AnyRef, @Advice.Argument(0) boundaryEvent: BoundaryEvent): Unit = if (boundaryEvent.shell.isTerminated) { ActorGraphInterpreterDecorator.shellFinished(boundaryEvent.shell, self.asInstanceOf[Actor]) } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala index 9383e0cbb..64259d11b 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala @@ -1,7 +1,8 @@ package akka import akka.stream.impl.ExtendedActorMaterializer -import akka.stream.impl.fusing.{ GraphInterpreter, GraphInterpreterShell } +import akka.stream.impl.fusing.GraphInterpreter +import akka.stream.impl.fusing.GraphInterpreterShell import akka.stream.stage.GraphStageLogic import akka.util.{ OptionVal => AkkaOptionVal } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala index 7fb193e51..b6bfd404f 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphInterpreterPushAdvice.scala @@ -1,8 +1,9 @@ package io.scalac.mesmer.agent.akka.stream.impl -import io.scalac.mesmer.agent.akka.stream.impl.ConnectionOps._ import net.bytebuddy.asm.Advice._ +import io.scalac.mesmer.agent.akka.stream.impl.ConnectionOps._ + object GraphInterpreterPushAdvice { @OnMethodEnter diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphLogicOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphLogicOps.scala index cf470fac0..e37547ad2 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphLogicOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphLogicOps.scala @@ -1,8 +1,8 @@ package akka.stream - import akka.stream.impl.fusing.GraphInterpreter.Connection import akka.stream.stage.GraphStageLogic + import io.scalac.mesmer.agent.akka.stream.impl.GraphStageIslandOps.TerminalSink import io.scalac.mesmer.core.model.Tag.StageName import io.scalac.mesmer.core.model.Tag.StageName.StreamUniqueStageName diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphStageIslandOps.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphStageIslandOps.scala index 9a606ef3f..1cdf6aa32 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphStageIslandOps.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/GraphStageIslandOps.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.agent.akka.stream.impl +import akka.stream.Attributes import akka.stream.Attributes.Attribute -import akka.stream.{ Attributes, Shape, SinkShape } +import akka.stream.Shape +import akka.stream.SinkShape object GraphStageIslandOps { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala index a5cc149ed..e6f6282bb 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala @@ -3,10 +3,13 @@ package io.scalac.mesmer.agent.akka.stream.impl import akka.AkkaMirrorTypes import akka.actor.ActorRef import akka.actor.typed.scaladsl.adapter._ -import io.scalac.mesmer.core.event.{ ActorEvent, EventBus } -import io.scalac.mesmer.core.model.{ ActorRefTags, Tag } import net.bytebuddy.asm.Advice._ +import io.scalac.mesmer.core.event.ActorEvent +import io.scalac.mesmer.core.event.EventBus +import io.scalac.mesmer.core.model.ActorRefTags +import io.scalac.mesmer.core.model.Tag + object PhasedFusingActorMaterializerAdvice { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala index 03e9a6830..11a1f3558 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/InstrumentModuleFactory.scala @@ -1,14 +1,17 @@ package io.scalac.mesmer.agent.util.i13n import com.typesafe.config.Config +import net.bytebuddy.description.`type`.TypeDescription +import net.bytebuddy.description.method.MethodDescription +import net.bytebuddy.matcher.ElementMatchers + import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.util.i13n.InstrumentationDSL.NameDSL import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails.FQCN import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.{ MesmerModule, Module, RegisterGlobalConfiguration } +import io.scalac.mesmer.core.module.MesmerModule +import io.scalac.mesmer.core.module.Module +import io.scalac.mesmer.core.module.RegisterGlobalConfiguration import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo -import net.bytebuddy.description.`type`.TypeDescription -import net.bytebuddy.description.method.MethodDescription -import net.bytebuddy.matcher.ElementMatchers object InstrumentationDSL { final class NameDSL(private val value: String) extends AnyVal { def method: MethodDesc = ElementMatchers.named[MethodDescription](value) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index b61e9d08f..3722bcff4 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -1,16 +1,20 @@ package io.scalac.mesmer.agent.util -import io.scalac.mesmer.agent.AgentInstrumentation -import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails._ import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription import net.bytebuddy.description.method.MethodDescription import net.bytebuddy.dynamic.DynamicType -import net.bytebuddy.implementation.{ Implementation, MethodDelegation } -import net.bytebuddy.matcher.{ ElementMatcher, ElementMatchers => EM } +import net.bytebuddy.implementation.Implementation +import net.bytebuddy.implementation.MethodDelegation +import net.bytebuddy.matcher.ElementMatcher +import net.bytebuddy.matcher.{ElementMatchers => EM} import scala.language.implicitConversions -import scala.reflect.{ classTag, ClassTag } +import scala.reflect.ClassTag +import scala.reflect.classTag + +import io.scalac.mesmer.agent.AgentInstrumentation +import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails._ package object i13n { diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala index 6d2382ec3..4dd369919 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/AgentInstrumentationTest.scala @@ -1,9 +1,10 @@ package io.scalac.mesmer.agent -import io.scalac.mesmer.agent.Agent.LoadingResult import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import io.scalac.mesmer.agent.Agent.LoadingResult + class AgentInstrumentationTest extends AnyFlatSpec with Matchers { behavior of "AgentInstrumentation" diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala index 4cfe7b026..9cd848b7c 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/AgentTest.scala @@ -1,12 +1,13 @@ package io.scalac.mesmer.agent -import io.scalac.mesmer.agent.Agent.LoadingResult +import java.lang.instrument.Instrumentation + import net.bytebuddy.agent.ByteBuddyAgent import net.bytebuddy.agent.builder.AgentBuilder import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import java.lang.instrument.Instrumentation +import io.scalac.mesmer.agent.Agent.LoadingResult class AgentTest extends AnyFlatSpec with Matchers { diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala index a52df9316..09d1949ca 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala @@ -1,17 +1,16 @@ package io.scalac.mesmer.agent.akka +import akka.actor.PoisonPill +import akka.actor.Props import akka.actor.testkit.typed.scaladsl.TestProbe +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.SupervisorStrategy +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.scaladsl.StashBuffer import akka.actor.typed.scaladsl.adapter._ -import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer} -import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy} -import akka.actor.{PoisonPill, Props} -import akka.{actor => classic} -import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent -import io.scalac.mesmer.agent.utils.{InstallAgent, InstallModule, SafeLoadSystem} -import io.scalac.mesmer.core.event.ActorEvent -import io.scalac.mesmer.core.util.MetricsToolKit.Counter -import io.scalac.mesmer.core.util.ReceptionistOps -import io.scalac.mesmer.extension.actor.{ActorCellDecorator, ActorCellMetrics} +import akka.{ actor => classic } import org.scalatest.OptionValues import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike @@ -20,6 +19,14 @@ import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ import scala.util.control.NoStackTrace +import io.scalac.mesmer.agent.utils.InstallAgent +import io.scalac.mesmer.agent.utils.SafeLoadSystem +import io.scalac.mesmer.core.event.ActorEvent +import io.scalac.mesmer.core.util.MetricsToolKit.Counter +import io.scalac.mesmer.core.util.ReceptionistOps +import io.scalac.mesmer.extension.actor.ActorCellDecorator +import io.scalac.mesmer.extension.actor.ActorCellMetrics + class AkkaActorAgentTest extends InstallAgent // extends InstallModule(AkkaActorAgent) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala index 1590a53fe..eb674a32a 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaHttpAgentTest.scala @@ -3,25 +3,17 @@ package io.scalac.mesmer.agent.akka import akka.actor.testkit.typed.scaladsl.TestProbe import akka.actor.typed import akka.actor.typed.receptionist.Receptionist -import akka.actor.typed.receptionist.Receptionist.{ Deregister, Register } +import akka.actor.typed.receptionist.Receptionist.Deregister +import akka.actor.typed.receptionist.Receptionist.Register import akka.actor.typed.scaladsl.adapter._ import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.model.headers.Connection import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route -import akka.http.scaladsl.testkit.{ RouteTestTimeout, ScalatestRouteTest } -import com.typesafe.config.{ Config, ConfigFactory } -import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent -import io.scalac.mesmer.agent.utils.InstallModule -import io.scalac.mesmer.core.event.HttpEvent -import io.scalac.mesmer.core.event.HttpEvent.{ - ConnectionCompleted, - ConnectionStarted, - RequestCompleted, - RequestStarted -} -import io.scalac.mesmer.core.httpServiceKey -import io.scalac.mesmer.core.util.TestOps +import akka.http.scaladsl.testkit.RouteTestTimeout +import akka.http.scaladsl.testkit.ScalatestRouteTest +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory import org.scalatest.OptionValues import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers @@ -29,6 +21,16 @@ import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ import scala.language.postfixOps +import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent +import io.scalac.mesmer.agent.utils.InstallModule +import io.scalac.mesmer.core.event.HttpEvent +import io.scalac.mesmer.core.event.HttpEvent.ConnectionCompleted +import io.scalac.mesmer.core.event.HttpEvent.ConnectionStarted +import io.scalac.mesmer.core.event.HttpEvent.RequestCompleted +import io.scalac.mesmer.core.event.HttpEvent.RequestStarted +import io.scalac.mesmer.core.httpServiceKey +import io.scalac.mesmer.core.util.TestOps + class AkkaHttpAgentTest extends InstallModule(AkkaHttpAgent) with ScalatestRouteTest diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentTest.scala index d8e3050c3..c21d4848f 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaPersistenceAgentTest.scala @@ -1,6 +1,7 @@ package io.scalac.mesmer.agent.akka import java.util.UUID + import _root_.akka.actor.testkit.typed.scaladsl.TestProbe import _root_.akka.actor.typed.receptionist.Receptionist import _root_.akka.actor.typed.receptionist.Receptionist.Deregister @@ -12,13 +13,15 @@ import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ + import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent -import io.scalac.mesmer.agent.utils.{DummyEventSourcedActor, InstallAgent, InstallModule, SafeLoadSystem} +import io.scalac.mesmer.agent.utils.DummyEventSourcedActor import io.scalac.mesmer.agent.utils.DummyEventSourcedActor.DoNothing import io.scalac.mesmer.agent.utils.DummyEventSourcedActor.Persist +import io.scalac.mesmer.agent.utils.InstallModule +import io.scalac.mesmer.agent.utils.SafeLoadSystem import io.scalac.mesmer.core.event.PersistenceEvent import io.scalac.mesmer.core.event.PersistenceEvent._ -import io.scalac.mesmer.core.module.AkkaPersistenceModule import io.scalac.mesmer.core.persistenceServiceKey import io.scalac.mesmer.core.util.ReceptionistOps @@ -44,8 +47,7 @@ class AkkaPersistenceAgentTest } "AkkaPersistenceAgent" should "generate only recovery events" in test { monitor => - - agent.instrumentations should have size(4) + agent.instrumentations should have size (4) val id = UUID.randomUUID() Receptionist(system).ref ! Register(persistenceServiceKey, monitor.ref) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorEventTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorEventTest.scala index d5778d4eb..e605be5e6 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorEventTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorEventTest.scala @@ -14,7 +14,9 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.time.Span import scala.concurrent.duration._ -import io.scalac.mesmer.agent.utils.{InstallAgent, InstallModule, SafeLoadSystem} + +import io.scalac.mesmer.agent.utils.InstallModule +import io.scalac.mesmer.agent.utils.SafeLoadSystem import io.scalac.mesmer.core.event.ActorEvent import io.scalac.mesmer.core.event.ActorEvent.ActorCreated import io.scalac.mesmer.core.event.Service.actorService diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala index 34cca7f25..83f413111 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala @@ -1,26 +1,39 @@ package io.scalac.mesmer.agent.akka.actor +import java.util.Comparator + +import akka.actor.ActorSystem +import akka.actor.PoisonPill +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.MailboxSelector +import akka.actor.typed.Props +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.adapter._ -import akka.actor.typed.scaladsl.{ActorContext, Behaviors} -import akka.actor.typed.{ActorRef, Behavior, MailboxSelector, Props} -import akka.actor.{ActorSystem, PoisonPill} -import akka.dispatch.{BoundedPriorityMailbox, BoundedStablePriorityMailbox, Envelope} -import akka.{actor => classic} -import com.typesafe.config.{Config, ConfigFactory} -import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish -import io.scalac.mesmer.agent.utils.{InstallModule, SafeLoadSystem} -import io.scalac.mesmer.core.config.AkkaPatienceConfig -import io.scalac.mesmer.core.util.TestOps -import io.scalac.mesmer.extension.actor.{ActorCellDecorator, ActorCellMetrics, DroppedMessagesCellMetrics} +import akka.dispatch.BoundedPriorityMailbox +import akka.dispatch.BoundedStablePriorityMailbox +import akka.dispatch.Envelope +import akka.{ actor => classic } +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import java.util.Comparator import scala.annotation.unused import scala.concurrent.duration.Duration import scala.jdk.DurationConverters._ +import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish +import io.scalac.mesmer.agent.utils.InstallModule +import io.scalac.mesmer.agent.utils.SafeLoadSystem +import io.scalac.mesmer.core.config.AkkaPatienceConfig +import io.scalac.mesmer.core.util.TestOps +import io.scalac.mesmer.extension.actor.ActorCellDecorator +import io.scalac.mesmer.extension.actor.ActorCellMetrics +import io.scalac.mesmer.extension.actor.DroppedMessagesCellMetrics + final class HashCodePriorityMailbox( capacity: Int, pushTimeOut: Duration diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala index 87f385289..214a544df 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala @@ -1,17 +1,20 @@ package io.scalac.mesmer.agent.akka.impl +import java.util.UUID + import akka.actor.testkit.typed.scaladsl.TestProbe import akka.actor.typed.ActorSystem import akka.actor.typed.receptionist.Receptionist -import akka.actor.typed.receptionist.Receptionist.{ Deregister, Register } +import akka.actor.typed.receptionist.Receptionist.Deregister +import akka.actor.typed.receptionist.Receptionist.Register import akka.actor.typed.scaladsl.adapter._ import akka.{ actor => classic } -import com.typesafe.config.{ Config, ConfigFactory } +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory + import io.scalac.mesmer.core.event.HttpEvent import io.scalac.mesmer.core.httpServiceKey -import java.util.UUID - object AkkaHttpTestImpl { private val testConfig: Config = ConfigFactory.load("application-test") diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgentTest.scala index 8d32d85f6..3971addfe 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgentTest.scala @@ -3,29 +3,40 @@ package io.scalac.mesmer.agent.akka.stream import akka.Done import akka.actor.ActorRef import akka.actor.testkit.typed.scaladsl.TestProbe -import akka.actor.typed.{ActorSystem, Behavior} +import akka.actor.typed.ActorSystem +import akka.actor.typed.Behavior import akka.actor.typed.receptionist.Receptionist._ import akka.actor.typed.receptionist.ServiceKey import akka.actor.typed.scaladsl.Behaviors -import akka.stream.{Attributes, BufferOverflowException, OverflowStrategy, QueueOfferResult} +import akka.stream.Attributes +import akka.stream.BufferOverflowException +import akka.stream.OverflowStrategy +import akka.stream.QueueOfferResult import akka.stream.scaladsl._ -import io.scalac.mesmer.agent.utils.{InstallAgent, InstallModule, SafeLoadSystem} +import org.scalatest._ +import org.scalatest.concurrent.Futures +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.flatspec.AnyFlatSpecLike +import org.scalatest.matchers.should.Matchers + +import scala.concurrent.ExecutionContext +import scala.concurrent.Future +import scala.concurrent.duration._ + +import io.scalac.mesmer.agent.utils.InstallModule +import io.scalac.mesmer.agent.utils.SafeLoadSystem import io.scalac.mesmer.core.akka.model.PushMetrics import io.scalac.mesmer.core.config.AkkaPatienceConfig +import io.scalac.mesmer.core.event.ActorEvent import io.scalac.mesmer.core.event.ActorEvent.TagsSet -import io.scalac.mesmer.core.event.{ActorEvent, Service, StreamEvent} -import io.scalac.mesmer.core.event.StreamEvent.{LastStreamStats, StreamInterpreterStats} +import io.scalac.mesmer.core.event.Service +import io.scalac.mesmer.core.event.StreamEvent +import io.scalac.mesmer.core.event.StreamEvent.LastStreamStats +import io.scalac.mesmer.core.event.StreamEvent.StreamInterpreterStats import io.scalac.mesmer.core.model.ActorRefTags import io.scalac.mesmer.core.model.Tag.stream import io.scalac.mesmer.core.util.TestBehaviors.Pass import io.scalac.mesmer.core.util.TestCase.CommonMonitorTestFactory -import org.scalatest._ -import org.scalatest.concurrent.{Futures, ScalaFutures} -import org.scalatest.flatspec.AnyFlatSpecLike -import org.scalatest.matchers.should.Matchers - -import scala.concurrent.{ExecutionContext, Future} -import scala.concurrent.duration._ class AkkaStreamAgentTest extends InstallModule(AkkaStreamAgent) @@ -142,7 +153,6 @@ class AkkaStreamAgentTest "AkkaStreamAgentTest" should "accurately detect push / demand" in testCase { implicit c => implicit val ec: ExecutionContext = system.executionContext - val Demand = 5L val ExpectedElements = Demand + 1L // somehow sinkQueue demand 1 element in advance diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala index bfdfc1715..ff54b2a25 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/utils/InstallAgent.scala @@ -1,5 +1,12 @@ package io.scalac.mesmer.agent.utils +import net.bytebuddy.ByteBuddy +import net.bytebuddy.agent.ByteBuddyAgent +import net.bytebuddy.agent.builder.AgentBuilder +import net.bytebuddy.dynamic.scaffold.TypeValidation +import org.scalatest.BeforeAndAfterAll +import org.scalatest.TestSuite + import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent @@ -8,13 +15,10 @@ import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory import io.scalac.mesmer.agent.util.i13n.InstrumentModuleFactory._ import io.scalac.mesmer.agent.utils.InstallAgent.allInstrumentations -import io.scalac.mesmer.core.module.{ MesmerModule, RegisterGlobalConfiguration } -import io.scalac.mesmer.core.util.LibraryInfo.{ extractModulesInformation, LibraryInfo } -import net.bytebuddy.ByteBuddy -import net.bytebuddy.agent.ByteBuddyAgent -import net.bytebuddy.agent.builder.AgentBuilder -import net.bytebuddy.dynamic.scaffold.TypeValidation -import org.scalatest.{ BeforeAndAfterAll, TestSuite } +import io.scalac.mesmer.core.module.MesmerModule +import io.scalac.mesmer.core.module.RegisterGlobalConfiguration +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo +import io.scalac.mesmer.core.util.LibraryInfo.extractModulesInformation object InstallAgent { def allInstrumentations(info: LibraryInfo): Agent = AkkaActorAgent.defaultAgent(info) ++ diff --git a/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala b/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala index af1459dd4..e80d8923d 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala @@ -1,12 +1,15 @@ package io.scalac.mesmer.core.config -import com.typesafe.config.{ Config, ConfigException } -import io.scalac.mesmer.core.config.ConfigurationUtils.ConfigOps +import com.typesafe.config.Config +import com.typesafe.config.ConfigException import scala.language.implicitConversions -import scala.reflect.{ classTag, ClassTag } +import scala.reflect.ClassTag +import scala.reflect.classTag import scala.util.Try +import io.scalac.mesmer.core.config.ConfigurationUtils.ConfigOps + object ConfigurationUtils { private[core] class ConfigOps(private val value: Config) extends AnyVal { @@ -46,7 +49,7 @@ trait MesmerConfigurationBase extends Configuration { */ private final val mesmerBase: String = "io.scalac.mesmer" - protected lazy val absoluteBase = s"$mesmerBase.$mesmerConfig" + protected lazy val absoluteBase: String = s"$mesmerBase.$mesmerConfig" /** * Name of configuration inside mesmer branch diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala index 2f89edbea..27928d526 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.module.Module.Combine +import io.scalac.mesmer.core.module.Module.Traverse import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaActorMetrics extends MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala index 5791057ad..82bc2bf4a 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala @@ -1,5 +1,6 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala index e2d2f3329..dda9275df 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala @@ -1,5 +1,6 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala index 486fab1aa..7d858492c 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -1,8 +1,10 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.module.Module.Combine +import io.scalac.mesmer.core.module.Module.Traverse import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo /** diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala index 7eaf42055..2a196cc8e 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.module.Module.Combine +import io.scalac.mesmer.core.module.Module.Traverse import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaPersistenceMetricsModule extends MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala index 8f9fd9176..04f44aa48 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.module.Module.Combine +import io.scalac.mesmer.core.module.Module.Traverse import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaStreamMetrics extends MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala index 08fad89da..486e2106b 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -1,6 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.config.MesmerConfigurationBase import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo @@ -21,7 +22,7 @@ trait Module { object Module { - implicit class AllOps[M[X] <: Module#All[X], T](val value: M[T]) extends AnyVal { + implicit class AllOps[M[X] <: Module#All[X], T](private val value: M[T]) extends AnyVal { def combine(other: M[T])(implicit combine: Combine[M[T]]): M[T] = combine.combine(value, other) def exists(check: T => Boolean)(implicit traverse: Traverse[M]): Boolean = traverse.sequence(value).exists(check) } @@ -44,7 +45,7 @@ trait MesmerModule extends Module with MesmerConfigurationBase { def defaultConfig: Result - val mesmerConfig = s"module.$name" + val mesmerConfig: String = s"module.$name" } trait MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/LibraryInfo.scala b/core/src/main/scala/io/scalac/mesmer/core/util/LibraryInfo.scala index 6dd5f8ae3..6cfe877c4 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/LibraryInfo.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/LibraryInfo.scala @@ -1,10 +1,12 @@ package io.scalac.mesmer.core.util -import io.scalac.mesmer.core.model.Version +import java.util.jar.Attributes +import java.util.jar.Manifest -import java.util.jar.{ Attributes, Manifest } import scala.jdk.CollectionConverters._ +import io.scalac.mesmer.core.model.Version + object LibraryInfo { /** diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/ReflectionFieldUtils.scala b/core/src/main/scala/io/scalac/mesmer/core/util/ReflectionFieldUtils.scala index 0a823cea3..1fc95123c 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/ReflectionFieldUtils.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/ReflectionFieldUtils.scala @@ -1,10 +1,11 @@ package io.scalac.mesmer.core.util -import io.scalac.mesmer.core.invoke.Lookup - -import java.lang.invoke.{ MethodHandle, MethodHandles } +import java.lang.invoke.MethodHandle +import java.lang.invoke.MethodHandles import java.lang.reflect.Field +import io.scalac.mesmer.core.invoke.Lookup + object ReflectionFieldUtils extends Lookup { @inline final def getHandlers(className: String, fieldName: String): (MethodHandle, MethodHandle) = diff --git a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala index 5eda02348..257de3526 100644 --- a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala +++ b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala @@ -1,14 +1,15 @@ package io.scalac.mesmer.core.model -import com.typesafe.config.{Config => TypesafeConfig} -import io.scalac.mesmer.core.module.Module -import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo +import com.typesafe.config.{ Config => TypesafeConfig } import org.scalatest.Inspectors import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import scala.runtime.BoxedUnit +import io.scalac.mesmer.core.module.Module +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo + class SupportedModulesTest extends AnyFlatSpec with Matchers with Inspectors { type Id[T] = T diff --git a/example/src/main/resources/common/application.conf b/example/src/main/resources/common/application.conf index 498b305fc..eb0fe45e5 100644 --- a/example/src/main/resources/common/application.conf +++ b/example/src/main/resources/common/application.conf @@ -10,7 +10,7 @@ akka { "example.serialization.SerializableMessage" = jackson-cbor } - typed.extensions = ["io.scalac.mesmer.extension.AkkaMonitoring"] + typed.extensions = ["io.scalac.mesmer.extension.Mesmer"] } coordinated-shutdown.exit-jvm = on diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala index d238e63a2..4a72d4b19 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaStreamMonitoring.scala @@ -1,40 +1,54 @@ package io.scalac.mesmer.extension +import java.util +import java.util.concurrent.atomic.AtomicReference + +import akka.actor.ActorRef +import akka.actor.typed import akka.actor.typed._ import akka.actor.typed.receptionist.Receptionist.Register +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.scaladsl.TimerScheduler import akka.actor.typed.scaladsl.adapter._ -import akka.actor.typed.scaladsl.{ ActorContext, Behaviors, TimerScheduler } -import akka.actor.{ typed, ActorRef } import akka.util.Timeout + +import scala.annotation.tailrec +import scala.collection.mutable +import scala.collection.mutable.ListBuffer +import scala.concurrent.duration.FiniteDuration +import scala.concurrent.duration._ +import scala.jdk.CollectionConverters._ +import scala.jdk.DurationConverters._ +import scala.util.Failure +import scala.util.Success + import io.scalac.mesmer.core.akka.model.PushMetrics import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.core.event.Service.streamService import io.scalac.mesmer.core.event.StreamEvent -import io.scalac.mesmer.core.event.StreamEvent.{ LastStreamStats, StreamInterpreterStats } -import io.scalac.mesmer.core.model.Tag.{ StageName, StreamName } +import io.scalac.mesmer.core.event.StreamEvent.LastStreamStats +import io.scalac.mesmer.core.event.StreamEvent.StreamInterpreterStats +import io.scalac.mesmer.core.model.Tag.StageName +import io.scalac.mesmer.core.model.Tag.StreamName import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.model.stream.{ ConnectionStats, StageInfo } +import io.scalac.mesmer.core.model.stream.ConnectionStats +import io.scalac.mesmer.core.model.stream.StageInfo import io.scalac.mesmer.core.module.AkkaStreamModule import io.scalac.mesmer.extension.AkkaStreamMonitoring._ -import io.scalac.mesmer.extension.config.{ BufferConfig, CachingConfig } +import io.scalac.mesmer.extension.config.BufferConfig +import io.scalac.mesmer.extension.config.CachingConfig import io.scalac.mesmer.extension.metric.MetricObserver.Result -import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.{ EagerLabels, Labels => GlobalLabels } +import io.scalac.mesmer.extension.metric.StreamMetricsMonitor +import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.EagerLabels +import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.{Labels => GlobalLabels} +import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.Labels -import io.scalac.mesmer.extension.metric.{ StreamMetricsMonitor, StreamOperatorMetricsMonitor } +import io.scalac.mesmer.extension.service.ActorTreeService import io.scalac.mesmer.extension.service.ActorTreeService.Command.GetActors -import io.scalac.mesmer.extension.service.{ actorTreeServiceKey, ActorTreeService } +import io.scalac.mesmer.extension.service.actorTreeServiceKey import io.scalac.mesmer.extension.util.GenericBehaviors -import java.util -import java.util.concurrent.atomic.AtomicReference -import scala.annotation.tailrec -import scala.collection.mutable -import scala.collection.mutable.ListBuffer -import scala.concurrent.duration.{ FiniteDuration, _ } -import scala.jdk.CollectionConverters._ -import scala.jdk.DurationConverters._ -import scala.util.{ Failure, Success } - object AkkaStreamMonitoring { sealed trait Command diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/ClusterRegionsMonitorActor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/ClusterRegionsMonitorActor.scala index f4c60725c..3401344df 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/ClusterRegionsMonitorActor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/ClusterRegionsMonitorActor.scala @@ -18,9 +18,9 @@ import scala.concurrent.Future import scala.concurrent.duration._ import scala.jdk.DurationConverters.JavaDurationOps +import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.util.CachedQueryResult -import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.extension.metric.ClusterMetricsMonitor import io.scalac.mesmer.extension.metric.ClusterMetricsMonitor.Labels diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/HttpEventsActor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/HttpEventsActor.scala index 08a8d2be0..292168b2e 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/HttpEventsActor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/HttpEventsActor.scala @@ -1,17 +1,22 @@ package io.scalac.mesmer.extension +import akka.actor.typed.Behavior +import akka.actor.typed.PostStop import akka.actor.typed.receptionist.Receptionist -import akka.actor.typed.receptionist.Receptionist.{ Deregister, Register } +import akka.actor.typed.receptionist.Receptionist.Deregister +import akka.actor.typed.receptionist.Receptionist.Register import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.{ Behavior, PostStop } import akka.util.Timeout + import io.scalac.mesmer.core._ import io.scalac.mesmer.core.event.HttpEvent import io.scalac.mesmer.core.event.HttpEvent._ -import io.scalac.mesmer.core.model.{ Method, Path, _ } -import io.scalac.mesmer.core.module.AkkaHttpModule +import io.scalac.mesmer.core.model.Method +import io.scalac.mesmer.core.model.Path +import io.scalac.mesmer.core.model._ import io.scalac.mesmer.extension.http.RequestStorage -import io.scalac.mesmer.extension.metric.{ HttpConnectionMetricsMonitor, HttpMetricsMonitor } +import io.scalac.mesmer.extension.metric.HttpConnectionMetricsMonitor +import io.scalac.mesmer.extension.metric.HttpMetricsMonitor import io.scalac.mesmer.extension.service.PathService class HttpEventsActor diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/Mesmer.scala similarity index 85% rename from extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala rename to extension/src/main/scala/io/scalac/mesmer/extension/Mesmer.scala index 97273dda6..0c4c371ea 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/Mesmer.scala @@ -5,42 +5,50 @@ import akka.actor.typed.receptionist.Receptionist.Register import akka.actor.typed.scaladsl.Behaviors import akka.cluster.Cluster import akka.util.Timeout + +import scala.concurrent.duration._ +import scala.language.postfixOps +import scala.reflect.ClassTag +import scala.reflect.classTag +import scala.util.Try + import io.scalac.mesmer.core.AkkaDispatcher import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaHttpModule +import io.scalac.mesmer.core.module.AkkaPersistenceModule import io.scalac.mesmer.core.module.Module._ -import io.scalac.mesmer.core.module.{ AkkaHttpModule, AkkaPersistenceModule, _ } +import io.scalac.mesmer.core.module._ import io.scalac.mesmer.core.util.Timestamp import io.scalac.mesmer.extension.ActorEventsMonitorActor.ReflectiveActorMetricsReader -import io.scalac.mesmer.extension.AkkaMonitoring.ExportInterval +import io.scalac.mesmer.extension.Mesmer.ExportInterval import io.scalac.mesmer.extension.actor.MutableActorMetricStorageFactory -import io.scalac.mesmer.extension.config.{ AkkaMonitoringConfig, CachingConfig, InstrumentationLibrary } +import io.scalac.mesmer.extension.config.AkkaMonitoringConfig +import io.scalac.mesmer.extension.config.CachingConfig +import io.scalac.mesmer.extension.config.InstrumentationLibrary import io.scalac.mesmer.extension.http.CleanableRequestStorage import io.scalac.mesmer.extension.metric.CachingMonitor -import io.scalac.mesmer.extension.persistence.{ CleanablePersistingStorage, CleanableRecoveryStorage } +import io.scalac.mesmer.extension.persistence.CleanablePersistingStorage +import io.scalac.mesmer.extension.persistence.CleanableRecoveryStorage import io.scalac.mesmer.extension.service._ -import io.scalac.mesmer.extension.upstream.{ OpenTelemetryClusterMetricsMonitor, _ } +import io.scalac.mesmer.extension.upstream._ -import scala.concurrent.duration._ -import scala.language.postfixOps -import scala.reflect.{ classTag, ClassTag } -import scala.util.Try - -object AkkaMonitoring extends ExtensionId[AkkaMonitoring] { +object Mesmer extends ExtensionId[Mesmer] { private val ExportInterval = 5.seconds - def createExtension(system: ActorSystem[_]): AkkaMonitoring = { + def createExtension(system: ActorSystem[_]): Mesmer = { val config = AkkaMonitoringConfig(system.settings.config) - new AkkaMonitoring(system, config) + new Mesmer(system, config) } } -final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaMonitoringConfig) extends Extension { +final class Mesmer(private val system: ActorSystem[_], val config: AkkaMonitoringConfig) extends Extension { import system.log - private val meter = InstrumentationLibrary.mesmerMeter - private val actorSystemConfig = system.settings.config - private val openTelemetryClusterMetricsMonitor = OpenTelemetryClusterMetricsMonitor(meter, actorSystemConfig) + private val meter = InstrumentationLibrary.mesmerMeter + private val actorSystemConfig = system.settings.config + private val openTelemetryClusterMetricsMonitor = + OpenTelemetryClusterMetricsMonitor(meter, AkkaClusterModule.fromConfig(actorSystemConfig), actorSystemConfig) implicit private val timeout: Timeout = 5 seconds @@ -110,8 +118,10 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM startWithConfig[AkkaActorModule.type](AkkaActorModule, akkaActorConfig) { _ => val actorSystemMonitor = OpenTelemetryActorSystemMonitor( meter, + AkkaActorSystemModule.fromConfig(actorSystemConfig), actorSystemConfig ) + val actorConfigurationService = new ConfigBasedConfigurationService(system.settings.config) val serviceRef = system.systemActorOf( @@ -164,10 +174,10 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM def startStreamMonitor(): Unit = startWithConfig[AkkaStreamModule.type](AkkaStreamModule, akkaStreamConfig) { moduleConfig => log.debug("Start stream monitor") - val streamOperatorMonitor = OpenTelemetryStreamOperatorMetricsMonitor(meter, actorSystemConfig) + val streamOperatorMonitor = OpenTelemetryStreamOperatorMetricsMonitor(meter, moduleConfig, actorSystemConfig) val streamMonitor = CachingMonitor( - OpenTelemetryStreamMetricsMonitor(meter, actorSystemConfig), + OpenTelemetryStreamMetricsMonitor(meter, moduleConfig, actorSystemConfig), CachingConfig.fromConfig(actorSystemConfig, AkkaStreamModule) ) @@ -210,10 +220,10 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM * Start actor responsible for measuring akka persistence metrics */ def startPersistenceMonitor(): Unit = - startWithConfig[AkkaPersistenceModule.type](AkkaPersistenceModule, akkaPersistenceConfig) { _ => + startWithConfig[AkkaPersistenceModule.type](AkkaPersistenceModule, akkaPersistenceConfig) { moduleConfig => val cachingConfig = CachingConfig.fromConfig(actorSystemConfig, AkkaPersistenceModule) val openTelemetryPersistenceMonitor = CachingMonitor( - OpenTelemetryPersistenceMetricsMonitor(meter, actorSystemConfig), + OpenTelemetryPersistenceMetricsMonitor(meter, moduleConfig, actorSystemConfig), cachingConfig ) val pathService = new CachingPathService(cachingConfig) @@ -254,7 +264,7 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM CachingMonitor(OpenTelemetryHttpMetricsMonitor(meter, moduleConfig, actorSystemConfig), cachingConfig) val openTelemetryHttpConnectionMonitor = - CachingMonitor(OpenTelemetryHttpConnectionMetricsMonitor(meter, actorSystemConfig), cachingConfig) + CachingMonitor(OpenTelemetryHttpConnectionMetricsMonitor(meter, moduleConfig, actorSystemConfig), cachingConfig) val pathService = new CachingPathService(cachingConfig) @@ -275,7 +285,7 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM } private def autoStart(): Unit = { - import config.{autoStart => autoStartConfig} + import config.{ autoStart => autoStartConfig } if (autoStartConfig.akkaActor || autoStartConfig.akkaStream) { startActorTreeService() diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala index 332141130..3ae2caf00 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala @@ -12,14 +12,24 @@ case class AkkaMonitoringConfig( cleaning: CleaningSettings ) -case class AutoStartSettings(akkaActor: Boolean, akkaHttp: Boolean, akkaPersistence: Boolean, akkaCluster: Boolean, akkaStream: Boolean) +case class AutoStartSettings( + akkaActor: Boolean, + akkaHttp: Boolean, + akkaPersistence: Boolean, + akkaCluster: Boolean, + akkaStream: Boolean +) object AkkaMonitoringConfig { - - private val autoStartDefaults = - AutoStartSettings(akkaActor = false, akkaHttp = false, akkaCluster = false, akkaPersistence = false, akkaStream = false) + AutoStartSettings( + akkaActor = false, + akkaHttp = false, + akkaCluster = false, + akkaPersistence = false, + akkaStream = false + ) private val cleaningSettingsDefaults = CleaningSettings(20.seconds, 5.second) private val akkaMonitoringDefaults = AkkaMonitoringConfig(autoStartDefaults, cleaningSettingsDefaults) diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala index 6a6a1bd06..a40aa0ec8 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/BufferConfig.scala @@ -1,6 +1,7 @@ package io.scalac.mesmer.extension.config import com.typesafe.config.Config + import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.core.module.Module diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala index 486c75a4b..e204987c5 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/CachingConfig.scala @@ -1,6 +1,7 @@ package io.scalac.mesmer.extension.config import com.typesafe.config.Config + import io.scalac.mesmer.core.config.ConfigurationUtils._ import io.scalac.mesmer.core.module.Module diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorSystemMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorSystemMonitor.scala index 7d4737cc6..70b60f70c 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorSystemMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/ActorSystemMonitor.scala @@ -2,13 +2,14 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaActorSystemModule object ActorSystemMonitor { final case class Labels(node: Option[Node]) extends LabelSerializable { override def serialize: RawLabels = node.serialize } - trait BoundMonitor extends Bound { + trait BoundMonitor extends Bound with AkkaActorSystemModule.All[Metric[Long]] { def createdActors: Counter[Long] def terminatedActors: Counter[Long] } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/ClusterMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/ClusterMetricsMonitor.scala index 4e20baeaa..7c7598271 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/ClusterMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/ClusterMetricsMonitor.scala @@ -2,6 +2,7 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaClusterModule object ClusterMetricsMonitor { @@ -12,7 +13,7 @@ object ClusterMetricsMonitor { def withRegion(region: Region): Labels = copy(region = Some(region)) } - trait BoundMonitor extends Synchronized with Bound { + trait BoundMonitor extends Synchronized with Bound with AkkaClusterModule.All[Metric[Long]] { def shardPerRegions: MetricObserver[Long, Labels] def entityPerRegion: MetricObserver[Long, Labels] def shardRegionsOnNode: MetricObserver[Long, Labels] diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpConnectionMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpConnectionMetricsMonitor.scala index 1c9fd3220..d4ca1a646 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpConnectionMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/HttpConnectionMetricsMonitor.scala @@ -1,7 +1,10 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable -import io.scalac.mesmer.core.model.{ Interface, Node, Port, RawLabels } +import io.scalac.mesmer.core.model.Interface +import io.scalac.mesmer.core.model.Node +import io.scalac.mesmer.core.model.Port +import io.scalac.mesmer.core.model.RawLabels import io.scalac.mesmer.core.module.AkkaHttpModule._ object HttpConnectionMetricsMonitor { diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala index 3c8642bc4..d48005e3a 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/Metric.scala @@ -1,10 +1,11 @@ package io.scalac.mesmer.extension.metric -import io.scalac.mesmer.extension.metric.SyncWith.UpdaterPair - import java.util.concurrent.atomic.AtomicInteger + import scala.annotation.tailrec +import io.scalac.mesmer.extension.metric.SyncWith.UpdaterPair + sealed trait Metric[-T] trait MetricRecorder[-T] extends Metric[T] { diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/PersistenceMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/PersistenceMetricsMonitor.scala index 2b09ee819..d349a48d8 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/PersistenceMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/PersistenceMetricsMonitor.scala @@ -1,6 +1,7 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaPersistenceModule object PersistenceMetricsMonitor { @@ -8,7 +9,7 @@ object PersistenceMetricsMonitor { val serialize: RawLabels = node.serialize ++ path.serialize ++ persistenceId.serialize } - trait BoundMonitor extends Bound { + trait BoundMonitor extends Bound with AkkaPersistenceModule.Metrics[Metric[Long]] { def recoveryTime: MetricRecorder[Long] def recoveryTotal: Counter[Long] def persistentEvent: MetricRecorder[Long] diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/StreamMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/StreamMetricsMonitor.scala index bf480b9d5..47e340b7f 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/StreamMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/StreamMetricsMonitor.scala @@ -3,20 +3,21 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable import io.scalac.mesmer.core.model.Tag.StreamName import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaStreamModule object StreamMetricsMonitor { - case class EagerLabels( + final case class EagerLabels( node: Option[Node] ) extends LabelSerializable { lazy val serialize: RawLabels = node.serialize } - case class Labels(node: Option[Node], streamName: StreamName) extends LabelSerializable { + final case class Labels(node: Option[Node], streamName: StreamName) extends LabelSerializable { lazy val serialize: RawLabels = node.serialize ++ streamName.serialize } - trait BoundMonitor extends Bound { + trait BoundMonitor extends Bound with AkkaStreamModule.StreamMetricsDef[Metric[Long]] { def runningStreamsTotal: MetricRecorder[Long] def streamActorsTotal: MetricRecorder[Long] def streamProcessedMessages: MetricObserver[Long, Labels] diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/metric/StreamOperatorMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/metric/StreamOperatorMetricsMonitor.scala index 8154f09d2..3fc63d7ca 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/metric/StreamOperatorMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/metric/StreamOperatorMetricsMonitor.scala @@ -3,6 +3,7 @@ package io.scalac.mesmer.extension.metric import io.scalac.mesmer.core.LabelSerializable import io.scalac.mesmer.core.model.Tag._ import io.scalac.mesmer.core.model._ +import io.scalac.mesmer.core.module.AkkaStreamModule object StreamOperatorMetricsMonitor { @@ -25,7 +26,7 @@ object StreamOperatorMetricsMonitor { } } - trait BoundMonitor extends Bound { + trait BoundMonitor extends Bound with AkkaStreamModule.StreamOperatorMetricsDef[Metric[Long]] { def processedMessages: MetricObserver[Long, StreamOperatorMetricsMonitor.Labels] def operators: MetricObserver[Long, StreamOperatorMetricsMonitor.Labels] def demand: MetricObserver[Long, StreamOperatorMetricsMonitor.Labels] diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/service/ActorConfigurationService.scala b/extension/src/main/scala/io/scalac/mesmer/extension/service/ActorConfigurationService.scala index 12fb177c7..ac65733c7 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/service/ActorConfigurationService.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/service/ActorConfigurationService.scala @@ -8,8 +8,8 @@ import org.slf4j.LoggerFactory import scala.jdk.CollectionConverters._ import io.scalac.mesmer.core.PathMatcher -import io.scalac.mesmer.core.model.ActorConfiguration import io.scalac.mesmer.core.config.ConfigurationUtils._ +import io.scalac.mesmer.core.model.ActorConfiguration trait ActorConfigurationService { def forActorPath(ref: classic.ActorPath): ActorConfiguration diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala index a177f5b7b..78d326e56 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala @@ -2,9 +2,12 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter + import io.scalac.mesmer.core.config.MesmerConfiguration import io.scalac.mesmer.core.module.AkkaActorModule -import io.scalac.mesmer.extension.metric.{ ActorMetricsMonitor, MetricObserver, RegisterRoot } +import io.scalac.mesmer.extension.metric.ActorMetricsMonitor +import io.scalac.mesmer.extension.metric.MetricObserver +import io.scalac.mesmer.extension.metric.RegisterRoot import io.scalac.mesmer.extension.upstream.OpenTelemetryActorMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ @@ -112,7 +115,7 @@ object OpenTelemetryActorMetricsMonitor { ) } - protected val defaultConfig: MetricNames = + val defaultConfig: MetricNames = MetricNames( "akka_actor_mailbox_size", "akka_actor_mailbox_time_avg", @@ -142,7 +145,7 @@ object OpenTelemetryActorMetricsMonitor { } -class OpenTelemetryActorMetricsMonitor( +final class OpenTelemetryActorMetricsMonitor( meter: Meter, moduleConfig: AkkaActorModule.All[Boolean], metricNames: MetricNames diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala index 1a05fae01..78f5d402e 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitor.scala @@ -2,11 +2,15 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter + import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.core.module.AkkaActorSystemModule +import io.scalac.mesmer.extension.metric.ActorSystemMonitor import io.scalac.mesmer.extension.metric.ActorSystemMonitor.BoundMonitor -import io.scalac.mesmer.extension.metric.{ActorSystemMonitor, RegisterRoot} +import io.scalac.mesmer.extension.metric.RegisterRoot import io.scalac.mesmer.extension.upstream.OpenTelemetryActorSystemMonitor.MetricNames -import io.scalac.mesmer.extension.upstream.opentelemetry.{SynchronousInstrumentFactory, WrappedCounter} +import io.scalac.mesmer.extension.upstream.opentelemetry.SynchronousInstrumentFactory +import io.scalac.mesmer.extension.metric.Counter object OpenTelemetryActorSystemMonitor { @@ -16,13 +20,13 @@ object OpenTelemetryActorSystemMonitor { ) object MetricNames extends MesmerConfiguration[MetricNames] { - protected val defaultConfig: MetricNames = + val defaultConfig: MetricNames = MetricNames("akka_system_created_actors_total", "akka_system_terminated_actors_total") protected val mesmerConfig: String = "metrics.actor-system-metrics" protected def extractFromConfig(config: Config): MetricNames = { - val createdActors = config.tryValue("created-actors")(_.getString).getOrElse(defaultConfig.createdActors) + val createdActors = config.tryValue("created-actors")(_.getString).getOrElse(defaultConfig.createdActors) val terminatedActors = config.tryValue("terminated-actors")(_.getString).getOrElse(defaultConfig.createdActors) @@ -30,18 +34,26 @@ object OpenTelemetryActorSystemMonitor { } } - def apply(meter: Meter, config: Config): OpenTelemetryActorSystemMonitor = - new OpenTelemetryActorSystemMonitor(meter, MetricNames.fromConfig(config)) + def apply( + meter: Meter, + moduleConfig: AkkaActorSystemModule.All[Boolean], + config: Config + ): OpenTelemetryActorSystemMonitor = + new OpenTelemetryActorSystemMonitor(meter, moduleConfig, MetricNames.fromConfig(config)) } -final class OpenTelemetryActorSystemMonitor(val meter: Meter, metricNames: MetricNames) extends ActorSystemMonitor { +final class OpenTelemetryActorSystemMonitor( + val meter: Meter, + moduleConfig: AkkaActorSystemModule.All[Boolean], + metricNames: MetricNames +) extends ActorSystemMonitor { - private val createdActorsCounter = meter + private lazy val createdActorsCounter = meter .longCounterBuilder(metricNames.createdActors) .setDescription("Amount of actors created measured from Actor System start") .build() - private val terminatedActorsCounter = meter + private lazy val terminatedActorsCounter = meter .longCounterBuilder(metricNames.terminatedActors) .setDescription("Amount of actors terminated measured from Actor System start") .build() @@ -55,8 +67,10 @@ final class OpenTelemetryActorSystemMonitor(val meter: Meter, metricNames: Metri with SynchronousInstrumentFactory { private[this] val otLabels = LabelsFactory.of(labels.serialize) - override lazy val createdActors: WrappedCounter = counter(createdActorsCounter, otLabels)(this) + lazy val createdActors: Counter[Long] = + if (moduleConfig.createdActors) counter(createdActorsCounter, otLabels)(this) else noopCounter - override lazy val terminatedActors: WrappedCounter = counter(terminatedActorsCounter, otLabels)(this) + lazy val terminatedActors: Counter[Long] = + if (moduleConfig.terminatedActors) counter(terminatedActorsCounter, otLabels)(this) else noopCounter } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala index c4a25211f..3584796cd 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitor.scala @@ -2,10 +2,14 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter + import io.scalac.mesmer.core.config.MesmerConfiguration -import io.scalac.mesmer.extension.metric.{ ClusterMetricsMonitor, _ } +import io.scalac.mesmer.core.module.AkkaClusterModule +import io.scalac.mesmer.extension.metric.ClusterMetricsMonitor +import io.scalac.mesmer.extension.metric._ import io.scalac.mesmer.extension.upstream.OpenTelemetryClusterMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ +import io.opentelemetry.api.metrics.common.Labels object OpenTelemetryClusterMetricsMonitor { final case class MetricNames( @@ -19,7 +23,7 @@ object OpenTelemetryClusterMetricsMonitor { ) object MetricNames extends MesmerConfiguration[MetricNames] { - protected val defaultConfig: MetricNames = + val defaultConfig: MetricNames = MetricNames( "akka_cluster_shards_per_region", "akka_cluster_entities_per_region", @@ -73,82 +77,90 @@ object OpenTelemetryClusterMetricsMonitor { } } - def apply(meter: Meter, config: Config): OpenTelemetryClusterMetricsMonitor = - new OpenTelemetryClusterMetricsMonitor(meter, MetricNames.fromConfig(config)) + def apply( + meter: Meter, + moduleConfig: AkkaClusterModule.All[Boolean], + config: Config + ): OpenTelemetryClusterMetricsMonitor = + new OpenTelemetryClusterMetricsMonitor(meter, moduleConfig, MetricNames.fromConfig(config)) } -final class OpenTelemetryClusterMetricsMonitor(meter: Meter, metricNames: MetricNames) extends ClusterMetricsMonitor { +final class OpenTelemetryClusterMetricsMonitor( + meter: Meter, + moduleConfig: AkkaClusterModule.All[Boolean], + metricNames: MetricNames +) extends ClusterMetricsMonitor { - private val shardsPerRegionRecorder = new LongMetricObserverBuilderAdapter[ClusterMetricsMonitor.Labels]( + private lazy val shardsPerRegionRecorder = new LongMetricObserverBuilderAdapter[ClusterMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.shardPerEntity) .setDescription("Amount of shards in region") ) - private val entityPerRegionRecorder = new LongMetricObserverBuilderAdapter[ClusterMetricsMonitor.Labels]( + private lazy val entityPerRegionRecorder = new LongMetricObserverBuilderAdapter[ClusterMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.entityPerRegion) .setDescription("Amount of entities in region") ) - private val reachableNodeCounter = meter + private lazy val reachableNodeCounter = meter .longUpDownCounterBuilder(metricNames.reachableNodes) .setDescription("Amount of reachable nodes") .build() - private val unreachableNodeCounter = meter + private lazy val unreachableNodeCounter = meter .longUpDownCounterBuilder(metricNames.unreachableNodes) .setDescription("Amount of unreachable nodes") .build() - private val shardRegionsOnNodeRecorder = new LongMetricObserverBuilderAdapter[ClusterMetricsMonitor.Labels]( + private lazy val shardRegionsOnNodeRecorder = new LongMetricObserverBuilderAdapter[ClusterMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.shardRegionsOnNode) .setDescription("Amount of shard regions on node") ) - private val entitiesOnNodeObserver = new LongMetricObserverBuilderAdapter[ClusterMetricsMonitor.Labels]( + private lazy val entitiesOnNodeObserver = new LongMetricObserverBuilderAdapter[ClusterMetricsMonitor.Labels]( meter .longValueObserverBuilder(metricNames.entitiesOnNode) .setDescription("Amount of entities on node") ) - private val nodeDownCounter = meter + private lazy val nodeDownCounter = meter .longCounterBuilder(metricNames.nodeDown) .setDescription("Counter for node down events") .build() def bind(labels: ClusterMetricsMonitor.Labels): ClusterBoundMonitor = new ClusterBoundMonitor(labels) -// new ClusterBoundMonitor(LabelsFactory.of(LabelNames.Node -> labels.node)(LabelNames.Region -> labels.region)) - class ClusterBoundMonitor(labels: ClusterMetricsMonitor.Labels) + final class ClusterBoundMonitor(labels: ClusterMetricsMonitor.Labels) extends opentelemetry.Synchronized(meter) with ClusterMetricsMonitor.BoundMonitor with RegisterRoot with SynchronousInstrumentFactory { - protected val otLabels = LabelsFactory.of(labels.serialize) + protected val otLabels: Labels = LabelsFactory.of(labels.serialize) - val shardPerRegions: MetricObserver[Long, ClusterMetricsMonitor.Labels] = - shardsPerRegionRecorder.createObserver(this) + lazy val shardPerRegions: MetricObserver[Long, ClusterMetricsMonitor.Labels] = { + if (moduleConfig.shardPerRegions) shardsPerRegionRecorder.createObserver(this) else MetricObserver.noop + } - val entityPerRegion: MetricObserver[Long, ClusterMetricsMonitor.Labels] = - entityPerRegionRecorder.createObserver(this) + lazy val entityPerRegion: MetricObserver[Long, ClusterMetricsMonitor.Labels] = + if (moduleConfig.entityPerRegion) entityPerRegionRecorder.createObserver(this) else MetricObserver.noop - val shardRegionsOnNode: MetricObserver[Long, ClusterMetricsMonitor.Labels] = - shardRegionsOnNodeRecorder.createObserver(this) + lazy val shardRegionsOnNode: MetricObserver[Long, ClusterMetricsMonitor.Labels] = + if (moduleConfig.shardRegionsOnNode) shardRegionsOnNodeRecorder.createObserver(this) else MetricObserver.noop - val entitiesOnNode: MetricObserver[Long, ClusterMetricsMonitor.Labels] = - entitiesOnNodeObserver.createObserver(this) + lazy val entitiesOnNode: MetricObserver[Long, ClusterMetricsMonitor.Labels] = + if (moduleConfig.entitiesOnNode) entitiesOnNodeObserver.createObserver(this) else MetricObserver.noop - val reachableNodes: UpDownCounter[Long] with Instrument[Long] = - upDownCounter(reachableNodeCounter, otLabels)(this) + lazy val reachableNodes: UpDownCounter[Long] with Instrument[Long] = + if (moduleConfig.reachableNodes) upDownCounter(reachableNodeCounter, otLabels)(this) else noopUpDownCounter - val unreachableNodes: UpDownCounter[Long] with Instrument[Long] = - upDownCounter(unreachableNodeCounter, otLabels)(this) + lazy val unreachableNodes: UpDownCounter[Long] with Instrument[Long] = + if (moduleConfig.unreachableNodes) upDownCounter(unreachableNodeCounter, otLabels)(this) else noopUpDownCounter - val nodeDown: Counter[Long] with Instrument[Long] = - counter(nodeDownCounter, otLabels)(this) + lazy val nodeDown: Counter[Long] with Instrument[Long] = + if (moduleConfig.nodeDown) counter(nodeDownCounter, otLabels)(this) else noopCounter } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala index 585f093b9..67ad2c596 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitor.scala @@ -1,44 +1,54 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config -import io.opentelemetry.api.metrics.{Meter, common} -import io.scalac.mesmer.extension.metric.{HttpConnectionMetricsMonitor, Metric, RegisterRoot, UpDownCounter} -import io.scalac.mesmer.extension.upstream.opentelemetry._ -import OpenTelemetryHttpConnectionMetricsMonitor.MetricNames +import io.opentelemetry.api.metrics.Meter + import io.scalac.mesmer.core.config.MesmerConfiguration +import io.scalac.mesmer.core.module.AkkaHttpModule +import io.scalac.mesmer.extension.metric.HttpConnectionMetricsMonitor +import io.scalac.mesmer.extension.metric.RegisterRoot +import io.scalac.mesmer.extension.metric.UpDownCounter +import io.scalac.mesmer.extension.upstream.OpenTelemetryHttpConnectionMetricsMonitor.MetricNames +import io.scalac.mesmer.extension.upstream.opentelemetry._ +import io.opentelemetry.api.metrics.common object OpenTelemetryHttpConnectionMetricsMonitor { final case class MetricNames(connectionTotal: String) object MetricNames extends MesmerConfiguration[MetricNames] { - protected val defaultConfig: MetricNames = + val defaultConfig: MetricNames = MetricNames("akka_http_connections") - protected val mesmerConfig: String = "metrics.http-metrics" - + protected val mesmerConfig: String = "metrics.http-metrics" - protected def extractFromConfig(config: Config): MetricNames = { + protected def extractFromConfig(config: Config): MetricNames = { - val connectionTotal = config - .tryValue("connections")(_.getString) - .getOrElse(defaultConfig.connectionTotal) - - MetricNames(connectionTotal) - } + val connectionTotal = config + .tryValue("connections")(_.getString) + .getOrElse(defaultConfig.connectionTotal) + MetricNames(connectionTotal) + } } - def apply(meter: Meter, config: Config): OpenTelemetryHttpConnectionMetricsMonitor = - new OpenTelemetryHttpConnectionMetricsMonitor(meter, MetricNames.fromConfig(config)) + def apply( + meter: Meter, + moduleConfig: AkkaHttpModule.AkkaHttpConnectionsMetricsDef[Boolean], + config: Config + ): OpenTelemetryHttpConnectionMetricsMonitor = + new OpenTelemetryHttpConnectionMetricsMonitor(meter, moduleConfig, MetricNames.fromConfig(config)) } -class OpenTelemetryHttpConnectionMetricsMonitor(meter: Meter, metricNames: MetricNames) - extends HttpConnectionMetricsMonitor { +final class OpenTelemetryHttpConnectionMetricsMonitor( + meter: Meter, + moduleConfig: AkkaHttpModule.AkkaHttpConnectionsMetricsDef[Boolean], + metricNames: MetricNames +) extends HttpConnectionMetricsMonitor { import HttpConnectionMetricsMonitor._ - private val connectionTotalCounter = meter + private lazy val connectionTotalCounter = meter .longUpDownCounterBuilder(metricNames.connectionTotal) .setDescription("Amount of connections") .build() @@ -51,12 +61,10 @@ class OpenTelemetryHttpConnectionMetricsMonitor(meter: Meter, metricNames: Metri with SynchronousInstrumentFactory with RegisterRoot { - protected val otLabels = LabelsFactory.of(labels.serialize) - - val connections: UpDownCounter[Long] with Instrument[Long] = - upDownCounter(connectionTotalCounter, otLabels).register(this) - + protected lazy val otLabels: common.Labels = LabelsFactory.of(labels.serialize) -// override def connections: Metric[Long] = ??? + lazy val connections: UpDownCounter[Long] with Instrument[Long] = + if (moduleConfig.connections) upDownCounter(connectionTotalCounter, otLabels).register(this) + else noopUpDownCounter } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala index 401b8c32d..5d6c48a49 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitor.scala @@ -2,11 +2,15 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter + import io.scalac.mesmer.core.config.MesmerConfiguration import io.scalac.mesmer.core.module.AkkaHttpModule -import io.scalac.mesmer.extension.metric.{ HttpMetricsMonitor, RegisterRoot } +import io.scalac.mesmer.extension.metric.HttpMetricsMonitor +import io.scalac.mesmer.extension.metric.RegisterRoot import io.scalac.mesmer.extension.upstream.OpenTelemetryHttpMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ +import io.opentelemetry.api.metrics.common +import io.scalac.mesmer.extension.metric.{ Counter, MetricRecorder } object OpenTelemetryHttpMetricsMonitor { final case class MetricNames( @@ -18,7 +22,7 @@ object OpenTelemetryHttpMetricsMonitor { protected val mesmerConfig: String = "metrics.http-metrics" - protected val defaultConfig: MetricNames = MetricNames( + val defaultConfig: MetricNames = MetricNames( "akka_http_request_duration", "akka_http_request_total" ) @@ -70,13 +74,13 @@ final class OpenTelemetryHttpMetricsMonitor( with SynchronousInstrumentFactory with RegisterRoot { - protected val otLabels = LabelsFactory.of(labels.serialize) + protected val otLabels: common.Labels = LabelsFactory.of(labels.serialize) - val requestTime = + lazy val requestTime: MetricRecorder[Long] with Instrument[Long] = if (moduleConfig.requestTime) metricRecorder(requestTimeRequest, otLabels).register(this) else noopMetricRecorder[Long] - val requestCounter = + lazy val requestCounter: Counter[Long] with Instrument[Long] = if (moduleConfig.requestCounter) counter(requestTotalCounter, otLabels).register(this) else noopCounter[Long] } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala index 19ed32308..d85d63075 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitor.scala @@ -2,8 +2,13 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter + import io.scalac.mesmer.core.config.MesmerConfiguration -import io.scalac.mesmer.extension.metric.{ Counter, MetricRecorder, PersistenceMetricsMonitor, RegisterRoot } +import io.scalac.mesmer.core.module.AkkaPersistenceModule +import io.scalac.mesmer.extension.metric.Counter +import io.scalac.mesmer.extension.metric.MetricRecorder +import io.scalac.mesmer.extension.metric.PersistenceMetricsMonitor +import io.scalac.mesmer.extension.metric.RegisterRoot import io.scalac.mesmer.extension.upstream.OpenTelemetryPersistenceMetricsMonitor._ import io.scalac.mesmer.extension.upstream.opentelemetry._ @@ -19,7 +24,7 @@ object OpenTelemetryPersistenceMetricsMonitor { ) object MetricNames extends MesmerConfiguration[MetricNames] { - protected val defaultConfig: MetricNames = + val defaultConfig: MetricNames = MetricNames( "akka_persistence_recovery_time", "akka_persistence_recovery_total", @@ -52,60 +57,71 @@ object OpenTelemetryPersistenceMetricsMonitor { } } - def apply(meter: Meter, config: Config): OpenTelemetryPersistenceMetricsMonitor = - new OpenTelemetryPersistenceMetricsMonitor(meter, MetricNames.fromConfig(config)) + def apply( + meter: Meter, + moduleConfig: AkkaPersistenceModule.All[Boolean], + config: Config + ): OpenTelemetryPersistenceMetricsMonitor = + new OpenTelemetryPersistenceMetricsMonitor(meter, moduleConfig, MetricNames.fromConfig(config)) } -final class OpenTelemetryPersistenceMetricsMonitor(meter: Meter, metricNames: MetricNames) extends PersistenceMetricsMonitor { +final class OpenTelemetryPersistenceMetricsMonitor( + meter: Meter, + moduleConfig: AkkaPersistenceModule.All[Boolean], + metricNames: MetricNames +) extends PersistenceMetricsMonitor { import PersistenceMetricsMonitor._ - private val recoveryTimeRecorder = meter + private lazy val recoveryTimeRecorder = meter .longValueRecorderBuilder(metricNames.recoveryTime) .setDescription("Amount of time needed for entity recovery") .build() - private val recoveryTotalCounter = meter + private lazy val recoveryTotalCounter = meter .longCounterBuilder(metricNames.recoveryTotal) .setDescription("Amount of recoveries") .build() - private val persistentEventRecorder = meter + private lazy val persistentEventRecorder = meter .longValueRecorderBuilder(metricNames.persistentEvent) .setDescription("Amount of time needed for entity to persist events") .build() - private val persistentEventTotalCounter = meter + private lazy val persistentEventTotalCounter = meter .longCounterBuilder(metricNames.persistentEventTotal) .setDescription("Amount of persist events") .build() - private val snapshotCounter = meter + private lazy val snapshotCounter = meter .longCounterBuilder(metricNames.snapshotTotal) .setDescription("Amount of snapshots created") .build() def bind(labels: Labels): BoundMonitor = new OpenTelemetryBoundMonitor(labels) - class OpenTelemetryBoundMonitor(labels: Labels) + final class OpenTelemetryBoundMonitor(labels: Labels) extends BoundMonitor with RegisterRoot with SynchronousInstrumentFactory { private val openTelemetryLabels = LabelsFactory.of(labels.serialize) lazy val recoveryTime: MetricRecorder[Long] = - metricRecorder(recoveryTimeRecorder, openTelemetryLabels).register(this) + if (moduleConfig.recoveryTime) metricRecorder(recoveryTimeRecorder, openTelemetryLabels).register(this) + else noopMetricRecorder lazy val persistentEvent: MetricRecorder[Long] = - metricRecorder(persistentEventRecorder, openTelemetryLabels).register(this) + if (moduleConfig.persistentEvent) metricRecorder(persistentEventRecorder, openTelemetryLabels).register(this) + else noopMetricRecorder lazy val persistentEventTotal: Counter[Long] = - counter(persistentEventTotalCounter, openTelemetryLabels).register(this) + if (moduleConfig.persistentEventTotal) counter(persistentEventTotalCounter, openTelemetryLabels).register(this) + else noopCounter lazy val snapshot: Counter[Long] = - counter(snapshotCounter, openTelemetryLabels).register(this) + if (moduleConfig.snapshot) counter(snapshotCounter, openTelemetryLabels).register(this) else noopCounter lazy val recoveryTotal: Counter[Long] = - counter(recoveryTotalCounter, openTelemetryLabels).register(this) + if (moduleConfig.recoveryTotal) counter(recoveryTotalCounter, openTelemetryLabels).register(this) else noopCounter } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitor.scala index 219130870..1fdaa3a9a 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitor.scala @@ -2,14 +2,16 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter + import io.scalac.mesmer.core.config.MesmerConfiguration -import io.scalac.mesmer.extension.metric.{ MetricObserver, RegisterRoot, StreamMetricsMonitor } +import io.scalac.mesmer.core.module.AkkaStreamModule +import io.scalac.mesmer.extension.metric.MetricObserver +import io.scalac.mesmer.extension.metric.RegisterRoot +import io.scalac.mesmer.extension.metric.StreamMetricsMonitor import io.scalac.mesmer.extension.upstream.OpenTelemetryStreamMetricsMonitor.MetricNames -import io.scalac.mesmer.extension.upstream.opentelemetry.{ - LongSumObserverBuilderAdapter, - SynchronousInstrumentFactory, - WrappedLongValueRecorder -} +import io.scalac.mesmer.extension.upstream.opentelemetry.LongSumObserverBuilderAdapter +import io.scalac.mesmer.extension.upstream.opentelemetry.SynchronousInstrumentFactory +import io.scalac.mesmer.extension.metric.MetricRecorder object OpenTelemetryStreamMetricsMonitor { final case class MetricNames(runningStreams: String, streamActors: String, streamProcessed: String) @@ -18,7 +20,7 @@ object OpenTelemetryStreamMetricsMonitor { protected val mesmerConfig: String = "metrics.stream-metrics" - protected val defaultConfig: MetricNames = + val defaultConfig: MetricNames = MetricNames("akka_streams_running_streams", "akka_streams_actors", "akka_stream_processed_messages") protected def extractFromConfig(config: Config): MetricNames = { @@ -38,25 +40,33 @@ object OpenTelemetryStreamMetricsMonitor { } } - def apply(meter: Meter, config: Config): OpenTelemetryStreamMetricsMonitor = - new OpenTelemetryStreamMetricsMonitor(meter, MetricNames.fromConfig(config)) + def apply( + meter: Meter, + moduleConfig: AkkaStreamModule.StreamMetricsDef[Boolean], + config: Config + ): OpenTelemetryStreamMetricsMonitor = + new OpenTelemetryStreamMetricsMonitor(meter, moduleConfig, MetricNames.fromConfig(config)) } -final class OpenTelemetryStreamMetricsMonitor(meter: Meter, metricNames: MetricNames) extends StreamMetricsMonitor { +final class OpenTelemetryStreamMetricsMonitor( + meter: Meter, + moduleConfig: AkkaStreamModule.StreamMetricsDef[Boolean], + metricNames: MetricNames +) extends StreamMetricsMonitor { import StreamMetricsMonitor._ - private val runningStreamsTotalRecorder = meter + private lazy val runningStreamsTotalRecorder = meter .longValueRecorderBuilder(metricNames.runningStreams) .setDescription("Amount of running streams on a system") .build() - private val streamActorsTotalRecorder = meter + private lazy val streamActorsTotalRecorder = meter .longValueRecorderBuilder(metricNames.streamActors) .setDescription("Amount of actors running streams on a system") .build() - private val streamProcessedMessagesBuilder = new LongSumObserverBuilderAdapter[Labels]( + private lazy val streamProcessedMessagesBuilder = new LongSumObserverBuilderAdapter[Labels]( meter .longSumObserverBuilder(metricNames.streamProcessed) .setDescription("Amount of messages processed by whole stream") @@ -64,19 +74,25 @@ final class OpenTelemetryStreamMetricsMonitor(meter: Meter, metricNames: MetricN def bind(labels: EagerLabels): BoundMonitor = new StreamMetricsBoundMonitor(labels) - class StreamMetricsBoundMonitor(labels: EagerLabels) + final class StreamMetricsBoundMonitor(labels: EagerLabels) extends BoundMonitor with RegisterRoot with SynchronousInstrumentFactory { private val openTelemetryLabels = LabelsFactory.of(labels.serialize) - val runningStreamsTotal: WrappedLongValueRecorder = - metricRecorder(runningStreamsTotalRecorder, openTelemetryLabels).register(this) + lazy val runningStreamsTotal: MetricRecorder[Long] = + if (moduleConfig.runningStreamsTotal) + metricRecorder(runningStreamsTotalRecorder, openTelemetryLabels).register(this) + else noopMetricRecorder - val streamActorsTotal: WrappedLongValueRecorder = - metricRecorder(streamActorsTotalRecorder, openTelemetryLabels).register(this) + lazy val streamActorsTotal: MetricRecorder[Long] = + if (moduleConfig.streamActorsTotal) + metricRecorder(streamActorsTotalRecorder, openTelemetryLabels).register(this) + else noopMetricRecorder - lazy val streamProcessedMessages: MetricObserver[Long, Labels] = - streamProcessedMessagesBuilder.createObserver(this) + lazy val streamProcessedMessages: MetricObserver[Long,Labels] = + if (moduleConfig.streamProcessedMessages) { + streamProcessedMessagesBuilder.createObserver(this) + } else MetricObserver.noop } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitor.scala index ba870fd0e..34358b929 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitor.scala @@ -2,9 +2,14 @@ package io.scalac.mesmer.extension.upstream import com.typesafe.config.Config import io.opentelemetry.api.metrics.Meter + import io.scalac.mesmer.core.config.MesmerConfiguration -import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.{ BoundMonitor, Labels } -import io.scalac.mesmer.extension.metric.{ MetricObserver, RegisterRoot, StreamOperatorMetricsMonitor } +import io.scalac.mesmer.core.module.AkkaStreamModule +import io.scalac.mesmer.extension.metric.MetricObserver +import io.scalac.mesmer.extension.metric.RegisterRoot +import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor +import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.BoundMonitor +import io.scalac.mesmer.extension.metric.StreamOperatorMetricsMonitor.Labels import io.scalac.mesmer.extension.upstream.OpenTelemetryStreamOperatorMetricsMonitor.MetricNames import io.scalac.mesmer.extension.upstream.opentelemetry._ @@ -15,7 +20,7 @@ object OpenTelemetryStreamOperatorMetricsMonitor { protected val mesmerConfig: String = "metrics.stream-metrics" - protected val defaultConfig: MetricNames = MetricNames( + val defaultConfig: MetricNames = MetricNames( "akka_streams_operator_processed_total", "akka_streams_operator_connections", "akka_streams_running_operators", @@ -44,26 +49,33 @@ object OpenTelemetryStreamOperatorMetricsMonitor { } - def apply(meter: Meter, config: Config): OpenTelemetryStreamOperatorMetricsMonitor = - new OpenTelemetryStreamOperatorMetricsMonitor(meter, MetricNames.fromConfig(config)) + def apply( + meter: Meter, + moduleConfig: AkkaStreamModule.StreamOperatorMetricsDef[Boolean], + config: Config + ): OpenTelemetryStreamOperatorMetricsMonitor = + new OpenTelemetryStreamOperatorMetricsMonitor(meter, moduleConfig, MetricNames.fromConfig(config)) } -class OpenTelemetryStreamOperatorMetricsMonitor(meter: Meter, metricNames: MetricNames) - extends StreamOperatorMetricsMonitor { +final class OpenTelemetryStreamOperatorMetricsMonitor( + meter: Meter, + moduleConfig: AkkaStreamModule.StreamOperatorMetricsDef[Boolean], + metricNames: MetricNames +) extends StreamOperatorMetricsMonitor { - private val processedMessageAdapter = new LongSumObserverBuilderAdapter[Labels]( + private lazy val processedMessageAdapter = new LongSumObserverBuilderAdapter[Labels]( meter .longSumObserverBuilder(metricNames.operatorProcessed) .setDescription("Amount of messages process by operator") ) - private val operatorsAdapter = new LongMetricObserverBuilderAdapter[Labels]( + private lazy val operatorsAdapter = new LongMetricObserverBuilderAdapter[Labels]( meter .longValueObserverBuilder(metricNames.runningOperators) .setDescription("Amount of operators in a system") ) - private val demandAdapter = new LongSumObserverBuilderAdapter[Labels]( + private lazy val demandAdapter = new LongSumObserverBuilderAdapter[Labels]( meter .longSumObserverBuilder(metricNames.demand) .setDescription("Amount of messages demanded by operator") @@ -72,10 +84,12 @@ class OpenTelemetryStreamOperatorMetricsMonitor(meter: Meter, metricNames: Metri def bind(): StreamOperatorMetricsMonitor.BoundMonitor = new BoundMonitor with RegisterRoot { lazy val processedMessages: MetricObserver[Long, Labels] = - processedMessageAdapter.createObserver(this) + if (moduleConfig.processedMessages) processedMessageAdapter.createObserver(this) else MetricObserver.noop - lazy val operators: MetricObserver[Long, Labels] = operatorsAdapter.createObserver(this) + lazy val operators: MetricObserver[Long, Labels] = + if (moduleConfig.operators) operatorsAdapter.createObserver(this) else MetricObserver.noop - lazy val demand: MetricObserver[Long, Labels] = demandAdapter.createObserver(this) + lazy val demand: MetricObserver[Long, Labels] = + if (moduleConfig.demand) demandAdapter.createObserver(this) else MetricObserver.noop } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/Synchronized.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/Synchronized.scala index 1ed08c4fb..0d089d273 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/Synchronized.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/Synchronized.scala @@ -1,11 +1,13 @@ package io.scalac.mesmer.extension.upstream.opentelemetry +import io.opentelemetry.api.metrics.BatchRecorder +import io.opentelemetry.api.metrics.Meter import io.opentelemetry.api.metrics.common.Labels -import io.opentelemetry.api.metrics.{BatchRecorder, Meter} -import io.scalac.mesmer.extension.metric.{Synchronized => BaseSynchronized} import scala.collection.mutable.ListBuffer +import io.scalac.mesmer.extension.metric.{ Synchronized => BaseSynchronized } + abstract class Synchronized(private val meter: Meter) extends BaseSynchronized { import Synchronized._ diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedSynchronousInstrument.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedSynchronousInstrument.scala index 316eb65f5..6b9cfc69d 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedSynchronousInstrument.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/opentelemetry/WrappedSynchronousInstrument.scala @@ -1,7 +1,11 @@ package io.scalac.mesmer.extension.upstream.opentelemetry +import io.opentelemetry.api.metrics.LongCounter +import io.opentelemetry.api.metrics.LongUpDownCounter +import io.opentelemetry.api.metrics.LongValueRecorder +import io.opentelemetry.api.metrics.SynchronousInstrument import io.opentelemetry.api.metrics.common.Labels -import io.opentelemetry.api.metrics.{ LongCounter, LongUpDownCounter, LongValueRecorder, SynchronousInstrument } + import io.scalac.mesmer.extension.metric._ trait SynchronousInstrumentFactory { diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitorTest.scala new file mode 100644 index 000000000..1d8b78ca6 --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitorTest.scala @@ -0,0 +1,101 @@ +package io.scalac.mesmer.extension.upstream + +import io.opentelemetry.api.metrics.OpenTelemetryNoopMeter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.scalac.mesmer.core.module.AkkaActorModule +import io.scalac.mesmer.extension.metric.MetricObserver +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedMetricObserver + +class OpenTelemetryActorMetricsMonitorTest extends AnyFlatSpec with Matchers { + + behavior of "OpenTelemetryActorMetricsMonitor" + + it should "bind to OpenTelemetry instruments if metric is enables" in { + val allEnabled = AkkaActorModule.Impl( + mailboxSize = true, + mailboxTimeAvg = true, + mailboxTimeMin = true, + mailboxTimeMax = true, + mailboxTimeSum = true, + stashSize = true, + receivedMessages = true, + processedMessages = true, + failedMessages = true, + processingTimeAvg = true, + processingTimeMin = true, + processingTimeMax = true, + processingTimeSum = true, + sentMessages = true, + droppedMessages = true + ) + val sut = new OpenTelemetryActorMetricsMonitor( + OpenTelemetryNoopMeter.instance, + allEnabled, + OpenTelemetryActorMetricsMonitor.MetricNames.defaultConfig + ) + + val monitor = sut.bind() + + monitor.mailboxSize should be(a[WrappedMetricObserver[_, _]]) + monitor.mailboxTimeAvg should be(a[WrappedMetricObserver[_, _]]) + monitor.mailboxTimeMin should be(a[WrappedMetricObserver[_, _]]) + monitor.mailboxTimeMax should be(a[WrappedMetricObserver[_, _]]) + monitor.mailboxTimeSum should be(a[WrappedMetricObserver[_, _]]) + monitor.stashSize should be(a[WrappedMetricObserver[_, _]]) + monitor.receivedMessages should be(a[WrappedMetricObserver[_, _]]) + monitor.processedMessages should be(a[WrappedMetricObserver[_, _]]) + monitor.failedMessages should be(a[WrappedMetricObserver[_, _]]) + monitor.processingTimeAvg should be(a[WrappedMetricObserver[_, _]]) + monitor.processingTimeMin should be(a[WrappedMetricObserver[_, _]]) + monitor.processingTimeMax should be(a[WrappedMetricObserver[_, _]]) + monitor.processingTimeSum should be(a[WrappedMetricObserver[_, _]]) + monitor.sentMessages should be(a[WrappedMetricObserver[_, _]]) + monitor.droppedMessages should be(a[WrappedMetricObserver[_, _]]) + } + + it should "bind to noop instruments if metric is disabled" in { + val allEnabled = AkkaActorModule.Impl( + mailboxSize = false, + mailboxTimeAvg = false, + mailboxTimeMin = false, + mailboxTimeMax = false, + mailboxTimeSum = false, + stashSize = false, + receivedMessages = false, + processedMessages = false, + failedMessages = false, + processingTimeAvg = false, + processingTimeMin = false, + processingTimeMax = false, + processingTimeSum = false, + sentMessages = false, + droppedMessages = false + ) + val sut = new OpenTelemetryActorMetricsMonitor( + OpenTelemetryNoopMeter.instance, + allEnabled, + OpenTelemetryActorMetricsMonitor.MetricNames.defaultConfig + ) + + val monitor = sut.bind() + MetricObserver.noop + + monitor.mailboxSize should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.mailboxTimeMin should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.mailboxTimeAvg should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.mailboxTimeMax should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.mailboxTimeSum should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.stashSize should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.receivedMessages should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.processedMessages should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.failedMessages should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.processingTimeAvg should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.processingTimeMin should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.processingTimeMax should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.processingTimeSum should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.sentMessages should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.droppedMessages should be(a[MetricObserver.NoopMetricObserver.type]) + } +} diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitorTest.scala new file mode 100644 index 000000000..ea07fd4b1 --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorSystemMonitorTest.scala @@ -0,0 +1,49 @@ +package io.scalac.mesmer.extension.upstream + +import io.opentelemetry.api.metrics.OpenTelemetryNoopMeter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.scalac.mesmer.core.module.AkkaActorSystemModule.ActorSystemModuleConfig +import io.scalac.mesmer.extension.metric.ActorSystemMonitor.Labels +import io.scalac.mesmer.extension.upstream.opentelemetry.NoopCounter +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedCounter + +class OpenTelemetryActorSystemMonitorTest extends AnyFlatSpec with Matchers { + + behavior of "OpenTelemetryActorSystemMonitor" + val TestLabels: Labels = Labels(None) + + private def config(value: Boolean) = ActorSystemModuleConfig( + createdActors = value, + terminatedActors = value + ) + + it should "bind to OpenTelemetry instruments if metric is enabled" in { + + val sut = new OpenTelemetryActorSystemMonitor( + OpenTelemetryNoopMeter.instance, + config(true), + OpenTelemetryActorSystemMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + + bound.createdActors should be(a[WrappedCounter]) + bound.terminatedActors should be(a[WrappedCounter]) + } + + it should "bind to noop instruments if metric is disabled" in { + + val sut = new OpenTelemetryActorSystemMonitor( + OpenTelemetryNoopMeter.instance, + config(false), + OpenTelemetryActorSystemMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + + bound.createdActors should be(a[NoopCounter.type]) + bound.terminatedActors should be(a[NoopCounter.type]) + } +} diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitorTest.scala new file mode 100644 index 000000000..7b41ac038 --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryClusterMetricsMonitorTest.scala @@ -0,0 +1,63 @@ +package io.scalac.mesmer.extension.upstream + +import io.opentelemetry.api.metrics.OpenTelemetryNoopMeter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.scalac.mesmer.core.module.AkkaClusterModule +import io.scalac.mesmer.extension.metric.ClusterMetricsMonitor.Labels +import io.scalac.mesmer.extension.metric.MetricObserver.NoopMetricObserver +import io.scalac.mesmer.extension.upstream.opentelemetry._ + +class OpenTelemetryClusterMetricsMonitorTest extends AnyFlatSpec with Matchers { + + behavior of "OpenTelemetryClusterMetricsMonitor" + + val TestLabels: Labels = Labels("some-node", None) + + private def config(value: Boolean) = AkkaClusterModule.Impl( + shardPerRegions = value, + entityPerRegion = value, + shardRegionsOnNode = value, + entitiesOnNode = value, + reachableNodes = value, + unreachableNodes = value, + nodeDown = value + ) + + it should "bind to OpenTelemetry instruments if metric is enabled" in { + val sut = new OpenTelemetryClusterMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(true), + OpenTelemetryClusterMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + + bound.shardPerRegions should be(a[WrappedMetricObserver[_, _]]) + bound.entityPerRegion should be(a[WrappedMetricObserver[_, _]]) + bound.shardRegionsOnNode should be(a[WrappedMetricObserver[_, _]]) + bound.entitiesOnNode should be(a[WrappedMetricObserver[_, _]]) + bound.reachableNodes should be(a[WrappedUpDownCounter]) + bound.unreachableNodes should be(a[WrappedUpDownCounter]) + bound.nodeDown should be(a[WrappedCounter]) + + } + + it should "bind to noop instruments if metric is disabled" in { + val sut = new OpenTelemetryClusterMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(false), + OpenTelemetryClusterMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + bound.shardPerRegions should be(a[NoopMetricObserver.type]) + bound.entityPerRegion should be(a[NoopMetricObserver.type]) + bound.shardRegionsOnNode should be(a[NoopMetricObserver.type]) + bound.entitiesOnNode should be(a[NoopMetricObserver.type]) + bound.reachableNodes should be(a[NoopUpDownCounter.type]) + bound.unreachableNodes should be(a[NoopUpDownCounter.type]) + bound.nodeDown should be(a[NoopCounter.type]) + } +} diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitorTest.scala new file mode 100644 index 000000000..788ecdfe6 --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpConnectionMetricsMonitorTest.scala @@ -0,0 +1,47 @@ +package io.scalac.mesmer.extension.upstream + +import io.opentelemetry.api.metrics.OpenTelemetryNoopMeter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.scalac.mesmer.core.module.AkkaHttpModule +import io.scalac.mesmer.extension.metric.HttpConnectionMetricsMonitor.Labels +import io.scalac.mesmer.extension.upstream.opentelemetry.NoopUpDownCounter +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedUpDownCounter + +class OpenTelemetryHttpConnectionMetricsMonitorTest extends AnyFlatSpec with Matchers { + + behavior of "OpenTelemetryHttpConnectionMetricsMonitor" + + val TestLabels: Labels = Labels(None, "localhost", 0) + + private def config(value: Boolean) = AkkaHttpModule.Impl( + requestTime = value, + requestCounter = value, + connections = value + ) + + it should "bind to OpenTelemetry instruments if metric is enabled" in { + val sut = new OpenTelemetryHttpConnectionMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(true), + OpenTelemetryHttpConnectionMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + + bound.connections should be(a[WrappedUpDownCounter]) + + } + + it should "bind to noop instruments if metric is disabled" in { + val sut = new OpenTelemetryHttpConnectionMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(false), + OpenTelemetryHttpConnectionMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + bound.connections should be(a[NoopUpDownCounter.type]) + } +} diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitorTest.scala new file mode 100644 index 000000000..734ffe11b --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryHttpMetricsMonitorTest.scala @@ -0,0 +1,50 @@ +package io.scalac.mesmer.extension.upstream + +import io.opentelemetry.api.metrics.OpenTelemetryNoopMeter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.scalac.mesmer.core.module.AkkaHttpModule +import io.scalac.mesmer.extension.metric.HttpMetricsMonitor.Labels +import io.scalac.mesmer.extension.upstream.opentelemetry.NoopCounter +import io.scalac.mesmer.extension.upstream.opentelemetry.NoopLongValueRecorder +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedCounter +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedLongValueRecorder + +class OpenTelemetryHttpMetricsMonitorTest extends AnyFlatSpec with Matchers { + behavior of "OpenTelemetryHttpConnectionMetricsMonitor" + + val TestLabels: Labels = Labels(None, "/test", "GET", "200") + + private def config(value: Boolean) = AkkaHttpModule.Impl( + requestTime = value, + requestCounter = value, + connections = value + ) + + it should "bind to OpenTelemetry instruments if metric is enabled" in { + val sut = new OpenTelemetryHttpMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(true), + OpenTelemetryHttpMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + + bound.requestTime should be(a[WrappedLongValueRecorder]) + bound.requestCounter should be(a[WrappedCounter]) + + } + + it should "bind to noop instruments if metric is disabled" in { + val sut = new OpenTelemetryHttpMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(false), + OpenTelemetryHttpMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + bound.requestTime should be(a[NoopLongValueRecorder.type]) + bound.requestCounter should be(a[NoopCounter.type]) + } +} diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitorTest.scala new file mode 100644 index 000000000..84ee719ee --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryPersistenceMetricsMonitorTest.scala @@ -0,0 +1,59 @@ +package io.scalac.mesmer.extension.upstream + +import io.opentelemetry.api.metrics.OpenTelemetryNoopMeter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.scalac.mesmer.core.module.AkkaPersistenceModule +import io.scalac.mesmer.extension.metric.PersistenceMetricsMonitor.Labels +import io.scalac.mesmer.extension.upstream.opentelemetry.NoopCounter +import io.scalac.mesmer.extension.upstream.opentelemetry.NoopLongValueRecorder +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedCounter +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedLongValueRecorder + +class OpenTelemetryPersistenceMetricsMonitorTest extends AnyFlatSpec with Matchers { + behavior of "OpenTelemetryHttpConnectionMetricsMonitor" + + val TestLabels: Labels = Labels(None, "/", "") + + private def config(value: Boolean) = AkkaPersistenceModule.Impl( + recoveryTime = value, + recoveryTotal = value, + persistentEvent = value, + persistentEventTotal = value, + snapshot = value + ) + + it should "bind to OpenTelemetry instruments if metric is enabled" in { + val sut = new OpenTelemetryPersistenceMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(true), + OpenTelemetryPersistenceMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + + bound.recoveryTime should be(a[WrappedLongValueRecorder]) + bound.persistentEvent should be(a[WrappedLongValueRecorder]) + bound.recoveryTotal should be(a[WrappedCounter]) + bound.persistentEventTotal should be(a[WrappedCounter]) + bound.snapshot should be(a[WrappedCounter]) + } + + it should "bind to noop instruments if metric is disabled" in { + val sut = new OpenTelemetryPersistenceMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(false), + OpenTelemetryPersistenceMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(TestLabels) + + bound.recoveryTime should be(a[NoopLongValueRecorder.type]) + bound.persistentEvent should be(a[NoopLongValueRecorder.type]) + bound.recoveryTotal should be(a[NoopCounter.type]) + bound.persistentEventTotal should be(a[NoopCounter.type]) + bound.snapshot should be(a[NoopCounter.type]) + } + +} diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitorTest.scala new file mode 100644 index 000000000..afb471223 --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamMetricsMonitorTest.scala @@ -0,0 +1,56 @@ +package io.scalac.mesmer.extension.upstream + +import io.opentelemetry.api.metrics.OpenTelemetryNoopMeter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.scalac.mesmer.core.module.AkkaStreamModule +import io.scalac.mesmer.extension.metric.MetricObserver +import io.scalac.mesmer.extension.metric.StreamMetricsMonitor.EagerLabels +import io.scalac.mesmer.extension.upstream.opentelemetry.NoopLongValueRecorder +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedLongValueRecorder +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedMetricObserver + +class OpenTelemetryStreamMetricsMonitorTest extends AnyFlatSpec with Matchers { + + private def config(value: Boolean) = AkkaStreamModule.Impl( + runningStreamsTotal = value, + streamActorsTotal = value, + streamProcessedMessages = value, + processedMessages = value, + operators = value, + demand = value + ) + + val testLabels: EagerLabels = EagerLabels(None) + + it should "bind to OpenTelemetry instruments if metric is enabled" in { + + val sut = new OpenTelemetryStreamMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(true), + OpenTelemetryStreamMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(testLabels) + + bound.runningStreamsTotal should be(a[WrappedLongValueRecorder]) + bound.streamActorsTotal should be(a[WrappedLongValueRecorder]) + bound.streamProcessedMessages should be(a[WrappedMetricObserver[_, _]]) + } + + it should "bind to noop instruments if metric is disabled" in { + + val sut = new OpenTelemetryStreamMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(false), + OpenTelemetryStreamMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind(testLabels) + + bound.runningStreamsTotal should be(a[NoopLongValueRecorder.type]) + bound.streamActorsTotal should be(a[NoopLongValueRecorder.type]) + bound.streamProcessedMessages should be(a[MetricObserver.NoopMetricObserver.type]) + } +} diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitorTest.scala new file mode 100644 index 000000000..97991a571 --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryStreamOperatorMetricsMonitorTest.scala @@ -0,0 +1,49 @@ +package io.scalac.mesmer.extension.upstream + +import io.opentelemetry.api.metrics.OpenTelemetryNoopMeter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +import io.scalac.mesmer.core.module.AkkaStreamModule +import io.scalac.mesmer.extension.metric.MetricObserver +import io.scalac.mesmer.extension.upstream.opentelemetry.WrappedMetricObserver + +class OpenTelemetryStreamOperatorMetricsMonitorTest extends AnyFlatSpec with Matchers { + + private def config(value: Boolean) = AkkaStreamModule.Impl( + runningStreamsTotal = value, + streamActorsTotal = value, + streamProcessedMessages = value, + processedMessages = value, + operators = value, + demand = value + ) + + it should "bind to OpenTelemetry instruments if metric is enabled" in { + + val sut = new OpenTelemetryStreamOperatorMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(true), + OpenTelemetryStreamOperatorMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind() + + bound.processedMessages should be(a[WrappedMetricObserver[_, _]]) + bound.operators should be(a[WrappedMetricObserver[_, _]]) + bound.demand should be(a[WrappedMetricObserver[_, _]]) + } + it should "bind to noop instruments if metric is disabled" in { + val sut = new OpenTelemetryStreamOperatorMetricsMonitor( + OpenTelemetryNoopMeter.instance, + config(false), + OpenTelemetryStreamOperatorMetricsMonitor.MetricNames.defaultConfig + ) + + val bound = sut.bind() + + bound.processedMessages should be(a[MetricObserver.NoopMetricObserver.type]) + bound.operators should be(a[MetricObserver.NoopMetricObserver.type]) + bound.demand should be(a[MetricObserver.NoopMetricObserver.type]) + } +} diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/util/OpenTelemetryNoopMeter.scala b/extension/src/test/scala/io/scalac/mesmer/extension/util/OpenTelemetryNoopMeter.scala new file mode 100644 index 000000000..c04c4e446 --- /dev/null +++ b/extension/src/test/scala/io/scalac/mesmer/extension/util/OpenTelemetryNoopMeter.scala @@ -0,0 +1,6 @@ +package io.opentelemetry.api.metrics + +object OpenTelemetryNoopMeter { + + lazy val instance: Meter = DefaultMeter.getInstance() +} From 1afb0ef8ea363f1b8e62ed73e25504acc4a62751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Mon, 28 Jun 2021 12:07:20 +0200 Subject: [PATCH 12/31] Rename Mesmer to AkkaMonitoring --- example/src/main/resources/common/application.conf | 2 +- .../extension/{Mesmer.scala => AkkaMonitoring.scala} | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) rename extension/src/main/scala/io/scalac/mesmer/extension/{Mesmer.scala => AkkaMonitoring.scala} (96%) diff --git a/example/src/main/resources/common/application.conf b/example/src/main/resources/common/application.conf index eb0fe45e5..498b305fc 100644 --- a/example/src/main/resources/common/application.conf +++ b/example/src/main/resources/common/application.conf @@ -10,7 +10,7 @@ akka { "example.serialization.SerializableMessage" = jackson-cbor } - typed.extensions = ["io.scalac.mesmer.extension.Mesmer"] + typed.extensions = ["io.scalac.mesmer.extension.AkkaMonitoring"] } coordinated-shutdown.exit-jvm = on diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/Mesmer.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala similarity index 96% rename from extension/src/main/scala/io/scalac/mesmer/extension/Mesmer.scala rename to extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala index 0c4c371ea..ae986b1bb 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/Mesmer.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala @@ -20,7 +20,7 @@ import io.scalac.mesmer.core.module.Module._ import io.scalac.mesmer.core.module._ import io.scalac.mesmer.core.util.Timestamp import io.scalac.mesmer.extension.ActorEventsMonitorActor.ReflectiveActorMetricsReader -import io.scalac.mesmer.extension.Mesmer.ExportInterval +import io.scalac.mesmer.extension.AkkaMonitoring.ExportInterval import io.scalac.mesmer.extension.actor.MutableActorMetricStorageFactory import io.scalac.mesmer.extension.config.AkkaMonitoringConfig import io.scalac.mesmer.extension.config.CachingConfig @@ -32,17 +32,17 @@ import io.scalac.mesmer.extension.persistence.CleanableRecoveryStorage import io.scalac.mesmer.extension.service._ import io.scalac.mesmer.extension.upstream._ -object Mesmer extends ExtensionId[Mesmer] { +object AkkaMonitoring extends ExtensionId[AkkaMonitoring] { private val ExportInterval = 5.seconds - def createExtension(system: ActorSystem[_]): Mesmer = { + def createExtension(system: ActorSystem[_]): AkkaMonitoring = { val config = AkkaMonitoringConfig(system.settings.config) - new Mesmer(system, config) + new AkkaMonitoring(system, config) } } -final class Mesmer(private val system: ActorSystem[_], val config: AkkaMonitoringConfig) extends Extension { +final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaMonitoringConfig) extends Extension { import system.log private val meter = InstrumentationLibrary.mesmerMeter From 39233efe452cb268cedfec11c0df7e3e05e5f40f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Mon, 28 Jun 2021 14:22:12 +0200 Subject: [PATCH 13/31] Rename packages --- .../agent/akka/actor/AkkaActorAgent.scala | 11 ++-- .../actor/AkkaMailboxInstrumentations.scala | 6 +-- .../ActorCellConstructorInstrumentation.scala | 3 +- ...torCellReceiveMessageInstrumentation.scala | 3 +- ...CellSendMessageMetricInstrumentation.scala | 3 +- .../impl/ActorUnhandledInstrumentation.scala | 3 +- .../ClassicStashInstrumentationStash.scala | 4 +- .../impl/MailboxDequeueInstrumentation.scala | 3 +- .../akka/actor/impl/StashBufferAdvice.scala | 3 +- ...andleReceiveExceptionInstrumentation.scala | 3 +- .../agent/akka/AkkaActorAgentTest.scala | 6 +-- .../agent/akka/actor/ActorMailboxTest.scala | 8 +-- .../actor/ActorCellDecorator.scala | 7 +-- .../mesmer/core/actor/ActorCellMetrics.scala | 53 +++++++++++++++++++ .../mesmer/core/module/AkkaActorModule.scala | 12 ++--- .../core/util/LongNoLockAggregator.scala | 10 ++-- .../mesmer/core/util/MetricsToolKit.scala | 8 +-- ....scala => MinMaxSumCountAggregation.scala} | 25 ++++----- .../extension/actor/ActorCellMetrics.scala | 27 ---------- .../extension/ActorEventsMonitorActor.scala | 8 ++- .../mesmer/extension/actor/ActorMetrics.scala | 18 +++---- .../actor/MutableActorMetricsStorage.scala | 2 +- .../OpenTelemetryActorMetricsMonitor.scala | 4 +- .../ActorEventsMonitorActorTest.scala | 43 ++++++++++----- ...MutableActorMetricStorageFactoryTest.scala | 6 +-- ...OpenTelemetryActorMetricsMonitorTest.scala | 8 +-- .../util/probe/ActorMonitorTestProbe.scala | 6 +-- 27 files changed, 158 insertions(+), 135 deletions(-) rename core/src/main/scala/io/scalac/mesmer/{extension => core}/actor/ActorCellDecorator.scala (85%) create mode 100644 core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala rename core/src/main/scala/io/scalac/mesmer/core/util/{AggMetric.scala => MinMaxSumCountAggregation.scala} (53%) delete mode 100644 core/src/main/scala/io/scalac/mesmer/extension/actor/ActorCellMetrics.scala diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala index f01ae8059..d4067d29c 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala @@ -4,11 +4,10 @@ import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.AgentInstrumentation import io.scalac.mesmer.agent.akka.actor.impl._ import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics} import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.module.AkkaActorModule import io.scalac.mesmer.core.util.Timestamp -import io.scalac.mesmer.extension.actor.ActorCellDecorator -import io.scalac.mesmer.extension.actor.ActorCellMetrics object AkkaActorAgent extends InstrumentModuleFactory(AkkaActorModule) @@ -29,7 +28,7 @@ object AkkaActorAgent val mailboxTimeMaxAgent = if (config.mailboxTimeMax) mailboxTimeMax(jars) else None val mailboxTimeSumAgent = if (config.mailboxTimeSum) mailboxTimeSum(jars) else None val mailboxTimeCountAgent = if (config.mailboxTimeCount) mailboxTimeCount(jars) else None - val stashSizeAgent = if (config.stashSize) stashSize(jars) else None + val stashedMessagesAgent = if (config.stashedMessages) stashedMessages(jars) else None val receivedMessagesAgent = if (config.receivedMessages) receivedMessages(jars) else None val processedMessagesAgent = if (config.processedMessages) processedMessages(jars) else None val failedMessagesAgent = if (config.failedMessages) failedMessages(jars) else None @@ -45,7 +44,7 @@ object AkkaActorAgent mailboxTimeMaxAgent.getOrElse(Agent.empty) ++ mailboxTimeSumAgent.getOrElse(Agent.empty) ++ mailboxTimeCountAgent.getOrElse(Agent.empty) ++ - stashSizeAgent.getOrElse(Agent.empty) ++ + stashedMessagesAgent.getOrElse(Agent.empty) ++ receivedMessagesAgent.getOrElse(Agent.empty) ++ processedMessagesAgent.getOrElse(Agent.empty) ++ failedMessagesAgent.getOrElse(Agent.empty) ++ @@ -62,7 +61,7 @@ object AkkaActorAgent mailboxTimeMax = mailboxTimeMaxAgent.isDefined, mailboxTimeSum = mailboxTimeSumAgent.isDefined, mailboxTimeCount = mailboxTimeCountAgent.isDefined, - stashSize = stashSizeAgent.isDefined, + stashedMessages = stashedMessagesAgent.isDefined, receivedMessages = receivedMessagesAgent.isDefined, processedMessages = processedMessagesAgent.isDefined, failedMessages = failedMessagesAgent.isDefined, @@ -91,7 +90,7 @@ object AkkaActorAgent lazy val mailboxTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation ++ mailboxInstrumentation) - lazy val stashSize: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + lazy val stashedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation) lazy val receivedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala index fba344e6b..feef66ece 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala @@ -3,12 +3,11 @@ package io.scalac.mesmer.agent.akka.actor import java.util.concurrent.BlockingQueue import java.util.concurrent.Callable import java.util.concurrent.LinkedBlockingQueue - import akka.AkkaMirror.ActorRefWithCell import akka.AkkaMirror.Cell import akka.dispatch._ import akka.util.BoundedBlockingQueue -import akka.{ actor => classic } +import akka.{actor => classic} import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription import net.bytebuddy.implementation.FieldAccessor @@ -19,12 +18,11 @@ import net.bytebuddy.matcher.ElementMatchers import scala.reflect.ClassTag import scala.reflect.classTag - import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.AgentInstrumentation import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.core.actor.ActorCellDecorator import io.scalac.mesmer.core.util.ReflectionFieldUtils -import io.scalac.mesmer.extension.actor.ActorCellDecorator object BoundedNodeMessageQueueAdvice { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala index d5e709afc..af71841fc 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala @@ -1,12 +1,11 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.dispatch.MailboxType +import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice.Argument import net.bytebuddy.asm.Advice.OnMethodExit import net.bytebuddy.asm.Advice.This -import io.scalac.mesmer.extension.actor.ActorCellDecorator - object ActorCellConstructorInstrumentation { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala index a198ac2b9..a99eeba2a 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala @@ -1,12 +1,11 @@ package io.scalac.mesmer.agent.akka.actor.impl +import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice.OnMethodEnter import net.bytebuddy.asm.Advice.OnMethodExit import net.bytebuddy.asm.Advice.This import net.bytebuddy.asm.Advice.Thrown -import io.scalac.mesmer.extension.actor.ActorCellDecorator - object ActorCellReceiveMessageInstrumentation { @OnMethodEnter diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala index 90293b440..d122a9a7a 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala @@ -1,10 +1,9 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.Actor +import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice._ - import io.scalac.mesmer.core.util.ActorRefOps -import io.scalac.mesmer.extension.actor.ActorCellDecorator object ActorCellSendMessageMetricInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala index 262840d4f..de9ee2c6e 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala @@ -1,10 +1,9 @@ package io.scalac.mesmer.agent.akka.actor.impl +import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice.OnMethodExit import net.bytebuddy.asm.Advice.This -import io.scalac.mesmer.extension.actor.ActorCellDecorator - object ActorUnhandledInstrumentation { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala index 1398b8e3d..2fd514104 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala @@ -2,15 +2,13 @@ package io.scalac.mesmer.agent.akka.actor.impl import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType.methodType - import akka.actor.Actor import akka.actor.ActorContext +import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice.Argument import net.bytebuddy.asm.Advice.OnMethodExit import net.bytebuddy.asm.Advice.This -import io.scalac.mesmer.extension.actor.ActorCellDecorator - object StashConstructorAdvice { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala index 26cb1b74e..58ffa4ac8 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala @@ -1,11 +1,10 @@ package io.scalac.mesmer.agent.akka.actor.impl +import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice.OnMethodExit import net.bytebuddy.asm.Advice.Return import net.bytebuddy.asm.Advice.This - import io.scalac.mesmer.core.util.Interval -import io.scalac.mesmer.extension.actor.ActorCellDecorator object MailboxDequeueInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala index 00c5a1c56..daad1bdda 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala @@ -2,10 +2,9 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.adapter._ +import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice -import io.scalac.mesmer.extension.actor.ActorCellDecorator - object StashBufferAdvice { @Advice.OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala index 6a5f091c3..b105dc0e8 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala @@ -1,11 +1,10 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.typed.TypedActorContext +import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice.Argument import net.bytebuddy.asm.Advice.OnMethodExit -import io.scalac.mesmer.extension.actor.ActorCellDecorator - object SupervisorHandleReceiveExceptionInstrumentation { @OnMethodExit(onThrowable = classOf[Throwable]) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala index b7285ae7c..375531457 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala @@ -10,7 +10,7 @@ import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.StashBuffer import akka.actor.typed.scaladsl.adapter._ -import akka.{ actor => classic } +import akka.{actor => classic} import org.scalatest.OptionValues import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike @@ -18,14 +18,12 @@ import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ import scala.util.control.NoStackTrace - import io.scalac.mesmer.agent.utils.InstallAgent import io.scalac.mesmer.agent.utils.SafeLoadSystem +import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics} import io.scalac.mesmer.core.event.ActorEvent import io.scalac.mesmer.core.util.MetricsToolKit.Counter import io.scalac.mesmer.core.util.ReceptionistOps -import io.scalac.mesmer.extension.actor.ActorCellDecorator -import io.scalac.mesmer.extension.actor.ActorCellMetrics class AkkaActorAgentTest extends InstallAgent diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala index 83f413111..67278f544 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala @@ -1,7 +1,6 @@ package io.scalac.mesmer.agent.akka.actor import java.util.Comparator - import akka.actor.ActorSystem import akka.actor.PoisonPill import akka.actor.typed.ActorRef @@ -14,7 +13,7 @@ import akka.actor.typed.scaladsl.adapter._ import akka.dispatch.BoundedPriorityMailbox import akka.dispatch.BoundedStablePriorityMailbox import akka.dispatch.Envelope -import akka.{ actor => classic } +import akka.{actor => classic} import com.typesafe.config.Config import com.typesafe.config.ConfigFactory import org.scalatest.concurrent.Eventually @@ -24,15 +23,12 @@ import org.scalatest.matchers.should.Matchers import scala.annotation.unused import scala.concurrent.duration.Duration import scala.jdk.DurationConverters._ - import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish import io.scalac.mesmer.agent.utils.InstallModule import io.scalac.mesmer.agent.utils.SafeLoadSystem +import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics, DroppedMessagesCellMetrics} import io.scalac.mesmer.core.config.AkkaPatienceConfig import io.scalac.mesmer.core.util.TestOps -import io.scalac.mesmer.extension.actor.ActorCellDecorator -import io.scalac.mesmer.extension.actor.ActorCellMetrics -import io.scalac.mesmer.extension.actor.DroppedMessagesCellMetrics final class HashCodePriorityMailbox( capacity: Int, diff --git a/core/src/main/scala/io/scalac/mesmer/extension/actor/ActorCellDecorator.scala b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala similarity index 85% rename from core/src/main/scala/io/scalac/mesmer/extension/actor/ActorCellDecorator.scala rename to core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala index 7a87b05c7..d1284bcbe 100644 --- a/core/src/main/scala/io/scalac/mesmer/extension/actor/ActorCellDecorator.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala @@ -1,9 +1,6 @@ -package io.scalac.mesmer.extension.actor - -import akka.dispatch.MailboxType -import akka.dispatch.SingleConsumerOnlyUnboundedMailbox -import akka.dispatch.UnboundedMailbox +package io.scalac.mesmer.core.actor +import akka.dispatch.{MailboxType, SingleConsumerOnlyUnboundedMailbox, UnboundedMailbox} import io.scalac.mesmer.core.util.ReflectionFieldUtils object ActorCellDecorator { diff --git a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala new file mode 100644 index 000000000..ea08bd4e9 --- /dev/null +++ b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala @@ -0,0 +1,53 @@ +package io.scalac.mesmer.core.actor + +import io.scalac.mesmer.core.util.MetricsToolKit._ + +class ActorCellMetrics { + val mailboxTimeAgg: TimeAggregation = new TimeAggregation() + val processingTimeAgg: TimeAggregation = new TimeAggregation() + val processingTimer: Timer = new Timer + val receivedMessages: Counter = new Counter + val processedMessages: Counter = new Counter + val unhandledMessages: Counter = new Counter + val sentMessages: Counter = new Counter + val failedMessages: Counter = new Counter + val exceptionHandledMarker: Marker = new Marker + val stashSize: UninitializedCounter = new UninitializedCounter + def droppedMessages: Option[Counter] = None +} + +/** + * Mixed in trait for actor cells with bounded mailboxes + */ +trait DroppedMessagesCellMetrics extends ActorCellMetrics { + val _droppedMessages = new Counter + override def droppedMessages: Some[Counter] = Some(_droppedMessages) +} + +//trait CellMetrics { +// def mailboxTimeAgg: +// def processingTimeAgg +// def processingTimer +// def receivedMessages +// def processedMessages +// def unhandledMessages +// def sentMessages +// def failedMessages +// def exceptionHandledMarker +// def stashSize +// def droppedMessages +//} +// +// +//final class CellMetricsImpl { +// val mailboxTimeAgg: TimeAggregation = new TimeAggregation() +// val processingTimeAgg: TimeAggregation = new TimeAggregation() +// val processingTimer: Timer = new Timer +// val receivedMessages: Counter = new Counter +// val processedMessages: Counter = new Counter +// val unhandledMessages: Counter = new Counter +// val sentMessages: Counter = new Counter +// val failedMessages: Counter = new Counter +// val exceptionHandledMarker: Marker = new Marker +// val stashSize: UninitializedCounter = new UninitializedCounter +//} diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala index 426db20ec..adb693608 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala @@ -17,7 +17,7 @@ sealed trait AkkaActorMetrics extends MetricsModule { def mailboxTimeMax: T def mailboxTimeSum: T def mailboxTimeCount: T - def stashSize: T + def stashedMessages: T def receivedMessages: T def processedMessages: T def failedMessages: T @@ -41,7 +41,7 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics with RegisterG mailboxTimeMax: T, mailboxTimeSum: T, mailboxTimeCount: T, - stashSize: T, + stashedMessages: T, receivedMessages: T, processedMessages: T, failedMessages: T, @@ -85,7 +85,7 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics with RegisterG val stashSize = config .tryValue("stash-size")(_.getBoolean) - .getOrElse(defaultConfig.stashSize) + .getOrElse(defaultConfig.stashedMessages) val receivedMessages = config .tryValue("received-messages")(_.getBoolean) @@ -129,7 +129,7 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics with RegisterG mailboxTimeMax = mailboxTimeMax, mailboxTimeSum = mailboxTimeSum, mailboxTimeCount = mailboxTimeCount, - stashSize = stashSize, + stashedMessages = stashSize, receivedMessages = receivedMessages, processedMessages = processedMessages, failedMessages = failedMessages, @@ -166,7 +166,7 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics with RegisterG mailboxTimeMax = first.mailboxTimeMax && second.mailboxTimeMax, mailboxTimeSum = first.mailboxTimeSum && second.mailboxTimeSum, mailboxTimeCount = first.mailboxTimeCount && second.mailboxTimeCount, - stashSize = first.stashSize && second.stashSize, + stashedMessages = first.stashedMessages && second.stashedMessages, receivedMessages = first.receivedMessages && second.receivedMessages, processedMessages = first.processedMessages && second.processedMessages, failedMessages = first.failedMessages && second.failedMessages, @@ -186,7 +186,7 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics with RegisterG obj.mailboxTimeMax, obj.mailboxTimeSum, obj.mailboxTimeCount, - obj.stashSize, + obj.stashedMessages, obj.receivedMessages, obj.processedMessages, obj.failedMessages, diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/LongNoLockAggregator.scala b/core/src/main/scala/io/scalac/mesmer/core/util/LongNoLockAggregator.scala index 2362f465e..2de778e3b 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/LongNoLockAggregator.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/LongNoLockAggregator.scala @@ -7,13 +7,13 @@ import java.util.concurrent.locks.ReentrantLock import scala.collection.mutable.ListBuffer import scala.jdk.CollectionConverters._ -import io.scalac.mesmer.core.util.AggMetric.LongValueAggMetric +import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl import io.scalac.mesmer.core.util.TimeSeries.LongTimeSeries // TODO Can we generalize it? final class LongNoLockAggregator(val maxSize: Int = 100, val compactionRemainingSize: Int = 25) { - private[this] val aggRef = new AtomicReference[Option[LongValueAggMetric]](None) + private[this] val aggRef = new AtomicReference[Option[LongMinMaxSumCountAggregationImpl]](None) private[this] val reentrantLock = new ReentrantLock() @volatile @@ -33,7 +33,7 @@ final class LongNoLockAggregator(val maxSize: Int = 100, val compactionRemaining } } - def fetch(): Option[LongValueAggMetric] = { + def fetch(): Option[LongMinMaxSumCountAggregationImpl] = { val snapshot = aggRef.get() if (compacting) { // producer is compacting queue, return stale data snapshot @@ -59,7 +59,9 @@ final class LongNoLockAggregator(val maxSize: Int = 100, val compactionRemaining val ts = new LongTimeSeries(listBuffer.toSeq) aggRef .get() - .fold(aggRef.set(Some(LongValueAggMetric.fromTimeSeries(ts))))(agg => aggRef.set(Some(agg.sum(ts)))) + .fold(aggRef.set(Some(LongMinMaxSumCountAggregationImpl.fromTimeSeries(ts))))(agg => + aggRef.set(Some(agg.sum(ts))) + ) true } finally reentrantLock.unlock() } else false diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala b/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala index 5d8508b77..a024e8cad 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala @@ -4,7 +4,7 @@ import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicReference -import io.scalac.mesmer.core.util.AggMetric.LongValueAggMetric +import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl object MetricsToolKit { @@ -23,9 +23,9 @@ object MetricsToolKit { } final class TimeAggregation { - private[core] val aggregator = new LongNoLockAggregator() - def add(time: Interval): Unit = aggregator.push(time) - def metrics: Option[LongValueAggMetric] = aggregator.fetch() + private[core] val aggregator = new LongNoLockAggregator() + def add(time: Interval): Unit = aggregator.push(time) + def metrics: Option[LongMinMaxSumCountAggregationImpl] = aggregator.fetch() } final class Timer { diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/AggMetric.scala b/core/src/main/scala/io/scalac/mesmer/core/util/MinMaxSumCountAggregation.scala similarity index 53% rename from core/src/main/scala/io/scalac/mesmer/core/util/AggMetric.scala rename to core/src/main/scala/io/scalac/mesmer/core/util/MinMaxSumCountAggregation.scala index 535e42b71..49e2f4d3a 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/AggMetric.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/MinMaxSumCountAggregation.scala @@ -1,15 +1,15 @@ package io.scalac.mesmer.core.util -import io.scalac.mesmer.core.util.AggMetric.LongValueAggMetric.fromTimeSeries +import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl.fromTimeSeries -sealed trait AggMetric[@specialized(Long) T] { +sealed trait MinMaxSumCountAggregation[@specialized(Long) T] { def min: T def max: T def sum: T - def count: Int + def count: Long } -object AggMetric { +object MinMaxSumCountAggregation { /** * Case class with all aggregating values in milliseconds @@ -19,9 +19,10 @@ object AggMetric { * @param sum * @param count */ - final case class LongValueAggMetric(min: Long, max: Long, sum: Long, count: Int) extends AggMetric[Long] { + final case class LongMinMaxSumCountAggregationImpl(min: Long, max: Long, sum: Long, count: Long) + extends MinMaxSumCountAggregation[Long] { - def sum(timeSeries: TimeSeries[Long, Long]): LongValueAggMetric = + def sum(timeSeries: TimeSeries[Long, Long]): LongMinMaxSumCountAggregationImpl = sum(fromTimeSeries(timeSeries)) /** @@ -30,11 +31,11 @@ object AggMetric { * @param other * @return */ - def sum(other: LongValueAggMetric): LongValueAggMetric = { + def sum(other: LongMinMaxSumCountAggregationImpl): LongMinMaxSumCountAggregationImpl = { val count = this.count + other.count val sum = this.sum + other.sum - LongValueAggMetric( + LongMinMaxSumCountAggregationImpl( min = if (this.min < other.min) this.min else other.min, max = if (this.max > other.max) this.max else other.max, sum = sum, @@ -48,13 +49,13 @@ object AggMetric { * @param next aggregations which min and max will be preserved * @return */ - def addTo(next: LongValueAggMetric): LongValueAggMetric = + def addTo(next: LongMinMaxSumCountAggregationImpl): LongMinMaxSumCountAggregationImpl = next.copy(sum = next.sum + this.sum, count = next.count + this.count) } - final object LongValueAggMetric { - def fromTimeSeries(ts: TimeSeries[Long, Long]): LongValueAggMetric = - LongValueAggMetric(ts.min, ts.max, ts.sum, ts.count) + final object LongMinMaxSumCountAggregationImpl { + def fromTimeSeries(ts: TimeSeries[Long, Long]): LongMinMaxSumCountAggregationImpl = + LongMinMaxSumCountAggregationImpl(ts.min, ts.max, ts.sum, ts.count) } } diff --git a/core/src/main/scala/io/scalac/mesmer/extension/actor/ActorCellMetrics.scala b/core/src/main/scala/io/scalac/mesmer/extension/actor/ActorCellMetrics.scala deleted file mode 100644 index 97bebe7ff..000000000 --- a/core/src/main/scala/io/scalac/mesmer/extension/actor/ActorCellMetrics.scala +++ /dev/null @@ -1,27 +0,0 @@ -package io.scalac.mesmer.extension.actor - -import io.scalac.mesmer.core.util.MetricsToolKit._ - -class ActorCellMetrics { - val mailboxTimeAgg: TimeAggregation = new TimeAggregation() - val processingTimeAgg: TimeAggregation = new TimeAggregation() - - //TODO remove this - val processingTimer: Timer = new Timer - val receivedMessages: Counter = new Counter - val processedMessages: Counter = new Counter - val unhandledMessages: Counter = new Counter - val sentMessages: Counter = new Counter - val failedMessages: Counter = new Counter - val exceptionHandledMarker: Marker = new Marker - val stashSize: UninitializedCounter = new UninitializedCounter - def droppedMessages: Option[Counter] = None -} - -/** - * Mixed in trait for actor cells with bounded mailboxes - */ -trait DroppedMessagesCellMetrics extends ActorCellMetrics { - val _droppedMessages = new Counter - override def droppedMessages: Some[Counter] = Some(_droppedMessages) -} diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala index c105996e2..baa65c7ca 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala @@ -2,7 +2,6 @@ package io.scalac.mesmer.extension import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicReference - import akka.Done import akka.actor.typed._ import akka.actor.typed.receptionist.Receptionist.Listing @@ -10,13 +9,13 @@ import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.TimerScheduler import akka.util.Timeout -import akka.{ actor => classic } +import akka.{actor => classic} +import io.scalac.mesmer.core.actor.ActorCellDecorator import org.slf4j.LoggerFactory import scala.concurrent.duration._ import scala.util.Failure import scala.util.Success - import io.scalac.mesmer.core.akka.actorPathPartialOrdering import io.scalac.mesmer.core.model.ActorKey import io.scalac.mesmer.core.model.ActorRefDetails @@ -26,7 +25,6 @@ import io.scalac.mesmer.core.util.ActorCellOps import io.scalac.mesmer.core.util.ActorPathOps import io.scalac.mesmer.core.util.ActorRefOps import io.scalac.mesmer.extension.ActorEventsMonitorActor._ -import io.scalac.mesmer.extension.actor.ActorCellDecorator import io.scalac.mesmer.extension.actor.ActorMetrics import io.scalac.mesmer.extension.actor.MetricStorageFactory import io.scalac.mesmer.extension.metric.ActorMetricsMonitor @@ -171,7 +169,7 @@ private[extension] class ActorEventsMonitorActor private[extension] ( processingTimeMax.setUpdater(updateMetric(_.processingTime.map(_.max))) processingTimeSum.setUpdater(updateMetric(_.processingTime.map(_.sum))) sentMessages.setUpdater(updateMetric(_.sentMessages)) - stashSize.setUpdater(updateMetric(_.stashSize)) + stashedMessages.setUpdater(updateMetric(_.stashSize)) droppedMessages.setUpdater(updateMetric(_.droppedMessages)) } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/actor/ActorMetrics.scala b/extension/src/main/scala/io/scalac/mesmer/extension/actor/ActorMetrics.scala index efaefe6a3..acd7a0d44 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/actor/ActorMetrics.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/actor/ActorMetrics.scala @@ -1,14 +1,14 @@ package io.scalac.mesmer.extension.actor -import io.scalac.mesmer.core.util.AggMetric.LongValueAggMetric +import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl final case class ActorMetrics( mailboxSize: Option[Long], - mailboxTime: Option[LongValueAggMetric], + mailboxTime: Option[LongMinMaxSumCountAggregationImpl], receivedMessages: Option[Long], unhandledMessages: Option[Long], failedMessages: Option[Long], - processingTime: Option[LongValueAggMetric], + processingTime: Option[LongMinMaxSumCountAggregationImpl], sentMessages: Option[Long], stashSize: Option[Long], droppedMessages: Option[Long] @@ -59,14 +59,14 @@ final case class ActorMetrics( combineOption(first, second)(_ + _) private def combineAggregation( - first: Option[LongValueAggMetric], - second: Option[LongValueAggMetric] - ): Option[LongValueAggMetric] = combineOption(first, second)(_.sum(_)) + first: Option[LongMinMaxSumCountAggregationImpl], + second: Option[LongMinMaxSumCountAggregationImpl] + ): Option[LongMinMaxSumCountAggregationImpl] = combineOption(first, second)(_.sum(_)) private def addToAggregation( - first: Option[LongValueAggMetric], - second: Option[LongValueAggMetric] - ): Option[LongValueAggMetric] = combineOption(first, second)(_.addTo(_)) + first: Option[LongMinMaxSumCountAggregationImpl], + second: Option[LongMinMaxSumCountAggregationImpl] + ): Option[LongMinMaxSumCountAggregationImpl] = combineOption(first, second)(_.addTo(_)) private def combineOption[T](first: Option[T], second: Option[T])(combine: (T, T) => T): Option[T] = (first, second) match { diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/actor/MutableActorMetricsStorage.scala b/extension/src/main/scala/io/scalac/mesmer/extension/actor/MutableActorMetricsStorage.scala index 31ef9b2b4..7bd5603ba 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/actor/MutableActorMetricsStorage.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/actor/MutableActorMetricsStorage.scala @@ -7,7 +7,7 @@ import io.scalac.mesmer.extension.resource.MutableStorage final class MutableActorMetricStorageFactory[K] extends MetricStorageFactory[K] { type Storage = MutableActorMetricsStorage - final class MutableActorMetricsStorage private[actor] ( + final class MutableActorMetricsStorage private[actor]( protected val buffer: mutable.Map[K, ActorMetrics], protected val persistentBuffer: mutable.Map[K, ActorMetrics] ) extends MutableStorage[K, ActorMetrics] diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala index 9dc0fea7c..4d0099356 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitor.scala @@ -264,8 +264,8 @@ final class OpenTelemetryActorMetricsMonitor( val mailboxTimeSum: MetricObserver[Long, ActorMetricsMonitor.Labels] = if (moduleConfig.mailboxTimeSum) mailboxTimeSumObserver.createObserver(this) else MetricObserver.noop - val stashSize: MetricObserver[Long, ActorMetricsMonitor.Labels] = - if (moduleConfig.stashSize) stashSizeCounter.createObserver(this) else MetricObserver.noop + val stashedMessages: MetricObserver[Long, ActorMetricsMonitor.Labels] = + if (moduleConfig.stashedMessages) stashSizeCounter.createObserver(this) else MetricObserver.noop val receivedMessages: MetricObserver[Long, ActorMetricsMonitor.Labels] = if (moduleConfig.receivedMessages) receivedMessagesSumObserver.createObserver(this) else MetricObserver.noop diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/ActorEventsMonitorActorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/ActorEventsMonitorActorTest.scala index ccd077aa5..c54940996 100644 --- a/extension/src/test/scala/io/scalac/mesmer/extension/ActorEventsMonitorActorTest.scala +++ b/extension/src/test/scala/io/scalac/mesmer/extension/ActorEventsMonitorActorTest.scala @@ -26,7 +26,7 @@ import scala.util.Random import scala.util.control.NoStackTrace import io.scalac.mesmer.core.model._ -import io.scalac.mesmer.core.util.AggMetric.LongValueAggMetric +import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl import io.scalac.mesmer.core.util.TestCase._ import io.scalac.mesmer.core.util.TestConfig import io.scalac.mesmer.core.util.TestOps @@ -147,11 +147,11 @@ final class ActorEventsMonitorActorTest private val ConstActorMetrics: ActorMetrics = ActorMetrics( Some(1), - Some(LongValueAggMetric(1, 10, 20, 10)), + Some(LongMinMaxSumCountAggregationImpl(1, 10, 20, 10)), Some(2), Some(3), Some(4), - Some(LongValueAggMetric(10, 100, 200, 10)), + Some(LongMinMaxSumCountAggregationImpl(10, 100, 200, 10)), Some(5), Some(6), Some(7) @@ -162,7 +162,8 @@ final class ActorEventsMonitorActorTest val y = Random.nextLong(1000) val sum = Random.nextLong(1000) val count = Random.nextInt(100) + 1 - if (x > y) LongValueAggMetric(y, x, sum, count) else LongValueAggMetric(x, y, sum, count) + if (x > y) LongMinMaxSumCountAggregationImpl(y, x, sum, count) + else LongMinMaxSumCountAggregationImpl(x, y, sum, count) } override implicit val timeout: Timeout = pingOffset @@ -558,17 +559,22 @@ final class ActorEventsMonitorActorTest probeMax: ActorMonitorTestProbe => TestProbe[MetricObserverCommand[Labels]], probeSum: ActorMonitorTestProbe => TestProbe[MetricObserverCommand[Labels]], probeCount: ActorMonitorTestProbe => TestProbe[MetricObserverCommand[Labels]], - extract: ActorMetrics => Option[LongValueAggMetric], + extract: ActorMetrics => Option[LongMinMaxSumCountAggregationImpl], name: String ): Unit = { - val args - : List[(String, LongValueAggMetric => Long, ActorMonitorTestProbe => TestProbe[MetricObserverCommand[Labels]])] = + val args: List[ + ( + String, + LongMinMaxSumCountAggregationImpl => Long, + ActorMonitorTestProbe => TestProbe[MetricObserverCommand[Labels]] + ) + ] = List(("min", _.min, probeMin), ("max", _.max, probeMax), ("sum", _.sum, probeSum), ("count", _.count, probeCount)) for { (suffix, mapping, probe) <- args } { - collect[Option[LongValueAggMetric]](probe, extract.andThen(_.map(mapping).get), s"$name $suffix") - reportingAggregation[Option[LongValueAggMetric]]( + collect[Option[LongMinMaxSumCountAggregationImpl]](probe, extract.andThen(_.map(mapping).get), s"$name $suffix") + reportingAggregation[Option[LongMinMaxSumCountAggregationImpl]]( probe, extract, s"$name $suffix", @@ -576,7 +582,13 @@ final class ActorEventsMonitorActorTest addToAgg, _.map(mapping).get )((addRandomMetrics)) - collectMany[Option[LongValueAggMetric]](probe, extract, s"$name $suffix", addToAgg, _.map(mapping).get)( + collectMany[Option[LongMinMaxSumCountAggregationImpl]]( + probe, + extract, + s"$name $suffix", + addToAgg, + _.map(mapping).get + )( Seq.fill(10)(randomActorMetrics()) ) } @@ -590,7 +602,9 @@ final class ActorEventsMonitorActorTest } yield (x + y)) } - private val sumAgg: (Option[LongValueAggMetric], Option[LongValueAggMetric]) => Option[LongValueAggMetric] = + private val sumAgg: (Option[LongMinMaxSumCountAggregationImpl], Option[LongMinMaxSumCountAggregationImpl]) => Option[ + LongMinMaxSumCountAggregationImpl + ] = (optX, optY) => { (for { x <- optX @@ -598,7 +612,10 @@ final class ActorEventsMonitorActorTest } yield x.sum(y)) } - private val addToAgg: (Option[LongValueAggMetric], Option[LongValueAggMetric]) => Option[LongValueAggMetric] = + private val addToAgg + : (Option[LongMinMaxSumCountAggregationImpl], Option[LongMinMaxSumCountAggregationImpl]) => Option[ + LongMinMaxSumCountAggregationImpl + ] = (optX, optY) => { (for { x <- optX @@ -610,7 +627,7 @@ final class ActorEventsMonitorActorTest it should behave like allBehaviorsLong(_.receivedMessagesProbe, _.receivedMessages, "received messages") it should behave like allBehaviorsLong(_.failedMessagesProbe, _.failedMessages, "failed messages") it should behave like allBehaviorsLong(_.sentMessagesProbe, _.sentMessages, "sent messages") - it should behave like allBehaviorsLong(_.stashSizeProbe, _.stashSize, "stash messages") + it should behave like allBehaviorsLong(_.stashedMessagesProbe, _.stashSize, "stash messages") it should behave like allBehaviorsLong(_.droppedMessagesProbe, _.droppedMessages, "dropped messages") it should behave like allBehaviorsLong(_.processedMessagesProbe, _.processedMessages, "processed messages") diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/actor/MutableActorMetricStorageFactoryTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/actor/MutableActorMetricStorageFactoryTest.scala index 621b7e9ea..4e65ecb2f 100644 --- a/extension/src/test/scala/io/scalac/mesmer/extension/actor/MutableActorMetricStorageFactoryTest.scala +++ b/extension/src/test/scala/io/scalac/mesmer/extension/actor/MutableActorMetricStorageFactoryTest.scala @@ -3,7 +3,7 @@ package io.scalac.mesmer.extension.actor import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import io.scalac.mesmer.core.util.AggMetric.LongValueAggMetric +import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl import io.scalac.mesmer.core.util.TimeSeries class MutableActorMetricStorageFactoryTest extends AnyFlatSpec with Matchers { @@ -12,11 +12,11 @@ class MutableActorMetricStorageFactoryTest extends AnyFlatSpec with Matchers { private def TestMetrics(value: Int) = ActorMetrics( Some(value), - Some(LongValueAggMetric.fromTimeSeries(TimeSeries(1L, 1L, 10L))), + Some(LongMinMaxSumCountAggregationImpl.fromTimeSeries(TimeSeries(1L, 1L, 10L))), Some(value), Some(value), Some(value), - Some(LongValueAggMetric.fromTimeSeries(TimeSeries(1L, 1L, 10L))), + Some(LongMinMaxSumCountAggregationImpl.fromTimeSeries(TimeSeries(1L, 1L, 10L))), Some(value), Some(value), Some(value) diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitorTest.scala b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitorTest.scala index 5ae026576..d8532753e 100644 --- a/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitorTest.scala +++ b/extension/src/test/scala/io/scalac/mesmer/extension/upstream/OpenTelemetryActorMetricsMonitorTest.scala @@ -19,7 +19,7 @@ class OpenTelemetryActorMetricsMonitorTest extends AnyFlatSpec with Matchers { mailboxTimeMax = true, mailboxTimeSum = true, mailboxTimeCount = true, - stashSize = true, + stashedMessages = true, receivedMessages = true, processedMessages = true, failedMessages = true, @@ -43,7 +43,7 @@ class OpenTelemetryActorMetricsMonitorTest extends AnyFlatSpec with Matchers { monitor.mailboxTimeMax should be(a[WrappedMetricObserver[_, _]]) monitor.mailboxTimeSum should be(a[WrappedMetricObserver[_, _]]) monitor.mailboxTimeCount should be(a[WrappedMetricObserver[_, _]]) - monitor.stashSize should be(a[WrappedMetricObserver[_, _]]) + monitor.stashedMessages should be(a[WrappedMetricObserver[_, _]]) monitor.receivedMessages should be(a[WrappedMetricObserver[_, _]]) monitor.processedMessages should be(a[WrappedMetricObserver[_, _]]) monitor.failedMessages should be(a[WrappedMetricObserver[_, _]]) @@ -62,7 +62,7 @@ class OpenTelemetryActorMetricsMonitorTest extends AnyFlatSpec with Matchers { mailboxTimeMin = false, mailboxTimeMax = false, mailboxTimeSum = false, - stashSize = false, + stashedMessages = false, receivedMessages = false, processedMessages = false, failedMessages = false, @@ -87,7 +87,7 @@ class OpenTelemetryActorMetricsMonitorTest extends AnyFlatSpec with Matchers { monitor.mailboxTimeMax should be(a[MetricObserver.NoopMetricObserver.type]) monitor.mailboxTimeSum should be(a[MetricObserver.NoopMetricObserver.type]) monitor.mailboxTimeCount should be(a[MetricObserver.NoopMetricObserver.type]) - monitor.stashSize should be(a[MetricObserver.NoopMetricObserver.type]) + monitor.stashedMessages should be(a[MetricObserver.NoopMetricObserver.type]) monitor.receivedMessages should be(a[MetricObserver.NoopMetricObserver.type]) monitor.processedMessages should be(a[MetricObserver.NoopMetricObserver.type]) monitor.failedMessages should be(a[MetricObserver.NoopMetricObserver.type]) diff --git a/extension/src/test/scala/io/scalac/mesmer/extension/util/probe/ActorMonitorTestProbe.scala b/extension/src/test/scala/io/scalac/mesmer/extension/util/probe/ActorMonitorTestProbe.scala index 8f5dedc86..24c61bf99 100644 --- a/extension/src/test/scala/io/scalac/mesmer/extension/util/probe/ActorMonitorTestProbe.scala +++ b/extension/src/test/scala/io/scalac/mesmer/extension/util/probe/ActorMonitorTestProbe.scala @@ -16,7 +16,7 @@ final case class ActorMonitorTestProbe( mailboxTimeMaxProbe: TestProbe[MetricObserverCommand[Labels]], mailboxTimeSumProbe: TestProbe[MetricObserverCommand[Labels]], mailboxTimeCountProbe: TestProbe[MetricObserverCommand[Labels]], - stashSizeProbe: TestProbe[MetricObserverCommand[Labels]], + stashedMessagesProbe: TestProbe[MetricObserverCommand[Labels]], receivedMessagesProbe: TestProbe[MetricObserverCommand[Labels]], processedMessagesProbe: TestProbe[MetricObserverCommand[Labels]], failedMessagesProbe: TestProbe[MetricObserverCommand[Labels]], @@ -48,8 +48,8 @@ final case class ActorMonitorTestProbe( ObserverTestProbeWrapper(mailboxTimeMaxProbe, collector) val mailboxTimeSum: MetricObserver[Long, Labels] = ObserverTestProbeWrapper(mailboxTimeSumProbe, collector) - val stashSize: MetricObserver[Long, Labels] = - ObserverTestProbeWrapper(stashSizeProbe, collector) + val stashedMessages: MetricObserver[Long, Labels] = + ObserverTestProbeWrapper(stashedMessagesProbe, collector) val receivedMessages: MetricObserver[Long, Labels] = ObserverTestProbeWrapper(receivedMessagesProbe, collector) val processedMessages: MetricObserver[Long, Labels] = From 4ab7009d9e0512bf8fa6d6d3b20354262801d41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Mon, 28 Jun 2021 14:31:03 +0200 Subject: [PATCH 14/31] Move mirror types to core --- .../actor/AkkaMailboxInstrumentations.scala | 4 +-- .../mesmer/agent/akka/mirror/AkkaMirror.scala | 6 ---- .../impl/ActorGraphInterpreterDecorator.scala | 2 +- ...orGraphInterpreterProcessEventAdvice.scala | 2 +- .../akka/stream/impl/AkkaMirrorTypes.scala | 17 ----------- .../PhasedFusingActorMaterializerAdvice.scala | 3 +- .../mesmer/core/actor/ActorCellMetrics.scala | 30 +++++++++---------- 7 files changed, 20 insertions(+), 44 deletions(-) delete mode 100644 agent/src/main/scala/io/scalac/mesmer/agent/akka/mirror/AkkaMirror.scala delete mode 100644 agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala index feef66ece..4f5772e55 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala @@ -3,8 +3,8 @@ package io.scalac.mesmer.agent.akka.actor import java.util.concurrent.BlockingQueue import java.util.concurrent.Callable import java.util.concurrent.LinkedBlockingQueue -import akka.AkkaMirror.ActorRefWithCell -import akka.AkkaMirror.Cell +import akka.MesmerMirrorTypes.ActorRefWithCell +import akka.MesmerMirrorTypes.Cell import akka.dispatch._ import akka.util.BoundedBlockingQueue import akka.{actor => classic} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/mirror/AkkaMirror.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/mirror/AkkaMirror.scala deleted file mode 100644 index d4e469e74..000000000 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/mirror/AkkaMirror.scala +++ /dev/null @@ -1,6 +0,0 @@ -package akka - -object AkkaMirror { - type ActorRefWithCell = akka.actor.ActorRefWithCell - type Cell = akka.actor.Cell -} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala index a7cb02ac3..8adfa6a49 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterDecorator.scala @@ -2,7 +2,7 @@ package io.scalac.mesmer.agent.akka.stream.impl import java.lang.invoke.MethodType.methodType -import akka.AkkaMirrorTypes.GraphInterpreterShellMirror +import akka.MesmerMirrorTypes.GraphInterpreterShellMirror import akka.actor.Actor import akka.actor.typed.scaladsl.adapter._ import akka.stream.GraphLogicOps._ diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala index 113e63e85..47b92adc1 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/ActorGraphInterpreterProcessEventAdvice.scala @@ -1,6 +1,6 @@ package akka.stream.impl.fusing -import akka.AkkaMirrorTypes.GraphInterpreterShellMirror +import akka.MesmerMirrorTypes.GraphInterpreterShellMirror import akka.actor.Actor import akka.stream.impl.fusing.ActorGraphInterpreter.BoundaryEvent import net.bytebuddy.asm.Advice diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala deleted file mode 100644 index 64259d11b..000000000 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/AkkaMirrorTypes.scala +++ /dev/null @@ -1,17 +0,0 @@ -package akka - -import akka.stream.impl.ExtendedActorMaterializer -import akka.stream.impl.fusing.GraphInterpreter -import akka.stream.impl.fusing.GraphInterpreterShell -import akka.stream.stage.GraphStageLogic -import akka.util.{ OptionVal => AkkaOptionVal } - -object AkkaMirrorTypes { - - type ExtendedActorMaterializerMirror = ExtendedActorMaterializer - type GraphInterpreterMirror = GraphInterpreter - type GraphInterpreterShellMirror = GraphInterpreterShell - type GraphStageLogicMirror = GraphStageLogic - type OptionVal[+T >: Null] = AkkaOptionVal[T] - -} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala index e6f6282bb..49c62ff6f 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/impl/PhasedFusingActorMaterializerAdvice.scala @@ -1,6 +1,5 @@ package io.scalac.mesmer.agent.akka.stream.impl -import akka.AkkaMirrorTypes import akka.actor.ActorRef import akka.actor.typed.scaladsl.adapter._ import net.bytebuddy.asm.Advice._ @@ -14,6 +13,6 @@ object PhasedFusingActorMaterializerAdvice { @OnMethodExit def actorOf(@Return ref: ActorRef, @This self: Object): Unit = - EventBus(self.asInstanceOf[AkkaMirrorTypes.ExtendedActorMaterializerMirror].system.toTyped) + EventBus(self.asInstanceOf[akka.MesmerMirrorTypes.ExtendedActorMaterializerMirror].system.toTyped) .publishEvent(ActorEvent.TagsSet(ActorRefTags(ref, Set(Tag.stream)))) } diff --git a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala index ea08bd4e9..0e2e23f84 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala @@ -25,7 +25,7 @@ trait DroppedMessagesCellMetrics extends ActorCellMetrics { } //trait CellMetrics { -// def mailboxTimeAgg: +// def mailboxTimeAgg // def processingTimeAgg // def processingTimer // def receivedMessages @@ -37,17 +37,17 @@ trait DroppedMessagesCellMetrics extends ActorCellMetrics { // def stashSize // def droppedMessages //} -// -// -//final class CellMetricsImpl { -// val mailboxTimeAgg: TimeAggregation = new TimeAggregation() -// val processingTimeAgg: TimeAggregation = new TimeAggregation() -// val processingTimer: Timer = new Timer -// val receivedMessages: Counter = new Counter -// val processedMessages: Counter = new Counter -// val unhandledMessages: Counter = new Counter -// val sentMessages: Counter = new Counter -// val failedMessages: Counter = new Counter -// val exceptionHandledMarker: Marker = new Marker -// val stashSize: UninitializedCounter = new UninitializedCounter -//} + + +final class CellMetricsImpl { + val mailboxTimeAgg: TimeAggregation = new TimeAggregation() + val processingTimeAgg: TimeAggregation = new TimeAggregation() + val processingTimer: Timer = new Timer + val receivedMessages: Counter = new Counter + val processedMessages: Counter = new Counter + val unhandledMessages: Counter = new Counter + val sentMessages: Counter = new Counter + val failedMessages: Counter = new Counter + val exceptionHandledMarker: Marker = new Marker + val stashSize: UninitializedCounter = new UninitializedCounter +} From b59446642069c1004b7497d23f5e18a2e5361c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Tue, 29 Jun 2021 15:46:58 +0200 Subject: [PATCH 15/31] Change initialization of ActorCellMetrics --- .../akka/actor/impl/ActorCellInitAdvice.java | 12 ++ .../agent/akka/actor/AkkaActorAgent.scala | 109 +++++++++++++++--- .../actor/AkkaMailboxInstrumentations.scala | 33 +++--- .../ActorCellConstructorInstrumentation.scala | 31 ++--- .../impl/ActorCellDroppedMessagesAdvice.scala | 19 +++ .../actor/impl/ActorCellInitializer.scala | 11 ++ ...torCellReceiveMessageInstrumentation.scala | 27 +++-- ...CellSendMessageMetricInstrumentation.scala | 6 +- .../impl/ActorUnhandledInstrumentation.scala | 11 +- .../ClassicStashInstrumentationStash.scala | 24 ++-- .../impl/MailboxDequeueInstrumentation.scala | 18 +-- .../akka/actor/impl/StashBufferAdvice.scala | 7 +- ...andleReceiveExceptionInstrumentation.scala | 14 ++- .../mesmer/agent/util/i13n/package.scala | 21 ++-- .../agent/akka/AkkaActorAgentTest.scala | 87 +++++++------- .../agent/akka/actor/ActorMailboxTest.scala | 61 +++++----- .../core/actor/ActorCellDecorator.scala | 24 ++-- .../mesmer/core/actor/ActorCellMetrics.scala | 77 +++++-------- .../mesmer/core/util/MetricsToolKit.scala | 63 +++++----- .../extension/ActorEventsMonitorActor.scala | 62 ++++------ .../actor/CleanableActorMetricsStorage.scala | 20 ---- 21 files changed, 410 insertions(+), 327 deletions(-) create mode 100644 agent/src/main/java/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitAdvice.java create mode 100644 agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala create mode 100644 agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitializer.scala delete mode 100644 extension/src/main/scala/io/scalac/mesmer/extension/actor/CleanableActorMetricsStorage.scala diff --git a/agent/src/main/java/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitAdvice.java b/agent/src/main/java/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitAdvice.java new file mode 100644 index 000000000..055e0eb82 --- /dev/null +++ b/agent/src/main/java/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitAdvice.java @@ -0,0 +1,12 @@ +package io.scalac.mesmer.agent.akka.actor.impl; + +import io.scalac.mesmer.core.actor.ActorCellMetrics; +import net.bytebuddy.asm.Advice; + +public class ActorCellInitAdvice { + + @Advice.OnMethodEnter + public static void initActorCell(@Advice.FieldValue(value = "_actorCellMetrics", readOnly = false) ActorCellMetrics metrics) { + metrics = new ActorCellMetrics(); + } +} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala index d4067d29c..be0ff3fdd 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala @@ -1,13 +1,15 @@ package io.scalac.mesmer.agent.akka.actor -import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.AgentInstrumentation import io.scalac.mesmer.agent.akka.actor.impl._ import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics} +import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } +import io.scalac.mesmer.core.actor.{ ActorCellDecorator, ActorCellMetrics } import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.module.AkkaActorModule import io.scalac.mesmer.core.util.Timestamp +import net.bytebuddy.asm.Advice +import net.bytebuddy.dynamic.TargetType +import net.bytebuddy.implementation.{ FixedValue, MethodCall, MethodDelegation, SuperMethodCall } object AkkaActorAgent extends InstrumentModuleFactory(AkkaActorModule) @@ -79,40 +81,96 @@ object AkkaActorAgent lazy val mailboxSize: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) lazy val mailboxTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxInstrumentation) + Some(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) lazy val mailboxTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxInstrumentation) + Some(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) lazy val mailboxTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxInstrumentation) + Some(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) lazy val mailboxTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxInstrumentation) + Some(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) lazy val stashedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation) - lazy val receivedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) + lazy val receivedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some(sharedInstrumentation ++ initField("received-messages", _.initReceivedMessages())) - lazy val processedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) + lazy val processedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some( + sharedInstrumentation ++ initField( + "processed-messages", + _.initUnhandledMessages() + ) + ) lazy val failedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ abstractSupervisionInstrumentation) + Some( + sharedInstrumentation ++ abstractSupervisionInstrumentation ++ initField( + "mailbox-size", + metrics => { + metrics.initFailedMessages() + metrics.initExceptionHandledMarker() + } + ) + ) - lazy val processingTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) + lazy val processingTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some( + sharedInstrumentation ++ initField( + "processing-time", + metrics => { + metrics.initProcessingTimeAgg() + metrics.initProcessingTimer() + } + ) + ) - lazy val processingTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) + lazy val processingTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some( + sharedInstrumentation ++ initField( + "processing-time", + metrics => { + metrics.initProcessingTimeAgg() + metrics.initProcessingTimer() + } + ) + ) - lazy val processingTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) + lazy val processingTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some( + sharedInstrumentation ++ initField( + "processing-time", + metrics => { + metrics.initProcessingTimeAgg() + metrics.initProcessingTimer() + } + ) + ) - lazy val processingTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) + lazy val processingTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => + Some( + sharedInstrumentation ++ initField( + "processing-time", + metrics => { + metrics.initProcessingTimeAgg() + metrics.initProcessingTimer() + } + ) + ) lazy val sentMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxTimeSendMessageIncInstrumentation) + Some( + sharedInstrumentation ++ mailboxTimeSendMessageIncInstrumentation ++ initField( + "sent-messages", + _.initSentMessages() + ) + ) lazy val droppedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ boundedQueueAgent) + Some(sharedInstrumentation ++ boundedQueueAgent ++ initDroppedMessages) /** * Instrumentation for classic stash @@ -143,7 +201,6 @@ object AkkaActorAgent val mailboxTimeTimestampInstrumentation = instrument("akka.dispatch.Envelope".fqcn) .defineField[Timestamp](EnvelopeDecorator.TimestampVarName) - // .defineField[Boolean](EnvelopeDecorator.TimestampVarName) /** * Instrumentation that sets envelope timestamp to current time on each dispatch @@ -182,9 +239,21 @@ object AkkaActorAgent */ private val actorCellInstrumentation = instrument("akka.actor.ActorCell".fqcnWithTags("metrics")) .defineField[ActorCellMetrics](ActorCellDecorator.fieldName) - .visit(ActorCellConstructorInstrumentation, "init") + .defineMethod("setupMetrics", TargetType.DESCRIPTION, FixedValue.self()) + .intercept( + named("init").method, + Advice + .to(classOf[ActorCellInitAdvice]) + .wrap( + SuperMethodCall.INSTANCE.andThen(MethodCall.invoke(named("setupMetrics").method)) + ) + ) .visit(ActorCellReceiveMessageInstrumentation, "receiveMessage") + private def initField(name: String, init: ActorCellMetrics => Unit): AgentInstrumentation = + instrument("akka.actor.ActorCell".fqcnWithTags(name)) + .intercept("setupMetrics", MethodDelegation.to(new ActorCellInitializer(init)).andThen(SuperMethodCall.INSTANCE)) + private lazy val sharedInstrumentation: Agent = Agent( actorCellInstrumentation, @@ -215,6 +284,9 @@ object AkkaActorAgent instrument(hierarchy("akka.actor.typed.internal.StashBufferImpl".fqcnWithTags("typed_stash_buffer"))) .visit(StashBufferAdvice, "stash") + private val initDroppedMessages = instrument("akka.actor.ActorCell".fqcnWithTags("dropped-messages")) + .visit(ActorCellDroppedMessagesAdvice, "init") + /** * Instrumentation to publish events when new actor is created. This must be enabled * for any other instrumentation here to work. @@ -222,4 +294,5 @@ object AkkaActorAgent private val localActorRefProviderInstrumentation: AgentInstrumentation = instrument("akka.actor.LocalActorRefProvider".fqcnWithTags("create")) .visit(LocalActorRefProviderAdvice, "actorOf") + } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala index 4f5772e55..ff184aca3 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala @@ -1,28 +1,21 @@ package io.scalac.mesmer.agent.akka.actor -import java.util.concurrent.BlockingQueue -import java.util.concurrent.Callable -import java.util.concurrent.LinkedBlockingQueue -import akka.MesmerMirrorTypes.ActorRefWithCell -import akka.MesmerMirrorTypes.Cell +import akka.MesmerMirrorTypes.{ ActorRefWithCell, Cell } import akka.dispatch._ import akka.util.BoundedBlockingQueue -import akka.{actor => classic} +import akka.{ actor => classic } +import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } +import io.scalac.mesmer.core.actor.ActorCellDecorator +import io.scalac.mesmer.core.util.ReflectionFieldUtils import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription -import net.bytebuddy.implementation.FieldAccessor -import net.bytebuddy.implementation.MethodDelegation -import net.bytebuddy.implementation.bind.annotation.SuperCall -import net.bytebuddy.implementation.bind.annotation.This +import net.bytebuddy.implementation.bind.annotation.{ SuperCall, This } +import net.bytebuddy.implementation.{ FieldAccessor, MethodDelegation } import net.bytebuddy.matcher.ElementMatchers -import scala.reflect.ClassTag -import scala.reflect.classTag -import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.AgentInstrumentation -import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.core.actor.ActorCellDecorator -import io.scalac.mesmer.core.util.ReflectionFieldUtils +import java.util.concurrent.{ BlockingQueue, Callable, LinkedBlockingQueue } +import scala.reflect.{ classTag, ClassTag } object BoundedNodeMessageQueueAdvice { @@ -47,9 +40,9 @@ object BoundedNodeMessageQueueAdvice { private def incDropped(result: Boolean, cell: Cell): Unit = if (result && (cell ne null)) { for { - actorMetrics <- ActorCellDecorator.get(cell) - dropped <- actorMetrics.droppedMessages - } dropped.inc() + actorMetrics <- ActorCellDecorator.get(cell) if actorMetrics.droppedMessages.isDefined + + } actorMetrics.droppedMessages.get.inc() } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala index af71841fc..37b3c7969 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala @@ -1,14 +1,17 @@ -package io.scalac.mesmer.agent.akka.actor.impl - -import akka.dispatch.MailboxType -import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.Argument -import net.bytebuddy.asm.Advice.OnMethodExit -import net.bytebuddy.asm.Advice.This - -object ActorCellConstructorInstrumentation { - - @OnMethodExit - def onEnter(@This actorCell: Object, @Argument(1) mailboxType: MailboxType): Unit = - ActorCellDecorator.initialize(actorCell, mailboxType) -} +//package io.scalac.mesmer.agent.akka.actor.impl +// +//import akka.dispatch.MailboxType +//import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics} +//import net.bytebuddy.asm.Advice.{Argument, FieldValue, OnMethodExit, This} +// +//object ActorCellConstructorInstrumentation { +// +//// @OnMethodExit +//// def onEnter(@This actorCell: Object, @Argument(1) mailboxType: MailboxType): Unit = { +//// +//// } +// +// @OnMethodExit +// def setUpCellMetrics(@FieldValue(ActorCellDecorator.fieldName) cellMetrics: ActorCellMetrics) +//// ActorCellDecorator.initialize(actorCell, mailboxType) +//} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala new file mode 100644 index 000000000..37ed3f4c8 --- /dev/null +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala @@ -0,0 +1,19 @@ +package io.scalac.mesmer.agent.akka.actor.impl + +import akka.dispatch.{ MailboxType, SingleConsumerOnlyUnboundedMailbox, UnboundedMailbox } +import io.scalac.mesmer.core.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit, This } + +object ActorCellDroppedMessagesAdvice { + + @OnMethodExit + def init(@This actorCell: Object, @Argument(1) mailboxType: MailboxType): Unit = + mailboxType match { + case _: UnboundedMailbox | _: SingleConsumerOnlyUnboundedMailbox => + ActorCellDecorator.get(actorCell).foreach { metrics => + metrics.initDroppedMessages() + } + case _ => + } + +} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitializer.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitializer.scala new file mode 100644 index 000000000..ad49d3cb1 --- /dev/null +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitializer.scala @@ -0,0 +1,11 @@ +package io.scalac.mesmer.agent.akka.actor.impl + +import io.scalac.mesmer.core.actor.{ ActorCellDecorator, ActorCellMetrics } +import net.bytebuddy.implementation.bind.annotation.FieldValue + +final class ActorCellInitializer(init: ActorCellMetrics => Unit) { + + def initField(@FieldValue(ActorCellDecorator.fieldName) metrics: ActorCellMetrics): Unit = + init(metrics) + +} diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala index a99eeba2a..d3e8fa9f4 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala @@ -1,27 +1,32 @@ package io.scalac.mesmer.agent.akka.actor.impl import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.OnMethodEnter -import net.bytebuddy.asm.Advice.OnMethodExit -import net.bytebuddy.asm.Advice.This -import net.bytebuddy.asm.Advice.Thrown +import net.bytebuddy.asm.Advice.{ OnMethodEnter, OnMethodExit, This, Thrown } object ActorCellReceiveMessageInstrumentation { @OnMethodEnter def onEnter(@This actorCell: Object): Unit = - ActorCellDecorator.get(actorCell).foreach { spy => - spy.receivedMessages.inc() - spy.processingTimer.start() + ActorCellDecorator.get(actorCell).foreach { metrics => + import metrics._ + if (receivedMessages.isDefined) receivedMessages.get.inc() + if (processingTimer.isDefined) processingTimer.get.start() } @OnMethodExit(onThrowable = classOf[Throwable]) def onExit(@This actorCell: Object, @Thrown exception: Throwable): Unit = - ActorCellDecorator.get(actorCell).foreach { spy => - if (exception != null && !spy.exceptionHandledMarker.checkAndReset()) { - spy.failedMessages.inc() + ActorCellDecorator.get(actorCell).foreach { metrics => + import metrics._ + + if ( + exception != null && exceptionHandledMarker.isDefined && failedMessages.isDefined && !exceptionHandledMarker.get + .checkAndReset() + ) { + failedMessages.get.inc() + } + if (processingTimeAgg.isDefined && processingTimeAgg.isDefined) { + processingTimeAgg.get.add(metrics.processingTimer.get.interval()) } - spy.processingTimeAgg.add(spy.processingTimer.interval()) } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala index d122a9a7a..08f47b703 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala @@ -2,8 +2,8 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.Actor import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice._ import io.scalac.mesmer.core.util.ActorRefOps +import net.bytebuddy.asm.Advice._ object ActorCellSendMessageMetricInstrumentation { @@ -14,8 +14,8 @@ object ActorCellSendMessageMetricInstrumentation { if (sender != Actor.noSender) for { cell <- ActorRefOps.Local.cell(sender) - metrics <- ActorCellDecorator.get(cell) - } metrics.sentMessages.inc() + metrics <- ActorCellDecorator.get(cell) if metrics.sentMessages.isDefined + } metrics.sentMessages.get.inc() } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala index de9ee2c6e..f43ab5e7e 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala @@ -1,13 +1,18 @@ package io.scalac.mesmer.agent.akka.actor.impl import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.OnMethodExit -import net.bytebuddy.asm.Advice.This +import net.bytebuddy.asm.Advice.{ OnMethodExit, This } object ActorUnhandledInstrumentation { @OnMethodExit def onExit(@This actor: Object): Unit = - ActorCellDecorator.get(ClassicActorOps.getContext(actor)).foreach(_.unhandledMessages.inc()) + ActorCellDecorator + .get(ClassicActorOps.getContext(actor)) + .foreach { metrics => + if(metrics.unhandledMessages.isDefined) { + metrics.unhandledMessages.get.inc() + } + } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala index 2fd514104..a83a5c4ab 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala @@ -1,13 +1,11 @@ package io.scalac.mesmer.agent.akka.actor.impl +import akka.actor.{ Actor, ActorContext } +import io.scalac.mesmer.core.actor.ActorCellDecorator +import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit, This } + import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType.methodType -import akka.actor.Actor -import akka.actor.ActorContext -import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.Argument -import net.bytebuddy.asm.Advice.OnMethodExit -import net.bytebuddy.asm.Advice.This object StashConstructorAdvice { @@ -15,7 +13,7 @@ object StashConstructorAdvice { def initStash(@This self: Actor): Unit = ActorCellDecorator .get(ClassicActorOps.getContext(self)) - .foreach(_.stashSize.initialize()) + .foreach(_.initStashedMessages()) } @@ -45,7 +43,11 @@ object ClassicStashInstrumentationStash extends StashGetters { @OnMethodExit def onStashExit(@This stash: AnyRef): Unit = - ActorCellDecorator.get(getActorCell(stash)).foreach(_.stashSize.inc()) + ActorCellDecorator.get(getActorCell(stash)).foreach { metrics => + if (metrics.stashedMessages.isDefined) { + metrics.stashedMessages.get.inc() + } + } } @@ -54,6 +56,10 @@ object ClassicStashInstrumentationPrepend extends StashGetters { @OnMethodExit def onStashExit(@This stash: AnyRef, @Argument(0) seq: Seq[_]): Unit = - ActorCellDecorator.get(getActorCell(stash)).foreach(_.stashSize.add(seq.size)) + ActorCellDecorator.get(getActorCell(stash)).foreach { metrics => + if (metrics.stashedMessages.isDefined) { + metrics.stashedMessages.get.add(seq.size) + } + } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala index 58ffa4ac8..1b9cf5b02 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala @@ -1,23 +1,25 @@ package io.scalac.mesmer.agent.akka.actor.impl -import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.OnMethodExit -import net.bytebuddy.asm.Advice.Return -import net.bytebuddy.asm.Advice.This +import io.scalac.mesmer.core.actor.{ ActorCellDecorator, ActorCellMetrics } import io.scalac.mesmer.core.util.Interval +import net.bytebuddy.asm.Advice.{ OnMethodExit, Return, This } object MailboxDequeueInstrumentation { @OnMethodExit def onExit(@Return envelope: Object, @This mailbox: Object): Unit = if (envelope != null) { - add(mailbox, computeTime(envelope)) + ActorCellDecorator.get(MailboxOps.getActor(mailbox)).foreach { metrics => + if (metrics.mailboxTimeAgg.isDefined) { + add(metrics, computeTime(envelope)) + } + } } - @inline final def computeTime(envelope: Object): Interval = + @inline private def computeTime(envelope: Object): Interval = EnvelopeDecorator.getTimestamp(envelope).interval() - @inline final def add(mailbox: Object, time: Interval): Unit = - ActorCellDecorator.get(MailboxOps.getActor(mailbox)).foreach(_.mailboxTimeAgg.add(time)) + @inline private def add(metrics: ActorCellMetrics, time: Interval): Unit = + metrics.mailboxTimeAgg.get.add(time) } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala index daad1bdda..77eb3c415 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala @@ -11,6 +11,11 @@ object StashBufferAdvice { def stash( @Advice.FieldValue("akka$actor$typed$internal$StashBufferImpl$$ctx") ctx: ActorContext[_] ): Unit = - ActorCellDecorator.get(ctx.toClassic).foreach(_.stashSize.inc()) + ActorCellDecorator.get(ctx.toClassic).foreach { metrics => + if (metrics.stashedMessages.isEmpty) { + metrics.initStashedMessages() + } + metrics.stashedMessages.get.inc() + } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala index b105dc0e8..a73c7b205 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala @@ -2,16 +2,20 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.typed.TypedActorContext import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.Argument -import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit } object SupervisorHandleReceiveExceptionInstrumentation { @OnMethodExit(onThrowable = classOf[Throwable]) def onExit(@Argument(0) context: TypedActorContext[_]): Unit = - ActorCellDecorator.get(ClassicActorContextProviderOps.classicActorContext(context)).foreach { actorMetrics => - actorMetrics.failedMessages.inc() - actorMetrics.exceptionHandledMarker.mark() + ActorCellDecorator.get(ClassicActorContextProviderOps.classicActorContext(context)).foreach { metrics => + import metrics._ + if (failedMessages.isDefined && exceptionHandledMarker.isDefined) { + + failedMessages.get.inc() + exceptionHandledMarker.get.mark() + + } } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index e5e99fa52..76c486194 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -1,20 +1,16 @@ package io.scalac.mesmer.agent.util +import io.scalac.mesmer.agent.AgentInstrumentation +import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails._ import net.bytebuddy.asm.Advice -import net.bytebuddy.description.`type`.TypeDescription +import net.bytebuddy.description.`type`.{ TypeDefinition, TypeDescription } import net.bytebuddy.description.method.MethodDescription import net.bytebuddy.dynamic.DynamicType -import net.bytebuddy.implementation.Implementation -import net.bytebuddy.implementation.MethodDelegation -import net.bytebuddy.matcher.ElementMatcher -import net.bytebuddy.matcher.{ ElementMatchers => EM } +import net.bytebuddy.implementation.{ Implementation, MethodDelegation } +import net.bytebuddy.matcher.{ ElementMatcher, ElementMatchers => EM } import scala.language.implicitConversions -import scala.reflect.ClassTag -import scala.reflect.classTag - -import io.scalac.mesmer.agent.AgentInstrumentation -import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails._ +import scala.reflect.{ classTag, ClassTag } package object i13n { @@ -86,6 +82,11 @@ package object i13n { def defineField[T](name: String)(implicit ct: ClassTag[T]): TypeInstrumentation = chain(_.defineField(name, ct.runtimeClass)) + def defineMethod[T](name: String, result: TypeDefinition, impl: Implementation)(implicit + ct: ClassTag[T] + ): TypeInstrumentation = + chain(_.defineMethod(name, result).intercept(impl)) + def implement[C: ClassTag](impl: Option[Implementation]): TypeInstrumentation = chain { builder => val implemented = builder.implement(classTag[C].runtimeClass) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala index 375531457..29d2b4bd8 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala @@ -1,16 +1,16 @@ package io.scalac.mesmer.agent.akka -import akka.actor.PoisonPill -import akka.actor.Props import akka.actor.testkit.typed.scaladsl.TestProbe -import akka.actor.typed.ActorRef -import akka.actor.typed.Behavior -import akka.actor.typed.SupervisorStrategy -import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.scaladsl.StashBuffer import akka.actor.typed.scaladsl.adapter._ +import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer} +import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy} +import akka.actor.{PoisonPill, Props} import akka.{actor => classic} +import io.scalac.mesmer.agent.utils.{InstallAgent, SafeLoadSystem} +import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics} +import io.scalac.mesmer.core.event.ActorEvent +import io.scalac.mesmer.core.util.MetricsToolKit.Counter +import io.scalac.mesmer.core.util.ReceptionistOps import org.scalatest.OptionValues import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike @@ -18,12 +18,6 @@ import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ import scala.util.control.NoStackTrace -import io.scalac.mesmer.agent.utils.InstallAgent -import io.scalac.mesmer.agent.utils.SafeLoadSystem -import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics} -import io.scalac.mesmer.core.event.ActorEvent -import io.scalac.mesmer.core.util.MetricsToolKit.Counter -import io.scalac.mesmer.core.util.ReceptionistOps class AkkaActorAgentTest extends InstallAgent @@ -116,7 +110,12 @@ class AkkaActorAgentTest val waitingMessages = messages - 1 val check: classic.ActorContext => Any = ctx => { - val metrics = ActorCellDecorator.get(ctx).flatMap(_.mailboxTimeAgg.metrics).value + + val metrics = (for { + cellMetrics <- ActorCellDecorator.get(ctx) if cellMetrics.mailboxTimeAgg.isDefined + agg <- cellMetrics.mailboxTimeAgg.get.metrics + } yield agg).value + metrics.count should be(messages) metrics.sum should be((waitingMessages * idle.toNanos) +- ToleranceNanos) metrics.min should be(0L +- ToleranceNanos) @@ -137,7 +136,11 @@ class AkkaActorAgentTest val workingMessages = messages - 1 val check: classic.ActorContext => Any = ctx => { - val metrics = ActorCellDecorator.get(ctx).flatMap(_.processingTimeAgg.metrics).value +// val metrics = ActorCellDecorator.get(ctx).flatMap(_.processingTimeAgg.metrics).value +val metrics = (for { + cellMetrics <- ActorCellDecorator.get(ctx) if cellMetrics.processingTimeAgg.isDefined + agg <- cellMetrics.processingTimeAgg.get.metrics +} yield agg).value metrics.count should be(messages) metrics.sum should be((workingMessages * processing.toNanos) +- ToleranceNanos) metrics.min should be(0L +- ToleranceNanos) @@ -213,10 +216,10 @@ class AkkaActorAgentTest it should "record the amount of received messages" in { testWithoutEffect[Unit]((), (), ())( - (0, check(_.receivedMessages)(_.get() should be(0))), - (1, check(_.receivedMessages)(_.get() should be(1))), - (0, check(_.receivedMessages)(_.get() should be(1))), - (2, check(_.receivedMessages)(_.get() should be(3))) + (0, check(_.receivedMessages)(_.get.get() should be(0))), + (1, check(_.receivedMessages)(_.get.get() should be(1))), + (0, check(_.receivedMessages)(_.get.get() should be(1))), + (2, check(_.receivedMessages)(_.get.get() should be(3))) ) } @@ -229,12 +232,12 @@ class AkkaActorAgentTest }, false )("fail", "", "fail")( - (0, check(_.failedMessages)(_.get() should be(0))), - (1, check(_.failedMessages)(_.get() should be(1))), - (0, check(_.failedMessages)(_.get() should be(1))), - (1, check(_.failedMessages)(_.get() should be(1))), + (0, check(_.failedMessages)(_.get.get() should be(0))), + (1, check(_.failedMessages)(_.get.get() should be(1))), + (0, check(_.failedMessages)(_.get.get() should be(1))), + (1, check(_.failedMessages)(_.get.get() should be(1))), // why zero? because akka suspend any further message processing after an unsupervisioned failure - (1, check(_.failedMessages)(_.get() should be(1))) + (1, check(_.failedMessages)(_.get.get() should be(1))) ) } @@ -249,11 +252,11 @@ class AkkaActorAgentTest strategy, probes = false )("fail", "", "fail", "fail")( - (0, check(_.failedMessages)(_.get() should be(0))), - (1, check(_.failedMessages)(_.get() should be(1))), - (0, check(_.failedMessages)(_.get() should be(1))), - (1, check(_.failedMessages)(_.get() should be(1))), - (2, check(_.failedMessages)(_.get() should be(if (strategy != SupervisorStrategy.stop) 3 else 1))) + (0, check(_.failedMessages)(_.get.get() should be(0))), + (1, check(_.failedMessages)(_.get.get() should be(1))), + (0, check(_.failedMessages)(_.get.get() should be(1))), + (1, check(_.failedMessages)(_.get.get() should be(1))), + (2, check(_.failedMessages)(_.get.get() should be(if (strategy != SupervisorStrategy.stop) 3 else 1))) ) testForStrategy(SupervisorStrategy.restart) @@ -267,11 +270,11 @@ class AkkaActorAgentTest case "unhandled" => Behaviors.unhandled case _ => Behaviors.same }("unhandled", "unhandled", "unhandled", "other")( - (0, check(_.unhandledMessages)(_.get() should be(0))), - (1, check(_.unhandledMessages)(_.get() should be(1))), - (0, check(_.unhandledMessages)(_.get() should be(1))), - (2, check(_.unhandledMessages)(_.get() should be(3))), - (1, check(_.unhandledMessages)(_.get() should be(3))) + (0, check(_.unhandledMessages)(_.get.get() should be(0))), + (1, check(_.unhandledMessages)(_.get.get() should be(1))), + (0, check(_.unhandledMessages)(_.get.get() should be(1))), + (2, check(_.unhandledMessages)(_.get.get() should be(3))), + (1, check(_.unhandledMessages)(_.get.get() should be(3))) ) } @@ -296,7 +299,7 @@ class AkkaActorAgentTest val receiver = classicSystem.actorOf(classic.Props(new Receiver), createUniqueId) val sender = system.classicSystem.actorOf(classic.Props(new Sender(receiver)), createUniqueId) - val sent = createCounterChecker(senderContext.get, _.sentMessages) + val sent = createCounterChecker(senderContext.get, _.sentMessages.get) sender ! "forward" sent(1) @@ -328,10 +331,10 @@ class AkkaActorAgentTest }, false )("forward", "", "forward", "forward")( - (0, check(_.sentMessages)(_.get() should be(0))), - (1, check(_.sentMessages)(_.get() should be(0))), - (0, check(_.sentMessages)(_.get() should be(0))), - (2, check(_.sentMessages)(_.get() should be(0))) + (0, check(_.sentMessages)(_.get.get() should be(0))), + (1, check(_.sentMessages)(_.get.get() should be(0))), + (0, check(_.sentMessages)(_.get.get() should be(0))), + (2, check(_.sentMessages)(_.get.get() should be(0))) ) } @@ -367,7 +370,9 @@ object AkkaActorAgentTest { trait Inspectable { protected def inspectStashSize(ref: classic.ActorRef, ctx: classic.ActorContext): Unit = { - val size = ActorCellDecorator.get(ctx).flatMap(_.stashSize.get()) + val size = for { + cellMetrics <- ActorCellDecorator.get(ctx) if cellMetrics.stashedMessages.isDefined + } yield cellMetrics.stashedMessages.get.get() ref ! StashSize(size) } } diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala index 67278f544..3d173ad1d 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala @@ -1,34 +1,25 @@ package io.scalac.mesmer.agent.akka.actor -import java.util.Comparator -import akka.actor.ActorSystem -import akka.actor.PoisonPill -import akka.actor.typed.ActorRef -import akka.actor.typed.Behavior -import akka.actor.typed.MailboxSelector -import akka.actor.typed.Props -import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.scaladsl.Behaviors +import akka.actor.{ ActorSystem, PoisonPill } +import akka.actor.typed.{ ActorRef, Behavior, MailboxSelector, Props } +import akka.actor.typed.scaladsl.{ ActorContext, Behaviors } import akka.actor.typed.scaladsl.adapter._ -import akka.dispatch.BoundedPriorityMailbox -import akka.dispatch.BoundedStablePriorityMailbox -import akka.dispatch.Envelope -import akka.{actor => classic} -import com.typesafe.config.Config -import com.typesafe.config.ConfigFactory +import akka.dispatch.{ BoundedPriorityMailbox, BoundedStablePriorityMailbox, Envelope } +import akka.{ actor => classic } +import com.typesafe.config.{ Config, ConfigFactory } +import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish +import io.scalac.mesmer.agent.utils.{ InstallModule, SafeLoadSystem } +import io.scalac.mesmer.core.actor.ActorCellDecorator +import io.scalac.mesmer.core.config.AkkaPatienceConfig +import io.scalac.mesmer.core.util.TestOps import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers +import java.util.Comparator import scala.annotation.unused import scala.concurrent.duration.Duration import scala.jdk.DurationConverters._ -import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish -import io.scalac.mesmer.agent.utils.InstallModule -import io.scalac.mesmer.agent.utils.SafeLoadSystem -import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics, DroppedMessagesCellMetrics} -import io.scalac.mesmer.core.config.AkkaPatienceConfig -import io.scalac.mesmer.core.util.TestOps final class HashCodePriorityMailbox( capacity: Int, @@ -147,7 +138,7 @@ class ActorMailboxTest ) eventually { val metrics = ActorCellDecorator.get(context.toClassic).get - metrics.droppedMessages.map(_.get()) should be(Some(expectedValue)) + metrics.droppedMessages.toOption.map(_.get()) should be(Some(expectedValue)) } sut.unsafeUpcast[Any] ! PoisonPill } @@ -180,25 +171,25 @@ class ActorMailboxTest testWithProps(props) } - it should "not have dropped messages defined for default typed configuration" in { - val (sut, context) = actorRefWithContext(Props.empty) - - val metrics = ActorCellDecorator.get(context.toClassic).get - metrics.droppedMessages should be(None) - assertThrows[ClassCastException] { - metrics.asInstanceOf[ActorCellMetrics with DroppedMessagesCellMetrics] - } - sut.unsafeUpcast ! PoisonPill - } +// it should "not have dropped messages defined for default typed configuration" in { +// val (sut, context) = actorRefWithContext(Props.empty) +// +// val metrics = ActorCellDecorator.get(context.toClassic).get +// metrics.droppedMessages should be(None) +// assertThrows[ClassCastException] { +// metrics.asInstanceOf[ActorCellMetrics with DroppedMessagesCellMetrics] +// } +// sut.unsafeUpcast ! PoisonPill +// } it should "not have dropped messages defined for default classic configuration" in { val (sut, context) = classicActorRefWithContext(classic.Props.empty) val metrics = ActorCellDecorator.get(context).get metrics.droppedMessages should be(None) - assertThrows[ClassCastException] { - metrics.asInstanceOf[ActorCellMetrics with DroppedMessagesCellMetrics] - } +// assertThrows[ClassCastException] { +// metrics.asInstanceOf[ActorCellMetrics with DroppedMessagesCellMetrics] +// } sut.unsafeUpcast ! PoisonPill } diff --git a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala index d1284bcbe..784ed4991 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala @@ -5,21 +5,21 @@ import io.scalac.mesmer.core.util.ReflectionFieldUtils object ActorCellDecorator { - val fieldName = "_actorCellMetrics" + final val fieldName = "_actorCellMetrics" private lazy val (getter, setter) = ReflectionFieldUtils.getHandlers("akka.actor.ActorCell", fieldName) - /** - * Initialize actor cell for usage by mesmer. - * Basically this means assigning meaningful values for fields added by mesmer. - * @param actorCell actor cell to be initialized - */ - def initialize(actorCell: Object, mailboxType: MailboxType): Unit = - mailboxType match { - case _: UnboundedMailbox | _: SingleConsumerOnlyUnboundedMailbox => - setter.invoke(actorCell, new ActorCellMetrics()) - case _ => setter.invoke(actorCell, new ActorCellMetrics() with DroppedMessagesCellMetrics) - } +// /** +// * Initialize actor cell for usage by mesmer. +// * Basically this means assigning meaningful values for fields added by mesmer. +// * @param actorCell actor cell to be initialized +// */ +// def initialize(actorCell: Object, mailboxType: MailboxType): Unit = +// mailboxType match { +// case _: UnboundedMailbox | _: SingleConsumerOnlyUnboundedMailbox => +// setter.invoke(actorCell, new ActorCellMetrics()) +// case _ => setter.invoke(actorCell, new ActorCellMetrics() with DroppedMessagesCellMetrics) +// } //TODO this shouldn't fail when agent is not present - None should be returned def get(actorCell: Object): Option[ActorCellMetrics] = diff --git a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala index 0e2e23f84..9462bcf4c 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala @@ -1,53 +1,40 @@ package io.scalac.mesmer.core.actor +import akka.OptionVal.{ apply, none, _ } import io.scalac.mesmer.core.util.MetricsToolKit._ -class ActorCellMetrics { - val mailboxTimeAgg: TimeAggregation = new TimeAggregation() - val processingTimeAgg: TimeAggregation = new TimeAggregation() - val processingTimer: Timer = new Timer - val receivedMessages: Counter = new Counter - val processedMessages: Counter = new Counter - val unhandledMessages: Counter = new Counter - val sentMessages: Counter = new Counter - val failedMessages: Counter = new Counter - val exceptionHandledMarker: Marker = new Marker - val stashSize: UninitializedCounter = new UninitializedCounter - def droppedMessages: Option[Counter] = None -} - -/** - * Mixed in trait for actor cells with bounded mailboxes - */ -trait DroppedMessagesCellMetrics extends ActorCellMetrics { - val _droppedMessages = new Counter - override def droppedMessages: Some[Counter] = Some(_droppedMessages) -} +final class ActorCellMetrics { + private var _mailboxTimeAgg: OptionVal[TimeAggregation] = none + private var _processingTimeAgg: OptionVal[TimeAggregation] = none + private var _processingTimer: OptionVal[Timer] = none + private var _receivedMessages: OptionVal[Counter] = none + private var _unhandledMessages: OptionVal[Counter] = none + private var _sentMessages: OptionVal[Counter] = none + private var _failedMessages: OptionVal[Counter] = none + private var _exceptionHandledMarker: OptionVal[Marker] = none + private var _stashedMessages: OptionVal[Counter] = none + private var _droppedMessages: OptionVal[Counter] = none -//trait CellMetrics { -// def mailboxTimeAgg -// def processingTimeAgg -// def processingTimer -// def receivedMessages -// def processedMessages -// def unhandledMessages -// def sentMessages -// def failedMessages -// def exceptionHandledMarker -// def stashSize -// def droppedMessages -//} + def mailboxTimeAgg: OptionVal[TimeAggregation] = _mailboxTimeAgg + def processingTimeAgg: OptionVal[TimeAggregation] = _processingTimeAgg + def processingTimer: OptionVal[Timer] = _processingTimer + def receivedMessages: OptionVal[Counter] = _receivedMessages + def unhandledMessages: OptionVal[Counter] = _unhandledMessages + def sentMessages: OptionVal[Counter] = _sentMessages + def failedMessages: OptionVal[Counter] = _failedMessages + def exceptionHandledMarker: OptionVal[Marker] = _exceptionHandledMarker + def stashedMessages: OptionVal[Counter] = _stashedMessages + def droppedMessages: OptionVal[Counter] = _droppedMessages + def initMailboxTimeAgg(): Unit = _mailboxTimeAgg = apply(new TimeAggregation()) + def initProcessingTimeAgg(): Unit = _processingTimeAgg = apply(new TimeAggregation()) + def initProcessingTimer(): Unit = _processingTimer = apply(new Timer()) + def initReceivedMessages(): Unit = _receivedMessages = apply(new Counter()) + def initUnhandledMessages(): Unit = _unhandledMessages = apply(new Counter()) + def initSentMessages(): Unit = _sentMessages = apply(new Counter()) + def initFailedMessages(): Unit = _failedMessages = apply(new Counter()) + def initExceptionHandledMarker(): Unit = _exceptionHandledMarker = apply(new Marker) + def initStashedMessages(): Unit = _stashedMessages = apply(new Counter()) + def initDroppedMessages(): Unit = _droppedMessages = apply(new Counter()) -final class CellMetricsImpl { - val mailboxTimeAgg: TimeAggregation = new TimeAggregation() - val processingTimeAgg: TimeAggregation = new TimeAggregation() - val processingTimer: Timer = new Timer - val receivedMessages: Counter = new Counter - val processedMessages: Counter = new Counter - val unhandledMessages: Counter = new Counter - val sentMessages: Counter = new Counter - val failedMessages: Counter = new Counter - val exceptionHandledMarker: Marker = new Marker - val stashSize: UninitializedCounter = new UninitializedCounter } diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala b/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala index a024e8cad..fa028273b 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala @@ -1,19 +1,18 @@ package io.scalac.mesmer.core.util -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicLong -import java.util.concurrent.atomic.AtomicReference - import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl +import java.util.concurrent.atomic.{ AtomicBoolean, AtomicLong, AtomicReference } + object MetricsToolKit { final class Counter { - private val counter = new AtomicLong(0) - def inc(): Unit = counter.getAndIncrement() - def take(): Long = counter.getAndSet(0) - def get(): Long = counter.get() - def reset(): Unit = counter.set(0) + private val counter = new AtomicLong(0) + def inc(): Unit = counter.getAndIncrement() + def add(value: Long): Unit = counter.getAndAdd(value) + def take(): Long = counter.getAndSet(0) + def get(): Long = counter.get() + def reset(): Unit = counter.set(0) } final class Marker { @@ -34,28 +33,28 @@ object MetricsToolKit { def interval(): Interval = timestamp.get().interval() } - final class UninitializedCounter { - - @volatile - private var counter: AtomicLong = _ - - def inc(): Unit = ensureInitialized(_.getAndIncrement()) - def add(value: Long): Unit = ensureInitialized(_.getAndAdd(value)) - def take(): Option[Long] = ifInitialized(_.getAndSet(0L)) - def get(): Option[Long] = ifInitialized(_.get()) - def reset(): Unit = ifInitialized(_.set(0L)) - def set(value: Long): Unit = ensureInitialized(_.set(value)) - - def initialize(): Unit = counter = new AtomicLong(0L) - - private def ifInitialized[@specialized(Long) T](map: AtomicLong => T): Option[T] = - if (counter ne null) Some(map(counter)) else None - - private def ensureInitialized[@specialized(Long) T](map: AtomicLong => T): T = { - if (counter eq null) initialize() - map(counter) - } - - } +// final class UninitializedCounter { +// +// @volatile +// private var counter: AtomicLong = _ +// +// def inc(): Unit = ensureInitialized(_.getAndIncrement()) +// def add(value: Long): Unit = ensureInitialized(_.getAndAdd(value)) +// def take(): Option[Long] = ifInitialized(_.getAndSet(0L)) +// def get(): Option[Long] = ifInitialized(_.get()) +// def reset(): Unit = ifInitialized(_.set(0L)) +// def set(value: Long): Unit = ensureInitialized(_.set(value)) +// +// def initialize(): Unit = counter = new AtomicLong(0L) +// +// private def ifInitialized[@specialized(Long) T](map: AtomicLong => T): Option[T] = +// if (counter ne null) Some(map(counter)) else None +// +// private def ensureInitialized[@specialized(Long) T](map: AtomicLong => T): T = { +// if (counter eq null) initialize() +// map(counter) +// } +// +// } } diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala index baa65c7ca..ecf7b3ebc 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala @@ -1,45 +1,29 @@ package io.scalac.mesmer.extension -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicReference -import akka.Done import akka.actor.typed._ import akka.actor.typed.receptionist.Receptionist.Listing -import akka.actor.typed.scaladsl.ActorContext -import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.scaladsl.TimerScheduler +import akka.actor.typed.scaladsl.{ ActorContext, Behaviors, TimerScheduler } import akka.util.Timeout -import akka.{actor => classic} +import akka.{ Done, actor => classic } import io.scalac.mesmer.core.actor.ActorCellDecorator -import org.slf4j.LoggerFactory - -import scala.concurrent.duration._ -import scala.util.Failure -import scala.util.Success import io.scalac.mesmer.core.akka.actorPathPartialOrdering -import io.scalac.mesmer.core.model.ActorKey -import io.scalac.mesmer.core.model.ActorRefDetails -import io.scalac.mesmer.core.model.Node -import io.scalac.mesmer.core.model.Tag -import io.scalac.mesmer.core.util.ActorCellOps -import io.scalac.mesmer.core.util.ActorPathOps -import io.scalac.mesmer.core.util.ActorRefOps +import io.scalac.mesmer.core.model.{ ActorKey, ActorRefDetails, Node, Tag } +import io.scalac.mesmer.core.util.{ ActorCellOps, ActorPathOps, ActorRefOps } import io.scalac.mesmer.extension.ActorEventsMonitorActor._ -import io.scalac.mesmer.extension.actor.ActorMetrics -import io.scalac.mesmer.extension.actor.MetricStorageFactory +import io.scalac.mesmer.extension.actor.{ ActorMetrics, MetricStorageFactory } import io.scalac.mesmer.extension.metric.ActorMetricsMonitor import io.scalac.mesmer.extension.metric.ActorMetricsMonitor.Labels import io.scalac.mesmer.extension.metric.MetricObserver.Result -import io.scalac.mesmer.extension.service.ActorTreeService -import io.scalac.mesmer.extension.service.ActorTreeService.Command.GetActorTree -import io.scalac.mesmer.extension.service.ActorTreeService.Command.TagSubscribe -import io.scalac.mesmer.extension.service.actorTreeServiceKey -import io.scalac.mesmer.extension.util.GenericBehaviors -import io.scalac.mesmer.extension.util.Tree -import io.scalac.mesmer.extension.util.Tree.Tree +import io.scalac.mesmer.extension.service.ActorTreeService.Command.{ GetActorTree, TagSubscribe } +import io.scalac.mesmer.extension.service.{ actorTreeServiceKey, ActorTreeService } import io.scalac.mesmer.extension.util.Tree.TreeOrdering._ -import io.scalac.mesmer.extension.util.Tree._ -import io.scalac.mesmer.extension.util.TreeF +import io.scalac.mesmer.extension.util.Tree.{ Tree, _ } +import io.scalac.mesmer.extension.util.{ GenericBehaviors, Tree, TreeF } +import org.slf4j.LoggerFactory + +import java.util.concurrent.atomic.AtomicReference +import scala.concurrent.duration._ +import scala.util.{ Failure, Success } object ActorEventsMonitorActor { @@ -97,14 +81,14 @@ object ActorEventsMonitorActor { metrics <- ActorCellDecorator.get(cell) } yield ActorMetrics( mailboxSize = safeRead(ActorCellOps.numberOfMessages(cell)), - mailboxTime = metrics.mailboxTimeAgg.metrics, - processingTime = metrics.processingTimeAgg.metrics, - receivedMessages = Some(metrics.receivedMessages.take()), - unhandledMessages = Some(metrics.unhandledMessages.take()), - failedMessages = Some(metrics.failedMessages.take()), - sentMessages = Some(metrics.sentMessages.take()), - stashSize = metrics.stashSize.take(), - droppedMessages = metrics.droppedMessages.map(_.take()) + mailboxTime = metrics.mailboxTimeAgg.toOption.flatMap(_.metrics), + processingTime = metrics.processingTimeAgg.toOption.flatMap(_.metrics), + receivedMessages = metrics.receivedMessages.toOption.map(_.take), + unhandledMessages = metrics.unhandledMessages.toOption.map(_.take), + failedMessages = metrics.failedMessages.toOption.map(_.take), + sentMessages = metrics.sentMessages.toOption.map(_.take), + stashSize = metrics.stashedMessages.toOption.map(_.take), + droppedMessages = metrics.droppedMessages.toOption.map(_.take) ) private def safeRead[T](value: => T): Option[T] = @@ -141,8 +125,6 @@ private[extension] class ActorEventsMonitorActor private[extension] ( private[this] val treeSnapshot = new AtomicReference[Option[Vector[(Labels, ActorMetrics)]]](None) - private[this] val exported = new AtomicBoolean(false) - private def updateMetric(extractor: ActorMetrics => Option[Long])(result: Result[Long, Labels]): Unit = { val state = treeSnapshot.get() state diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/actor/CleanableActorMetricsStorage.scala b/extension/src/main/scala/io/scalac/mesmer/extension/actor/CleanableActorMetricsStorage.scala deleted file mode 100644 index 414537d94..000000000 --- a/extension/src/main/scala/io/scalac/mesmer/extension/actor/CleanableActorMetricsStorage.scala +++ /dev/null @@ -1,20 +0,0 @@ -//package io.scalac.mesmer.extension.actor -// -//import scala.collection.mutable -// -//import io.scalac.mesmer.core.model.ActorKey -//import io.scalac.mesmer.core.util.Timestamp -//import io.scalac.mesmer.extension.config.CleaningSettings -//import io.scalac.mesmer.extension.resource.MutableCleanableStorage -// -//class CleanableActorMetricsStorage private ( -// buffer: mutable.Map[ActorKey, ActorMetrics], -// val cleaningConfig: CleaningSettings -//) extends MutableActorMetricsStorage(buffer) -// with MutableCleanableStorage[ActorKey, ActorMetrics] { -// protected def extractTimestamp(value: ActorMetrics): Timestamp = value.timestamp -//} -//object CleanableActorMetricsStorage { -// def withConfig(cleaningConfig: CleaningSettings): CleanableActorMetricsStorage = -// new CleanableActorMetricsStorage(mutable.Map.empty, cleaningConfig) -//} From 97f962e167c627d53dff58af644b0a343941d28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Tue, 29 Jun 2021 15:53:26 +0200 Subject: [PATCH 16/31] Remove commented code --- .../scala/io/scalac/mesmer/agent/Boot.scala | 14 +++++------ .../ActorCellConstructorInstrumentation.scala | 17 ------------- .../core/actor/ActorCellDecorator.scala | 15 +----------- .../io/scalac/mesmer/core/model/Version.scala | 1 - .../mesmer/core/support/ModulesSupport.scala | 7 ------ .../mesmer/core/util/MetricsToolKit.scala | 24 ------------------- .../core/model/SupportedModulesTest.scala | 14 ----------- 7 files changed, 7 insertions(+), 85 deletions(-) delete mode 100644 agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala index 622e422db..35ac1ce4c 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala @@ -1,19 +1,17 @@ package io.scalac.mesmer.agent -import java.lang.instrument.Instrumentation - import com.typesafe.config.ConfigFactory -import net.bytebuddy.ByteBuddy -import net.bytebuddy.agent.builder.AgentBuilder -import net.bytebuddy.dynamic.scaffold.TypeValidation - -import scala.annotation.unused - import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent import io.scalac.mesmer.core.util.LibraryInfo +import net.bytebuddy.ByteBuddy +import net.bytebuddy.agent.builder.AgentBuilder +import net.bytebuddy.dynamic.scaffold.TypeValidation + +import java.lang.instrument.Instrumentation +import scala.annotation.unused object Boot { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala deleted file mode 100644 index 37b3c7969..000000000 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellConstructorInstrumentation.scala +++ /dev/null @@ -1,17 +0,0 @@ -//package io.scalac.mesmer.agent.akka.actor.impl -// -//import akka.dispatch.MailboxType -//import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics} -//import net.bytebuddy.asm.Advice.{Argument, FieldValue, OnMethodExit, This} -// -//object ActorCellConstructorInstrumentation { -// -//// @OnMethodExit -//// def onEnter(@This actorCell: Object, @Argument(1) mailboxType: MailboxType): Unit = { -//// -//// } -// -// @OnMethodExit -// def setUpCellMetrics(@FieldValue(ActorCellDecorator.fieldName) cellMetrics: ActorCellMetrics) -//// ActorCellDecorator.initialize(actorCell, mailboxType) -//} diff --git a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala index 784ed4991..658076af0 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellDecorator.scala @@ -1,25 +1,12 @@ package io.scalac.mesmer.core.actor -import akka.dispatch.{MailboxType, SingleConsumerOnlyUnboundedMailbox, UnboundedMailbox} import io.scalac.mesmer.core.util.ReflectionFieldUtils object ActorCellDecorator { final val fieldName = "_actorCellMetrics" - private lazy val (getter, setter) = ReflectionFieldUtils.getHandlers("akka.actor.ActorCell", fieldName) - -// /** -// * Initialize actor cell for usage by mesmer. -// * Basically this means assigning meaningful values for fields added by mesmer. -// * @param actorCell actor cell to be initialized -// */ -// def initialize(actorCell: Object, mailboxType: MailboxType): Unit = -// mailboxType match { -// case _: UnboundedMailbox | _: SingleConsumerOnlyUnboundedMailbox => -// setter.invoke(actorCell, new ActorCellMetrics()) -// case _ => setter.invoke(actorCell, new ActorCellMetrics() with DroppedMessagesCellMetrics) -// } + private lazy val (getter, _) = ReflectionFieldUtils.getHandlers("akka.actor.ActorCell", fieldName) //TODO this shouldn't fail when agent is not present - None should be returned def get(actorCell: Object): Option[ActorCellMetrics] = diff --git a/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala b/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala index 2998aead3..60de369b9 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala @@ -11,4 +11,3 @@ object Version { def apply(major: Int, minor: Int, patch: Int): Version = Version(major.toString, minor.toString, patch.toString) } -//final case class Module(name: String) diff --git a/core/src/main/scala/io/scalac/mesmer/core/support/ModulesSupport.scala b/core/src/main/scala/io/scalac/mesmer/core/support/ModulesSupport.scala index 7f3680acf..358768cab 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/support/ModulesSupport.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/support/ModulesSupport.scala @@ -23,13 +23,6 @@ object ModulesSupport extends ModulesSupport { AkkaClusterModule ) -// val akkaHttpModule: Module = Module("akka-http") -// val akkaClusterTypedModule: Module = Module("akka-cluster-typed") -// val akkaPersistenceTypedModule: Module = Module("akka-persistence-typed") -// val akkaActorTypedModule: Module = Module("akka-actor-typed") -// val akkaActorModule: Module = Module("akka-actor") -// val akkaStreamModule: Module = Module("akka-stream") - private val commonAkkaSupportedVersion: SupportedVersion = majors("2").and(minors("6")).and(patches("8", "9", "10", "11", "12", "13", "14")) diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala b/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala index fa028273b..22413f590 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala @@ -33,28 +33,4 @@ object MetricsToolKit { def interval(): Interval = timestamp.get().interval() } -// final class UninitializedCounter { -// -// @volatile -// private var counter: AtomicLong = _ -// -// def inc(): Unit = ensureInitialized(_.getAndIncrement()) -// def add(value: Long): Unit = ensureInitialized(_.getAndAdd(value)) -// def take(): Option[Long] = ifInitialized(_.getAndSet(0L)) -// def get(): Option[Long] = ifInitialized(_.get()) -// def reset(): Unit = ifInitialized(_.set(0L)) -// def set(value: Long): Unit = ensureInitialized(_.set(value)) -// -// def initialize(): Unit = counter = new AtomicLong(0L) -// -// private def ifInitialized[@specialized(Long) T](map: AtomicLong => T): Option[T] = -// if (counter ne null) Some(map(counter)) else None -// -// private def ensureInitialized[@specialized(Long) T](map: AtomicLong => T): T = { -// if (counter eq null) initialize() -// map(counter) -// } -// -// } - } diff --git a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala index 257de3526..ec52ffc67 100644 --- a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala +++ b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala @@ -13,20 +13,6 @@ import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo class SupportedModulesTest extends AnyFlatSpec with Matchers with Inspectors { type Id[T] = T -// object TestModuleOne extends Module { -// val name: String = "test-module-one" -// -// type All[T] = Any -// -// def enabled(config: TypesafeConfig) = () -// -// override type AkkaJar = Any -// -// def jarsFromLibraryInfo(info: LibraryInfo) = None -// -// val requiredAkkaJars: Any = () -// } - object TestModuleOne extends Module { val name: String = "test-module-one" From 283cfe816d0f60a55a293ec60c9d5d05ad05c12e Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Wed, 30 Jun 2021 02:35:01 +0200 Subject: [PATCH 17/31] Update grpc-netty-shaded to 1.39.0 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6b194cbc8..52ac7cb82 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -75,6 +75,6 @@ object Dependencies { "com.lightbend.akka.management" %% "akka-management-cluster-bootstrap" % AkkaManagementVersion, "com.lightbend.akka.discovery" %% "akka-discovery-kubernetes-api" % AkkaManagementVersion, "io.opentelemetry" % "opentelemetry-exporter-otlp-metrics" % OpentelemetryMetricsVersion, - "io.grpc" % "grpc-netty-shaded" % "1.38.1" + "io.grpc" % "grpc-netty-shaded" % "1.39.0" ) } From 5daf3830bc06e4870afb847ec2a1a2d943a7487b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Wed, 30 Jun 2021 11:00:12 +0200 Subject: [PATCH 18/31] Add supported versions --- .../agent/akka/actor/AkkaActorAgent.scala | 53 ++++++++----------- .../impl/ActorCellDroppedMessagesAdvice.scala | 3 +- .../agent/akka/http/AkkaHttpAgent.scala | 14 +++-- .../persistence/AkkaPersistenceAgent.scala | 28 ++++++---- .../agent/akka/stream/AkkaStreamAgent.scala | 37 ++++++++----- .../agent/akka/actor/ActorMailboxTest.scala | 26 +++++---- .../agent/akka/impl/AkkaHttpTestImpl.scala | 36 ------------- .../main/scala/akka/MesmerMirrorTypes.scala | 18 +++++++ core/src/main/scala/akka/OptionVal.scala | 11 ++++ .../io/scalac/mesmer/core/akka/package.scala | 10 +++- .../mesmer/core/module/AkkaStreamModule.scala | 14 ++--- 11 files changed, 134 insertions(+), 116 deletions(-) delete mode 100644 agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala create mode 100644 core/src/main/scala/akka/MesmerMirrorTypes.scala create mode 100644 core/src/main/scala/akka/OptionVal.scala diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala index be0ff3fdd..60f653086 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala @@ -9,6 +9,7 @@ import io.scalac.mesmer.core.module.AkkaActorModule import io.scalac.mesmer.core.util.Timestamp import net.bytebuddy.asm.Advice import net.bytebuddy.dynamic.TargetType +import io.scalac.mesmer.core.akka.version26x import net.bytebuddy.implementation.{ FixedValue, MethodCall, MethodDelegation, SuperMethodCall } object AkkaActorAgent @@ -77,37 +78,34 @@ object AkkaActorAgent (resultantAgent, enabled) } + private def ifSupported(versions: AkkaActorModule.AkkaJar[Version])(agent: => Agent): Option[Agent] = { + if(version26x.supports(versions.akkaActor) && version26x.supports(versions.akkaActorTyped)) { + Some(agent) + } else None + } - lazy val mailboxSize: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedInstrumentation) + lazy val mailboxSize: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation) - lazy val mailboxTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) + lazy val mailboxTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) - lazy val mailboxTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) + lazy val mailboxTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) - lazy val mailboxTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) + lazy val mailboxTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) - lazy val mailboxTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) + lazy val mailboxTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) - lazy val stashedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation) + lazy val stashedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation) - lazy val receivedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ initField("received-messages", _.initReceivedMessages())) + lazy val receivedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ initField("received-messages", _.initReceivedMessages())) - lazy val processedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some( + lazy val processedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( sharedInstrumentation ++ initField( "processed-messages", _.initUnhandledMessages() ) ) - lazy val failedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some( + lazy val failedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( sharedInstrumentation ++ abstractSupervisionInstrumentation ++ initField( "mailbox-size", metrics => { @@ -117,8 +115,7 @@ object AkkaActorAgent ) ) - lazy val processingTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some( + lazy val processingTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( sharedInstrumentation ++ initField( "processing-time", metrics => { @@ -128,8 +125,7 @@ object AkkaActorAgent ) ) - lazy val processingTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some( + lazy val processingTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( sharedInstrumentation ++ initField( "processing-time", metrics => { @@ -139,8 +135,7 @@ object AkkaActorAgent ) ) - lazy val processingTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some( + lazy val processingTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( sharedInstrumentation ++ initField( "processing-time", metrics => { @@ -150,8 +145,7 @@ object AkkaActorAgent ) ) - lazy val processingTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some( + lazy val processingTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( sharedInstrumentation ++ initField( "processing-time", metrics => { @@ -161,16 +155,14 @@ object AkkaActorAgent ) ) - lazy val sentMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some( + lazy val sentMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( sharedInstrumentation ++ mailboxTimeSendMessageIncInstrumentation ++ initField( "sent-messages", _.initSentMessages() ) ) - lazy val droppedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedInstrumentation ++ boundedQueueAgent ++ initDroppedMessages) + lazy val droppedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ boundedQueueAgent ++ initDroppedMessages) /** * Instrumentation for classic stash @@ -248,11 +240,12 @@ object AkkaActorAgent SuperMethodCall.INSTANCE.andThen(MethodCall.invoke(named("setupMetrics").method)) ) ) - .visit(ActorCellReceiveMessageInstrumentation, "receiveMessage") + .visit(ActorCellReceiveMessageInstrumentation, "receiveMessage").deferred private def initField(name: String, init: ActorCellMetrics => Unit): AgentInstrumentation = instrument("akka.actor.ActorCell".fqcnWithTags(name)) .intercept("setupMetrics", MethodDelegation.to(new ActorCellInitializer(init)).andThen(SuperMethodCall.INSTANCE)) + .deferred private lazy val sharedInstrumentation: Agent = Agent( diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala index 37ed3f4c8..4de9fee61 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala @@ -10,10 +10,11 @@ object ActorCellDroppedMessagesAdvice { def init(@This actorCell: Object, @Argument(1) mailboxType: MailboxType): Unit = mailboxType match { case _: UnboundedMailbox | _: SingleConsumerOnlyUnboundedMailbox => + + case _ => ActorCellDecorator.get(actorCell).foreach { metrics => metrics.initDroppedMessages() } - case _ => } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala index c0ea297cf..65fe38bfe 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala @@ -2,6 +2,7 @@ package io.scalac.mesmer.agent.akka.http import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.core.akka._ import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaHttpModule import io.scalac.mesmer.core.module.AkkaHttpModule._ @@ -11,11 +12,18 @@ object AkkaHttpAgent with AkkaHttpModule.AkkaHttpConnectionsMetricsDef[AkkaHttpModule.AkkaJar[Version] => Option[Agent]] with AkkaHttpModule.AkkaHttpRequestMetricsDef[AkkaHttpModule.AkkaJar[Version] => Option[Agent]] { - def requestTime: AkkaHttpModule.Jars[Version] => Option[Agent] = _ => Some(requestEvents) // Version => Option[Agent] + private val supportedVersions = version101x.or(version102x) - def requestCounter: AkkaHttpModule.Jars[Version] => Option[Agent] = _ => Some(requestEvents) + private def ifSupported(versions: AkkaHttpModule.AkkaJar[Version])(agent: => Agent): Option[Agent] = + if (supportedVersions.supports(versions.akkaHttp)) + Some(agent) + else None - def connections: AkkaHttpModule.Jars[Version] => Option[Agent] = _ => Some(connectionEvents) + val requestTime: AkkaHttpModule.Jars[Version] => Option[Agent] = versions => ifSupported(versions)(requestEvents) // Version => Option[Agent] + + val requestCounter: AkkaHttpModule.Jars[Version] => Option[Agent] = versions => ifSupported(versions)(requestEvents) + + val connections: AkkaHttpModule.Jars[Version] => Option[Agent] = versions => ifSupported(versions)(connectionEvents) private lazy val requestEvents = Agent( diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala index 1519b2972..f19eb0765 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala @@ -1,12 +1,12 @@ package io.scalac.mesmer.agent.akka.persistence -import org.slf4j.LoggerFactory - import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.akka.persistence.impl._ import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.core.akka.version26x import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaPersistenceModule +import org.slf4j.LoggerFactory object AkkaPersistenceAgent extends InstrumentModuleFactory(AkkaPersistenceModule) @@ -46,18 +46,26 @@ object AkkaPersistenceAgent (resultantAgent, enabled) } - lazy val recoveryTime: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => Some(recoveryAgent) + private def ifSupported(agent: => Agent)(versions: AkkaPersistenceModule.AkkaJar[Version]): Option[Agent] = + if (version26x.supports(versions.akkaPersistence) && version26x.supports(versions.akkaPersistenceTyped)) + Some(agent) + else None + + lazy val recoveryTime: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = ifSupported(recoveryAgent) - lazy val recoveryTotal: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => Some(recoveryAgent) + lazy val recoveryTotal: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = ifSupported(recoveryAgent) - lazy val persistentEvent: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => - Some(Agent(eventWriteSuccessInstrumentation)) + lazy val persistentEvent: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = ifSupported( + Agent(eventWriteSuccessInstrumentation) + ) - lazy val persistentEventTotal: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => - Some(Agent(eventWriteSuccessInstrumentation)) + lazy val persistentEventTotal: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = ifSupported( + Agent(eventWriteSuccessInstrumentation) + ) - lazy val snapshot: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = _ => - Some(Agent(snapshotLoadingInstrumentation)) + lazy val snapshot: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = ifSupported( + Agent(snapshotLoadingInstrumentation) + ) private[persistence] val logger = LoggerFactory.getLogger(AkkaPersistenceAgent.getClass) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala index 5a9bce88e..d0b0a8e24 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala @@ -2,15 +2,16 @@ package io.scalac.mesmer.agent.akka.stream import akka.ActorGraphInterpreterAdvice import akka.stream.GraphStageIslandAdvice -import akka.stream.impl.fusing.ActorGraphInterpreterProcessEventAdvice -import akka.stream.impl.fusing.ActorGraphInterpreterTryInitAdvice - +import akka.stream.impl.fusing.{ ActorGraphInterpreterProcessEventAdvice, ActorGraphInterpreterTryInitAdvice } import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.akka.stream.impl.ConnectionOps -import io.scalac.mesmer.agent.akka.stream.impl.GraphInterpreterPullAdvice -import io.scalac.mesmer.agent.akka.stream.impl.GraphInterpreterPushAdvice -import io.scalac.mesmer.agent.akka.stream.impl.PhasedFusingActorMaterializerAdvice +import io.scalac.mesmer.agent.akka.stream.impl.{ + ConnectionOps, + GraphInterpreterPullAdvice, + GraphInterpreterPushAdvice, + PhasedFusingActorMaterializerAdvice +} import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.core.akka.version26x import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaStreamModule @@ -54,18 +55,26 @@ object AkkaStreamAgent (resultantAgent, enabled) } - lazy val runningStreamsTotal: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) + private def ifSupported(agent: => Agent)(versions: AkkaStreamModule.AkkaJar[Version]): Option[Agent] = { + import versions._ + if (version26x.supports(akkaStream) && version26x.supports(akkaActorTyped) && version26x.supports(akkaActor)) { + Some(agent) + } else None + } + + lazy val runningStreamsTotal: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = ifSupported(sharedImplementations) - lazy val streamActorsTotal: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) + lazy val streamActorsTotal: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = ifSupported(sharedImplementations) - lazy val streamProcessedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => - Some(sharedImplementations) + lazy val streamProcessedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = ifSupported( + sharedImplementations + ) - lazy val processedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) + lazy val processedMessages: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = ifSupported(sharedImplementations) - lazy val operators: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) + lazy val operators: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = ifSupported(sharedImplementations) - lazy val demand: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = _ => Some(sharedImplementations) + lazy val demand: AkkaStreamModule.AkkaJar[Version] => Option[Agent] = ifSupported(sharedImplementations) /** * actorOf methods is called when island decide to materialize itself diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala index 3d173ad1d..a65b0cf22 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala @@ -1,9 +1,9 @@ package io.scalac.mesmer.agent.akka.actor -import akka.actor.{ ActorSystem, PoisonPill } -import akka.actor.typed.{ ActorRef, Behavior, MailboxSelector, Props } -import akka.actor.typed.scaladsl.{ ActorContext, Behaviors } import akka.actor.typed.scaladsl.adapter._ +import akka.actor.typed.scaladsl.{ ActorContext, Behaviors } +import akka.actor.typed.{ ActorRef, Behavior, MailboxSelector, Props } +import akka.actor.{ ActorSystem, PoisonPill } import akka.dispatch.{ BoundedPriorityMailbox, BoundedStablePriorityMailbox, Envelope } import akka.{ actor => classic } import com.typesafe.config.{ Config, ConfigFactory } @@ -171,22 +171,20 @@ class ActorMailboxTest testWithProps(props) } -// it should "not have dropped messages defined for default typed configuration" in { -// val (sut, context) = actorRefWithContext(Props.empty) -// -// val metrics = ActorCellDecorator.get(context.toClassic).get -// metrics.droppedMessages should be(None) -// assertThrows[ClassCastException] { -// metrics.asInstanceOf[ActorCellMetrics with DroppedMessagesCellMetrics] -// } -// sut.unsafeUpcast ! PoisonPill -// } + it should "not have dropped messages defined for default typed configuration" in { + val (sut, context) = actorRefWithContext(Props.empty) + + val metrics = ActorCellDecorator.get(context.toClassic).get + metrics.droppedMessages.toOption should be(None) + + sut.unsafeUpcast ! PoisonPill + } it should "not have dropped messages defined for default classic configuration" in { val (sut, context) = classicActorRefWithContext(classic.Props.empty) val metrics = ActorCellDecorator.get(context).get - metrics.droppedMessages should be(None) + metrics.droppedMessages.toOption should be(None) // assertThrows[ClassCastException] { // metrics.asInstanceOf[ActorCellMetrics with DroppedMessagesCellMetrics] // } diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala deleted file mode 100644 index 214a544df..000000000 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/impl/AkkaHttpTestImpl.scala +++ /dev/null @@ -1,36 +0,0 @@ -package io.scalac.mesmer.agent.akka.impl - -import java.util.UUID - -import akka.actor.testkit.typed.scaladsl.TestProbe -import akka.actor.typed.ActorSystem -import akka.actor.typed.receptionist.Receptionist -import akka.actor.typed.receptionist.Receptionist.Deregister -import akka.actor.typed.receptionist.Receptionist.Register -import akka.actor.typed.scaladsl.adapter._ -import akka.{ actor => classic } -import com.typesafe.config.Config -import com.typesafe.config.ConfigFactory - -import io.scalac.mesmer.core.event.HttpEvent -import io.scalac.mesmer.core.httpServiceKey - -object AkkaHttpTestImpl { - - private val testConfig: Config = ConfigFactory.load("application-test") - - def systemWithHttpService(body: ActorSystem[Nothing] => TestProbe[HttpEvent] => Any): Any = { - val cl = Thread.currentThread().getContextClassLoader - println(s"Initializing ActorSystem with classLoader ${cl}") - implicit val typedSystem: ActorSystem[Nothing] = - classic.ActorSystem(UUID.randomUUID().toString, testConfig, cl).toTyped - val monitor = TestProbe[HttpEvent]("http-test-probe") - - Receptionist(typedSystem).ref ! Register(httpServiceKey, monitor.ref) - - body(typedSystem)(monitor) - - Receptionist(typedSystem).ref ! Deregister(httpServiceKey, monitor.ref) - } - -} diff --git a/core/src/main/scala/akka/MesmerMirrorTypes.scala b/core/src/main/scala/akka/MesmerMirrorTypes.scala new file mode 100644 index 000000000..0672426cd --- /dev/null +++ b/core/src/main/scala/akka/MesmerMirrorTypes.scala @@ -0,0 +1,18 @@ +package akka + +import akka.stream.impl.ExtendedActorMaterializer +import akka.stream.impl.fusing.{ GraphInterpreter, GraphInterpreterShell } +import akka.stream.stage.GraphStageLogic +import akka.util.{ OptionVal => AkkaOptionVal } + +object MesmerMirrorTypes { + type ActorRefWithCell = akka.actor.ActorRefWithCell + type Cell = akka.actor.Cell + type ExtendedActorMaterializerMirror = ExtendedActorMaterializer + type GraphInterpreterMirror = GraphInterpreter + type GraphInterpreterShellMirror = GraphInterpreterShell + type GraphStageLogicMirror = GraphStageLogic + + val c: Cell = ??? + c.isLocal +} diff --git a/core/src/main/scala/akka/OptionVal.scala b/core/src/main/scala/akka/OptionVal.scala new file mode 100644 index 000000000..90c675de6 --- /dev/null +++ b/core/src/main/scala/akka/OptionVal.scala @@ -0,0 +1,11 @@ +package akka +import akka.util.{ OptionVal => AkkaOptionVal } + +object OptionVal { + type OptionVal[+T] = AkkaOptionVal[T] + + def none[A]: OptionVal[A] = AkkaOptionVal.none[A] + + def apply[A](value: A): OptionVal[A] = AkkaOptionVal(value) + +} diff --git a/core/src/main/scala/io/scalac/mesmer/core/akka/package.scala b/core/src/main/scala/io/scalac/mesmer/core/akka/package.scala index 3924ed0a3..960056645 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/akka/package.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/akka/package.scala @@ -1,8 +1,8 @@ package io.scalac.mesmer.core -import scala.math.PartialOrdering +import io.scalac.mesmer.core.model.{ ActorPath, SupportedVersion } -import io.scalac.mesmer.core.model.ActorPath +import scala.math.PartialOrdering package object akka { @@ -20,4 +20,10 @@ package object akka { private def actorLevel(path: ActorPath): Int = path.count(_ == '/') } + val version26x = SupportedVersion.majors("2").and(SupportedVersion.minors("6")) + + val version101x = SupportedVersion.majors("10").and(SupportedVersion.minors("1")) + + val version102x = SupportedVersion.majors("10").and(SupportedVersion.minors("2")) + } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala index 04f44aa48..5fe4ef5d4 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala @@ -1,9 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } - import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.Combine -import io.scalac.mesmer.core.module.Module.Traverse +import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaStreamMetrics extends MetricsModule { @@ -100,12 +98,16 @@ object AkkaStreamModule override type AkkaJar[T] = Jars[T] - final case class Jars[T](akkaStream: T) + final case class Jars[T](akkaStream: T, akkaActor: T, akkaActorTyped: T) def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = - info.get(requiredAkkaJars.akkaStream).map(Jars.apply[Version]) + for { + stream <- info.get(requiredAkkaJars.akkaStream) + actor <- info.get(requiredAkkaJars.akkaActor) + actorTyped <- info.get(requiredAkkaJars.akkaActorTyped) + } yield Jars(stream, actor, actorTyped) - val requiredAkkaJars: AkkaJar[String] = Jars("akka-stream") + val requiredAkkaJars: AkkaJar[String] = Jars("akka-stream", "akka-actor", "akka-actor-typed") implicit val combine: Combine[All[Boolean]] = (first, second) => { Impl( From ac17064df9bf299f84572af34ddea21512123997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Wed, 30 Jun 2021 11:43:25 +0200 Subject: [PATCH 19/31] Add akkaActor and akkaActorTyped dependencies for all modules --- .../scala/io/scalac/mesmer/agent/Boot.scala | 14 ++-- .../agent/akka/actor/AkkaActorAgent.scala | 79 +++++++++++++------ .../actor/AkkaMailboxInstrumentations.scala | 27 ++++--- .../impl/ActorCellDroppedMessagesAdvice.scala | 9 ++- .../actor/impl/ActorCellInitializer.scala | 4 +- ...torCellReceiveMessageInstrumentation.scala | 6 +- ...CellSendMessageMetricInstrumentation.scala | 3 +- .../impl/ActorUnhandledInstrumentation.scala | 6 +- .../ClassicStashInstrumentationStash.scala | 12 ++- .../impl/MailboxDequeueInstrumentation.scala | 8 +- .../akka/actor/impl/StashBufferAdvice.scala | 3 +- ...andleReceiveExceptionInstrumentation.scala | 4 +- .../agent/akka/http/AkkaHttpAgent.scala | 13 ++- .../persistence/AkkaPersistenceAgent.scala | 12 ++- .../agent/akka/stream/AkkaStreamAgent.scala | 14 ++-- .../mesmer/agent/util/i13n/package.scala | 17 ++-- .../agent/akka/AkkaActorAgentTest.scala | 34 +++++--- .../agent/akka/actor/ActorMailboxTest.scala | 33 +++++--- .../mesmer/core/module/AkkaActorModule.scala | 12 +-- .../core/module/AkkaActorSystemModule.scala | 10 ++- .../core/module/AkkaClusterModule.scala | 14 ++-- .../mesmer/core/module/AkkaHttpModule.scala | 14 ++-- .../core/module/AkkaPersistenceModule.scala | 17 ++-- .../mesmer/core/module/AkkaStreamModule.scala | 14 ++-- .../io/scalac/mesmer/core/module/Module.scala | 22 +++++- .../core/model/SupportedModulesTest.scala | 9 +-- 26 files changed, 259 insertions(+), 151 deletions(-) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala index 35ac1ce4c..622e422db 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/Boot.scala @@ -1,18 +1,20 @@ package io.scalac.mesmer.agent +import java.lang.instrument.Instrumentation + import com.typesafe.config.ConfigFactory -import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent -import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent -import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent -import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent -import io.scalac.mesmer.core.util.LibraryInfo import net.bytebuddy.ByteBuddy import net.bytebuddy.agent.builder.AgentBuilder import net.bytebuddy.dynamic.scaffold.TypeValidation -import java.lang.instrument.Instrumentation import scala.annotation.unused +import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent +import io.scalac.mesmer.agent.akka.http.AkkaHttpAgent +import io.scalac.mesmer.agent.akka.persistence.AkkaPersistenceAgent +import io.scalac.mesmer.agent.akka.stream.AkkaStreamAgent +import io.scalac.mesmer.core.util.LibraryInfo + object Boot { //TODO better configuration specification diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala index 60f653086..14e80ce81 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaActorAgent.scala @@ -1,16 +1,22 @@ package io.scalac.mesmer.agent.akka.actor +import net.bytebuddy.asm.Advice +import net.bytebuddy.dynamic.TargetType +import net.bytebuddy.implementation.FixedValue +import net.bytebuddy.implementation.MethodCall +import net.bytebuddy.implementation.MethodDelegation +import net.bytebuddy.implementation.SuperMethodCall + +import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.AgentInstrumentation import io.scalac.mesmer.agent.akka.actor.impl._ import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } -import io.scalac.mesmer.core.actor.{ ActorCellDecorator, ActorCellMetrics } +import io.scalac.mesmer.core.actor.ActorCellDecorator +import io.scalac.mesmer.core.actor.ActorCellMetrics +import io.scalac.mesmer.core.akka.version26x import io.scalac.mesmer.core.model._ import io.scalac.mesmer.core.module.AkkaActorModule import io.scalac.mesmer.core.util.Timestamp -import net.bytebuddy.asm.Advice -import net.bytebuddy.dynamic.TargetType -import io.scalac.mesmer.core.akka.version26x -import net.bytebuddy.implementation.{ FixedValue, MethodCall, MethodDelegation, SuperMethodCall } object AkkaActorAgent extends InstrumentModuleFactory(AkkaActorModule) @@ -78,34 +84,50 @@ object AkkaActorAgent (resultantAgent, enabled) } - private def ifSupported(versions: AkkaActorModule.AkkaJar[Version])(agent: => Agent): Option[Agent] = { - if(version26x.supports(versions.akkaActor) && version26x.supports(versions.akkaActorTyped)) { + private def ifSupported(versions: AkkaActorModule.AkkaJar[Version])(agent: => Agent): Option[Agent] = + if (version26x.supports(versions.akkaActor) && version26x.supports(versions.akkaActorTyped)) { Some(agent) } else None - } - lazy val mailboxSize: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation) + lazy val mailboxSize: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)(sharedInstrumentation) - lazy val mailboxTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) + lazy val mailboxTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( + sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg()) + ) - lazy val mailboxTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) + lazy val mailboxTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( + sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg()) + ) - lazy val mailboxTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) + lazy val mailboxTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( + sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg()) + ) - lazy val mailboxTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg())) + lazy val mailboxTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( + sharedInstrumentation ++ mailboxInstrumentation ++ initField("mailbox-time", _.initMailboxTimeAgg()) + ) - lazy val stashedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation) + lazy val stashedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)(sharedInstrumentation ++ classicStashInstrumentationAgent ++ stashBufferImplementation) - lazy val receivedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ initField("received-messages", _.initReceivedMessages())) + lazy val receivedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)(sharedInstrumentation ++ initField("received-messages", _.initReceivedMessages())) - lazy val processedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( + lazy val processedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( sharedInstrumentation ++ initField( "processed-messages", _.initUnhandledMessages() ) ) - lazy val failedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( + lazy val failedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( sharedInstrumentation ++ abstractSupervisionInstrumentation ++ initField( "mailbox-size", metrics => { @@ -115,7 +137,8 @@ object AkkaActorAgent ) ) - lazy val processingTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( + lazy val processingTimeMin: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( sharedInstrumentation ++ initField( "processing-time", metrics => { @@ -125,7 +148,8 @@ object AkkaActorAgent ) ) - lazy val processingTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( + lazy val processingTimeMax: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( sharedInstrumentation ++ initField( "processing-time", metrics => { @@ -135,7 +159,8 @@ object AkkaActorAgent ) ) - lazy val processingTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( + lazy val processingTimeSum: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( sharedInstrumentation ++ initField( "processing-time", metrics => { @@ -145,7 +170,8 @@ object AkkaActorAgent ) ) - lazy val processingTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( + lazy val processingTimeCount: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( sharedInstrumentation ++ initField( "processing-time", metrics => { @@ -155,14 +181,16 @@ object AkkaActorAgent ) ) - lazy val sentMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)( + lazy val sentMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)( sharedInstrumentation ++ mailboxTimeSendMessageIncInstrumentation ++ initField( "sent-messages", _.initSentMessages() ) ) - lazy val droppedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => ifSupported(versions)(sharedInstrumentation ++ boundedQueueAgent ++ initDroppedMessages) + lazy val droppedMessages: AkkaActorModule.AkkaJar[Version] => Option[Agent] = versions => + ifSupported(versions)(sharedInstrumentation ++ boundedQueueAgent ++ initDroppedMessages) /** * Instrumentation for classic stash @@ -240,7 +268,8 @@ object AkkaActorAgent SuperMethodCall.INSTANCE.andThen(MethodCall.invoke(named("setupMetrics").method)) ) ) - .visit(ActorCellReceiveMessageInstrumentation, "receiveMessage").deferred + .visit(ActorCellReceiveMessageInstrumentation, "receiveMessage") + .deferred private def initField(name: String, init: ActorCellMetrics => Unit): AgentInstrumentation = instrument("akka.actor.ActorCell".fqcnWithTags(name)) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala index ff184aca3..c12682fa9 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/AkkaMailboxInstrumentations.scala @@ -1,21 +1,30 @@ package io.scalac.mesmer.agent.akka.actor -import akka.MesmerMirrorTypes.{ ActorRefWithCell, Cell } +import java.util.concurrent.BlockingQueue +import java.util.concurrent.Callable +import java.util.concurrent.LinkedBlockingQueue + +import akka.MesmerMirrorTypes.ActorRefWithCell +import akka.MesmerMirrorTypes.Cell import akka.dispatch._ import akka.util.BoundedBlockingQueue import akka.{ actor => classic } -import io.scalac.mesmer.agent.util.i13n._ -import io.scalac.mesmer.agent.{ Agent, AgentInstrumentation } -import io.scalac.mesmer.core.actor.ActorCellDecorator -import io.scalac.mesmer.core.util.ReflectionFieldUtils import net.bytebuddy.asm.Advice import net.bytebuddy.description.`type`.TypeDescription -import net.bytebuddy.implementation.bind.annotation.{ SuperCall, This } -import net.bytebuddy.implementation.{ FieldAccessor, MethodDelegation } +import net.bytebuddy.implementation.FieldAccessor +import net.bytebuddy.implementation.MethodDelegation +import net.bytebuddy.implementation.bind.annotation.SuperCall +import net.bytebuddy.implementation.bind.annotation.This import net.bytebuddy.matcher.ElementMatchers -import java.util.concurrent.{ BlockingQueue, Callable, LinkedBlockingQueue } -import scala.reflect.{ classTag, ClassTag } +import scala.reflect.ClassTag +import scala.reflect.classTag + +import io.scalac.mesmer.agent.Agent +import io.scalac.mesmer.agent.AgentInstrumentation +import io.scalac.mesmer.agent.util.i13n._ +import io.scalac.mesmer.core.actor.ActorCellDecorator +import io.scalac.mesmer.core.util.ReflectionFieldUtils object BoundedNodeMessageQueueAdvice { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala index 4de9fee61..472d5c9d8 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellDroppedMessagesAdvice.scala @@ -1,8 +1,13 @@ package io.scalac.mesmer.agent.akka.actor.impl -import akka.dispatch.{ MailboxType, SingleConsumerOnlyUnboundedMailbox, UnboundedMailbox } +import akka.dispatch.MailboxType +import akka.dispatch.SingleConsumerOnlyUnboundedMailbox +import akka.dispatch.UnboundedMailbox +import net.bytebuddy.asm.Advice.Argument +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.This + import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit, This } object ActorCellDroppedMessagesAdvice { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitializer.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitializer.scala index ad49d3cb1..06e2d24df 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitializer.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellInitializer.scala @@ -1,8 +1,10 @@ package io.scalac.mesmer.agent.akka.actor.impl -import io.scalac.mesmer.core.actor.{ ActorCellDecorator, ActorCellMetrics } import net.bytebuddy.implementation.bind.annotation.FieldValue +import io.scalac.mesmer.core.actor.ActorCellDecorator +import io.scalac.mesmer.core.actor.ActorCellMetrics + final class ActorCellInitializer(init: ActorCellMetrics => Unit) { def initField(@FieldValue(ActorCellDecorator.fieldName) metrics: ActorCellMetrics): Unit = diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala index d3e8fa9f4..bbe74c9d9 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellReceiveMessageInstrumentation.scala @@ -1,7 +1,11 @@ package io.scalac.mesmer.agent.akka.actor.impl +import net.bytebuddy.asm.Advice.OnMethodEnter +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.This +import net.bytebuddy.asm.Advice.Thrown + import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ OnMethodEnter, OnMethodExit, This, Thrown } object ActorCellReceiveMessageInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala index 08f47b703..e07565077 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorCellSendMessageMetricInstrumentation.scala @@ -1,9 +1,10 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.Actor +import net.bytebuddy.asm.Advice._ + import io.scalac.mesmer.core.actor.ActorCellDecorator import io.scalac.mesmer.core.util.ActorRefOps -import net.bytebuddy.asm.Advice._ object ActorCellSendMessageMetricInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala index f43ab5e7e..d86a2e67a 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ActorUnhandledInstrumentation.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.agent.akka.actor.impl +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.This + import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ OnMethodExit, This } object ActorUnhandledInstrumentation { @@ -10,7 +12,7 @@ object ActorUnhandledInstrumentation { ActorCellDecorator .get(ClassicActorOps.getContext(actor)) .foreach { metrics => - if(metrics.unhandledMessages.isDefined) { + if (metrics.unhandledMessages.isDefined) { metrics.unhandledMessages.get.inc() } } diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala index a83a5c4ab..28d4a2cc3 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/ClassicStashInstrumentationStash.scala @@ -1,12 +1,16 @@ package io.scalac.mesmer.agent.akka.actor.impl -import akka.actor.{ Actor, ActorContext } -import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit, This } - import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType.methodType +import akka.actor.Actor +import akka.actor.ActorContext +import net.bytebuddy.asm.Advice.Argument +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.This + +import io.scalac.mesmer.core.actor.ActorCellDecorator + object StashConstructorAdvice { @OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala index 1b9cf5b02..b0d14f1ab 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/MailboxDequeueInstrumentation.scala @@ -1,8 +1,12 @@ package io.scalac.mesmer.agent.akka.actor.impl -import io.scalac.mesmer.core.actor.{ ActorCellDecorator, ActorCellMetrics } +import net.bytebuddy.asm.Advice.OnMethodExit +import net.bytebuddy.asm.Advice.Return +import net.bytebuddy.asm.Advice.This + +import io.scalac.mesmer.core.actor.ActorCellDecorator +import io.scalac.mesmer.core.actor.ActorCellMetrics import io.scalac.mesmer.core.util.Interval -import net.bytebuddy.asm.Advice.{ OnMethodExit, Return, This } object MailboxDequeueInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala index 77eb3c415..4292e7683 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/StashBufferAdvice.scala @@ -2,9 +2,10 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.adapter._ -import io.scalac.mesmer.core.actor.ActorCellDecorator import net.bytebuddy.asm.Advice +import io.scalac.mesmer.core.actor.ActorCellDecorator + object StashBufferAdvice { @Advice.OnMethodExit diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala index a73c7b205..22f5fc356 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/actor/impl/SupervisorHandleReceiveExceptionInstrumentation.scala @@ -1,8 +1,10 @@ package io.scalac.mesmer.agent.akka.actor.impl import akka.actor.typed.TypedActorContext +import net.bytebuddy.asm.Advice.Argument +import net.bytebuddy.asm.Advice.OnMethodExit + import io.scalac.mesmer.core.actor.ActorCellDecorator -import net.bytebuddy.asm.Advice.{ Argument, OnMethodExit } object SupervisorHandleReceiveExceptionInstrumentation { diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala index 65fe38bfe..10cbf4700 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/http/AkkaHttpAgent.scala @@ -12,14 +12,19 @@ object AkkaHttpAgent with AkkaHttpModule.AkkaHttpConnectionsMetricsDef[AkkaHttpModule.AkkaJar[Version] => Option[Agent]] with AkkaHttpModule.AkkaHttpRequestMetricsDef[AkkaHttpModule.AkkaJar[Version] => Option[Agent]] { - private val supportedVersions = version101x.or(version102x) + private val supportedHttpVersions = version101x.or(version102x) - private def ifSupported(versions: AkkaHttpModule.AkkaJar[Version])(agent: => Agent): Option[Agent] = - if (supportedVersions.supports(versions.akkaHttp)) + private def ifSupported(versions: AkkaHttpModule.AkkaJar[Version])(agent: => Agent): Option[Agent] = { + import versions._ + if ( + version26x.supports(akkaActor) && version26x.supports(akkaActorTyped) && supportedHttpVersions.supports(akkaHttp) + ) Some(agent) else None + } - val requestTime: AkkaHttpModule.Jars[Version] => Option[Agent] = versions => ifSupported(versions)(requestEvents) // Version => Option[Agent] + val requestTime: AkkaHttpModule.Jars[Version] => Option[Agent] = + versions => ifSupported(versions)(requestEvents) // Version => Option[Agent] val requestCounter: AkkaHttpModule.Jars[Version] => Option[Agent] = versions => ifSupported(versions)(requestEvents) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala index f19eb0765..27a5dfd41 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/persistence/AkkaPersistenceAgent.scala @@ -1,12 +1,13 @@ package io.scalac.mesmer.agent.akka.persistence +import org.slf4j.LoggerFactory + import io.scalac.mesmer.agent.Agent import io.scalac.mesmer.agent.akka.persistence.impl._ import io.scalac.mesmer.agent.util.i13n._ import io.scalac.mesmer.core.akka.version26x import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.AkkaPersistenceModule -import org.slf4j.LoggerFactory object AkkaPersistenceAgent extends InstrumentModuleFactory(AkkaPersistenceModule) @@ -46,10 +47,15 @@ object AkkaPersistenceAgent (resultantAgent, enabled) } - private def ifSupported(agent: => Agent)(versions: AkkaPersistenceModule.AkkaJar[Version]): Option[Agent] = - if (version26x.supports(versions.akkaPersistence) && version26x.supports(versions.akkaPersistenceTyped)) + private def ifSupported(agent: => Agent)(versions: AkkaPersistenceModule.AkkaJar[Version]): Option[Agent] = { + import versions._ + if ( + version26x.supports(akkaPersistence) && version26x.supports(akkaPersistenceTyped) && version26x + .supports(akkaActor) && version26x.supports(akkaActorTyped) + ) Some(agent) else None + } lazy val recoveryTime: AkkaPersistenceModule.AkkaJar[Version] => Option[Agent] = ifSupported(recoveryAgent) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala index d0b0a8e24..59b35b035 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/akka/stream/AkkaStreamAgent.scala @@ -2,14 +2,14 @@ package io.scalac.mesmer.agent.akka.stream import akka.ActorGraphInterpreterAdvice import akka.stream.GraphStageIslandAdvice -import akka.stream.impl.fusing.{ ActorGraphInterpreterProcessEventAdvice, ActorGraphInterpreterTryInitAdvice } +import akka.stream.impl.fusing.ActorGraphInterpreterProcessEventAdvice +import akka.stream.impl.fusing.ActorGraphInterpreterTryInitAdvice + import io.scalac.mesmer.agent.Agent -import io.scalac.mesmer.agent.akka.stream.impl.{ - ConnectionOps, - GraphInterpreterPullAdvice, - GraphInterpreterPushAdvice, - PhasedFusingActorMaterializerAdvice -} +import io.scalac.mesmer.agent.akka.stream.impl.ConnectionOps +import io.scalac.mesmer.agent.akka.stream.impl.GraphInterpreterPullAdvice +import io.scalac.mesmer.agent.akka.stream.impl.GraphInterpreterPushAdvice +import io.scalac.mesmer.agent.akka.stream.impl.PhasedFusingActorMaterializerAdvice import io.scalac.mesmer.agent.util.i13n._ import io.scalac.mesmer.core.akka.version26x import io.scalac.mesmer.core.model.Version diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index 76c486194..bcc3f7c2e 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -1,16 +1,21 @@ package io.scalac.mesmer.agent.util -import io.scalac.mesmer.agent.AgentInstrumentation -import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails._ import net.bytebuddy.asm.Advice -import net.bytebuddy.description.`type`.{ TypeDefinition, TypeDescription } +import net.bytebuddy.description.`type`.TypeDefinition +import net.bytebuddy.description.`type`.TypeDescription import net.bytebuddy.description.method.MethodDescription import net.bytebuddy.dynamic.DynamicType -import net.bytebuddy.implementation.{ Implementation, MethodDelegation } -import net.bytebuddy.matcher.{ ElementMatcher, ElementMatchers => EM } +import net.bytebuddy.implementation.Implementation +import net.bytebuddy.implementation.MethodDelegation +import net.bytebuddy.matcher.ElementMatcher +import net.bytebuddy.matcher.{ElementMatchers => EM} import scala.language.implicitConversions -import scala.reflect.{ classTag, ClassTag } +import scala.reflect.ClassTag +import scala.reflect.classTag + +import io.scalac.mesmer.agent.AgentInstrumentation +import io.scalac.mesmer.agent.util.i13n.InstrumentationDetails._ package object i13n { diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala index 29d2b4bd8..1f75629a1 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala @@ -1,16 +1,16 @@ package io.scalac.mesmer.agent.akka +import akka.actor.PoisonPill +import akka.actor.Props import akka.actor.testkit.typed.scaladsl.TestProbe +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.SupervisorStrategy +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.scaladsl.StashBuffer import akka.actor.typed.scaladsl.adapter._ -import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer} -import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy} -import akka.actor.{PoisonPill, Props} -import akka.{actor => classic} -import io.scalac.mesmer.agent.utils.{InstallAgent, SafeLoadSystem} -import io.scalac.mesmer.core.actor.{ActorCellDecorator, ActorCellMetrics} -import io.scalac.mesmer.core.event.ActorEvent -import io.scalac.mesmer.core.util.MetricsToolKit.Counter -import io.scalac.mesmer.core.util.ReceptionistOps +import akka.{ actor => classic } import org.scalatest.OptionValues import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike @@ -19,6 +19,14 @@ import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ import scala.util.control.NoStackTrace +import io.scalac.mesmer.agent.utils.InstallAgent +import io.scalac.mesmer.agent.utils.SafeLoadSystem +import io.scalac.mesmer.core.actor.ActorCellDecorator +import io.scalac.mesmer.core.actor.ActorCellMetrics +import io.scalac.mesmer.core.event.ActorEvent +import io.scalac.mesmer.core.util.MetricsToolKit.Counter +import io.scalac.mesmer.core.util.ReceptionistOps + class AkkaActorAgentTest extends InstallAgent // extends InstallModule(AkkaActorAgent) @@ -137,10 +145,10 @@ class AkkaActorAgentTest val check: classic.ActorContext => Any = ctx => { // val metrics = ActorCellDecorator.get(ctx).flatMap(_.processingTimeAgg.metrics).value -val metrics = (for { - cellMetrics <- ActorCellDecorator.get(ctx) if cellMetrics.processingTimeAgg.isDefined - agg <- cellMetrics.processingTimeAgg.get.metrics -} yield agg).value + val metrics = (for { + cellMetrics <- ActorCellDecorator.get(ctx) if cellMetrics.processingTimeAgg.isDefined + agg <- cellMetrics.processingTimeAgg.get.metrics + } yield agg).value metrics.count should be(messages) metrics.sum should be((workingMessages * processing.toNanos) +- ToleranceNanos) metrics.min should be(0L +- ToleranceNanos) diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala index a65b0cf22..371dc10e2 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/actor/ActorMailboxTest.scala @@ -1,26 +1,37 @@ package io.scalac.mesmer.agent.akka.actor +import java.util.Comparator + +import akka.actor.ActorSystem +import akka.actor.PoisonPill +import akka.actor.typed.ActorRef +import akka.actor.typed.Behavior +import akka.actor.typed.MailboxSelector +import akka.actor.typed.Props +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.adapter._ -import akka.actor.typed.scaladsl.{ ActorContext, Behaviors } -import akka.actor.typed.{ ActorRef, Behavior, MailboxSelector, Props } -import akka.actor.{ ActorSystem, PoisonPill } -import akka.dispatch.{ BoundedPriorityMailbox, BoundedStablePriorityMailbox, Envelope } +import akka.dispatch.BoundedPriorityMailbox +import akka.dispatch.BoundedStablePriorityMailbox +import akka.dispatch.Envelope import akka.{ actor => classic } -import com.typesafe.config.{ Config, ConfigFactory } -import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish -import io.scalac.mesmer.agent.utils.{ InstallModule, SafeLoadSystem } -import io.scalac.mesmer.core.actor.ActorCellDecorator -import io.scalac.mesmer.core.config.AkkaPatienceConfig -import io.scalac.mesmer.core.util.TestOps +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory import org.scalatest.concurrent.Eventually import org.scalatest.flatspec.AnyFlatSpecLike import org.scalatest.matchers.should.Matchers -import java.util.Comparator import scala.annotation.unused import scala.concurrent.duration.Duration import scala.jdk.DurationConverters._ +import io.scalac.mesmer.agent.akka.actor.ActorMailboxTest.ClassicContextPublish +import io.scalac.mesmer.agent.utils.InstallModule +import io.scalac.mesmer.agent.utils.SafeLoadSystem +import io.scalac.mesmer.core.actor.ActorCellDecorator +import io.scalac.mesmer.core.config.AkkaPatienceConfig +import io.scalac.mesmer.core.util.TestOps + final class HashCodePriorityMailbox( capacity: Int, pushTimeOut: Duration diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala index adb693608..8cae3ce0e 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala @@ -1,9 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } - import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.Combine -import io.scalac.mesmer.core.module.Module.Traverse +import io.scalac.mesmer.core.module.Module.{ Combine, JarsNames, Traverse } import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaActorMetrics extends MetricsModule { @@ -146,16 +144,14 @@ object AkkaActorModule extends MesmerModule with AkkaActorMetrics with RegisterG } - final case class Jars[T](akkaActor: T, akkaActorTyped: T) + final case class Jars[T](akkaActor: T, akkaActorTyped: T) extends Module.CommonJars[T] def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = for { - actor <- info.get(requiredAkkaJars.akkaActor) - actorTyped <- info.get(requiredAkkaJars.akkaActorTyped) + actor <- info.get(JarsNames.akkaActor) + actorTyped <- info.get(JarsNames.akkaActorTyped) } yield Jars(actor, actorTyped) - val requiredAkkaJars: Jars[String] = Jars("akka-actor", "akka-actor-typed") - /** * Combines config that with AND operator */ diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala index 82bc2bf4a..d9e5695df 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala @@ -1,7 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } - import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.module.Module.{ CommonJars, JarsNames } import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaActorSystemMetricsModule extends MetricsModule { @@ -39,10 +39,12 @@ object AkkaActorSystemModule extends MesmerModule with AkkaActorSystemMetricsMod override type AkkaJar[T] = Jars[T] - final case class Jars[T](akkaActor: T) + final case class Jars[T](akkaActor: T, akkaActorTyped: T) extends CommonJars[T] def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = - info.get(requiredAkkaJars.akkaActor).map(Jars.apply[Version]) + for { + actor <- info.get(JarsNames.akkaActor) + actorTyped <- info.get(JarsNames.akkaActorTyped) + } yield Jars(actor, actorTyped) - val requiredAkkaJars: AkkaJar[String] = Jars("akka-actor") } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala index dda9275df..329f4b19a 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala @@ -1,7 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } - import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.module.Module.{ CommonJars, JarsNames } import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaClusterMetricsModule extends MetricsModule { @@ -88,13 +88,13 @@ object AkkaClusterModule extends MesmerModule with AkkaClusterMetricsModule { override type All[T] = Metrics[T] override type AkkaJar[T] = Jars[T] - final case class Jars[T](akkaCluster: T, akkaClusterTyped: T) + final case class Jars[T](akkaActor: T, akkaActorTyped: T, akkaCluster: T, akkaClusterTyped: T) extends CommonJars[T] override def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = for { - cluster <- info.get(requiredAkkaJars.akkaCluster) - clusterTyped <- info.get(requiredAkkaJars.akkaClusterTyped) - } yield Jars(cluster, clusterTyped) - - val requiredAkkaJars: AkkaJar[String] = Jars("akka-cluster", "akka-cluster-typed") + actor <- info.get(JarsNames.akkaActor) + actorTyped <- info.get(JarsNames.akkaActorTyped) + cluster <- info.get(JarsNames.akkaCluster) + clusterTyped <- info.get(JarsNames.akkaClusterTyped) + } yield Jars(actor, actorTyped, cluster, clusterTyped) } diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala index 7d858492c..8cf631620 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -1,10 +1,8 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } - import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.Combine -import io.scalac.mesmer.core.module.Module.Traverse +import io.scalac.mesmer.core.module.Module.{ Combine, CommonJars, JarsNames, Traverse } import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo /** @@ -74,12 +72,14 @@ object AkkaHttpModule override type AkkaJar[T] = Jars[T] - final case class Jars[T](akkaHttp: T) + final case class Jars[T](akkaActor: T, akkaActorTyped: T, akkaHttp: T) extends CommonJars[T] def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = - info.get(requiredAkkaJars.akkaHttp).map(Jars.apply[Version]) - - val requiredAkkaJars: Jars[String] = Jars("akka-http") + for { + actor <- info.get(JarsNames.akkaActor) + actorTyped <- info.get(JarsNames.akkaActorTyped) + http <- info.get(JarsNames.akkaHttp) + } yield Jars(actor, actorTyped, http) implicit val combineConfig: Combine[All[Boolean]] = (first, second) => { Impl( diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala index 2a196cc8e..392f2bfce 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala @@ -1,9 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } - import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.Combine -import io.scalac.mesmer.core.module.Module.Traverse +import io.scalac.mesmer.core.module.Module.{ Combine, CommonJars, JarsNames, Traverse } import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaPersistenceMetricsModule extends MetricsModule { @@ -65,15 +63,16 @@ object AkkaPersistenceModule extends MesmerModule with AkkaPersistenceMetricsMod override type All[T] = Metrics[T] override type AkkaJar[T] = Jars[T] - final case class Jars[T](akkaPersistence: T, akkaPersistenceTyped: T) + final case class Jars[T](akkaActor: T, akkaActorTyped: T, akkaPersistence: T, akkaPersistenceTyped: T) + extends CommonJars[T] def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = for { - persistence <- info.get(requiredAkkaJars.akkaPersistence) - persistenceTyped <- info.get(requiredAkkaJars.akkaPersistenceTyped) - } yield Jars(persistence, persistenceTyped) - - val requiredAkkaJars: AkkaJar[String] = Jars("akka-persistence", "akka-persistence-typed") + actor <- info.get(JarsNames.akkaActor) + actorTyped <- info.get(JarsNames.akkaActorTyped) + persistence <- info.get(JarsNames.akkaPersistence) + persistenceTyped <- info.get(JarsNames.akkaPersistenceTyped) + } yield Jars(actor, actorTyped, persistence, persistenceTyped) implicit val combineConfig: Combine[All[Boolean]] = (first, second) => { Impl( diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala index 5fe4ef5d4..673cd11a2 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala @@ -1,7 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, Traverse } +import io.scalac.mesmer.core.module.Module.{ Combine, CommonJars, JarsNames, Traverse } import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaStreamMetrics extends MetricsModule { @@ -98,16 +98,14 @@ object AkkaStreamModule override type AkkaJar[T] = Jars[T] - final case class Jars[T](akkaStream: T, akkaActor: T, akkaActorTyped: T) + final case class Jars[T](akkaActor: T, akkaActorTyped: T, akkaStream: T) extends CommonJars[T] def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = for { - stream <- info.get(requiredAkkaJars.akkaStream) - actor <- info.get(requiredAkkaJars.akkaActor) - actorTyped <- info.get(requiredAkkaJars.akkaActorTyped) - } yield Jars(stream, actor, actorTyped) - - val requiredAkkaJars: AkkaJar[String] = Jars("akka-stream", "akka-actor", "akka-actor-typed") + actor <- info.get(JarsNames.akkaActor) + actorTyped <- info.get(JarsNames.akkaActorTyped) + stream <- info.get(JarsNames.akkaStream) + } yield Jars(actor, actorTyped, stream) implicit val combine: Combine[All[Boolean]] = (first, second) => { Impl( diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala index 486e2106b..e9cc7060d 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -1,9 +1,9 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } - import io.scalac.mesmer.core.config.MesmerConfigurationBase import io.scalac.mesmer.core.model.Version +import io.scalac.mesmer.core.module.Module.CommonJars import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo trait Module { @@ -13,11 +13,9 @@ trait Module { def enabled(config: TypesafeConfig): Config - type AkkaJar[T] + type AkkaJar[T] <: CommonJars[T] def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] - - def requiredAkkaJars: AkkaJar[String] } object Module { @@ -36,6 +34,22 @@ object Module { def sequence[T](obj: F[T]): Seq[T] } + trait CommonJars[T] { + def akkaActor: T + def akkaActorTyped: T + } + + object JarsNames { + final val akkaActor = "akka-actor" + final val akkaActorTyped = "akka-actor-typed" + final val akkaPersistence = "akka-persistence" + final val akkaPersistenceTyped = "akka-persistence-typed" + final val akkaStream = "akka-stream" + final val akkaHttp = "akka-http" + final val akkaCluster = "akka-cluster" + final val akkaClusterTyped = "akka-cluster-typed" + } + } trait MesmerModule extends Module with MesmerConfigurationBase { diff --git a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala index ec52ffc67..a5b577ad9 100644 --- a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala +++ b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala @@ -1,15 +1,15 @@ package io.scalac.mesmer.core.model import com.typesafe.config.{ Config => TypesafeConfig } +import io.scalac.mesmer.core.module.Module +import io.scalac.mesmer.core.module.Module.CommonJars +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo import org.scalatest.Inspectors import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import scala.runtime.BoxedUnit -import io.scalac.mesmer.core.module.Module -import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo - class SupportedModulesTest extends AnyFlatSpec with Matchers with Inspectors { type Id[T] = T @@ -20,11 +20,10 @@ class SupportedModulesTest extends AnyFlatSpec with Matchers with Inspectors { def enabled(config: TypesafeConfig) = BoxedUnit.UNIT - override type AkkaJar[T] = Any + override type AkkaJar[T] = CommonJars[T] def jarsFromLibraryInfo(info: LibraryInfo): Option[AkkaJar[Version]] = None - val requiredAkkaJars: Any = () } "SupportedModules" should "combine required versions" in { From dee95863bd1d21a30120923da42a724272b6d426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Wed, 30 Jun 2021 11:46:02 +0200 Subject: [PATCH 20/31] Add fix test setup --- .../scala/io/scalac/mesmer/agent/util/i13n/package.scala | 2 +- .../io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala index bcc3f7c2e..e4bcca8f7 100644 --- a/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala +++ b/agent/src/main/scala/io/scalac/mesmer/agent/util/i13n/package.scala @@ -8,7 +8,7 @@ import net.bytebuddy.dynamic.DynamicType import net.bytebuddy.implementation.Implementation import net.bytebuddy.implementation.MethodDelegation import net.bytebuddy.matcher.ElementMatcher -import net.bytebuddy.matcher.{ElementMatchers => EM} +import net.bytebuddy.matcher.{ ElementMatchers => EM } import scala.language.implicitConversions import scala.reflect.ClassTag diff --git a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala index 1f75629a1..76100a1b6 100644 --- a/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala +++ b/agent/src/test/scala/io/scalac/mesmer/agent/akka/AkkaActorAgentTest.scala @@ -19,7 +19,8 @@ import org.scalatest.matchers.should.Matchers import scala.concurrent.duration._ import scala.util.control.NoStackTrace -import io.scalac.mesmer.agent.utils.InstallAgent +import io.scalac.mesmer.agent.akka.actor.AkkaActorAgent +import io.scalac.mesmer.agent.utils.InstallModule import io.scalac.mesmer.agent.utils.SafeLoadSystem import io.scalac.mesmer.core.actor.ActorCellDecorator import io.scalac.mesmer.core.actor.ActorCellMetrics @@ -28,8 +29,7 @@ import io.scalac.mesmer.core.util.MetricsToolKit.Counter import io.scalac.mesmer.core.util.ReceptionistOps class AkkaActorAgentTest - extends InstallAgent -// extends InstallModule(AkkaActorAgent) + extends InstallModule(AkkaActorAgent) with AnyFlatSpecLike with ReceptionistOps with OptionValues From 8685167daaa10e58cfc19b71abe2740c8b5a83d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Wed, 30 Jun 2021 12:04:38 +0200 Subject: [PATCH 21/31] Fix formating --- .../main/scala/akka/MesmerMirrorTypes.scala | 4 +- .../mesmer/core/actor/ActorCellMetrics.scala | 5 ++- .../io/scalac/mesmer/core/akka/package.scala | 11 ++--- .../io/scalac/mesmer/core/model/Version.scala | 1 - .../mesmer/core/module/AkkaActorModule.scala | 5 ++- .../core/module/AkkaActorSystemModule.scala | 4 +- .../core/module/AkkaClusterModule.scala | 4 +- .../mesmer/core/module/AkkaHttpModule.scala | 6 ++- .../core/module/AkkaPersistenceModule.scala | 6 ++- .../mesmer/core/module/AkkaStreamModule.scala | 6 ++- .../io/scalac/mesmer/core/module/Module.scala | 1 + .../mesmer/core/util/MetricsToolKit.scala | 6 ++- .../core/model/SupportedModulesTest.scala | 7 +-- .../extension/ActorEventsMonitorActor.scala | 45 +++++++++++++------ .../actor/MutableActorMetricsStorage.scala | 2 +- 15 files changed, 78 insertions(+), 35 deletions(-) diff --git a/core/src/main/scala/akka/MesmerMirrorTypes.scala b/core/src/main/scala/akka/MesmerMirrorTypes.scala index 0672426cd..9aab5ecf3 100644 --- a/core/src/main/scala/akka/MesmerMirrorTypes.scala +++ b/core/src/main/scala/akka/MesmerMirrorTypes.scala @@ -1,9 +1,9 @@ package akka import akka.stream.impl.ExtendedActorMaterializer -import akka.stream.impl.fusing.{ GraphInterpreter, GraphInterpreterShell } +import akka.stream.impl.fusing.GraphInterpreter +import akka.stream.impl.fusing.GraphInterpreterShell import akka.stream.stage.GraphStageLogic -import akka.util.{ OptionVal => AkkaOptionVal } object MesmerMirrorTypes { type ActorRefWithCell = akka.actor.ActorRefWithCell diff --git a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala index 9462bcf4c..8d18804f7 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/actor/ActorCellMetrics.scala @@ -1,6 +1,9 @@ package io.scalac.mesmer.core.actor -import akka.OptionVal.{ apply, none, _ } +import akka.OptionVal._ +import akka.OptionVal.apply +import akka.OptionVal.none + import io.scalac.mesmer.core.util.MetricsToolKit._ final class ActorCellMetrics { diff --git a/core/src/main/scala/io/scalac/mesmer/core/akka/package.scala b/core/src/main/scala/io/scalac/mesmer/core/akka/package.scala index 960056645..2c5853884 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/akka/package.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/akka/package.scala @@ -1,9 +1,10 @@ package io.scalac.mesmer.core -import io.scalac.mesmer.core.model.{ ActorPath, SupportedVersion } - import scala.math.PartialOrdering +import io.scalac.mesmer.core.model.ActorPath +import io.scalac.mesmer.core.model.SupportedVersion + package object akka { implicit val actorPathPartialOrdering: PartialOrdering[ActorPath] = new PartialOrdering[ActorPath] { @@ -20,10 +21,10 @@ package object akka { private def actorLevel(path: ActorPath): Int = path.count(_ == '/') } - val version26x = SupportedVersion.majors("2").and(SupportedVersion.minors("6")) + val version26x: SupportedVersion = SupportedVersion.majors("2").and(SupportedVersion.minors("6")) - val version101x = SupportedVersion.majors("10").and(SupportedVersion.minors("1")) + val version101x: SupportedVersion = SupportedVersion.majors("10").and(SupportedVersion.minors("1")) - val version102x = SupportedVersion.majors("10").and(SupportedVersion.minors("2")) + val version102x: SupportedVersion = SupportedVersion.majors("10").and(SupportedVersion.minors("2")) } diff --git a/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala b/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala index 60de369b9..3d8d8e3a0 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/model/Version.scala @@ -10,4 +10,3 @@ object Version { def apply(major: Int, minor: Int, patch: Int): Version = Version(major.toString, minor.toString, patch.toString) } - diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala index 8cae3ce0e..b5c80b3a8 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorModule.scala @@ -1,7 +1,10 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, JarsNames, Traverse } +import io.scalac.mesmer.core.module.Module.Combine +import io.scalac.mesmer.core.module.Module.JarsNames +import io.scalac.mesmer.core.module.Module.Traverse import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaActorMetrics extends MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala index d9e5695df..250d19174 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaActorSystemModule.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ CommonJars, JarsNames } +import io.scalac.mesmer.core.module.Module.CommonJars +import io.scalac.mesmer.core.module.Module.JarsNames import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaActorSystemMetricsModule extends MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala index 329f4b19a..442d9441b 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaClusterModule.scala @@ -1,7 +1,9 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ CommonJars, JarsNames } +import io.scalac.mesmer.core.module.Module.CommonJars +import io.scalac.mesmer.core.module.Module.JarsNames import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaClusterMetricsModule extends MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala index 8cf631620..0ea2143a9 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaHttpModule.scala @@ -1,8 +1,12 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, CommonJars, JarsNames, Traverse } +import io.scalac.mesmer.core.module.Module.Combine +import io.scalac.mesmer.core.module.Module.CommonJars +import io.scalac.mesmer.core.module.Module.JarsNames +import io.scalac.mesmer.core.module.Module.Traverse import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo /** diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala index 392f2bfce..e7c03d444 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaPersistenceModule.scala @@ -1,7 +1,11 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, CommonJars, JarsNames, Traverse } +import io.scalac.mesmer.core.module.Module.Combine +import io.scalac.mesmer.core.module.Module.CommonJars +import io.scalac.mesmer.core.module.Module.JarsNames +import io.scalac.mesmer.core.module.Module.Traverse import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaPersistenceMetricsModule extends MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala index 673cd11a2..fe029b63d 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/AkkaStreamModule.scala @@ -1,7 +1,11 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.model.Version -import io.scalac.mesmer.core.module.Module.{ Combine, CommonJars, JarsNames, Traverse } +import io.scalac.mesmer.core.module.Module.Combine +import io.scalac.mesmer.core.module.Module.CommonJars +import io.scalac.mesmer.core.module.Module.JarsNames +import io.scalac.mesmer.core.module.Module.Traverse import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo sealed trait AkkaStreamMetrics extends MetricsModule { diff --git a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala index e9cc7060d..8c5ccae32 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/module/Module.scala @@ -1,6 +1,7 @@ package io.scalac.mesmer.core.module import com.typesafe.config.{ Config => TypesafeConfig } + import io.scalac.mesmer.core.config.MesmerConfigurationBase import io.scalac.mesmer.core.model.Version import io.scalac.mesmer.core.module.Module.CommonJars diff --git a/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala b/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala index 22413f590..ebd09ebd5 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/util/MetricsToolKit.scala @@ -1,8 +1,10 @@ package io.scalac.mesmer.core.util -import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicLong +import java.util.concurrent.atomic.AtomicReference -import java.util.concurrent.atomic.{ AtomicBoolean, AtomicLong, AtomicReference } +import io.scalac.mesmer.core.util.MinMaxSumCountAggregation.LongMinMaxSumCountAggregationImpl object MetricsToolKit { diff --git a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala index a5b577ad9..b7fb5da29 100644 --- a/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala +++ b/core/src/test/scala/io/scalac/mesmer/core/model/SupportedModulesTest.scala @@ -1,15 +1,16 @@ package io.scalac.mesmer.core.model import com.typesafe.config.{ Config => TypesafeConfig } -import io.scalac.mesmer.core.module.Module -import io.scalac.mesmer.core.module.Module.CommonJars -import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo import org.scalatest.Inspectors import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import scala.runtime.BoxedUnit +import io.scalac.mesmer.core.module.Module +import io.scalac.mesmer.core.module.Module.CommonJars +import io.scalac.mesmer.core.util.LibraryInfo.LibraryInfo + class SupportedModulesTest extends AnyFlatSpec with Matchers with Inspectors { type Id[T] = T diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala b/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala index ecf7b3ebc..c1067f1c2 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/ActorEventsMonitorActor.scala @@ -1,29 +1,46 @@ package io.scalac.mesmer.extension +import java.util.concurrent.atomic.AtomicReference + +import akka.Done import akka.actor.typed._ import akka.actor.typed.receptionist.Receptionist.Listing -import akka.actor.typed.scaladsl.{ ActorContext, Behaviors, TimerScheduler } +import akka.actor.typed.scaladsl.ActorContext +import akka.actor.typed.scaladsl.Behaviors +import akka.actor.typed.scaladsl.TimerScheduler import akka.util.Timeout -import akka.{ Done, actor => classic } +import akka.{ actor => classic } +import org.slf4j.LoggerFactory + +import scala.concurrent.duration._ +import scala.util.Failure +import scala.util.Success + import io.scalac.mesmer.core.actor.ActorCellDecorator import io.scalac.mesmer.core.akka.actorPathPartialOrdering -import io.scalac.mesmer.core.model.{ ActorKey, ActorRefDetails, Node, Tag } -import io.scalac.mesmer.core.util.{ ActorCellOps, ActorPathOps, ActorRefOps } +import io.scalac.mesmer.core.model.ActorKey +import io.scalac.mesmer.core.model.ActorRefDetails +import io.scalac.mesmer.core.model.Node +import io.scalac.mesmer.core.model.Tag +import io.scalac.mesmer.core.util.ActorCellOps +import io.scalac.mesmer.core.util.ActorPathOps +import io.scalac.mesmer.core.util.ActorRefOps import io.scalac.mesmer.extension.ActorEventsMonitorActor._ -import io.scalac.mesmer.extension.actor.{ ActorMetrics, MetricStorageFactory } +import io.scalac.mesmer.extension.actor.ActorMetrics +import io.scalac.mesmer.extension.actor.MetricStorageFactory import io.scalac.mesmer.extension.metric.ActorMetricsMonitor import io.scalac.mesmer.extension.metric.ActorMetricsMonitor.Labels import io.scalac.mesmer.extension.metric.MetricObserver.Result -import io.scalac.mesmer.extension.service.ActorTreeService.Command.{ GetActorTree, TagSubscribe } -import io.scalac.mesmer.extension.service.{ actorTreeServiceKey, ActorTreeService } +import io.scalac.mesmer.extension.service.ActorTreeService +import io.scalac.mesmer.extension.service.ActorTreeService.Command.GetActorTree +import io.scalac.mesmer.extension.service.ActorTreeService.Command.TagSubscribe +import io.scalac.mesmer.extension.service.actorTreeServiceKey +import io.scalac.mesmer.extension.util.GenericBehaviors +import io.scalac.mesmer.extension.util.Tree +import io.scalac.mesmer.extension.util.Tree.Tree import io.scalac.mesmer.extension.util.Tree.TreeOrdering._ -import io.scalac.mesmer.extension.util.Tree.{ Tree, _ } -import io.scalac.mesmer.extension.util.{ GenericBehaviors, Tree, TreeF } -import org.slf4j.LoggerFactory - -import java.util.concurrent.atomic.AtomicReference -import scala.concurrent.duration._ -import scala.util.{ Failure, Success } +import io.scalac.mesmer.extension.util.Tree._ +import io.scalac.mesmer.extension.util.TreeF object ActorEventsMonitorActor { diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/actor/MutableActorMetricsStorage.scala b/extension/src/main/scala/io/scalac/mesmer/extension/actor/MutableActorMetricsStorage.scala index 7bd5603ba..31ef9b2b4 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/actor/MutableActorMetricsStorage.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/actor/MutableActorMetricsStorage.scala @@ -7,7 +7,7 @@ import io.scalac.mesmer.extension.resource.MutableStorage final class MutableActorMetricStorageFactory[K] extends MetricStorageFactory[K] { type Storage = MutableActorMetricsStorage - final class MutableActorMetricsStorage private[actor]( + final class MutableActorMetricsStorage private[actor] ( protected val buffer: mutable.Map[K, ActorMetrics], protected val persistentBuffer: mutable.Map[K, ActorMetrics] ) extends MutableStorage[K, ActorMetrics] From 2e75ca85949065df4164b3c00f39cd6c7df5ef50 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Fri, 2 Jul 2021 12:44:19 +0200 Subject: [PATCH 22/31] Update akka-discovery-kubernetes-api to 1.1.1 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6b194cbc8..740c9ff4e 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -3,7 +3,7 @@ import sbt._ object Dependencies { val AkkaHttpVersion = "10.2.4" - val AkkaManagementVersion = "1.1.0" + val AkkaManagementVersion = "1.1.1" val AkkaVersion = "2.6.14" val CirceVersion = "0.14.1" val LogbackVersion = "1.2.3" From a0c42539002c63ed087e7362864915fd6f6a1994 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Fri, 2 Jul 2021 12:44:23 +0200 Subject: [PATCH 23/31] Update akka-management, ... to 1.1.1 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6b194cbc8..740c9ff4e 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -3,7 +3,7 @@ import sbt._ object Dependencies { val AkkaHttpVersion = "10.2.4" - val AkkaManagementVersion = "1.1.0" + val AkkaManagementVersion = "1.1.1" val AkkaVersion = "2.6.14" val CirceVersion = "0.14.1" val LogbackVersion = "1.2.3" From 55ac9ef0fc684fe58561cba243cfd734788e6f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20J=C3=B3siak?= Date: Fri, 2 Jul 2021 13:16:22 +0200 Subject: [PATCH 24/31] Fix configuration --- .../core/config/ConfigurationUtils.scala | 7 +- .../mesmer/extension/AkkaMonitoring.scala | 14 ++- .../config/AkkaMonitoringConfig.scala | 112 ++++++++++++------ 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala b/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala index e80d8923d..6f2941094 100644 --- a/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala +++ b/core/src/main/scala/io/scalac/mesmer/core/config/ConfigurationUtils.scala @@ -33,12 +33,14 @@ trait Configuration { type Result protected def defaultConfig: Result + def fromConfig(config: Config): Result = config .tryValue(absoluteBase)(_.getConfig) .map(extractFromConfig) .getOrElse(defaultConfig) protected val absoluteBase: String + protected def extractFromConfig(config: Config): Result } @@ -49,7 +51,10 @@ trait MesmerConfigurationBase extends Configuration { */ private final val mesmerBase: String = "io.scalac.mesmer" - protected lazy val absoluteBase: String = s"$mesmerBase.$mesmerConfig" + protected lazy val absoluteBase: String = { + val branch = mesmerConfig + if (mesmerConfig.isEmpty) mesmerBase else s"$mesmerBase.$branch" + } /** * Name of configuration inside mesmer branch diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala index 77189772f..df768635c 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/AkkaMonitoring.scala @@ -1,4 +1,5 @@ package io.scalac.mesmer.extension + import akka.actor.ExtendedActorSystem import akka.actor.typed._ import akka.actor.typed.receptionist.Receptionist.Register @@ -36,12 +37,13 @@ object AkkaMonitoring extends ExtensionId[AkkaMonitoring] { private val ExportInterval = 5.seconds def createExtension(system: ActorSystem[_]): AkkaMonitoring = { - val config = AkkaMonitoringConfig(system.settings.config) + val config = AkkaMonitoringConfig.fromConfig(system.settings.config) new AkkaMonitoring(system, config) } } final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaMonitoringConfig) extends Extension { + import system.log private val meter = InstrumentationLibrary.mesmerMeter @@ -286,22 +288,30 @@ final class AkkaMonitoring(private val system: ActorSystem[_], val config: AkkaM import config.{ autoStart => autoStartConfig } if (autoStartConfig.akkaActor || autoStartConfig.akkaStream) { + log.debug("Start actor tree service") startActorTreeService() } if (autoStartConfig.akkaStream) { + log.debug("Start akka stream service") + startStreamMonitor() } if (autoStartConfig.akkaActor) { + log.debug("Start akka actor service") startActorMonitor() } if (autoStartConfig.akkaHttp) { + log.debug("Start akka persistence service") startHttpMonitor() } - if (autoStartConfig.akkaHttp) { + if (autoStartConfig.akkaPersistence) { + log.debug("Start akka http service") + startPersistenceMonitor() } if (autoStartConfig.akkaCluster) { + log.debug("Start akka cluster service") startClusterEventsMonitor() startClusterRegionsMonitor() startSelfMemberMonitor() diff --git a/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala b/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala index 3ae2caf00..597745dca 100644 --- a/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala +++ b/extension/src/main/scala/io/scalac/mesmer/extension/config/AkkaMonitoringConfig.scala @@ -5,14 +5,14 @@ import com.typesafe.config.Config import scala.concurrent.duration._ import scala.jdk.DurationConverters._ -import io.scalac.mesmer.core.config.ConfigurationUtils._ +import io.scalac.mesmer.core.config.MesmerConfiguration -case class AkkaMonitoringConfig( +final case class AkkaMonitoringConfig( autoStart: AutoStartSettings, cleaning: CleaningSettings ) -case class AutoStartSettings( +final case class AutoStartSettings( akkaActor: Boolean, akkaHttp: Boolean, akkaPersistence: Boolean, @@ -20,7 +20,7 @@ case class AutoStartSettings( akkaStream: Boolean ) -object AkkaMonitoringConfig { +object AkkaMonitoringConfig extends MesmerConfiguration[AkkaMonitoringConfig] { private val autoStartDefaults = AutoStartSettings( @@ -32,43 +32,81 @@ object AkkaMonitoringConfig { ) private val cleaningSettingsDefaults = CleaningSettings(20.seconds, 5.second) - private val akkaMonitoringDefaults = AkkaMonitoringConfig(autoStartDefaults, cleaningSettingsDefaults) + /** + * Name of configuration inside mesmer branch + */ + protected val mesmerConfig: String = "" - def apply(config: Config): AkkaMonitoringConfig = - config - .tryValue("io.scalac.akka-monitoring")(_.getConfig) - .map { monitoringConfig => - val autoStartSettings = monitoringConfig - .tryValue("auto-start")(_.getConfig) - .map { autoStartConfig => - val akkaActor = autoStartConfig.tryValue("akka-actor")(_.getBoolean).getOrElse(autoStartDefaults.akkaActor) - val akkaHttp = autoStartConfig.tryValue("akka-http")(_.getBoolean).getOrElse(autoStartDefaults.akkaHttp) - val akkaPersistence = - autoStartConfig.tryValue("akka-persistence")(_.getBoolean).getOrElse(autoStartDefaults.akkaPersistence) - val akkaCluster = - autoStartConfig.tryValue("akka-cluster")(_.getBoolean).getOrElse(autoStartDefaults.akkaCluster) - val akkaStream = - autoStartConfig.tryValue("akka-stream")(_.getBoolean).getOrElse(autoStartDefaults.akkaStream) + val defaultConfig: AkkaMonitoringConfig = AkkaMonitoringConfig(autoStartDefaults, cleaningSettingsDefaults) - AutoStartSettings(akkaActor, akkaHttp, akkaPersistence, akkaCluster, akkaStream) - } - .getOrElse(autoStartDefaults) + override protected def extractFromConfig(monitoringConfig: Config): AkkaMonitoringConfig = { + val autoStartSettings = monitoringConfig + .tryValue("auto-start")(_.getConfig) + .map { autoStartConfig => + val akkaActor = autoStartConfig.tryValue("akka-actor")(_.getBoolean).getOrElse(autoStartDefaults.akkaActor) + val akkaHttp = autoStartConfig.tryValue("akka-http")(_.getBoolean).getOrElse(autoStartDefaults.akkaHttp) + val akkaPersistence = + autoStartConfig.tryValue("akka-persistence")(_.getBoolean).getOrElse(autoStartDefaults.akkaPersistence) + val akkaCluster = + autoStartConfig.tryValue("akka-cluster")(_.getBoolean).getOrElse(autoStartDefaults.akkaCluster) + val akkaStream = + autoStartConfig.tryValue("akka-stream")(_.getBoolean).getOrElse(autoStartDefaults.akkaStream) - val cleaningSettings = monitoringConfig - .tryValue("cleaning")(_.getConfig) - .flatMap { cleaningConfig => - for { - max <- cleaningConfig.tryValue("max-staleness")(_.getDuration) - every <- cleaningConfig.tryValue("every")(_.getDuration) - } yield CleaningSettings(max.toScala, every.toScala) - } - .getOrElse(cleaningSettingsDefaults) + AutoStartSettings(akkaActor, akkaHttp, akkaPersistence, akkaCluster, akkaStream) + } + .getOrElse(autoStartDefaults) - AkkaMonitoringConfig( - autoStartSettings, - cleaningSettings - ) + val cleaningSettings = monitoringConfig + .tryValue("cleaning")(_.getConfig) + .flatMap { cleaningConfig => + for { + max <- cleaningConfig.tryValue("max-staleness")(_.getDuration) + every <- cleaningConfig.tryValue("every")(_.getDuration) + } yield CleaningSettings(max.toScala, every.toScala) } - .getOrElse(akkaMonitoringDefaults) + .getOrElse(cleaningSettingsDefaults) + + AkkaMonitoringConfig( + autoStartSettings, + cleaningSettings + ) + } + + // def apply(config: Config): AkkaMonitoringConfig = + // config + // .tryValue("io.scalac.akka-monitoring")(_.getConfig) + // .map { monitoringConfig => + // val autoStartSettings = monitoringConfig + // .tryValue("auto-start")(_.getConfig) + // .map { autoStartConfig => + // val akkaActor = autoStartConfig.tryValue("akka-actor")(_.getBoolean).getOrElse(autoStartDefaults.akkaActor) + // val akkaHttp = autoStartConfig.tryValue("akka-http")(_.getBoolean).getOrElse(autoStartDefaults.akkaHttp) + // val akkaPersistence = + // autoStartConfig.tryValue("akka-persistence")(_.getBoolean).getOrElse(autoStartDefaults.akkaPersistence) + // val akkaCluster = + // autoStartConfig.tryValue("akka-cluster")(_.getBoolean).getOrElse(autoStartDefaults.akkaCluster) + // val akkaStream = + // autoStartConfig.tryValue("akka-stream")(_.getBoolean).getOrElse(autoStartDefaults.akkaStream) + // + // AutoStartSettings(akkaActor, akkaHttp, akkaPersistence, akkaCluster, akkaStream) + // } + // .getOrElse(autoStartDefaults) + // + // val cleaningSettings = monitoringConfig + // .tryValue("cleaning")(_.getConfig) + // .flatMap { cleaningConfig => + // for { + // max <- cleaningConfig.tryValue("max-staleness")(_.getDuration) + // every <- cleaningConfig.tryValue("every")(_.getDuration) + // } yield CleaningSettings(max.toScala, every.toScala) + // } + // .getOrElse(cleaningSettingsDefaults) + // + // AkkaMonitoringConfig( + // autoStartSettings, + // cleaningSettings + // ) + // } + // .getOrElse(akkaMonitoringDefaults) } From 30e743d2240ee23959b416cd541284512b9271a3 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Sat, 3 Jul 2021 02:35:25 +0200 Subject: [PATCH 25/31] Update byte-buddy, byte-buddy-agent to 1.11.6 --- project/Dependencies.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6b194cbc8..b43cc0e1b 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -32,8 +32,8 @@ object Dependencies { ) val byteBuddy = Seq( - "net.bytebuddy" % "byte-buddy" % "1.11.5", - "net.bytebuddy" % "byte-buddy-agent" % "1.11.5" + "net.bytebuddy" % "byte-buddy" % "1.11.6", + "net.bytebuddy" % "byte-buddy-agent" % "1.11.6" ) val logback = Seq("ch.qos.logback" % "logback-classic" % LogbackVersion) From 8dfeb9b9b3c93c4560433f94a4e6efc1d1bdde83 Mon Sep 17 00:00:00 2001 From: Jakub Czuchnowski Date: Tue, 6 Jul 2021 00:43:22 +0200 Subject: [PATCH 26/31] Update metrics.md --- metrics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metrics.md b/metrics.md index f5a8e569b..d27c0002f 100644 --- a/metrics.md +++ b/metrics.md @@ -59,7 +59,7 @@ In mesmer we support 3 types of metrics: - Recovery time - recorder - Snapshots - counter -### Akka Streams +### Akka Streams (experimental) - Running streams - gauge - Running operators per stream - gauge From 945935f669b240c204a23e17b8beb4e94c3baef6 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Tue, 6 Jul 2021 19:04:45 +0200 Subject: [PATCH 27/31] Update postgresql to 42.2.23 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6b194cbc8..e139d3c87 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -9,7 +9,7 @@ object Dependencies { val LogbackVersion = "1.2.3" val OpentelemetryVersion = "1.3.0" val OpentelemetryMetricsVersion = "1.2.0-alpha" - val PostgresVersion = "42.2.22" + val PostgresVersion = "42.2.23" val ScalatestVersion = "3.2.9" val SlickVersion = "3.3.3" From 7b022de53b6b01f4f22af4a030bd5e90d8d27db2 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Thu, 8 Jul 2021 10:03:49 +0200 Subject: [PATCH 28/31] Update akka-http-circe to 1.37.0 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6b194cbc8..b33206326 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -65,7 +65,7 @@ object Dependencies { "io.circe" %% "circe-core" % CirceVersion, "io.circe" %% "circe-generic" % CirceVersion, "io.circe" %% "circe-parser" % CirceVersion, - "de.heikoseeberger" %% "akka-http-circe" % "1.36.0", + "de.heikoseeberger" %% "akka-http-circe" % "1.37.0", "org.postgresql" % "postgresql" % PostgresVersion, "com.typesafe.slick" %% "slick" % SlickVersion, "com.typesafe.slick" %% "slick-hikaricp" % SlickVersion, From 08dbf8e22c259541ec7ec0c960adcb42b894461e Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Fri, 9 Jul 2021 03:45:04 +0200 Subject: [PATCH 29/31] Update sbt-scalafmt to 2.4.3 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 9bdb5e508..d06651dc0 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,7 +4,7 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.4.0") addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.8.1") -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.3") addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.29") From 26d090e700c97b473fcfc49784de3c8701594af1 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Fri, 9 Jul 2021 22:56:17 +0200 Subject: [PATCH 30/31] Update opentelemetry-api to 1.4.0 --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6b194cbc8..9142631eb 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -7,7 +7,7 @@ object Dependencies { val AkkaVersion = "2.6.14" val CirceVersion = "0.14.1" val LogbackVersion = "1.2.3" - val OpentelemetryVersion = "1.3.0" + val OpentelemetryVersion = "1.4.0" val OpentelemetryMetricsVersion = "1.2.0-alpha" val PostgresVersion = "42.2.22" val ScalatestVersion = "3.2.9" From db5453fb3ce38388ff8827355883e43418b25f99 Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Mon, 12 Jul 2021 13:28:31 +0200 Subject: [PATCH 31/31] Update sbt to 1.5.5 --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 9edb75b77..10fd9eee0 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.4 +sbt.version=1.5.5