diff options
5 files changed, 100 insertions, 20 deletions
diff --git a/src/main/resources/META-INF/aop.xml b/src/main/resources/META-INF/aop.xml index 3911af1b..152270a7 100644 --- a/src/main/resources/META-INF/aop.xml +++ b/src/main/resources/META-INF/aop.xml @@ -12,6 +12,8 @@ <aspect name="kamon.instrumentation.RunnableInstrumentation" /> <aspect name="kamon.instrumentation.MessageQueueInstrumentation" /> + <aspect name="kamon.instrumentation.InceptionAspect"/> + <!-- ExecutorService Instrumentation for Akka. --> <aspect name="kamon.instrumentation.ExecutorServiceFactoryProviderInstrumentation"/> <aspect name="kamon.instrumentation.NamedExecutorServiceFactoryDelegateInstrumentation"/> diff --git a/src/main/scala/kamon/instrumentation/ActorRefTellInstrumentation.scala b/src/main/scala/kamon/instrumentation/ActorRefTellInstrumentation.scala index b345eaae..6677f0f7 100644 --- a/src/main/scala/kamon/instrumentation/ActorRefTellInstrumentation.scala +++ b/src/main/scala/kamon/instrumentation/ActorRefTellInstrumentation.scala @@ -1,51 +1,59 @@ package kamon.instrumentation -import org.aspectj.lang.annotation.{Before, Around, Pointcut, Aspect} +import org.aspectj.lang.annotation._ import org.aspectj.lang.ProceedingJoinPoint import akka.actor.{Props, ActorSystem, ActorRef} import kamon.{Kamon, TraceContext} import akka.dispatch.Envelope -import com.codahale.metrics.{ExponentiallyDecayingReservoir, Histogram} +import com.codahale.metrics.{Timer, ExponentiallyDecayingReservoir, Histogram} import kamon.metric.{MetricDirectory, Metrics} +import com.codahale.metrics +import kamon.instrumentation.TraceableMessage +import scala.Some -case class TraceableMessage(traceContext: Option[TraceContext], message: Any, timeStamp: Long = System.nanoTime()) +case class TraceableMessage(traceContext: Option[TraceContext], message: Any, timer: Timer.Context) @Aspect class ActorRefTellInstrumentation { import ProceedingJoinPointPimp._ - @Pointcut("execution(* akka.actor.ScalaActorRef+.$bang(..)) && !within(akka.pattern.PromiseActorRef) && args(message, sender)") - def sendingMessageToActorRef(message: Any, sender: ActorRef) = {} + @Pointcut("execution(* akka.actor.LocalActorRef+.$bang(..)) && target(actor) && args(message, sender)") + def sendingMessageToActorRef(actor: ActorRef, message: Any, sender: ActorRef) = {} - @Around("sendingMessageToActorRef(message, sender)") - def around(pjp: ProceedingJoinPoint, message: Any, sender: ActorRef): Unit = pjp.proceedWith(TraceableMessage(Kamon.context, message)) + @Around("sendingMessageToActorRef(actor, message, sender)") + def around(pjp: ProceedingJoinPoint, actor: ActorRef, message: Any, sender: ActorRef): Unit = { + + val actorName = MetricDirectory.nameForActor(actor) + val t = Metrics.registry.timer(actorName + "LATENCY") + //println(s"About to proceed with: $actor $message $sender") + pjp.proceedWithTarget(actor, TraceableMessage(Kamon.context, message, t.time()), sender) + } } @Aspect("perthis(actorCellCreation(..))") class ActorCellInvokeInstrumentation { - val latencyHistogram: Histogram = new Histogram(new ExponentiallyDecayingReservoir) + var processingTimeTimer: Timer = _ var shouldTrack = false @Pointcut("execution(akka.actor.ActorCell.new(..)) && args(system, ref, props, parent)") def actorCellCreation(system: ActorSystem, ref: ActorRef, props: Props, parent: ActorRef): Unit = {} - @Before("actorCellCreation(system, ref, props, parent)") + @After("actorCellCreation(system, ref, props, parent)") def registerMetricsInRegistry(system: ActorSystem, ref: ActorRef, props: Props, parent: ActorRef): Unit = { val actorName = MetricDirectory.nameForActor(ref) val histogramName = MetricDirectory.nameForMailbox(system.name, actorName) - // TODO: Find a better way to filter the thins we don't want to measure. - if(system.name != "kamon" && actorName.startsWith("/user")) { - Metrics.registry.register(histogramName + "/cell", latencyHistogram) + /** TODO: Find a better way to filter the things we don't want to measure. */ + //if(system.name != "kamon" && actorName.startsWith("/user")) { + processingTimeTimer = Metrics.registry.timer(histogramName + "/PROCESSINGTIME") shouldTrack = true - } + //} } - @Pointcut("execution(* akka.actor.ActorCell.invoke(*)) && args(envelope)") def invokingActorBehaviourAtActorCell(envelope: Envelope) = {} @@ -53,12 +61,15 @@ class ActorCellInvokeInstrumentation { @Around("invokingActorBehaviourAtActorCell(envelope)") def around(pjp: ProceedingJoinPoint, envelope: Envelope): Unit = { import ProceedingJoinPointPimp._ - + //println("ENVELOPE --------------------->"+envelope) envelope match { - case Envelope(TraceableMessage(ctx, msg, timeStamp), sender) => { - latencyHistogram.update(System.nanoTime() - timeStamp) + case Envelope(TraceableMessage(ctx, msg, timer), sender) => { + timer.stop() val originalEnvelope = envelope.copy(message = msg) + + //println("PROCESSING TIME TIMER: "+processingTimeTimer) + val pt = processingTimeTimer.time() ctx match { case Some(c) => { Kamon.set(c) @@ -67,6 +78,7 @@ class ActorCellInvokeInstrumentation { } case None => pjp.proceedWith(originalEnvelope) } + pt.stop() } case _ => pjp.proceed } diff --git a/src/main/scala/kamon/instrumentation/AspectJPimps.scala b/src/main/scala/kamon/instrumentation/AspectJPimps.scala index 0663e801..84c20c52 100644 --- a/src/main/scala/kamon/instrumentation/AspectJPimps.scala +++ b/src/main/scala/kamon/instrumentation/AspectJPimps.scala @@ -16,4 +16,8 @@ case class RichProceedingJointPoint(pjp: ProceedingJoinPoint) { args.update(0, newUniqueArg) pjp.proceed(args) } + + def proceedWithTarget(args: AnyRef*) = { + pjp.proceed(args.toArray) + } } diff --git a/src/main/scala/kamon/instrumentation/SampleInstrumentation.scala b/src/main/scala/kamon/instrumentation/SampleInstrumentation.scala new file mode 100644 index 00000000..74261403 --- /dev/null +++ b/src/main/scala/kamon/instrumentation/SampleInstrumentation.scala @@ -0,0 +1,49 @@ +package kamon.instrumentation + +import com.codahale.metrics.{ExponentiallyDecayingReservoir, Histogram} +import org.aspectj.lang.annotation.{After, Pointcut, DeclareMixin, Aspect} + +class ActorCage(val name: String, val size: Int) { + + def doIt: Unit = println("name") +} + +trait CageMonitoring { + def histogram: Histogram + def count(value: Int): Unit +} + +class CageMonitoringImp extends CageMonitoring{ + final val histogram = new Histogram(new ExponentiallyDecayingReservoir()) + + def count(value: Int) = histogram.update(value) + +} + + +@Aspect +class InceptionAspect { + + @DeclareMixin("kamon.instrumentation.ActorCage") + def mixin: CageMonitoring = new CageMonitoringImp + + + @Pointcut("execution(* kamon.instrumentation.ActorCage.doIt()) && target(actorCage)") + def theActorCageDidIt(actorCage: CageMonitoring) = {} + + @After("theActorCageDidIt(actorCage)") + def afterDoingIt(actorCage: CageMonitoring) = { + actorCage.count(1) + actorCage.histogram.getSnapshot.dump(System.out) + } + + + +} + + +object Runner extends App { + val cage = new ActorCage("ivan", 10) + + cage.doIt +} diff --git a/src/main/scala/kamon/metric/Metrics.scala b/src/main/scala/kamon/metric/Metrics.scala index 30b8bda9..46fb2b64 100644 --- a/src/main/scala/kamon/metric/Metrics.scala +++ b/src/main/scala/kamon/metric/Metrics.scala @@ -14,11 +14,11 @@ trait MetricDepot { object Metrics extends MetricDepot { val registry: MetricRegistry = new MetricRegistry - val consoleReporter = ConsoleReporter.forRegistry(registry) + val consoleReporter = ConsoleReporter.forRegistry(registry).convertDurationsTo(TimeUnit.NANOSECONDS) val newrelicReporter = NewRelicReporter(registry) //newrelicReporter.start(5, TimeUnit.SECONDS) - consoleReporter.build().start(60, TimeUnit.SECONDS) + consoleReporter.build().start(10, TimeUnit.SECONDS) def include(name: String, metric: Metric) = registry.register(name, metric) @@ -43,5 +43,18 @@ object MetricDirectory { def nameForMailbox(actorSystem: String, actor: String) = s"/ActorSystem/$actorSystem/Actor/$actor/Mailbox" - def nameForActor(actorRef: ActorRef) = actorRef.path.elements.fold("")(_ + "/" + _) + def nameForActor(actorRef: ActorRef) = actorRef.path.elements.mkString("/") + + def shouldInstrument(actorSystem: String): Boolean = !actorSystem.startsWith("kamon") + + + def shouldInstrumentActor(actorPath: String): Boolean = { + !(actorPath.isEmpty || actorPath.startsWith("system")) + } + + + + } + + |