Now, I am asked to add logging function in akka's actor.
When a message is received, before it is handled, this message should be written into log.
And before a message is sent out, this message should be logged first.
I think I should override the receive and send functions in Actor. Suppose I create a trait actorlog which extends Actor. And class myActor extends actorlog. But in myActor, I need to override receive function (it seems it causes problems here). So I am confused what I should do.
PS. I know akka provides logging. But now I need implement this function by myself.
There is a utility to get logging of the received messages in Akka. It's briefly mentioned in the logging documentation. Basically you wrap your receive function in it like this:
def receive = LoggingReceive {
// your normal receive here
}
And then you enable it in your config with:
akka.actor.debug.receive=on
The information will be logged at debug level.
Besides the other answers here, another approach is to use orElse to prepend a partial function to your receive. In that partial function, put the logging in isDefinedAt so it gets called on every message.
For example:
trait ReceiveLogger {
this: Actor with ActorLogging =>
def logMessage: Receive = new Receive {
def isDefinedAt(x: Any) = {
log.debug(s"Got a $x")
false
}
def apply(x: Any) = throw new UnsupportedOperationException
}
}
class MyActor extends Actor with ActorLogging with ReceiveLogger {
def receive: Receive = logMessage orElse {
case ...
}
}
Using orElse is a general approach for composing receive behavior. In most cases I am composing things like this:
def otherBehavior: Receive = {
case OtherMessage => ...
}
class MyActor extends Actor {
def receive = otherBehavior orElse {
case ...
}
}
A good example of the stackable traits approach can be seen in this presentation: http://www.slideshare.net/EvanChan2/akka-inproductionpnw-scala2013
use stackable modificator abstract override for stackable call of receive method.
use new feature of Akka: event-sourced actor system (docs here).
Related
I wrote an Akka base-actor that can handle some common messages. I want to reuse this basic behavior in a sub-actor, by extending the base-actor (not by composition of the base-actor).
I have seen several approaches in previous questions. They are all valid but also may be improved:
How extend behaviour of super actor in akka
and
How do I best share behavior among Akka actors?
To make the implementation cleaner, I am trying to achieve the following:
When defining the sub-actor, I try to extend only the base-actor (not both Actor and sub-actor). However, I was not able to force the compiler to do this.
I also try to not rename the receive partial function, because it is a kind of convention.
Here is a sample of my implementation:
//This is the base-actor that implements the common behavior
trait BetterActor extends Actor {
abstract override def receive = {
super.receive orElse { case _ => println("Missing pattern!") }
}
}
//This is the actor that implements the additional behavior.
//I actually wanted to extend BetterActor. It was not possible.
class MyActor extends Actor {
def receive = {
case i: Int =>
println(s"Yay!!! Got $i")
}
}
Here are two alternative ways how I can create an instance of the sub-actor, which combines both the common and the additional behaviors:
//1.
val myBetterActor = system.actorOf(Props(new MyActor with BetterActor), "myBetterActor")
//2.
class MyBetterActor extends MyActor with BetterActor
val myBetterActor = system.actorOf(Props[MyBetterActor], "myBetterActor")
Finally, I may invoke the sub-actor by:
myBetterActor ! 2
myBetterActor ! "a"
Problems with my implementation:
When I create an instance of the sub-actor, only then I can mix in the base-actor, either directly (1) or by defining a new class that mixes in the base-actor.
Like I said before, I would prefer to mix in the base-actor when I define the sub-actor. Not when I try to create an instance of the sub-actor.
P.S. It's fascinating that the designers of this framework did not see it necessary to make this common requirement easy to accomplish.
i suppose as long as you're not trying to override behavior with BetterActor, you could try something like this:
trait BetterActor extends Actor {
override def unhandled(message: Any): Unit = message match {
case e: CommonMessage => println("COMMON!")
case e => super.unhandled(e)
}
}
class MyActor extends BetterActor {
override def receive = {
case i: Int => println(s"Yay!!! Got $i")
}
}
This is an continuation of my previous question How do I get around type erasure on Akka receive method
I have 10 type of events which extends from Event that I need to handle.
I want to implement business logic for each event in separate trait, because because mixing all 10 event handler functions will produce several hundreds(if not thousands) lines of code.
I don't want to create different Actor types for each event. For example:
class Event1Actor extend Actor{
def receive ={
case Event1(e) => //event1 Business Logic
}
}
class Event2Actor extend Actor{
def receive ={
case Event2(e) => //event2 Business Logic
}
}
and the same Event3Actor, Event4Actor,etc....
Such code seems ugly to me, because I need to implement business Logic inside each Actor.
Implementing 10 different traits and 10 different Actor classes seems also as bad design.
I'm seeking for some kind generic solution based on design pattern, for example strategy pattern.
case class EventOperation[T <: Event](eventType: T)
class OperationActor extends Actor {
def receive = {
case EventOperation(eventType) => eventType.execute
}
}
trait Event {
def execute //implement execute in specific event class
}
class Event1 extends Event {/*execute implemented with business logic*/}
class Event2 extends Event {/*execute implemented with business logic*/}
hope this is what you are looking for and helps, I have used this patternt to remove the redundant amount of actors wrapping all actions under a single actor executing different type of events.
You could try something like this, which involves auto-composing receive functionality via a base trait. First the code:
case class Event1(s:String)
case class Event2(i:Int)
case class Event3(f:Float)
trait EventHandlingActor extends Actor{
var handlers:List[Receive] = List.empty
override def preStart = {
val composedReceive = handlers.foldLeft(receive)((r,h) => r.orElse(h))
context.become(composedReceive)
}
def addHandler(r:Receive) {
handlers = r :: handlers
}
def receive = PartialFunction.empty[Any,Unit]
}
trait Event1Handling{ me:EventHandlingActor =>
addHandler{
case Event1(s) => println(s"${self.path.name} handling event1: $s")
}
}
trait Event2Handling{ me:EventHandlingActor =>
addHandler{
case Event2(i) => println(s"${self.path.name} handling event2: $i")
}
}
trait Event3Handling{ me:EventHandlingActor =>
addHandler{
case Event3(f) => println(s"${self.path.name} handling event3: $f")
}
}
So you can see in the EventHandlingActor trait we set up a List of type Receive that can be added to by each specific handling trait that we stack into a concrete actor. Then you can see the definitions of the handling functionality for each event defined in a separate trait that is calling addHandler to add another piece of handling functionality. In preStart for any kind of EventHandlingActor impl the receive functions will be composed together with receive being the starting point (empty by default) before hot-swapping out the receive impl with context.become.
Now for a couple of impl actors as an example:
class MyEventHandlingActor extends EventHandlingActor
with Event1Handling with Event2Handling with Event3Handling
case class SomeOtherMessage(s:String)
class MyOtherEventHandlingActor extends EventHandlingActor with Event1Handling{
override def receive = {
case SomeOtherMessage(s) => println(s"otherHandler handling some other message: $s")
}
}
The first one only handles events, so all it needs to do is define which ones it handles my mixing in the appropriate traits. The second one handles one type of event but also some other message that is not an event. This class overrides the default empty receive and provides functionality to handle the non-event message.
If we tested the code like so:
val system = ActorSystem("test")
val handler = system.actorOf(Props[MyEventHandlingActor], "handler")
handler ! Event1("foo")
handler ! Event2(123)
handler ! Event3(123.456f)
val otherHandler = system.actorOf(Props[MyOtherEventHandlingActor], "otherHandler")
otherHandler ! Event1("bar")
otherHandler ! SomeOtherMessage("baz")
Then we would see output similar to this (with the order changing due to asynch handling of messages):
otherHandler handling event1: bar
handler handling event1: foo
handler handling event2: 123
handler handling event3: 123.456
I want to log all received messages to all actors in my Akka app.
There is a config akka.actor.debug.receive that will log all messages sent to an actor if that actors receive method is a LoggingReceive.
According to http://doc.akka.io/docs/akka/current/additional/faq.html it means wrapping all receive methods with LoggingReceive as in How to log all incoming messages from Akka (Java)
def receive = {
LoggingReceive {
case x ⇒ // do something
}
}
Is there a way to do this implicitly, or by config?
Not that I know of, but you should very easily be able to do something like this:
trait LoggingReceiveActor extends Actor{
def receive = LoggingReceive(loggedReceive)
def loggedReceive:Receive
}
class MyActor extends LoggingReceiveActor{
def loggedReceive = {
case _ =>
}
}
Any actor that inherits from LoggingReceiveActor now has to provide an impl for loggingReceive and if you do that, then when debug logging is enabled then this kind of actor will log the messages received.
I noticed it is legal to write this scala code:
val fussyActor = actor {
loop {
receive {
case s: String => println("I got a String: " + s)
case _ => println("I have no idea what I just got.")
}
}
}
I know from documentation that actor is a trait, which has loop and receive value members. But how is it possible to stack these methods like above? Is it implementing or overriding these methods? I am quite confused at this syntax. Please provide some good references/pointers.
First, a standard disclaimer. Scala Actors have been deprecated in favor of Akka Actors. If you want to continue down the path of learning to use Actors with Scala, you should look into Akka instead of researching Scala Actors.
Now, about your question. There are a couple of things in play here, so let's first start out with what you need to do in order to define a new Scala Actor. If you look at the Scala Actor trait, you see that there is one abstract method that you must provide called act():Unit. This is a method that takes no inputs and returns no inputs. It defines the actors behavior. So in it's simplest form, a custom Scala Actor could be:
class MyActor extends Actor{
def act(){
}
}
Now this not a very interesting actor as it does nothing. Now, one way to provide behavior is to invoke the receive method, providing a PartialFunction[Any,R] where R is a generic return type. You could do that like so:
class MyActor extends Actor{
def act(){
receive{
case "foo" => println("bar")
}
}
}
So now if this actor receives a message "foo", it will print "bar". The problem here is that this will only happen for the first message and then won't do anything after. To fix that. we can wrap our call to receive with a call to loop to make it continue to do the provided receive call for each received message:
class MyActor extends Actor{
def act(){
loop{
receive{
case "foo" => println("bar")
}
}
}
}
So this is now starting to look like your example a bit more. We are leveraging the loop and receive methods that come with the Actor trait in order to give this actor behavior. Lastly, instead of defining an explicit class as my actor, I can define one on the fly with the actor method on the Actor companion object. That method takes a function body that will be used as the act impl like this:
def actor(body: => Unit){
val a = new Actor {
def act() = body
override final val scheduler: IScheduler = parentScheduler
}
}
So in your example, you are creating a new actor implementation on the fly and providing an impl for act that will loop and call receive continually with the partial function you supplied for message handling.
Hopefully this clarifies things a bit. The only method you are "overriding" (providing an impl for) is act. When you see loop and receive, those are not overrides; they are simply calls to those existing methods on the Actor trait.
Actually it's illegal without import Actor._.
Your code without that import:
val fussyActor = Actor.actor {
Actor.loop {
Actor.receive { ... }
}
}
actor, loop and receive are methods of object Actor.
def actor(body: ⇒ Unit): Actor
def loop(body: ⇒ Unit): Unit
def receive[A](f: PartialFunction[Any, A]): A
Method actor accepts by-name Untit parameter body - some code block to execute in separate thread and creates an Actor with act method implemented using parameter body.
Method loop accepts by-name Untit parameter body - some code block to execute in infinite loop.
Method receive accepts PartialFunction as parameter f and calls f with message as parameter. It takes message from actor associated with current thread.
Note that scala actors are deprecated, you should use akka actors. See The Scala Actors Migration Guide.
The usual way of detecting the type of message received in scala actors is by
loop{
react{
case x: String =>
}
}
However, I want to know how can we override this implementation of react construct so that we can do implicit logging of the message that is received.
I am trying to implement a use case mentioned below ->
1. Before a message is matched to any case class, I want to write a log statement on console / file showing the occurance of the message.
2. We can log these messages explicitly by println() / log4j logging . However, I want to design a generic logger for scala actors which will log all the messages sent or received.
Any help in this regard will be helpful.
Thanks in advance
First, be aware that the Scala actors library is being deprecated in favor of Akka. So this answer won't be helpful very long (though the other actors library will continue to be available for a while--and since it's open source potentially forever if people want to maintain it).
Anyway, the react method is defined in scala.actors.Actor. Simply fail to import it, or hide it with your own. Your own what?
Well, the method just takes a PartialFunction[Any,Unit]. So, your should also:
def react(pf: PartialFunction[Any,Unit]): Nothing = { /*how?;*/ Actor.react(/*what?*/) }
You really only have access to the partial function, and you have to defer to Actor.react to do what you want. So you need to wrap pf in another PartialFunction that performs your logging. So you can
val qf = new PartialFunction[Any,Unit] {
def isDefinedAt(a: Any) = pf.isDefinedAt(a)
def apply(a: Any): Unit = {
log(a) // Maybe add more logic to know what a is
pf(a)
}
}
If you want to see messages that come in and get examined but are not actually consumed, you could do more with isDefinedAt also.
So, obviously enough, I hope, /*how?*/ is the above to define (create) qf, and /*what?*/ is just qf.
If you want to know whether a is a case class, the answer is that you cannot (by design). A case class is just syntactic sugar on top of ordinary Scala features; it's just there to save you typing. See, for instance, this question.
However, you can get pretty close by pattern matching for Product and checking whether it has a copy method:
case class M(i: Int)
val a: Any = M(5)
scala> a match {
case p: Product if p.getClass.getMethods.exists(_.getName=="copy") => println("Yes")
case _ => println("No")
}
Yes
If you really want to get fancy, check if copy has the same number and type of parameters as the constructor.
//Following is a code for a logReact Method that does the same thing as react but also logs the message received hope this works for you
import scala.actors.Actor;
import scala.actors.Actor._
trait ActorLogging extends Actor {
def logReact(handler: PartialFunction[Any, Unit]): Nothing = {
val handler2: PartialFunction[Any, Unit] = {
case x =>
println("Inside Logs -- with message recieved -- " + x.toString);
handler.apply(x);
}
super.react(handler2)
}
}
class sumAct extends Actor with ActorLogging {
def act() {
loop {
logReact {
case a: Int =>
println("Inside actor Sum Act Received the message -- " + a)
exit;
}
}
}
}
object ActorLog {
def main(args: Array[String]): Unit = {
var s: sumAct = new sumAct;
s.start();
s ! 1.toInt;
}
}