Merge branch 'logging'

known failures in BalancingDispatcherModelSpec and ActorPoolSpec have
tickets
This commit is contained in:
Roland 2011-11-09 18:18:32 +01:00
commit 70ae4e1984
78 changed files with 1608 additions and 927 deletions

View file

@ -6,7 +6,6 @@ package akka.actor
import akka.testkit._
import org.scalatest.BeforeAndAfterEach
import akka.testkit.Testing.sleepFor
import akka.util.duration._
import akka.dispatch.Dispatchers
@ -84,7 +83,7 @@ class ActorFireForgetRequestReplySpec extends AkkaSpec with BeforeAndAfterEach {
actor.isShutdown must be(false)
actor ! "Die"
state.finished.await
sleepFor(1 second)
1.second.dilated.sleep()
actor.isShutdown must be(true)
supervisor.stop()
}

View file

@ -9,7 +9,6 @@ import org.scalatest.matchers.MustMatchers
import akka.testkit._
import akka.util.duration._
import akka.testkit.Testing.sleepFor
import java.lang.IllegalStateException
import akka.util.ReflectiveAccess
import akka.dispatch.{ DefaultPromise, Promise, Future }
@ -20,8 +19,6 @@ object ActorRefSpec {
case class ReplyTo(sender: ActorRef)
val latch = TestLatch(4)
class ReplyActor extends Actor {
var replyTo: ActorRef = null
@ -53,11 +50,11 @@ object ActorRefSpec {
}
private def work {
sleepFor(1 second)
1.second.dilated.sleep
}
}
class SenderActor(replyActor: ActorRef) extends Actor {
class SenderActor(replyActor: ActorRef, latch: TestLatch) extends Actor {
def receive = {
case "complex" replyActor ! "complexRequest"
@ -339,8 +336,9 @@ class ActorRefSpec extends AkkaSpec {
}
"support reply via sender" in {
val latch = new TestLatch(4)
val serverRef = actorOf(Props[ReplyActor])
val clientRef = actorOf(Props(new SenderActor(serverRef)))
val clientRef = actorOf(Props(new SenderActor(serverRef, latch)))
clientRef ! "complex"
clientRef ! "simple"

View file

@ -103,7 +103,7 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
}
"fail a monitor which does not handle Terminated()" in {
filterEvents(EventFilter[ActorKilledException], EventFilter[DeathPactException]) {
filterEvents(EventFilter[ActorKilledException](), EventFilter[DeathPactException]()) {
case class FF(fail: Failed)
val supervisor = actorOf(Props[Supervisor]
.withFaultHandler(new OneForOneStrategy(FaultHandlingStrategy.makeDecider(List(classOf[Exception])), Some(0)) {

View file

@ -7,7 +7,7 @@ package akka.actor
import org.scalatest.{ BeforeAndAfterAll, BeforeAndAfterEach }
import akka.testkit._
import TestEvent.{ Mute, UnMuteAll }
import TestEvent.Mute
import FSM._
import akka.util.Duration
import akka.util.duration._
@ -18,19 +18,23 @@ import akka.config.Configuration
object FSMActorSpec {
val unlockedLatch = TestLatch()
val lockedLatch = TestLatch()
val unhandledLatch = TestLatch()
val terminatedLatch = TestLatch()
val transitionLatch = TestLatch()
val initialStateLatch = TestLatch()
val transitionCallBackLatch = TestLatch()
class Latches(implicit app: AkkaApplication) {
val unlockedLatch = TestLatch()
val lockedLatch = TestLatch()
val unhandledLatch = TestLatch()
val terminatedLatch = TestLatch()
val transitionLatch = TestLatch()
val initialStateLatch = TestLatch()
val transitionCallBackLatch = TestLatch()
}
sealed trait LockState
case object Locked extends LockState
case object Open extends LockState
class Lock(code: String, timeout: Duration) extends Actor with FSM[LockState, CodeState] {
class Lock(code: String, timeout: Duration, latches: Latches) extends Actor with FSM[LockState, CodeState] {
import latches._
startWith(Locked, CodeState("", code))
@ -61,7 +65,7 @@ object FSMActorSpec {
whenUnhandled {
case Ev(msg) {
app.eventHandler.info(this, "unhandled event " + msg + " in state " + stateName + " with data " + stateData)
log.warning("unhandled event " + msg + " in state " + stateName + " with data " + stateData)
unhandledLatch.open
stay
}
@ -107,8 +111,11 @@ class FSMActorSpec extends AkkaSpec(Configuration("akka.actor.debug.fsm" -> true
"unlock the lock" in {
val latches = new Latches
import latches._
// lock that locked after being open for 1 sec
val lock = actorOf(new Lock("33221", 1 second))
val lock = actorOf(new Lock("33221", 1 second, latches))
val transitionTester = actorOf(new Actor {
def receive = {
@ -131,10 +138,7 @@ class FSMActorSpec extends AkkaSpec(Configuration("akka.actor.debug.fsm" -> true
transitionCallBackLatch.await
lockedLatch.await
filterEvents(EventFilter.custom {
case EventHandler.Info(_: Lock, _) true
case _ false
}) {
EventFilter.warning(start = "unhandled event", occurrences = 1) intercept {
lock ! "not_handled"
unhandledLatch.await
}
@ -163,18 +167,13 @@ class FSMActorSpec extends AkkaSpec(Configuration("akka.actor.debug.fsm" -> true
case Ev("go") goto(2)
}
})
val logger = actorOf(new Actor {
def receive = {
case x testActor forward x
}
})
filterException[EventHandler.EventHandlerException] {
app.eventHandler.addListener(logger)
filterException[Logging.EventHandlerException] {
app.mainbus.subscribe(testActor, classOf[Logging.Error])
fsm ! "go"
expectMsgPF(1 second) {
case EventHandler.Error(_: EventHandler.EventHandlerException, `fsm`, "Next state 2 does not exist") true
expectMsgPF(1 second, hint = "Next state 2 does not exist") {
case Logging.Error(_, `fsm`, "Next state 2 does not exist") true
}
app.eventHandler.removeListener(logger)
app.mainbus.unsubscribe(testActor)
}
}
@ -196,47 +195,40 @@ class FSMActorSpec extends AkkaSpec(Configuration("akka.actor.debug.fsm" -> true
"log events and transitions if asked to do so" in {
new TestKit(AkkaApplication("fsm event", AkkaApplication.defaultConfig ++
Configuration("akka.event-handler-level" -> "DEBUG",
Configuration("akka.loglevel" -> "DEBUG",
"akka.actor.debug.fsm" -> true))) {
app.eventHandler.notify(TestEvent.Mute(EventFilter.custom {
case _: EventHandler.Debug true
case _ false
}))
val fsm = TestActorRef(new Actor with LoggingFSM[Int, Null] {
startWith(1, null)
when(1) {
case Ev("go")
setTimer("t", Shutdown, 1.5 seconds, false)
goto(2)
EventFilter.debug() intercept {
val fsm = TestActorRef(new Actor with LoggingFSM[Int, Null] {
startWith(1, null)
when(1) {
case Ev("go")
setTimer("t", Shutdown, 1.5 seconds, false)
goto(2)
}
when(2) {
case Ev("stop")
cancelTimer("t")
stop
}
onTermination {
case StopEvent(r, _, _) testActor ! r
}
})
app.mainbus.subscribe(testActor, classOf[Logging.Debug])
fsm ! "go"
expectMsgPF(1 second, hint = "processing Event(go,null)") {
case Logging.Debug(`fsm`, s: String) if s.startsWith("processing Event(go,null) from Actor[testActor") true
}
when(2) {
case Ev("stop")
cancelTimer("t")
stop
expectMsg(1 second, Logging.Debug(fsm, "setting timer 't'/1500 milliseconds: Shutdown"))
expectMsg(1 second, Logging.Debug(fsm, "transition 1 -> 2"))
fsm ! "stop"
expectMsgPF(1 second, hint = "processing Event(stop,null)") {
case Logging.Debug(`fsm`, s: String) if s.startsWith("processing Event(stop,null) from Actor[testActor") true
}
onTermination {
case StopEvent(r, _, _) testActor ! r
}
})
val logger = actorOf(new Actor {
def receive = {
case x testActor forward x
}
})
app.eventHandler.addListener(logger)
fsm ! "go"
expectMsgPF(1 second) {
case EventHandler.Debug(`fsm`, s: String) if s.startsWith("processing Event(go,null) from Actor[testActor") true
expectMsgAllOf(1 second, Logging.Debug(fsm, "canceling timer 't'"), Normal)
expectNoMsg(1 second)
app.mainbus.unsubscribe(testActor)
}
expectMsg(1 second, EventHandler.Debug(fsm, "setting timer 't'/1500 milliseconds: Shutdown"))
expectMsg(1 second, EventHandler.Debug(fsm, "transition 1 -> 2"))
fsm ! "stop"
expectMsgPF(1 second) {
case EventHandler.Debug(`fsm`, s: String) if s.startsWith("processing Event(stop,null) from Actor[testActor") true
}
expectMsgAllOf(1 second, EventHandler.Debug(fsm, "canceling timer 't'"), Normal)
expectNoMsg(1 second)
app.eventHandler.removeListener(logger)
}
}

View file

@ -4,9 +4,10 @@
package akka.actor
import akka.testkit.{ AkkaSpec, ImplicitSender }
import akka.testkit._
import akka.util.Duration
import akka.util.duration._
import akka.event.Logging
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class FSMTimingSpec extends AkkaSpec with ImplicitSender {
@ -15,7 +16,7 @@ class FSMTimingSpec extends AkkaSpec with ImplicitSender {
val fsm = actorOf(new StateMachine(testActor))
fsm ! SubscribeTransitionCallBack(testActor)
expectMsg(200 millis, CurrentState(fsm, Initial))
expectMsg(1 second, CurrentState(fsm, Initial))
ignoreMsg {
case Transition(_, Initial, _) true
@ -24,8 +25,20 @@ class FSMTimingSpec extends AkkaSpec with ImplicitSender {
"A Finite State Machine" must {
"receive StateTimeout" in {
within(50 millis, 250 millis) {
within(1 second) {
within(500 millis, 1 second) {
fsm ! TestStateTimeout
expectMsg(Transition(fsm, TestStateTimeout, Initial))
}
expectNoMsg
}
}
"cancel a StateTimeout" in {
within(1 second) {
fsm ! TestStateTimeout
fsm ! Cancel
expectMsg(Cancel)
expectMsg(Transition(fsm, TestStateTimeout, Initial))
expectNoMsg
}
@ -36,7 +49,7 @@ class FSMTimingSpec extends AkkaSpec with ImplicitSender {
fsm ! TestStateTimeoutOverride
expectNoMsg
}
within(50 millis) {
within(500 millis) {
fsm ! Cancel
expectMsg(Cancel)
expectMsg(Transition(fsm, TestStateTimeout, Initial))
@ -44,71 +57,68 @@ class FSMTimingSpec extends AkkaSpec with ImplicitSender {
}
"receive single-shot timer" in {
within(50 millis, 250 millis) {
fsm ! TestSingleTimer
expectMsg(Tick)
expectMsg(Transition(fsm, TestSingleTimer, Initial))
within(1.5 seconds) {
within(500 millis, 1 second) {
fsm ! TestSingleTimer
expectMsg(Tick)
expectMsg(Transition(fsm, TestSingleTimer, Initial))
}
expectNoMsg
}
}
"correctly cancel a named timer" in {
fsm ! TestCancelTimer
within(100 millis, 200 millis) {
within(500 millis) {
fsm ! Tick
expectMsg(Tick)
}
within(300 millis, 1 second) {
expectMsg(Tock)
}
fsm ! Cancel
expectMsg(Transition(fsm, TestCancelTimer, Initial))
expectMsg(1 second, Transition(fsm, TestCancelTimer, Initial))
}
"not get confused between named and state timers" in {
fsm ! TestCancelStateTimerInNamedTimerMessage
fsm ! Tick
expectMsg(100 millis, Tick)
Thread.sleep(200)
expectMsg(500 millis, Tick)
Thread.sleep(200) // this is ugly: need to wait for StateTimeout to be queued
resume(fsm)
expectMsg(100 millis, Transition(fsm, TestCancelStateTimerInNamedTimerMessage, TestCancelStateTimerInNamedTimerMessage2))
expectMsg(500 millis, Transition(fsm, TestCancelStateTimerInNamedTimerMessage, TestCancelStateTimerInNamedTimerMessage2))
fsm ! Cancel
within(100 millis) {
expectMsg(Cancel)
within(500 millis) {
expectMsg(Cancel) // if this is not received, that means StateTimeout was not properly discarded
expectMsg(Transition(fsm, TestCancelStateTimerInNamedTimerMessage2, Initial))
}
}
"receive and cancel a repeated timer" in {
fsm ! TestRepeatedTimer
val seq = receiveWhile(600 millis) {
val seq = receiveWhile(1 second) {
case Tick Tick
}
seq must have length (5)
within(250 millis) {
seq must have length 5
within(500 millis) {
expectMsg(Transition(fsm, TestRepeatedTimer, Initial))
expectNoMsg
}
}
"notify unhandled messages" in {
fsm ! TestUnhandled
within(200 millis) {
fsm ! Tick
expectNoMsg
}
within(200 millis) {
fsm ! SetHandler
fsm ! Tick
expectMsg(Unhandled(Tick))
expectNoMsg
}
within(200 millis) {
fsm ! Unhandled("test")
expectNoMsg
}
within(200 millis) {
fsm ! Cancel
expectMsg(Transition(fsm, TestUnhandled, Initial))
}
filterEvents(EventFilter.warning("unhandled event Tick in state TestUnhandled", source = fsm, occurrences = 1),
EventFilter.warning("unhandled event Unhandled(test) in state TestUnhandled", source = fsm, occurrences = 1)) {
fsm ! TestUnhandled
within(1 second) {
fsm ! Tick
fsm ! SetHandler
fsm ! Tick
expectMsg(Unhandled(Tick))
fsm ! Unhandled("test")
fsm ! Cancel
expectMsg(Transition(fsm, TestUnhandled, Initial))
}
}
}
}
@ -151,7 +161,7 @@ object FSMTimingSpec {
startWith(Initial, 0)
when(Initial) {
case Ev(TestSingleTimer)
setTimer("tester", Tick, 100 millis, false)
setTimer("tester", Tick, 500 millis, false)
goto(TestSingleTimer)
case Ev(TestRepeatedTimer)
setTimer("tester", Tick, 100 millis, true)
@ -160,7 +170,7 @@ object FSMTimingSpec {
goto(TestStateTimeout) forMax (Duration.Inf)
case Ev(x: FSMTimingSpec.State) goto(x)
}
when(TestStateTimeout, stateTimeout = 100 millis) {
when(TestStateTimeout, stateTimeout = 500 millis) {
case Ev(StateTimeout) goto(Initial)
case Ev(Cancel) goto(Initial) replying (Cancel)
}
@ -173,9 +183,9 @@ object FSMTimingSpec {
case Ev(Tick)
tester ! Tick
setTimer("hallo", Tock, 1 milli, false)
Thread.sleep(10);
TestKit.awaitCond(context.hasMessages, 1 second)
cancelTimer("hallo")
setTimer("hallo", Tock, 100 millis, false)
setTimer("hallo", Tock, 500 millis, false)
stay
case Ev(Tock)
tester ! Tock
@ -195,11 +205,12 @@ object FSMTimingSpec {
}
}
when(TestCancelStateTimerInNamedTimerMessage) {
// FSM is suspended after processing this message and resumed 200ms later
// FSM is suspended after processing this message and resumed 500ms later
case Ev(Tick)
suspend(self)
setTimer("named", Tock, 10 millis, false)
stay forMax (100 millis) replying Tick
setTimer("named", Tock, 1 millis, false)
TestKit.awaitCond(context.hasMessages, 1 second)
stay forMax (1 millis) replying Tick
case Ev(Tock)
goto(TestCancelStateTimerInNamedTimerMessage2)
}

View file

@ -10,7 +10,8 @@ import org.scalatest.WordSpec
import akka.AkkaApplication
import akka.AkkaApplication.defaultConfig
import akka.config.Configuration
import akka.event.EventHandler
import akka.event.Logging
import akka.util.Duration
object LoggingReceiveSpec {
class TestLogActor extends Actor {
@ -18,6 +19,7 @@ object LoggingReceiveSpec {
}
}
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAndAfterAll {
import LoggingReceiveSpec._
@ -28,13 +30,13 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
val appLifecycle = AkkaApplication("lifecycle", config ++ Configuration("akka.actor.debug.lifecycle" -> true))
val filter = TestEvent.Mute(EventFilter.custom {
case _: EventHandler.Debug true
case _: EventHandler.Info true
case _ false
case _: Logging.Debug true
case _: Logging.Info true
case _ false
})
appLogging.eventHandler.notify(filter)
appAuto.eventHandler.notify(filter)
appLifecycle.eventHandler.notify(filter)
appLogging.mainbus.publish(filter)
appAuto.mainbus.publish(filter)
appLifecycle.mainbus.publish(filter)
def ignoreMute(t: TestKit) {
t.ignoreMsg {
@ -42,24 +44,31 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
}
}
override def afterAll {
appLogging.stop()
appAuto.stop()
appLifecycle.stop()
}
"A LoggingReceive" must {
"decorate a Receive" in {
new TestKit(appLogging) {
app.eventHandler.addListener(testActor)
app.mainbus.subscribe(testActor, classOf[Logging.Debug])
val r: Actor.Receive = {
case null
}
val log = Actor.LoggingReceive(this, r)
log.isDefinedAt("hallo")
expectMsg(1 second, EventHandler.Debug(this, "received unhandled message hallo"))
expectMsg(1 second, Logging.Debug(this, "received unhandled message hallo"))
}
}
"be added on Actor if requested" in {
new TestKit(appLogging) with ImplicitSender {
ignoreMute(this)
app.eventHandler.addListener(testActor)
app.mainbus.subscribe(testActor, classOf[Logging.Debug])
app.mainbus.subscribe(testActor, classOf[Logging.Error])
val actor = TestActorRef(new Actor {
def receive = loggable(this) {
case _ sender ! "x"
@ -67,7 +76,7 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
})
actor ! "buh"
within(1 second) {
expectMsg(EventHandler.Debug(actor.underlyingActor, "received handled message buh"))
expectMsg(Logging.Debug(actor.underlyingActor, "received handled message buh"))
expectMsg("x")
}
val r: Actor.Receive = {
@ -75,20 +84,19 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
}
actor ! HotSwap(_ r, false)
filterException[UnhandledMessageException] {
within(300 millis) {
within(500 millis) {
actor ! "bah"
expectMsgPF() {
case EventHandler.Error(_: UnhandledMessageException, `actor`, _) true
case Logging.Error(_: UnhandledMessageException, `actor`, _) true
}
}
}
actor.stop()
}
}
"not duplicate logging" in {
new TestKit(appLogging) with ImplicitSender {
app.eventHandler.addListener(testActor)
app.mainbus.subscribe(testActor, classOf[Logging.Debug])
val actor = TestActorRef(new Actor {
def receive = loggable(this)(loggable(this) {
case _ sender ! "x"
@ -96,7 +104,7 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
})
actor ! "buh"
within(1 second) {
expectMsg(EventHandler.Debug(actor.underlyingActor, "received handled message buh"))
expectMsg(Logging.Debug(actor.underlyingActor, "received handled message buh"))
expectMsg("x")
}
}
@ -108,62 +116,69 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
"log AutoReceiveMessages if requested" in {
new TestKit(appAuto) {
app.eventHandler.addListener(testActor)
app.mainbus.subscribe(testActor, classOf[Logging.Debug])
val actor = TestActorRef(new Actor {
def receive = {
case _
}
})
actor ! PoisonPill
expectMsg(300 millis, EventHandler.Debug(actor.underlyingActor, "received AutoReceiveMessage PoisonPill"))
expectMsg(300 millis, Logging.Debug(actor.underlyingActor, "received AutoReceiveMessage PoisonPill"))
awaitCond(actor.isShutdown, 100 millis)
}
}
// TODO remove ignore as soon as logging is working properly during start-up again
"log LifeCycle changes if requested" ignore {
"log LifeCycle changes if requested" in {
new TestKit(appLifecycle) {
ignoreMute(this)
app.eventHandler.addListener(testActor)
within(2 seconds) {
ignoreMsg {
case Logging.Debug(ref, _)
val s = ref.toString
s.contains("MainBusReaper") || s.contains("Supervisor")
}
app.mainbus.subscribe(testActor, classOf[Logging.Debug])
app.mainbus.subscribe(testActor, classOf[Logging.Error])
within(3 seconds) {
val supervisor = TestActorRef[TestLogActor](Props[TestLogActor].withFaultHandler(OneForOneStrategy(List(classOf[Throwable]), 5, 5000)))
expectMsg(EventHandler.Debug(supervisor, "started"))
expectMsgPF() {
case Logging.Debug(`supervisor`, msg: String) if msg startsWith "started"
}
val actor = new TestActorRef[TestLogActor](app, Props[TestLogActor], supervisor, "none")
expectMsgPF() {
case EventHandler.Debug(ref, msg: String) ref == supervisor && msg.startsWith("now supervising")
}
expectMsg(EventHandler.Debug(actor, "started"))
val set = receiveWhile(messages = 2) {
case Logging.Debug(`supervisor`, msg: String) if msg startsWith "now supervising" 1
case Logging.Debug(`actor`, msg: String) if msg startsWith "started" 2
}.toSet
expectNoMsg(Duration.Zero)
assert(set == Set(1, 2), set + " was not Set(1, 2)")
supervisor startsMonitoring actor
expectMsgPF(hint = "now monitoring") {
case EventHandler.Debug(ref, msg: String)
case Logging.Debug(ref, msg: String)
ref == supervisor.underlyingActor && msg.startsWith("now monitoring")
}
supervisor stopsMonitoring actor
expectMsgPF(hint = "stopped monitoring") {
case EventHandler.Debug(ref, msg: String)
case Logging.Debug(ref, msg: String)
ref == supervisor.underlyingActor && msg.startsWith("stopped monitoring")
}
filterException[ActorKilledException] {
actor ! Kill
expectMsgPF() {
case EventHandler.Error(_: ActorKilledException, `actor`, "Kill") true
}
expectMsg(EventHandler.Debug(actor, "restarting"))
}
awaitCond(msgAvailable)
expectMsgPF(hint = "restarted") {
case EventHandler.Debug(`actor`, "restarted") true
val set = receiveWhile(messages = 3) {
case Logging.Error(_: ActorKilledException, `actor`, "Kill") 1
case Logging.Debug(`actor`, "restarting") 2
case Logging.Debug(`actor`, "restarted") 3
}.toSet
expectNoMsg(Duration.Zero)
assert(set == Set(1, 2, 3), set + " was not Set(1, 2, 3)")
}
actor.stop()
expectMsg(EventHandler.Debug(actor, "stopping"))
expectMsg(Logging.Debug(actor, "stopping"))
supervisor.stop()
}
}

View file

@ -15,12 +15,8 @@ import akka.testkit.AkkaSpec
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class RestartStrategySpec extends AkkaSpec {
override def atStartup() {
app.eventHandler.notify(Mute(EventFilter[Exception]("Crashing...")))
}
override def atTermination() {
app.eventHandler.notify(UnMuteAll)
override def atStartup {
app.mainbus.publish(Mute(EventFilter[Exception]("Crashing...")))
}
object Ping

View file

@ -17,10 +17,6 @@ class SchedulerSpec extends AkkaSpec with BeforeAndAfterEach {
future
}
override def beforeEach {
app.eventHandler.notify(Mute(EventFilter[Exception]("CRASH")))
}
override def afterEach {
while (futures.peek() ne null) { Option(futures.poll()).foreach(_.cancel(true)) }
}

View file

@ -5,7 +5,6 @@
package akka.actor
import org.scalatest.BeforeAndAfterEach
import akka.testkit.Testing.sleepFor
import akka.util.duration._
import akka.{ Die, Ping }
import akka.actor.Actor._
@ -17,7 +16,6 @@ import akka.testkit.AkkaSpec
object SupervisorSpec {
val Timeout = 5 seconds
val TimeoutMillis = Timeout.dilated.toMillis.toInt
case object DieReply
@ -70,6 +68,8 @@ class SupervisorSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
import SupervisorSpec._
val TimeoutMillis = Timeout.dilated.toMillis.toInt
// =====================================================
// Creating actors and supervisors
// =====================================================
@ -121,14 +121,8 @@ class SupervisorSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
(pingpong1, pingpong2, pingpong3, topSupervisor)
}
override def atStartup() = {
app.eventHandler notify Mute(EventFilter[Exception]("Die"),
EventFilter[IllegalStateException]("Don't wanna!"),
EventFilter[RuntimeException]("Expected"))
}
override def atTermination() = {
app.eventHandler notify UnMuteAll
override def atStartup() {
app.mainbus.publish(Mute(EventFilter[RuntimeException](ExceptionMessage)))
}
override def beforeEach() = {

View file

@ -6,7 +6,6 @@ package akka.actor
import org.scalatest.WordSpec
import org.scalatest.matchers.MustMatchers
import akka.util.duration._
import akka.testkit.Testing.sleepFor
import akka.dispatch.Dispatchers
import akka.actor.Actor._
import akka.testkit.{ TestKit, EventFilter, filterEvents, filterException }

View file

@ -4,7 +4,7 @@
package akka.actor.dispatch
import org.scalatest.Assertions._
import akka.testkit.{ Testing, filterEvents, EventFilter, AkkaSpec }
import akka.testkit.{ filterEvents, EventFilter, AkkaSpec }
import akka.dispatch._
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.{ ConcurrentHashMap, CountDownLatch, TimeUnit }
@ -15,6 +15,7 @@ import akka.actor._
import util.control.NoStackTrace
import akka.AkkaApplication
import akka.util.duration._
import akka.event.Logging.Error
object ActorModelSpec {
@ -154,8 +155,8 @@ object ActorModelSpec {
await(deadline)(stops == dispatcher.stops.get)
} catch {
case e
app.eventHandler.error(e, dispatcher, "actual: starts=" + dispatcher.starts.get + ",stops=" + dispatcher.stops.get +
" required: starts=" + starts + ",stops=" + stops)
app.mainbus.publish(Error(e, dispatcher, "actual: starts=" + dispatcher.starts.get + ",stops=" + dispatcher.stops.get +
" required: starts=" + starts + ",stops=" + stops))
throw e
}
}
@ -215,9 +216,9 @@ object ActorModelSpec {
await(deadline)(stats.restarts.get() == restarts)
} catch {
case e
app.eventHandler.error(e, dispatcher, "actual: " + stats + ", required: InterceptorStats(susp=" + suspensions +
app.mainbus.publish(Error(e, dispatcher, "actual: " + stats + ", required: InterceptorStats(susp=" + suspensions +
",res=" + resumes + ",reg=" + registers + ",unreg=" + unregisters +
",recv=" + msgsReceived + ",proc=" + msgsProcessed + ",restart=" + restarts)
",recv=" + msgsReceived + ",proc=" + msgsProcessed + ",restart=" + restarts))
throw e
}
}
@ -284,13 +285,13 @@ abstract class ActorModelSpec extends AkkaSpec {
val a = newTestActor(dispatcher)
a ! CountDown(start)
assertCountDown(start, Testing.testTime(3000), "Should process first message within 3 seconds")
assertCountDown(start, 3.seconds.dilated.toMillis, "Should process first message within 3 seconds")
assertRefDefaultZero(a)(registers = 1, msgsReceived = 1, msgsProcessed = 1)
a ! Wait(1000)
a ! CountDown(oneAtATime)
// in case of serialization violation, restart would happen instead of count down
assertCountDown(oneAtATime, Testing.testTime(1500), "Processed message when allowed")
assertCountDown(oneAtATime, (1.5 seconds).dilated.toMillis, "Processed message when allowed")
assertRefDefaultZero(a)(registers = 1, msgsReceived = 3, msgsProcessed = 3)
a.stop()
@ -309,7 +310,7 @@ abstract class ActorModelSpec extends AkkaSpec {
}
}
}
assertCountDown(counter, Testing.testTime(3000), "Should process 200 messages")
assertCountDown(counter, 3.seconds.dilated.toMillis, "Should process 200 messages")
assertRefDefaultZero(a)(registers = 1, msgsReceived = 200, msgsProcessed = 200)
a.stop()
@ -321,7 +322,7 @@ abstract class ActorModelSpec extends AkkaSpec {
try {
f
} catch {
case e app.eventHandler.error(e, this, "error in spawned thread")
case e app.mainbus.publish(Error(e, this, "error in spawned thread"))
}
}
}
@ -338,7 +339,7 @@ abstract class ActorModelSpec extends AkkaSpec {
assertRefDefaultZero(a)(registers = 1, msgsReceived = 1, suspensions = 1)
a.resume
assertCountDown(done, Testing.testTime(3000), "Should resume processing of messages when resumed")
assertCountDown(done, 3.seconds.dilated.toMillis, "Should resume processing of messages when resumed")
assertRefDefaultZero(a)(registers = 1, msgsReceived = 1, msgsProcessed = 1,
suspensions = 1, resumes = 1)
@ -359,7 +360,7 @@ abstract class ActorModelSpec extends AkkaSpec {
}).withDispatcher(wavesSupervisorDispatcher(dispatcher)))
boss ! "run"
try {
assertCountDown(cachedMessage.latch, Testing.testTime(20000), "Should process " + num + " countdowns")
assertCountDown(cachedMessage.latch, (20 seconds).dilated.toMillis, "Should process " + num + " countdowns")
} catch {
case e
System.err.println(this.getClass.getName + " error: " + e.getMessage + " missing count downs == " + cachedMessage.latch.getCount() + " out of " + num)
@ -374,7 +375,7 @@ abstract class ActorModelSpec extends AkkaSpec {
}
"continue to process messages when a thread gets interrupted" in {
filterEvents(EventFilter[InterruptedException], EventFilter[akka.event.EventHandler.EventHandlerException]) {
filterEvents(EventFilter[InterruptedException](), EventFilter[akka.event.Logging.EventHandlerException]()) {
implicit val dispatcher = newInterceptedDispatcher
implicit val timeout = Timeout(5 seconds)
val a = newTestActor(dispatcher)
@ -395,7 +396,7 @@ abstract class ActorModelSpec extends AkkaSpec {
}
"continue to process messages when exception is thrown" in {
filterEvents(EventFilter[IndexOutOfBoundsException], EventFilter[RemoteException]) {
filterEvents(EventFilter[IndexOutOfBoundsException](), EventFilter[RemoteException]()) {
implicit val dispatcher = newInterceptedDispatcher
val a = newTestActor(dispatcher)
val f1 = a ? Reply("foo")
@ -435,10 +436,10 @@ class DispatcherModelSpec extends ActorModelSpec {
val a, b = newTestActor(dispatcher)
a ! Meet(aStart, aStop)
assertCountDown(aStart, Testing.testTime(3000), "Should process first message within 3 seconds")
assertCountDown(aStart, 3.seconds.dilated.toMillis, "Should process first message within 3 seconds")
b ! CountDown(bParallel)
assertCountDown(bParallel, Testing.testTime(3000), "Should process other actors in parallel")
assertCountDown(bParallel, 3.seconds.dilated.toMillis, "Should process other actors in parallel")
aStop.countDown()
@ -474,10 +475,10 @@ class BalancingDispatcherModelSpec extends ActorModelSpec {
val a, b = newTestActor(dispatcher)
a ! Meet(aStart, aStop)
assertCountDown(aStart, Testing.testTime(3000), "Should process first message within 3 seconds")
assertCountDown(aStart, 3.seconds.dilated.toMillis, "Should process first message within 3 seconds")
b ! CountDown(bParallel)
assertCountDown(bParallel, Testing.testTime(3000), "Should process other actors in parallel")
assertCountDown(bParallel, 3.seconds.dilated.toMillis, "Should process other actors in parallel")
aStop.countDown()

View file

@ -2,8 +2,7 @@ package akka.actor.dispatch
import java.util.concurrent.{ CountDownLatch, TimeUnit }
import akka.testkit.TestEvent._
import akka.testkit.EventFilter
import akka.testkit._
import akka.dispatch.{ PinnedDispatcher, Dispatchers }
import akka.actor.{ Props, Actor }
import akka.testkit.AkkaSpec
@ -24,14 +23,6 @@ class PinnedActorSpec extends AkkaSpec with BeforeAndAfterEach {
private val unit = TimeUnit.MILLISECONDS
override def beforeEach {
app.eventHandler.notify(Mute(EventFilter[RuntimeException]("Failure")))
}
override def afterEach {
app.eventHandler.notify(UnMuteAll)
}
"A PinnedActor" must {
"support tell" in {

View file

@ -147,7 +147,6 @@ object ActorEventBusSpec {
type Classifier = String
def classify(event: Event) = event.toString
protected def compareSubscribers(a: Subscriber, b: Subscriber): Int = a compareTo b
protected def mapSize = 32
def publish(event: Event, subscriber: Subscriber) = subscriber ! event
}

View file

@ -0,0 +1,75 @@
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.event
import akka.testkit.AkkaSpec
import akka.config.Configuration
import akka.util.duration._
import akka.actor.{ Actor, ActorRef }
object MainBusSpec {
case class M(i: Int)
case class SetTarget(ref: ActorRef)
class MyLog extends Actor {
var dst: ActorRef = app.deadLetters
def receive = {
case Logging.InitializeLogger(bus) bus.subscribe(context.self, classOf[SetTarget])
case SetTarget(ref) dst = ref
case e: Logging.LogEvent dst ! e
}
}
}
class MainBusSpec extends AkkaSpec(Configuration(
"akka.stdout-loglevel" -> "WARNING",
"akka.loglevel" -> "INFO",
"akka.event-handlers" -> Seq("akka.event.MainBusSpec$MyLog", Logging.StandardOutLoggerName))) {
import MainBusSpec._
"A MainBus" must {
"manage subscriptions" in {
val bus = new MainBus(true)
bus.start(app)
bus.subscribe(testActor, classOf[M])
bus.publish(M(42))
within(1 second) {
expectMsg(M(42))
bus.unsubscribe(testActor)
bus.publish(M(13))
expectNoMsg
}
}
"manage log levels" in {
val bus = new MainBus(false)
bus.start(app)
bus.startDefaultLoggers(app, app.AkkaConfig)
bus.publish(SetTarget(testActor))
within(1 second) {
import Logging._
verifyLevel(bus, InfoLevel)
bus.logLevel = WarningLevel
verifyLevel(bus, WarningLevel)
bus.logLevel = DebugLevel
verifyLevel(bus, DebugLevel)
bus.logLevel = ErrorLevel
verifyLevel(bus, ErrorLevel)
}
}
}
private def verifyLevel(bus: LoggingBus, level: Logging.LogLevel) {
import Logging._
val allmsg = Seq(Debug(this, "debug"), Info(this, "info"), Warning(this, "warning"), Error(this, "error"))
val msg = allmsg filter (_.level <= level)
allmsg foreach bus.publish
msg foreach (x expectMsg(x))
}
}

View file

@ -16,7 +16,7 @@ trait MatchingEngine {
}
class AkkaMatchingEngine(val meId: String, val orderbooks: List[Orderbook])
extends Actor with MatchingEngine {
extends Actor with MatchingEngine with ActorLogging {
var standby: Option[ActorRef] = None
@ -26,7 +26,7 @@ class AkkaMatchingEngine(val meId: String, val orderbooks: List[Orderbook])
case standbyRef: ActorRef
standby = Some(standbyRef)
case unknown
app.eventHandler.warning(this, "Received unknown message: " + unknown)
log.warning("Received unknown message: " + unknown)
}
def handleOrder(order: Order) {
@ -40,7 +40,7 @@ class AkkaMatchingEngine(val meId: String, val orderbooks: List[Orderbook])
done(true, order)
case None
app.eventHandler.warning(this, "Orderbook not handled by this MatchingEngine: " + order.orderbookSymbol)
log.warning("Orderbook not handled by this MatchingEngine: " + order.orderbookSymbol)
}
}

View file

@ -24,14 +24,14 @@ trait OrderReceiver {
}
class AkkaOrderReceiver extends Actor with OrderReceiver {
class AkkaOrderReceiver extends Actor with OrderReceiver with ActorLogging {
type ME = ActorRef
def receive = {
case order: Order placeOrder(order)
case routing @ MatchingEngineRouting(mapping)
refreshMatchingEnginePartitions(routing.asInstanceOf[MatchingEngineRouting[ActorRef]])
case unknown app.eventHandler.warning(this, "Received unknown message: " + unknown)
case unknown log.warning("Received unknown message: " + unknown)
}
def placeOrder(order: Order) = {
@ -40,7 +40,7 @@ class AkkaOrderReceiver extends Actor with OrderReceiver {
case Some(m)
m forward order
case None
app.eventHandler.warning(this, "Unknown orderbook: " + order.orderbookSymbol)
log.warning("Unknown orderbook: " + order.orderbookSymbol)
sender ! Rsp(order, false)
}
}

View file

@ -138,7 +138,7 @@ class TradingLatencyPerformanceSpec extends PerformanceSpec {
def receive = {
case Rsp(order, status)
if (!status) {
app.eventHandler.error(this, "Invalid rsp")
log.error("Invalid rsp")
}
val duration = System.nanoTime - order.nanoTime
stat.addValue(duration)

View file

@ -130,7 +130,7 @@ class TradingThroughputPerformanceSpec extends PerformanceSpec {
def receive = {
case Rsp(order, status)
if (!status) {
app.eventHandler.error(this, "Invalid rsp")
log.error("Invalid rsp")
}
received += 1
if (sent < repeat) {

View file

@ -12,6 +12,8 @@ import java.io.PrintWriter
import java.text.SimpleDateFormat
import java.util.Date
import scala.collection.mutable.{ Map MutableMap }
import akka.AkkaApplication
import akka.event.Logging
trait BenchResultRepository {
def add(stats: Stats)

View file

@ -90,7 +90,7 @@ trait PerformanceSpec extends AkkaSpec with BeforeAndAfterEach {
report.html(resultRepository.get(stats.name))
} catch {
// don't fail test due to problems saving bench report
case e: Exception app.eventHandler.error(e, this, e.getMessage)
case e: Exception log.error(e, e.getMessage)
}
}

View file

@ -6,6 +6,7 @@ import java.util.Date
import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.JavaConversions.enumerationAsScalaIterator
import akka.AkkaApplication
import akka.event.Logging
import scala.collection.immutable.TreeMap
class Report(
@ -13,7 +14,8 @@ class Report(
resultRepository: BenchResultRepository,
compareResultWith: Option[String] = None) {
private def log = System.getProperty("benchmark.logResult", "true").toBoolean
private def doLog = System.getProperty("benchmark.logResult", "true").toBoolean
val log = Logging(app, this)
val dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")
val legendTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm")
@ -58,8 +60,8 @@ class Report(
val reportName = current.name + "--" + timestamp + ".html"
resultRepository.saveHtmlReport(sb.toString, reportName)
if (log) {
app.eventHandler.info(this, resultTable + "Charts in html report: " + resultRepository.htmlReportUrl(reportName))
if (doLog) {
log.info(resultTable + "Charts in html report: " + resultRepository.htmlReportUrl(reportName))
}
}

View file

@ -2,7 +2,6 @@ package akka.routing
import akka.dispatch.{ KeptPromise, Future }
import akka.actor._
import akka.testkit.Testing._
import akka.testkit.{ TestLatch, filterEvents, EventFilter, filterException }
import akka.util.duration._
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
@ -88,7 +87,7 @@ class ActorPoolSpec extends AkkaSpec {
def instance(p: Props) = actorOf(p.withCreator(new Actor {
def receive = {
case req: String {
sleepFor(10 millis)
(10 millis).dilated.sleep
sender.tell("Response")
}
}
@ -116,7 +115,7 @@ class ActorPoolSpec extends AkkaSpec {
def instance(p: Props) = actorOf(p.withCreator(new Actor {
def receive = {
case n: Int
sleepFor(n millis)
(n millis).dilated.sleep
count.incrementAndGet
latch.countDown()
}
@ -142,7 +141,7 @@ class ActorPoolSpec extends AkkaSpec {
count.set(0)
for (m 0 until loops) {
pool ? t
sleepFor(50 millis)
(50 millis).dilated.sleep
}
}
@ -180,7 +179,7 @@ class ActorPoolSpec extends AkkaSpec {
def instance(p: Props) = actorOf(p.withCreator(new Actor {
def receive = {
case n: Int
sleepFor(n millis)
(n millis).dilated.sleep
count.incrementAndGet
latch.countDown()
}
@ -291,7 +290,7 @@ class ActorPoolSpec extends AkkaSpec {
def instance(p: Props) = actorOf(p.withCreator(new Actor {
def receive = {
case n: Int
sleepFor(n millis)
(n millis).dilated.sleep
latch.countDown()
}
}))
@ -311,7 +310,7 @@ class ActorPoolSpec extends AkkaSpec {
for (m 0 to 10) pool ! 250
sleepFor(5 millis)
(5 millis).dilated.sleep
val z = (pool ? ActorPool.Stat).as[ActorPool.Stats].get.size
@ -321,7 +320,7 @@ class ActorPoolSpec extends AkkaSpec {
for (m 0 to 3) {
pool ! 1
sleepFor(500 millis)
(500 millis).dilated.sleep
}
(pool ? ActorPool.Stat).as[ActorPool.Stats].get.size must be <= (z)
@ -416,7 +415,7 @@ class ActorPoolSpec extends AkkaSpec {
pool1 ! "ping"
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pool1 ! akka.Die
sleepFor(2 seconds)
(2 seconds).dilated.sleep
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pingCount.get must be(1)
@ -427,7 +426,7 @@ class ActorPoolSpec extends AkkaSpec {
pool1 ! "ping"
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pool1 ! akka.Die
sleepFor(2 seconds)
(2 seconds).dilated.sleep
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(1)
pool1 ! "ping"
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
@ -440,7 +439,7 @@ class ActorPoolSpec extends AkkaSpec {
pool2 ! "ping"
(pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pool2 ! akka.Die
sleepFor(2 seconds)
(2 seconds).dilated.sleep
(pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pingCount.get must be(1)
@ -451,7 +450,7 @@ class ActorPoolSpec extends AkkaSpec {
pool2 ! "ping"
(pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pool2 ! akka.Die
sleepFor(2 seconds)
(2 seconds).dilated.sleep
(pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(1)
pool2 ! "ping"
(pool2 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
@ -463,7 +462,7 @@ class ActorPoolSpec extends AkkaSpec {
pool3 ! "ping"
(pool3 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pool3 ! akka.Die
sleepFor(2 seconds)
(2 seconds).dilated.sleep
(pool3 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(1)
pool3 ! "ping"
pool3 ! "ping"
@ -474,7 +473,7 @@ class ActorPoolSpec extends AkkaSpec {
}
"support customizable supervision config of pooled actors" in {
filterEvents(EventFilter[IllegalStateException], EventFilter[RuntimeException]) {
filterEvents(EventFilter[IllegalStateException](), EventFilter[RuntimeException]()) {
val pingCount = new AtomicInteger(0)
val deathCount = new AtomicInteger(0)
var keepDying = new AtomicBoolean(false)
@ -512,7 +511,7 @@ class ActorPoolSpec extends AkkaSpec {
pool1 ! "ping"
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pool1 ! BadState
sleepFor(2 seconds)
(2 seconds).dilated.sleep
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pingCount.get must be(1)
@ -522,7 +521,7 @@ class ActorPoolSpec extends AkkaSpec {
pool1 ! "ping"
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
pool1 ! BadState
sleepFor(2 seconds)
(2 seconds).dilated.sleep
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(1)
pool1 ! "ping"
(pool1 ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)

View file

@ -11,7 +11,7 @@ import org.junit.{ After, Test }
class CallingThreadDispatcherModelSpec extends ActorModelSpec {
import ActorModelSpec._
def newInterceptedDispatcher = new CallingThreadDispatcher(app, "test", true) with MessageDispatcherInterceptor
def newInterceptedDispatcher = new CallingThreadDispatcher(app, "test") with MessageDispatcherInterceptor
def dispatcherType = "Calling Thread Dispatcher"
}

View file

@ -5,14 +5,14 @@ package akka
import akka.config._
import akka.actor._
import dispatch._
import event._
import akka.dispatch._
import akka.event._
import akka.util.duration._
import java.net.InetAddress
import com.eaio.uuid.UUID
import akka.dispatch.{ Dispatchers, Future }
import akka.util.Duration
import akka.util.ReflectiveAccess
import java.util.concurrent.TimeUnit
import akka.routing.Routing
import akka.remote.RemoteSupport
import akka.serialization.Serialization
@ -20,6 +20,8 @@ import java.net.InetSocketAddress
object AkkaApplication {
type AkkaConfig = a.AkkaConfig.type forSome { val a: AkkaApplication }
val Version = "2.0-SNAPSHOT"
val envHome = System.getenv("AKKA_HOME") match {
@ -87,21 +89,26 @@ class AkkaApplication(val name: String, val config: Configuration) extends Actor
val ProviderClass = getString("akka.actor.provider", "akka.actor.LocalActorRefProvider")
val DefaultTimeUnit = getString("akka.time-unit", "seconds")
val DefaultTimeUnit = Duration.timeUnit(getString("akka.time-unit", "seconds"))
val ActorTimeout = Timeout(Duration(getInt("akka.actor.timeout", 5), DefaultTimeUnit))
val ActorTimeoutMillis = ActorTimeout.duration.toMillis
val SerializeAllMessages = getBool("akka.actor.serialize-messages", false)
val LogLevel = getString("akka.event-handler-level", "INFO")
val TestTimeFactor = getDouble("akka.test.timefactor", 1.0)
val TestEventFilterLeeway = Duration(getDouble("akka.test.filter-leeway", 0.5), DefaultTimeUnit)
val LogLevel = getString("akka.loglevel", "INFO")
val StdoutLogLevel = getString("akka.stdout-loglevel", LogLevel)
val EventHandlers = getList("akka.event-handlers")
val AddLoggingReceive = getBool("akka.actor.debug.receive", false)
val DebugAutoReceive = getBool("akka.actor.debug.autoreceive", false)
val DebugLifecycle = getBool("akka.actor.debug.lifecycle", false)
val FsmDebugEvent = getBool("akka.actor.debug.fsm", false)
val DebugMainBus = getBool("akka.actor.debug.mainbus", false)
val DispatcherThroughput = getInt("akka.actor.throughput", 5)
val DispatcherDefaultShutdown = getLong("akka.actor.dispatcher-shutdown-timeout").
map(time Duration(time, DefaultTimeUnit)).getOrElse(Duration(1000, TimeUnit.MILLISECONDS))
map(time Duration(time, DefaultTimeUnit)).getOrElse(1 second)
val MailboxCapacity = getInt("akka.actor.default-dispatcher.mailbox-capacity", -1)
val MailboxPushTimeout = Duration(getInt("akka.actor.default-dispatcher.mailbox-push-timeout-time", 10), DefaultTimeUnit)
val DispatcherThroughputDeadlineTime = Duration(getInt("akka.actor.throughput-deadline-time", -1), DefaultTimeUnit)
@ -132,6 +139,8 @@ class AkkaApplication(val name: String, val config: Configuration) extends Actor
val ExpiredHeaderValue = config.getString("akka.http.expired-header-value", "expired")
}
private[akka] def systemActorOf(props: Props, address: String): ActorRef = provider.actorOf(props, systemGuardian, address, true)
import AkkaConfig._
if (ConfigVersion != Version)
@ -158,11 +167,14 @@ class AkkaApplication(val name: String, val config: Configuration) extends Actor
def port: Int = defaultAddress.getPort
// this provides basic logging (to stdout) until .start() is called below
val mainbus = new MainBus(DebugMainBus)
mainbus.startStdoutLogger(AkkaConfig)
val log = new BusLogging(mainbus, this)
// TODO correctly pull its config from the config
val dispatcherFactory = new Dispatchers(this)
implicit val dispatcher = dispatcherFactory.defaultGlobalDispatcher
def terminationFuture: Future[ExitStatus] = provider.terminationFuture
// TODO think about memory consistency effects when doing funky stuff inside constructor
@ -171,31 +183,53 @@ class AkkaApplication(val name: String, val config: Configuration) extends Actor
// TODO think about memory consistency effects when doing funky stuff inside constructor
val provider: ActorRefProvider = reflective.createProvider
// TODO make this configurable
protected[akka] val guardian: ActorRef = {
import akka.actor.FaultHandlingStrategy._
new LocalActorRef(this,
Props(context { case _ }).withFaultHandler(OneForOneStrategy {
case _: ActorKilledException Stop
case _: ActorInitializationException Stop
case _: Exception Restart
}).withDispatcher(dispatcher),
provider.theOneWhoWalksTheBubblesOfSpaceTime,
"ApplicationSupervisor",
true)
private class Guardian extends Actor {
def receive = {
case Terminated(_) context.self.stop()
}
}
private class SystemGuardian extends Actor {
def receive = {
case Terminated(_)
mainbus.stopDefaultLoggers()
context.self.stop()
}
}
private val guardianFaultHandlingStrategy = {
import akka.actor.FaultHandlingStrategy._
OneForOneStrategy {
case _: ActorKilledException Stop
case _: ActorInitializationException Stop
case _: Exception Restart
}
}
private val guardianProps = Props(new Guardian).withFaultHandler(guardianFaultHandlingStrategy)
// TODO think about memory consistency effects when doing funky stuff inside constructor
val eventHandler = new EventHandler(this)
private val guardianInChief: ActorRef =
provider.actorOf(guardianProps, provider.theOneWhoWalksTheBubblesOfSpaceTime, "GuardianInChief", true)
// TODO think about memory consistency effects when doing funky stuff inside constructor
val log: Logging = new EventHandlerLogging(eventHandler, this)
protected[akka] val guardian: ActorRef =
provider.actorOf(guardianProps, guardianInChief, "ApplicationSupervisor", true)
protected[akka] val systemGuardian: ActorRef =
provider.actorOf(guardianProps.withCreator(new SystemGuardian), guardianInChief, "SystemSupervisor", true)
// TODO think about memory consistency effects when doing funky stuff inside constructor
val deadLetters = new DeadLetterActorRef(this)
val deathWatch = provider.createDeathWatch()
// chain death watchers so that killing guardian stops the application
deathWatch.subscribe(systemGuardian, guardian)
deathWatch.subscribe(guardianInChief, systemGuardian)
// this starts the reaper actor and the user-configured logging subscribers, which are also actors
mainbus.start(this)
mainbus.startDefaultLoggers(this, AkkaConfig)
// TODO think about memory consistency effects when doing funky stuff inside an ActorRefProvider's constructor
val deployer = new Deployer(this)
// TODO think about memory consistency effects when doing funky stuff inside constructor
val typedActor = new TypedActor(this)

View file

@ -13,7 +13,7 @@ import akka.remote.RemoteSupport
import akka.cluster.ClusterNode
import akka.japi.{ Creator, Procedure }
import akka.serialization.{ Serializer, Serialization }
import akka.event.EventHandler
import akka.event.Logging.Debug
import akka.experimental
import akka.{ AkkaApplication, AkkaException }
@ -154,6 +154,10 @@ object Timeout {
implicit def defaultTimeout(implicit app: AkkaApplication) = app.AkkaConfig.ActorTimeout
}
trait ActorLogging { this: Actor
val log = akka.event.Logging(app.mainbus, context.self)
}
object Actor {
type Receive = PartialFunction[Any, Unit]
@ -164,7 +168,7 @@ object Actor {
class LoggingReceive(source: AnyRef, r: Receive)(implicit app: AkkaApplication) extends Receive {
def isDefinedAt(o: Any) = {
val handled = r.isDefinedAt(o)
app.eventHandler.debug(source, "received " + (if (handled) "handled" else "unhandled") + " message " + o)
app.mainbus.publish(Debug(source, "received " + (if (handled) "handled" else "unhandled") + " message " + o))
handled
}
def apply(o: Any): Unit = r(o)
@ -410,7 +414,7 @@ trait Actor {
private[akka] final def apply(msg: Any) = {
def autoReceiveMessage(msg: AutoReceivedMessage) {
if (app.AkkaConfig.DebugAutoReceive) app.eventHandler.debug(this, "received AutoReceiveMessage " + msg)
if (app.AkkaConfig.DebugAutoReceive) app.mainbus.publish(Debug(this, "received AutoReceiveMessage " + msg))
msg match {
case HotSwap(code, discardOld) become(code(self), discardOld)

View file

@ -11,6 +11,7 @@ import scala.collection.immutable.{ Stack, TreeMap }
import scala.collection.JavaConverters
import java.util.concurrent.{ ScheduledFuture, TimeUnit }
import akka.AkkaApplication
import akka.event.Logging.{ Debug, Warning, Error }
/**
* The actor context - the view of the actor cell from the actor.
@ -21,6 +22,8 @@ private[akka] trait ActorContext extends ActorRefFactory with TypedActorFactory
def self: ActorRef with ScalaActorRef
def hasMessages: Boolean
def receiveTimeout: Option[Long]
def receiveTimeout_=(timeout: Option[Long]): Unit
@ -90,6 +93,8 @@ private[akka] class ActorCell(
@volatile //This must be volatile since it isn't protected by the mailbox status
var mailbox: Mailbox = _
def hasMessages: Boolean = mailbox.hasMessages
final def start(): Unit = {
mailbox = dispatcher.createMailbox(this)
@ -155,11 +160,11 @@ private[akka] class ActorCell(
actor = created
created.preStart()
checkReceiveTimeout
if (app.AkkaConfig.DebugLifecycle) app.eventHandler.debug(self, "started")
if (app.AkkaConfig.DebugLifecycle) app.mainbus.publish(Debug(self, "started (" + actor + ")"))
} catch {
case e
try {
app.eventHandler.error(e, self, "error while creating actor")
app.mainbus.publish(Error(e, self, "error while creating actor"))
// prevent any further messages to be processed until the actor has been restarted
dispatcher.suspend(this)
} finally {
@ -169,7 +174,7 @@ private[akka] class ActorCell(
def recreate(cause: Throwable): Unit = try {
val failedActor = actor
if (app.AkkaConfig.DebugLifecycle) app.eventHandler.debug(self, "restarting")
if (app.AkkaConfig.DebugLifecycle) app.mainbus.publish(Debug(self, "restarting"))
val freshActor = newActor()
if (failedActor ne null) {
val c = currentMessage //One read only plz
@ -183,14 +188,14 @@ private[akka] class ActorCell(
}
actor = freshActor // assign it here so if preStart fails, we can null out the sef-refs next call
freshActor.postRestart(cause)
if (app.AkkaConfig.DebugLifecycle) app.eventHandler.debug(self, "restarted")
if (app.AkkaConfig.DebugLifecycle) app.mainbus.publish(Debug(self, "restarted"))
dispatcher.resume(this) //FIXME should this be moved down?
props.faultHandler.handleSupervisorRestarted(cause, self, children)
} catch {
case e try {
app.eventHandler.error(e, self, "error while creating actor")
app.mainbus.publish(Error(e, self, "error while creating actor"))
// prevent any further messages to be processed until the actor has been restarted
dispatcher.suspend(this)
} finally {
@ -211,7 +216,7 @@ private[akka] class ActorCell(
try {
try {
val a = actor
if (app.AkkaConfig.DebugLifecycle) app.eventHandler.debug(self, "stopping")
if (app.AkkaConfig.DebugLifecycle) app.mainbus.publish(Debug(self, "stopping"))
if (a ne null) a.postStop()
} finally {
//Stop supervised actors
@ -236,8 +241,8 @@ private[akka] class ActorCell(
val links = _children
if (!links.contains(child)) {
_children = _children.updated(child, ChildRestartStats())
if (app.AkkaConfig.DebugLifecycle) app.eventHandler.debug(self, "now supervising " + child)
} else app.eventHandler.warning(self, "Already supervising " + child)
if (app.AkkaConfig.DebugLifecycle) app.mainbus.publish(Debug(self, "now supervising " + child))
} else app.mainbus.publish(Warning(self, "Already supervising " + child))
}
try {
@ -248,10 +253,10 @@ private[akka] class ActorCell(
case Recreate(cause) recreate(cause)
case Link(subject)
app.deathWatch.subscribe(self, subject)
if (app.AkkaConfig.DebugLifecycle) app.eventHandler.debug(self, "now monitoring " + subject)
if (app.AkkaConfig.DebugLifecycle) app.mainbus.publish(Debug(self, "now monitoring " + subject))
case Unlink(subject)
app.deathWatch.unsubscribe(self, subject)
if (app.AkkaConfig.DebugLifecycle) app.eventHandler.debug(self, "stopped monitoring " + subject)
if (app.AkkaConfig.DebugLifecycle) app.mainbus.publish(Debug(self, "stopped monitoring " + subject))
case Suspend() suspend()
case Resume() resume()
case Terminate() terminate()
@ -260,7 +265,7 @@ private[akka] class ActorCell(
}
} catch {
case e //Should we really catch everything here?
app.eventHandler.error(e, self, "error while processing " + message)
app.mainbus.publish(Error(e, self, "error while processing " + message))
//TODO FIXME How should problems here be handled?
throw e
}
@ -279,7 +284,7 @@ private[akka] class ActorCell(
currentMessage = null // reset current message after successful invocation
} catch {
case e
app.eventHandler.error(e, self, e.getMessage)
app.mainbus.publish(Error(e, self, e.getMessage))
// prevent any further messages to be processed until the actor has been restarted
dispatcher.suspend(this)
@ -299,7 +304,7 @@ private[akka] class ActorCell(
}
} catch {
case e
app.eventHandler.error(e, self, e.getMessage)
app.mainbus.publish(Error(e, self, e.getMessage))
throw e
}
}
@ -308,7 +313,7 @@ private[akka] class ActorCell(
final def handleFailure(fail: Failed): Unit = _children.get(fail.actor) match {
case Some(stats) if (!props.faultHandler.handleFailure(fail, stats, _children)) throw fail.cause
case None app.eventHandler.warning(self, "dropping " + fail + " from unknown child")
case None app.mainbus.publish(Warning(self, "dropping " + fail + " from unknown child"))
}
final def handleChildTerminated(child: ActorRef): Unit = {

View file

@ -347,6 +347,9 @@ trait MinimalActorRef extends ActorRef with ScalaActorRef {
protected[akka] def sendSystemMessage(message: SystemMessage) {}
protected[akka] def postMessageToMailbox(msg: Any, sender: ActorRef) {}
def ?(message: Any)(implicit timeout: Timeout): Future[Any] =
throw new UnsupportedOperationException("Not supported for %s".format(getClass.getName))
}
case class DeadLetter(message: Any, sender: ActorRef)
@ -367,10 +370,10 @@ class DeadLetterActorRef(val app: AkkaApplication) extends MinimalActorRef {
override def isShutdown(): Boolean = true
protected[akka] override def postMessageToMailbox(message: Any, sender: ActorRef): Unit =
app.eventHandler.notify(DeadLetter(message, sender))
app.mainbus.publish(DeadLetter(message, sender))
def ?(message: Any)(implicit timeout: Timeout): Future[Any] = {
app.eventHandler.notify(DeadLetter(message, this))
override def ?(message: Any)(implicit timeout: Timeout): Future[Any] = {
app.mainbus.publish(DeadLetter(message, this))
brokenPromise
}

View file

@ -11,7 +11,7 @@ import akka.AkkaApplication
import java.util.concurrent.ConcurrentHashMap
import com.eaio.uuid.UUID
import akka.AkkaException
import akka.event.{ ActorClassification, DeathWatch, EventHandler }
import akka.event.{ ActorClassification, DeathWatch, Logging }
import akka.dispatch._
/**
@ -100,6 +100,7 @@ class LocalActorRefProvider(val app: AkkaApplication) extends ActorRefProvider {
private[akka] val deployer: Deployer = new Deployer(app)
val terminationFuture = new DefaultPromise[AkkaApplication.ExitStatus](Timeout.never)(app.dispatcher)
val log = Logging(app.mainbus, this)
/**
* Top-level anchor for the supervision hierarchy of this actor system. Will
@ -121,14 +122,14 @@ class LocalActorRefProvider(val app: AkkaApplication) extends ActorRefProvider {
msg match {
case Failed(child, ex) child.stop()
case ChildTerminated(child) terminationFuture.completeWithResult(AkkaApplication.Stopped)
case _ app.eventHandler.error(this, this + " received unexpected message " + msg)
case _ log.error(this + " received unexpected message " + msg)
}
}
protected[akka] override def sendSystemMessage(message: SystemMessage) {
message match {
case Supervise(child) // TODO register child in some map to keep track of it and enable shutdown after all dead
case _ app.eventHandler.error(this, this + " received unexpected system message " + message)
case _ log.error(this + " received unexpected system message " + message)
}
}
}

View file

@ -8,7 +8,7 @@ import collection.immutable.Seq
import java.util.concurrent.ConcurrentHashMap
import akka.event.EventHandler
import akka.event.Logging
import akka.actor.DeploymentConfig._
import akka.{ AkkaException, AkkaApplication }
import akka.config.{ Configuration, ConfigurationException }
@ -35,6 +35,7 @@ trait ActorDeployer {
class Deployer(val app: AkkaApplication) extends ActorDeployer {
val deploymentConfig = new DeploymentConfig(app)
val log = Logging(app.mainbus, this)
val instance: ActorDeployer = {
val deployer = new LocalDeployer()
@ -307,13 +308,13 @@ class Deployer(val app: AkkaApplication) extends ActorDeployer {
private[akka] def throwDeploymentBoundException(deployment: Deploy): Nothing = {
val e = new DeploymentAlreadyBoundException("Address [" + deployment.address + "] already bound to [" + deployment + "]")
app.eventHandler.error(e, this, e.getMessage)
log.error(e, e.getMessage)
throw e
}
private[akka] def thrownNoDeploymentBoundException(address: String): Nothing = {
val e = new NoDeploymentBoundException("Address [" + address + "] is not bound to a deployment")
app.eventHandler.error(e, this, e.getMessage)
log.error(e, e.getMessage)
throw e
}
}

View file

@ -4,7 +4,7 @@
package akka.actor
import akka.util._
import akka.event.EventHandler
import akka.event.Logging
import scala.collection.mutable
import java.util.concurrent.ScheduledFuture
@ -190,6 +190,8 @@ trait FSM[S, D] extends ListenerManagement {
type Timeout = Option[Duration]
type TransitionHandler = PartialFunction[(S, S), Unit]
val log = Logging(app.mainbus, context.self)
/**
* ****************************************
* DSL
@ -421,7 +423,7 @@ trait FSM[S, D] extends ListenerManagement {
*/
private val handleEventDefault: StateFunction = {
case Event(value, stateData)
app.eventHandler.warning(context.self, "unhandled event " + value + " in state " + stateName)
log.warning("unhandled event " + value + " in state " + stateName)
stay
}
private var handleEvent: StateFunction = handleEventDefault
@ -534,8 +536,8 @@ trait FSM[S, D] extends ListenerManagement {
if (!currentState.stopReason.isDefined) {
val reason = nextState.stopReason.get
reason match {
case Failure(ex: Throwable) app.eventHandler.error(ex, context.self, "terminating due to Failure")
case Failure(msg) app.eventHandler.error(context.self, msg)
case Failure(ex: Throwable) log.error(ex, "terminating due to Failure")
case Failure(msg: AnyRef) log.error(msg.toString)
case _
}
val stopEvent = StopEvent(reason, currentState.stateName, currentState.stateData)
@ -584,13 +586,13 @@ trait LoggingFSM[S, D] extends FSM[S, D] { this: Actor ⇒
protected[akka] abstract override def setTimer(name: String, msg: Any, timeout: Duration, repeat: Boolean): State = {
if (debugEvent)
app.eventHandler.debug(context.self, "setting " + (if (repeat) "repeating " else "") + "timer '" + name + "'/" + timeout + ": " + msg)
log.debug("setting " + (if (repeat) "repeating " else "") + "timer '" + name + "'/" + timeout + ": " + msg)
super.setTimer(name, msg, timeout, repeat)
}
protected[akka] abstract override def cancelTimer(name: String) = {
if (debugEvent)
app.eventHandler.debug(context.self, "canceling timer '" + name + "'")
log.debug("canceling timer '" + name + "'")
super.cancelTimer(name)
}
@ -602,7 +604,7 @@ trait LoggingFSM[S, D] extends FSM[S, D] { this: Actor ⇒
case a: ActorRef a.toString
case _ "unknown"
}
app.eventHandler.debug(context.self, "processing " + event + " from " + srcstr)
log.debug("processing " + event + " from " + srcstr)
}
if (logDepth > 0) {
@ -616,7 +618,7 @@ trait LoggingFSM[S, D] extends FSM[S, D] { this: Actor ⇒
val newState = stateName
if (debugEvent && oldState != newState)
app.eventHandler.debug(context.self, "transition " + oldState + " -> " + newState)
log.debug("transition " + oldState + " -> " + newState)
}
/**

View file

@ -5,7 +5,6 @@ package akka.actor
import akka.util.ByteString
import akka.dispatch.Envelope
import akka.event.EventHandler
import java.net.InetSocketAddress
import java.io.IOException
import java.util.concurrent.atomic.AtomicReference

View file

@ -130,7 +130,7 @@ class DefaultScheduler extends Scheduler {
}
}
private[akka] def shutdown() { service.shutdown() }
private[akka] def shutdown() { service.shutdownNow() }
}
private object SchedulerThreadFactory extends ThreadFactory {

View file

@ -6,7 +6,7 @@ package akka.dispatch
import java.util.concurrent._
import java.util.concurrent.atomic.AtomicLong
import akka.event.EventHandler
import akka.event.Logging.Error
import akka.config.Configuration
import akka.util.{ Duration, Switch, ReentrantGuard }
import java.util.concurrent.ThreadPoolExecutor.{ AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy, DiscardPolicy }
@ -66,7 +66,7 @@ final case class TaskInvocation(app: AkkaApplication, function: () ⇒ Unit, cle
try {
function()
} catch {
case e app.eventHandler.error(e, this, e.getMessage)
case e app.mainbus.publish(Error(e, this, e.getMessage))
} finally {
cleanup()
}

View file

@ -37,7 +37,18 @@ class BalancingDispatcher(
_timeoutMs: Long)
extends Dispatcher(_app, _name, throughput, throughputDeadlineTime, mailboxType, config, _timeoutMs) {
private val buddies = new ConcurrentSkipListSet[ActorCell](new Comparator[ActorCell] { def compare(a: ActorCell, b: ActorCell) = System.identityHashCode(a) - System.identityHashCode(b) }) //new ConcurrentLinkedQueue[ActorCell]()
private val buddies = new ConcurrentSkipListSet[ActorCell](
new Comparator[ActorCell] {
def compare(a: ActorCell, b: ActorCell): Int = {
/*
* make sure that there is no overflow or underflow in comparisons, so
* that the ordering is actually consistent and you cannot have a
* sequence which cyclically is monotone without end.
*/
val diff = ((System.identityHashCode(a) & 0xffffffffL) - (System.identityHashCode(b) & 0xffffffffL))
if (diff > 0) 1 else if (diff < 0) -1 else 0
}
})
protected val messageQueue: MessageQueue = mailboxType match {
case u: UnboundedMailbox new QueueBasedMessageQueue with UnboundedMessageQueueSemantics {

View file

@ -4,7 +4,7 @@
package akka.dispatch
import akka.event.EventHandler
import akka.event.Logging.Warning
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.{ TimeUnit, ExecutorService, RejectedExecutionException, ConcurrentLinkedQueue }
import akka.actor.{ ActorCell, ActorKilledException }
@ -93,7 +93,7 @@ class Dispatcher(
executorService.get() execute invocation
} catch {
case e: RejectedExecutionException
app.eventHandler.warning(this, e.toString)
app.mainbus.publish(Warning(this, e.toString))
throw e
}
}
@ -105,7 +105,7 @@ class Dispatcher(
protected[akka] def shutdown {
val old = executorService.getAndSet(new LazyExecutorServiceWrapper(executorServiceFactory.createExecutorService))
if (old ne null)
old.shutdown()
old.shutdownNow()
}
/**
@ -120,7 +120,7 @@ class Dispatcher(
} catch {
case e: RejectedExecutionException
try {
app.eventHandler.warning(this, e.toString)
app.mainbus.publish(Warning(this, e.toString))
} finally {
mbox.setAsIdle()
}

View file

@ -6,8 +6,8 @@
package akka.dispatch
import akka.AkkaException
import akka.event.EventHandler
import akka.actor.{ Timeout }
import akka.event.Logging.Error
import akka.actor.Timeout
import scala.Option
import akka.japi.{ Procedure, Function JFunc, Option JOption }
@ -262,7 +262,7 @@ object Future {
result completeWithResult currentValue
} catch {
case e: Exception
dispatcher.app.eventHandler.error(e, this, e.getMessage)
dispatcher.app.mainbus.publish(Error(e, this, e.getMessage))
result completeWithException e
} finally {
results.clear
@ -631,7 +631,7 @@ sealed trait Future[+T] extends japi.Future[T] {
Right(f(res))
} catch {
case e: Exception
dispatcher.app.eventHandler.error(e, this, e.getMessage)
dispatcher.app.mainbus.publish(Error(e, this, e.getMessage))
Left(e)
})
}
@ -683,7 +683,7 @@ sealed trait Future[+T] extends japi.Future[T] {
future.completeWith(f(r))
} catch {
case e: Exception
dispatcher.app.eventHandler.error(e, this, e.getMessage)
dispatcher.app.mainbus.publish(Error(e, this, e.getMessage))
future complete Left(e)
}
}
@ -716,7 +716,7 @@ sealed trait Future[+T] extends japi.Future[T] {
if (p(res)) r else Left(new MatchError(res))
} catch {
case e: Exception
dispatcher.app.eventHandler.error(e, this, e.getMessage)
dispatcher.app.mainbus.publish(Error(e, this, e.getMessage))
Left(e)
})
}
@ -811,7 +811,7 @@ trait Promise[T] extends Future[T] {
fr completeWith cont(f)
} catch {
case e: Exception
dispatcher.app.eventHandler.error(e, this, e.getMessage)
dispatcher.app.mainbus.publish(Error(e, this, e.getMessage))
fr completeWithException e
}
}
@ -825,7 +825,7 @@ trait Promise[T] extends Future[T] {
fr completeWith cont(f)
} catch {
case e: Exception
dispatcher.app.eventHandler.error(e, this, e.getMessage)
dispatcher.app.mainbus.publish(Error(e, this, e.getMessage))
fr completeWithException e
}
}
@ -1017,7 +1017,7 @@ class DefaultPromise[T](val timeout: Timeout)(implicit val dispatcher: MessageDi
} else this
private def notifyCompleted(func: Future[T] Unit) {
try { func(this) } catch { case e dispatcher.app.eventHandler.error(e, this, "Future onComplete-callback raised an exception") } //TODO catch, everything? Really?
try { func(this) } catch { case e dispatcher.app.mainbus.publish(Error(e, this, "Future onComplete-callback raised an exception")) } //TODO catch, everything? Really?
}
@inline

View file

@ -1,7 +1,6 @@
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.dispatch
import akka.AkkaException
@ -12,6 +11,7 @@ import akka.actor.{ ActorContext, ActorCell }
import java.util.concurrent._
import atomic.{ AtomicInteger, AtomicReferenceFieldUpdater }
import annotation.tailrec
import akka.event.Logging.Error
class MessageQueueAppendFailedException(message: String, cause: Throwable = null) extends AkkaException(message, cause)
@ -205,7 +205,7 @@ abstract class Mailbox(val actor: ActorCell) extends AbstractMailbox with Messag
}
} catch {
case e
actor.app.eventHandler.error(e, this, "exception during processing system messages, dropping " + SystemMessage.size(nextMessage) + " messages!")
actor.app.mainbus.publish(Error(e, this, "exception during processing system messages, dropping " + SystemMessage.size(nextMessage) + " messages!"))
throw e
}
}

View file

@ -9,7 +9,7 @@ import java.util.concurrent._
import atomic.{ AtomicLong, AtomicInteger }
import ThreadPoolExecutor.CallerRunsPolicy
import akka.util.Duration
import akka.event.EventHandler
import akka.event.Logging.{ Warning, Error }
import akka.AkkaApplication
object ThreadPoolConfig {
@ -227,10 +227,10 @@ class BoundedExecutorDecorator(val app: AkkaApplication, val executor: ExecutorS
})
} catch {
case e: RejectedExecutionException
app.eventHandler.warning(this, e.toString)
app.mainbus.publish(Warning(this, e.toString))
semaphore.release
case e: Throwable
app.eventHandler.error(e, this, e.getMessage)
app.mainbus.publish(Error(e, this, e.getMessage))
throw e
}
}

View file

@ -48,6 +48,7 @@ trait EventBus {
*/
trait ActorEventBus extends EventBus {
type Subscriber = ActorRef
protected def compareSubscribers(a: ActorRef, b: ActorRef) = a compareTo b
}
/**
@ -254,9 +255,9 @@ trait ActorClassification { self: ActorEventBus with ActorClassifier ⇒
*/
protected def mapSize: Int
def publish(event: Event): Unit = mappings.get(classify(event)) match {
case null
case raw: Vector[_] raw.asInstanceOf[Vector[ActorRef]] foreach { _ ! event }
def publish(event: Event): Unit = {
val receivers = mappings.get(classify(event))
if (receivers ne null) receivers foreach { _ ! event }
}
def subscribe(subscriber: Subscriber, to: Classifier): Boolean = associate(to, subscriber)

View file

@ -1,296 +0,0 @@
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.event
import akka.actor._
import akka.dispatch.Dispatchers
import akka.config.ConfigurationException
import akka.util.{ ListenerManagement, ReflectiveAccess }
import akka.serialization._
import akka.AkkaException
import akka.AkkaApplication
object EventHandler {
val ErrorLevel = 1
val WarningLevel = 2
val InfoLevel = 3
val DebugLevel = 4
val errorFormat = "[ERROR] [%s] [%s] [%s] %s\n%s".intern
val warningFormat = "[WARN] [%s] [%s] [%s] %s".intern
val infoFormat = "[INFO] [%s] [%s] [%s] %s".intern
val debugFormat = "[DEBUG] [%s] [%s] [%s] %s".intern
val genericFormat = "[GENERIC] [%s] [%s]".intern
class EventHandlerException extends AkkaException
lazy val StandardOutLogger = new StandardOutLogger {}
sealed trait Event {
@transient
val thread: Thread = Thread.currentThread
def level: Int
}
case class Error(cause: Throwable, instance: AnyRef, message: Any = "") extends Event {
def level = ErrorLevel
}
case class Warning(instance: AnyRef, message: Any = "") extends Event {
def level = WarningLevel
}
case class Info(instance: AnyRef, message: Any = "") extends Event {
def level = InfoLevel
}
case class Debug(instance: AnyRef, message: Any = "") extends Event {
def level = DebugLevel
}
trait StandardOutLogger {
import java.text.SimpleDateFormat
import java.util.Date
val dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.S")
def timestamp = dateFormat.format(new Date)
def print(event: Any) {
event match {
case e: Error error(e)
case e: Warning warning(e)
case e: Info info(e)
case e: Debug debug(e)
case e generic(e)
}
}
def error(event: Error) =
println(errorFormat.format(
timestamp,
event.thread.getName,
instanceName(event.instance),
event.message,
stackTraceFor(event.cause)))
def warning(event: Warning) =
println(warningFormat.format(
timestamp,
event.thread.getName,
instanceName(event.instance),
event.message))
def info(event: Info) =
println(infoFormat.format(
timestamp,
event.thread.getName,
instanceName(event.instance),
event.message))
def debug(event: Debug) =
println(debugFormat.format(
timestamp,
event.thread.getName,
instanceName(event.instance),
event.message))
def generic(event: Any) =
println(genericFormat.format(timestamp, event.toString))
def instanceName(instance: AnyRef): String = instance match {
case null "NULL"
case a: ActorRef a.address
case _ simpleName(instance)
}
}
class DefaultListener extends Actor with StandardOutLogger {
def receive = { case event print(event) }
}
def stackTraceFor(e: Throwable) = {
import java.io.{ StringWriter, PrintWriter }
val sw = new StringWriter
val pw = new PrintWriter(sw)
e.printStackTrace(pw)
sw.toString
}
private def levelFor(eventClass: Class[_ <: Event]) = {
if (classOf[Error].isAssignableFrom(eventClass)) ErrorLevel
else if (classOf[Warning].isAssignableFrom(eventClass)) WarningLevel
else if (classOf[Info].isAssignableFrom(eventClass)) InfoLevel
else if (classOf[Debug].isAssignableFrom(eventClass)) DebugLevel
else DebugLevel
}
}
/**
* Event handler.
* <p/>
* Create, add and remove a listener:
* <pre>
* val eventHandlerListener = Actor.actorOf(new Actor {
* self.dispatcher = EventHandler.EventHandlerDispatcher
*
* def receive = {
* case EventHandler.Error(cause, instance, message) ...
* case EventHandler.Warning(instance, message) ...
* case EventHandler.Info(instance, message) ...
* case EventHandler.Debug(instance, message) ...
* case genericEvent ...
* }
* })
*
* EventHandler.addListener(eventHandlerListener)
* ...
* EventHandler.removeListener(eventHandlerListener)
* </pre>
* <p/>
* However best is probably to register the listener in the 'akka.conf'
* configuration file.
* <p/>
* Log an error event:
* <pre>
* EventHandler.notify(EventHandler.Error(exception, this, message))
* </pre>
* Or use the direct methods (better performance):
* <pre>
* EventHandler.error(exception, this, message)
* </pre>
*
* Shut down the EventHandler:
* <pre>
* EventHandler.shutdown()
* </pre>
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
class EventHandler(app: AkkaApplication) extends ListenerManagement {
import EventHandler._
val synchronousLogging: Boolean = System.getProperty("akka.event.force-sync") match {
case null | "" false
case _ true
}
lazy val EventHandlerDispatcher =
app.dispatcherFactory.fromConfig("akka.event-handler-dispatcher", app.dispatcherFactory.newDispatcher("event-handler-dispatcher").setCorePoolSize(2).build)
implicit object defaultListenerFormat extends StatelessActorFormat[DefaultListener]
@volatile
var level: Int = app.AkkaConfig.LogLevel match {
case "ERROR" | "error" ErrorLevel
case "WARNING" | "warning" WarningLevel
case "INFO" | "info" InfoLevel
case "DEBUG" | "debug" DebugLevel
case unknown throw new ConfigurationException(
"Configuration option 'akka.event-handler-level' is invalid [" + unknown + "]")
}
def start() {
try {
val defaultListeners = app.AkkaConfig.EventHandlers match {
case Nil "akka.event.EventHandler$DefaultListener" :: Nil
case listeners listeners
}
defaultListeners foreach { listenerName
try {
ReflectiveAccess.getClassFor[Actor](listenerName) match {
case Right(actorClass) addListener(new LocalActorRef(app, Props(actorClass).withDispatcher(EventHandlerDispatcher), app.guardian, Props.randomAddress, systemService = true))
case Left(exception) throw exception
}
} catch {
case e: Exception
throw new ConfigurationException(
"Event Handler specified in config can't be loaded [" + listenerName +
"] due to [" + e.toString + "]", e)
}
}
info(this, "Starting up EventHandler")
} catch {
case e: Exception
System.err.println("error while starting up EventHandler")
e.printStackTrace()
throw new ConfigurationException("Could not start Event Handler due to [" + e.toString + "]")
}
}
/**
* Shuts down all event handler listeners including the event handle dispatcher.
*/
def shutdown() {
foreachListener { l
removeListener(l)
l.stop()
}
}
def notify(event: Any) {
if (event.isInstanceOf[Event]) {
if (level >= event.asInstanceOf[Event].level) log(event)
} else log(event)
}
def notify[T <: Event: ClassManifest](event: T) {
if (level >= levelFor(classManifest[T].erasure.asInstanceOf[Class[_ <: Event]])) log(event)
}
def error(cause: Throwable, instance: AnyRef, message: String) {
if (level >= ErrorLevel) log(Error(cause, instance, message))
}
def error(cause: Throwable, instance: AnyRef, message: Any) {
if (level >= ErrorLevel) log(Error(cause, instance, message))
}
def error(instance: AnyRef, message: String) {
if (level >= ErrorLevel) log(Error(new EventHandlerException, instance, message))
}
def error(instance: AnyRef, message: Any) {
if (level >= ErrorLevel) log(Error(new EventHandlerException, instance, message))
}
def warning(instance: AnyRef, message: String) {
if (level >= WarningLevel) log(Warning(instance, message))
}
def warning(instance: AnyRef, message: Any) {
if (level >= WarningLevel) log(Warning(instance, message))
}
def info(instance: AnyRef, message: String) {
if (level >= InfoLevel) log(Info(instance, message))
}
def info(instance: AnyRef, message: Any) {
if (level >= InfoLevel) log(Info(instance, message))
}
def debug(instance: AnyRef, message: String) {
if (level >= DebugLevel) log(Debug(instance, message))
}
def debug(instance: AnyRef, message: Any) {
if (level >= DebugLevel) log(Debug(instance, message))
}
def isInfoEnabled = level >= InfoLevel
def isDebugEnabled = level >= DebugLevel
private def log(event: Any) {
if (synchronousLogging) StandardOutLogger.print(event)
else notifyListeners(event)
}
start()
}

View file

@ -2,13 +2,396 @@
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.event
import akka.actor.Actor
import akka.actor.{ Actor, ActorRef, MinimalActorRef, LocalActorRef, Props }
import akka.{ AkkaException, AkkaApplication }
import akka.AkkaApplication.AkkaConfig
import akka.util.ReflectiveAccess
import akka.config.ConfigurationException
import akka.util.ReentrantGuard
/**
* This trait brings log level handling to the MainBus: it reads the log
* levels for the initial logging (StandardOutLogger) and the loggers&level
* for after-init logging, possibly keeping the StandardOutLogger enabled if
* it is part of the configured loggers. All configured loggers are treated as
* system services and managed by this trait, i.e. subscribed/unsubscribed in
* response to changes of LoggingBus.logLevel.
*/
trait LoggingBus extends ActorEventBus {
type Event >: Logging.LogEvent
type Classifier >: Class[_]
import Logging._
private val guard = new ReentrantGuard
private var loggers = Seq.empty[ActorRef]
private var _logLevel: LogLevel = _
/**
* Query currently set log level. See object Logging for more information.
*/
def logLevel = guard.withGuard { _logLevel }
/**
* Change log level: default loggers (i.e. from configuration file) are
* subscribed/unsubscribed as necessary so that they listen to all levels
* which are at least as severe as the given one. See object Logging for
* more information.
*
* NOTE: if the StandardOutLogger is configured also as normal logger, it
* will not participate in the automatic management of log level
* subscriptions!
*/
def logLevel_=(level: LogLevel): Unit = guard.withGuard {
for {
l AllLogLevels
// subscribe if previously ignored and now requested
if l > _logLevel && l <= level
log loggers
} subscribe(log, classFor(l))
for {
l AllLogLevels
// unsubscribe if previously registered and now ignored
if l <= _logLevel && l > level
log loggers
} unsubscribe(log, classFor(l))
_logLevel = level
}
private[akka] def startStdoutLogger(config: AkkaConfig) {
val level = levelFor(config.StdoutLogLevel) getOrElse {
StandardOutLogger.print(Error(new EventHandlerException, this, "unknown akka.stdout-loglevel " + config.StdoutLogLevel))
ErrorLevel
}
AllLogLevels filter (level >= _) foreach (l subscribe(StandardOutLogger, classFor(l)))
guard.withGuard {
loggers = Seq(StandardOutLogger)
_logLevel = level
}
publish(Info(this, "StandardOutLogger started"))
}
private[akka] def startDefaultLoggers(app: AkkaApplication, config: AkkaConfig) {
val level = levelFor(config.LogLevel) getOrElse {
StandardOutLogger.print(Error(new EventHandlerException, this, "unknown akka.stdout-loglevel " + config.LogLevel))
ErrorLevel
}
try {
val defaultLoggers = config.EventHandlers match {
case Nil "akka.event.Logging$DefaultLogger" :: Nil
case loggers loggers
}
val myloggers = for {
loggerName defaultLoggers
if loggerName != StandardOutLoggerName
} yield {
try {
ReflectiveAccess.getClassFor[Actor](loggerName) match {
case Right(actorClass) addLogger(app, actorClass, level)
case Left(exception) throw exception
}
} catch {
case e: Exception
throw new ConfigurationException(
"Event Handler specified in config can't be loaded [" + loggerName +
"] due to [" + e.toString + "]", e)
}
}
guard.withGuard {
loggers = myloggers
_logLevel = level
}
publish(Info(this, "Default Loggers started"))
if (!(defaultLoggers contains StandardOutLoggerName)) {
unsubscribe(StandardOutLogger)
}
} catch {
case e: Exception
System.err.println("error while starting up EventHandler")
e.printStackTrace()
throw new ConfigurationException("Could not start Event Handler due to [" + e.toString + "]")
}
}
private[akka] def stopDefaultLoggers() {
val level = _logLevel // volatile access before reading loggers
if (!(loggers contains StandardOutLogger)) {
AllLogLevels filter (level >= _) foreach (l subscribe(StandardOutLogger, classFor(l)))
publish(Info(this, "shutting down: StandardOutLogger started"))
}
for {
logger loggers
if logger != StandardOutLogger
} logger.stop()
publish(Info(this, "all default loggers stopped"))
}
private def addLogger(app: AkkaApplication, clazz: Class[_ <: Actor], level: LogLevel): ActorRef = {
val actor = app.systemActorOf(Props(clazz), Props.randomAddress)
actor ! InitializeLogger(this)
AllLogLevels filter (level >= _) foreach (l subscribe(actor, classFor(l)))
publish(Info(this, "logger " + clazz.getName + " started"))
actor
}
}
/**
* Main entry point for Akka logging: log levels and message types (aka
* channels) defined for the main transport medium, the main event bus. The
* recommended use is to obtain an implementation of the Logging trait with
* suitable and efficient methods for generating log events:
*
* <pre><code>
* val log = Logging(&lt;bus&gt;, &lt;source object&gt;)
* ...
* log.info("hello world!")
* </code></pre>
*
* Loggers are attached to the level-specific channels <code>Error</code>,
* <code>Warning</code>, <code>Info</code> and <code>Debug</code> as
* appropriate for the configured (or set) log level. If you want to implement
* your own, make sure to handle these four event types plus the <code>InitializeLogger</code>
* message which is sent before actually attaching it to the logging bus.
*
* Logging is configured in <code>akka.conf</code> by setting (some of) the following:
*
* <pre><code>
* akka {
* event-handlers = ["akka.slf4j.Slf4jEventHandler"] # for example
* loglevel = "INFO" # used when normal logging ("event-handlers") has been started
* stdout-loglevel = "WARN" # used during application start-up until normal logging is available
* }
* </code></pre>
*/
object Logging {
/**
* Marker trait for annotating LogLevel, which must be Int after erasure.
*/
trait LogLevelType
/**
* Log level in numeric form, used when deciding whether a certain log
* statement should generate a log event. Predefined levels are ErrorLevel (1)
* to DebugLevel (4). In case you want to add more levels, loggers need to
* be subscribed to their event bus channels manually.
*/
type LogLevel = Int with LogLevelType
final val ErrorLevel = 1.asInstanceOf[Int with LogLevelType]
final val WarningLevel = 2.asInstanceOf[Int with LogLevelType]
final val InfoLevel = 3.asInstanceOf[Int with LogLevelType]
final val DebugLevel = 4.asInstanceOf[Int with LogLevelType]
def levelFor(s: String): Option[LogLevel] = s match {
case "ERROR" | "error" Some(ErrorLevel)
case "WARNING" | "warning" Some(WarningLevel)
case "INFO" | "info" Some(InfoLevel)
case "DEBUG" | "debug" Some(DebugLevel)
case unknown None
}
def levelFor(eventClass: Class[_ <: LogEvent]) = {
if (classOf[Error].isAssignableFrom(eventClass)) ErrorLevel
else if (classOf[Warning].isAssignableFrom(eventClass)) WarningLevel
else if (classOf[Info].isAssignableFrom(eventClass)) InfoLevel
else if (classOf[Debug].isAssignableFrom(eventClass)) DebugLevel
else DebugLevel
}
def classFor(level: LogLevel): Class[_ <: LogEvent] = level match {
case ErrorLevel classOf[Error]
case WarningLevel classOf[Warning]
case InfoLevel classOf[Info]
case DebugLevel classOf[Debug]
}
// these type ascriptions/casts are necessary to avoid CCEs during construction while retaining correct type
val AllLogLevels = Seq(ErrorLevel: AnyRef, WarningLevel, InfoLevel, DebugLevel).asInstanceOf[Seq[LogLevel]]
val errorFormat = "[ERROR] [%s] [%s] [%s] %s\n%s".intern
val warningFormat = "[WARN] [%s] [%s] [%s] %s".intern
val infoFormat = "[INFO] [%s] [%s] [%s] %s".intern
val debugFormat = "[DEBUG] [%s] [%s] [%s] %s".intern
val genericFormat = "[GENERIC] [%s] [%s]".intern
/**
* Obtain LoggingAdapter for the given application and source object. The
* source object is used to identify the source of this logging channel.
*/
def apply(app: AkkaApplication, source: AnyRef): LoggingAdapter = new BusLogging(app.mainbus, source)
/**
* Java API: Obtain LoggingAdapter for the given application and source object. The
* source object is used to identify the source of this logging channel.
*/
def getLogger(app: AkkaApplication, source: AnyRef): LoggingAdapter = apply(app, source)
/**
* Obtain LoggingAdapter for the given event bus and source object. The
* source object is used to identify the source of this logging channel.
*/
def apply(bus: LoggingBus, source: AnyRef): LoggingAdapter = new BusLogging(bus, source)
/**
* Java API: Obtain LoggingAdapter for the given event bus and source object. The
* source object is used to identify the source of this logging channel.
*/
def getLogger(bus: LoggingBus, source: AnyRef): LoggingAdapter = apply(bus, source)
/**
* Artificial exception injected into Error events if no Throwable is
* supplied; used for getting a stack dump of error locations.
*/
class EventHandlerException extends AkkaException
sealed trait LogEvent {
@transient
val thread: Thread = Thread.currentThread
def level: LogLevel
}
case class Error(cause: Throwable, instance: AnyRef, message: Any = "") extends LogEvent {
def level = ErrorLevel
}
object Error {
def apply(instance: AnyRef, message: Any) = new Error(new EventHandlerException, instance, message)
}
case class Warning(instance: AnyRef, message: Any = "") extends LogEvent {
def level = WarningLevel
}
case class Info(instance: AnyRef, message: Any = "") extends LogEvent {
def level = InfoLevel
}
case class Debug(instance: AnyRef, message: Any = "") extends LogEvent {
def level = DebugLevel
}
/**
* Message which is sent to each default logger (i.e. from configuration file)
* after its creation but before attaching it to the logging bus. The logger
* actor should handle this message, e.g. to register for more channels.
*/
case class InitializeLogger(bus: LoggingBus)
trait StdOutLogger {
import java.text.SimpleDateFormat
import java.util.Date
val dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.S")
def timestamp = dateFormat.format(new Date)
def print(event: Any) {
event match {
case e: Error error(e)
case e: Warning warning(e)
case e: Info info(e)
case e: Debug debug(e)
case e generic(e)
}
}
def error(event: Error) =
println(errorFormat.format(
timestamp,
event.thread.getName,
instanceName(event.instance),
event.message,
stackTraceFor(event.cause)))
def warning(event: Warning) =
println(warningFormat.format(
timestamp,
event.thread.getName,
instanceName(event.instance),
event.message))
def info(event: Info) =
println(infoFormat.format(
timestamp,
event.thread.getName,
instanceName(event.instance),
event.message))
def debug(event: Debug) =
println(debugFormat.format(
timestamp,
event.thread.getName,
instanceName(event.instance),
event.message))
def generic(event: Any) =
println(genericFormat.format(timestamp, event.toString))
def instanceName(instance: AnyRef): String = instance match {
case null "NULL"
case a: ActorRef a.address
case _ instance.getClass.getSimpleName
}
}
/**
* Actor-less logging implementation for synchronous logging to standard
* output. This logger is always attached first in order to be able to log
* failures during application start-up, even before normal logging is
* started. Its log level can be configured by setting
* <code>akka.stdout-loglevel</code> in <code>akka.conf</code>.
*/
class StandardOutLogger extends MinimalActorRef with StdOutLogger {
override val toString = "StandardOutLogger"
override def postMessageToMailbox(obj: Any, sender: ActorRef) { print(obj) }
}
val StandardOutLogger = new StandardOutLogger
val StandardOutLoggerName = StandardOutLogger.getClass.getName
/**
* Actor wrapper around the standard output logger. If
* <code>akka.event-handlers</code> is not set, it defaults to just this
* logger.
*/
class DefaultLogger extends Actor with StdOutLogger {
def receive = {
case InitializeLogger(_)
case event: LogEvent print(event)
}
}
def stackTraceFor(e: Throwable) = {
if (e ne null) {
import java.io.{ StringWriter, PrintWriter }
val sw = new StringWriter
val pw = new PrintWriter(sw)
e.printStackTrace(pw)
sw.toString
} else {
"[NO STACK TRACE]"
}
}
}
/**
* Logging wrapper to make nicer and optimize: provide template versions which
* evaluate .toString only if the log level is actually enabled.
* evaluate .toString only if the log level is actually enabled. Typically used
* by obtaining an implementation from the Logging object:
*
* <code><pre>
* val log = Logging(&lt;bus&gt;, &lt;source object&gt;)
* ...
* log.info("hello world!")
* </pre></code>
*
* All log-level methods support simple interpolation templates with up to four
* arguments placed by using <code>{}</code> within the template (first string
* argument):
*
* <code><pre>
* log.error(exception, "Exception while processing {} in state {}", msg, state)
* </pre></code>
*/
trait Logging {
trait LoggingAdapter {
/*
* implement these as precisely as needed/possible: always returning true
@ -23,6 +406,7 @@ trait Logging {
* These actually implement the passing on of the messages to be logged.
* Will not be called if is...Enabled returned false.
*/
protected def notifyError(message: String)
protected def notifyError(cause: Throwable, message: String)
protected def notifyWarning(message: String)
protected def notifyInfo(message: String)
@ -38,7 +422,7 @@ trait Logging {
def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any) { if (isErrorEnabled) error(cause, format(template, arg1, arg2, arg3)) }
def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isErrorEnabled) error(cause, format(template, arg1, arg2, arg3, arg4)) }
def error(message: String) { if (isErrorEnabled) error(null: Throwable, message) }
def error(message: String) { if (isErrorEnabled) notifyError(message) }
def error(template: String, arg1: Any) { if (isErrorEnabled) error(format(template, arg1)) }
def error(template: String, arg1: Any, arg2: Any) { if (isErrorEnabled) error(format(template, arg1, arg2)) }
def error(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isErrorEnabled) error(format(template, arg1, arg2, arg3)) }
@ -62,47 +446,39 @@ trait Logging {
def debug(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isDebugEnabled) debug(format(template, arg1, arg2, arg3)) }
def debug(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isDebugEnabled) debug(format(template, arg1, arg2, arg3, arg4)) }
def format(t: String, arg1: Any) = t.replaceFirst("{}", arg1.asInstanceOf[AnyRef].toString)
def format(t: String, arg1: Any, arg2: Any) = t.replaceFirst("{}", arg1.asInstanceOf[AnyRef].toString).replaceFirst("{}", arg2.asInstanceOf[AnyRef].toString)
def format(t: String, arg1: Any, arg2: Any, arg3: Any) = t.replaceFirst("{}", arg1.asInstanceOf[AnyRef].toString).replaceFirst("{}", arg2.asInstanceOf[AnyRef].toString).replaceFirst("{}", arg3.asInstanceOf[AnyRef].toString)
def format(t: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) = t.replaceFirst("{}", arg1.asInstanceOf[AnyRef].toString).replaceFirst("{}", arg2.asInstanceOf[AnyRef].toString).replaceFirst("{}", arg3.asInstanceOf[AnyRef].toString).replaceFirst("{}", arg4.asInstanceOf[AnyRef].toString)
def format(t: String, arg: Any*) = {
val sb = new StringBuilder
var p = 0
var rest = t
while (p < arg.length) {
val index = rest.indexOf("{}")
sb.append(rest.substring(0, index))
sb.append(arg(p))
rest = rest.substring(index + 2)
p += 1
}
sb.append(rest)
sb.toString
}
}
trait ActorLogging extends Logging { this: Actor
class BusLogging(val bus: LoggingBus, val loggingInstance: AnyRef) extends LoggingAdapter {
import EventHandler._
import Logging._
def isErrorEnabled = app.eventHandler.level >= ErrorLevel
def isWarningEnabled = app.eventHandler.level >= WarningLevel
def isInfoEnabled = app.eventHandler.level >= InfoLevel
def isDebugEnabled = app.eventHandler.level >= DebugLevel
def isErrorEnabled = bus.logLevel >= ErrorLevel
def isWarningEnabled = bus.logLevel >= WarningLevel
def isInfoEnabled = bus.logLevel >= InfoLevel
def isDebugEnabled = bus.logLevel >= DebugLevel
protected def notifyError(cause: Throwable, message: String) { app.eventHandler.notifyListeners(Error(cause, context.self, message)) }
protected def notifyError(message: String) { bus.publish(Error(loggingInstance, message)) }
protected def notifyWarning(message: String) { app.eventHandler.notifyListeners(Warning(context.self, message)) }
protected def notifyError(cause: Throwable, message: String) { bus.publish(Error(cause, loggingInstance, message)) }
protected def notifyInfo(message: String) { app.eventHandler.notifyListeners(Info(context.self, message)) }
protected def notifyWarning(message: String) { bus.publish(Warning(loggingInstance, message)) }
protected def notifyDebug(message: String) { app.eventHandler.notifyListeners(Debug(context.self, message)) }
}
class EventHandlerLogging(val eventHandler: EventHandler, val loggingInstance: AnyRef) extends Logging {
import EventHandler._
def isErrorEnabled = eventHandler.level >= ErrorLevel
def isWarningEnabled = eventHandler.level >= WarningLevel
def isInfoEnabled = eventHandler.level >= InfoLevel
def isDebugEnabled = eventHandler.level >= DebugLevel
protected def notifyError(cause: Throwable, message: String) { eventHandler.notifyListeners(Error(cause, loggingInstance, message)) }
protected def notifyWarning(message: String) { eventHandler.notifyListeners(Warning(loggingInstance, message)) }
protected def notifyInfo(message: String) { eventHandler.notifyListeners(Info(loggingInstance, message)) }
protected def notifyDebug(message: String) { eventHandler.notifyListeners(Debug(loggingInstance, message)) }
protected def notifyInfo(message: String) { bus.publish(Info(loggingInstance, message)) }
protected def notifyDebug(message: String) { bus.publish(Debug(loggingInstance, message)) }
}

View file

@ -0,0 +1,56 @@
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.event
import akka.actor.{ ActorRef, Actor, Props }
import akka.AkkaApplication
import akka.actor.Terminated
class MainBus(debug: Boolean = false) extends LoggingBus with LookupClassification {
type Event = AnyRef
type Classifier = Class[_]
@volatile
private var reaper: ActorRef = _
protected def mapSize = 16
protected def classify(event: AnyRef): Class[_] = event.getClass
protected def publish(event: AnyRef, subscriber: ActorRef) = subscriber ! event
override def subscribe(subscriber: ActorRef, channel: Class[_]): Boolean = {
if (debug) publish(Logging.Debug(this, "subscribing " + subscriber + " to channel " + channel))
if (reaper ne null) reaper ! subscriber
super.subscribe(subscriber, channel)
}
override def unsubscribe(subscriber: ActorRef, channel: Class[_]): Boolean = {
if (debug) publish(Logging.Debug(this, "unsubscribing " + subscriber + " from channel " + channel))
super.unsubscribe(subscriber, channel)
}
override def unsubscribe(subscriber: ActorRef) {
if (debug) publish(Logging.Debug(this, "unsubscribing " + subscriber + " from all channels"))
super.unsubscribe(subscriber)
}
def start(app: AkkaApplication) {
reaper = app.systemActorOf(Props(new Actor {
def receive = {
case ref: ActorRef watch(ref)
case Terminated(ref) unsubscribe(ref)
}
}), "MainBusReaper")
subscribers.values foreach (reaper ! _)
}
def printSubscribers: String = {
val sb = new StringBuilder
for (c subscribers.keys) sb.append(c + " -> " + subscribers.valueIterator(c).mkString("[", ", ", "]"))
sb.toString
}
}

View file

@ -22,7 +22,7 @@ import java.lang.reflect.InvocationTargetException
class RemoteException(message: String) extends AkkaException(message)
trait RemoteModule {
protected[akka] def notifyListeners(message: Any): Unit
protected[akka] def notifyListeners(message: RemoteLifeCycleEvent): Unit
}
/**
@ -122,7 +122,7 @@ abstract class RemoteSupport(val app: AkkaApplication) extends RemoteServerModul
this.shutdownServerModule()
}
protected[akka] override def notifyListeners(message: Any): Unit = app.eventHandler.notify(message)
protected[akka] override def notifyListeners(message: RemoteLifeCycleEvent): Unit = app.mainbus.publish(message)
}
/**
@ -173,4 +173,4 @@ trait RemoteClientModule extends RemoteModule { self: RemoteSupport ⇒
remoteAddress: InetSocketAddress,
recipient: ActorRef,
loader: Option[ClassLoader]): Unit
}
}

View file

@ -6,7 +6,6 @@ package akka.routing
import akka.AkkaException
import akka.actor._
import akka.event.EventHandler
import akka.config.ConfigurationException
import akka.dispatch.{ Future, MessageDispatcher }
import akka.AkkaApplication

View file

@ -7,6 +7,7 @@ package akka.util
import java.util.concurrent.TimeUnit
import TimeUnit._
import java.lang.{ Long JLong, Double JDouble }
import akka.AkkaApplication
class TimerException(message: String) extends RuntimeException(message)
@ -119,15 +120,6 @@ object Duration {
case "ns" | "nano" | "nanos" | "nanosecond" | "nanoseconds" NANOSECONDS
}
/*
* Testing facilities
*/
val timeFactor: Double = {
val factor = System.getProperty("akka.test.timefactor", "1.0")
try { factor.toDouble }
catch { case e: java.lang.NumberFormatException 1.0 }
}
val Zero: Duration = new FiniteDuration(0, NANOSECONDS)
trait Infinite {
@ -272,9 +264,10 @@ abstract class Duration extends Serializable {
def /(other: Duration): Double
def unary_- : Duration
def finite_? : Boolean
def dilated: Duration = this * Duration.timeFactor
def dilated(implicit app: AkkaApplication): Duration = this * app.AkkaConfig.TestTimeFactor
def min(other: Duration): Duration = if (this < other) this else other
def max(other: Duration): Duration = if (this > other) this else other
def sleep(): Unit = Thread.sleep(toMillis)
// Java API
def lt(other: Duration) = this < other

View file

@ -1,10 +1,8 @@
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.util
import akka.event.EventHandler
import java.io.{ PrintWriter, StringWriter }
/**

View file

@ -8,6 +8,7 @@ import annotation.tailrec
import java.util.concurrent.{ ConcurrentSkipListSet, ConcurrentHashMap }
import java.util.{ Comparator, Set JSet }
import scala.collection.mutable
/**
* An implementation of a ConcurrentMultiMap
@ -98,6 +99,24 @@ class Index[K, V](val mapSize: Int, val valueComparator: Comparator[V]) {
container.entrySet foreach { e e.getValue.foreach(fun(e.getKey, _)) }
}
/**
* Returns the union of all value sets.
*/
def values: Set[V] = {
import scala.collection.JavaConversions._
val builder = mutable.Set.empty[V]
for {
entry container.entrySet
v entry.getValue
} builder += v
builder.toSet
}
/**
* Returns the key set.
*/
def keys = scala.collection.JavaConversions.collectionAsScalaIterable(container.keySet)
/**
* Disassociates the value of type V from the key of type K
* @return true if the value was disassociated from the key and false if it wasn't previously associated with the key

View file

@ -4,7 +4,7 @@
package akka.util
import akka.event.EventHandler
import akka.event.Logging.Error
import java.lang.management.ManagementFactory
import javax.management.{ ObjectInstance, ObjectName, InstanceAlreadyExistsException, InstanceNotFoundException }
import akka.AkkaApplication
@ -24,7 +24,7 @@ object JMX {
case e: InstanceAlreadyExistsException
Some(mbeanServer.getObjectInstance(name))
case e: Exception
app.eventHandler.error(e, this, "Error when registering mbean [%s]".format(mbean))
app.mainbus.publish(Error(e, this, "Error when registering mbean [%s]".format(mbean)))
None
}
@ -32,6 +32,6 @@ object JMX {
mbeanServer.unregisterMBean(mbean)
} catch {
case e: InstanceNotFoundException {}
case e: Exception app.eventHandler.error(e, this, "Error while unregistering mbean [%s]".format(mbean))
case e: Exception app.mainbus.publish(Error(e, this, "Error while unregistering mbean [%s]".format(mbean)))
}
}

View file

@ -6,7 +6,6 @@ package akka.util
import java.util.concurrent.locks.{ ReentrantReadWriteLock, ReentrantLock }
import java.util.concurrent.atomic.{ AtomicBoolean }
import akka.event.EventHandler
/**
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>

View file

@ -3,10 +3,12 @@
*/
package akka.util
import akka.dispatch.Envelope
import akka.actor._
import DeploymentConfig.ReplicationScheme
import akka.config.ModuleNotAvailableException
import akka.event.Logging.Debug
import akka.cluster.ClusterNode
import akka.routing.{ RoutedProps, Router }
import akka.AkkaApplication

View file

@ -7,20 +7,22 @@ import akka.util.duration._
//#imports
import akka.actor.Actor
import akka.event.EventHandler
import akka.event.Logging
import akka.config.Configuration
//#imports
//#my-actor
class MyActor extends Actor {
val log = Logging(app, this)
def receive = {
case "test" app.eventHandler.info(this, "received test")
case _ app.eventHandler.info(this, "received unknown message")
case "test" log.info("received test")
case _ log.info("received unknown message")
}
}
//#my-actor
class ActorDocSpec extends AkkaSpec {
class ActorDocSpec extends AkkaSpec(Configuration("akka.loglevel" -> "INFO")) {
"creating actor with AkkaSpec.actorOf" in {
//#creating-actorOf
@ -30,23 +32,21 @@ class ActorDocSpec extends AkkaSpec {
// testing the actor
// TODO: convert docs to AkkaSpec(Configuration(...))
app.eventHandler.notify(TestEvent.Mute(EventFilter.custom {
case e: EventHandler.Info true
case _ false
}))
app.eventHandler.addListener(testActor)
val eventLevel = app.eventHandler.level
app.eventHandler.level = EventHandler.InfoLevel
val filter = EventFilter.custom {
case e: Logging.Info true
case _ false
}
app.mainbus.publish(TestEvent.Mute(filter))
app.mainbus.subscribe(testActor, classOf[Logging.Info])
myActor ! "test"
expectMsgPF(1 second) { case EventHandler.Info(_, "received test") true }
expectMsgPF(1 second) { case Logging.Info(_, "received test") true }
myActor ! "unknown"
expectMsgPF(1 second) { case EventHandler.Info(_, "received unknown message") true }
expectMsgPF(1 second) { case Logging.Info(_, "received unknown message") true }
app.eventHandler.level = eventLevel
app.eventHandler.removeListener(testActor)
app.eventHandler.notify(TestEvent.UnMuteAll)
app.mainbus.unsubscribe(testActor)
app.mainbus.publish(TestEvent.UnMute(filter))
myActor.stop()
}

View file

@ -6,7 +6,6 @@ package akka.remote
import akka.actor.{ Actor, BootableActorLoaderService }
import akka.util.{ ReflectiveAccess, Bootable }
import akka.event.EventHandler
// TODO: remove me - remoting is enabled through the RemoteActorRefProvider

View file

@ -7,6 +7,7 @@ package akka.remote
import akka.AkkaApplication
import akka.actor._
import akka.actor.Status._
import akka.event.Logging
import akka.util.duration._
import akka.remote.RemoteProtocol._
import akka.remote.RemoteProtocol.RemoteSystemDaemonMessageType._
@ -104,6 +105,7 @@ class Gossiper(remote: Remote) {
nodeMembershipChangeListeners: Set[NodeMembershipChangeListener] = Set.empty[NodeMembershipChangeListener])
private val app = remote.app
private val log = Logging(app, this)
private val failureDetector = remote.failureDetector
private val connectionManager = new RemoteConnectionManager(app, remote, Map.empty[InetSocketAddress, ActorRef])
private val seeds = Set(address) // FIXME read in list of seeds from config
@ -241,18 +243,18 @@ class Gossiper(remote: Remote) {
try {
(connection ? (toRemoteMessage(newGossip), remote.remoteSystemDaemonAckTimeout)).as[Status] match {
case Some(Success(receiver))
app.eventHandler.debug(this, "Gossip sent to [%s] was successfully received".format(receiver))
log.debug("Gossip sent to [{}] was successfully received", receiver)
case Some(Failure(cause))
app.eventHandler.error(cause, this, cause.toString)
log.error(cause, cause.toString)
case None
val error = new RemoteException("Gossip to [%s] timed out".format(connection.address))
app.eventHandler.error(error, this, error.toString)
log.error(error, error.toString)
}
} catch {
case e: Exception
app.eventHandler.error(e, this, "Could not gossip to [%s] due to: %s".format(connection.address, e.toString))
log.error(e, "Could not gossip to [{}] due to: {}", connection.address, e.toString)
}
seeds exists (peer == _)

View file

@ -6,7 +6,7 @@ package akka.remote
import akka.AkkaApplication
import akka.actor._
import akka.event.EventHandler
import akka.event.Logging
import akka.actor.Status._
import akka.util._
import akka.util.duration._
@ -29,10 +29,14 @@ import akka.dispatch.{ Terminate, Dispatchers, Future, PinnedDispatcher }
*/
class Remote(val app: AkkaApplication) {
val log = Logging(app, this)
import app._
import app.config
import app.AkkaConfig._
val nodename = app.nodename
// TODO move to AkkaConfig?
val shouldCompressData = config.getBool("akka.remote.use-compression", false)
val remoteSystemDaemonAckTimeout = Duration(config.getInt("akka.remote.remote-daemon-ack-timeout", 30), DefaultTimeUnit).toMillis.toInt
@ -70,8 +74,8 @@ class Remote(val app: AkkaApplication) {
val remote = new akka.remote.netty.NettyRemoteSupport(app)
remote.start() //TODO FIXME Any application loader here?
app.eventHandler.addListener(eventStream.sender)
app.eventHandler.addListener(remoteClientLifeCycleHandler)
app.mainbus.subscribe(eventStream.sender, classOf[RemoteLifeCycleEvent])
app.mainbus.subscribe(remoteClientLifeCycleHandler, classOf[RemoteLifeCycleEvent])
// TODO actually register this provider in app in remote mode
//provider.register(ActorRefProvider.RemoteProvider, new RemoteActorRefProvider)
@ -81,7 +85,7 @@ class Remote(val app: AkkaApplication) {
def start(): Unit = {
val serverAddress = server.app.defaultAddress //Force init of server
val daemonAddress = remoteDaemon.address //Force init of daemon
eventHandler.info(this, "Starting remote server on [%s] and starting remoteDaemon with address [%s]".format(serverAddress, daemonAddress))
log.info("Starting remote server on [{}] and starting remoteDaemon with address [{}]", serverAddress, daemonAddress)
}
}
@ -95,15 +99,14 @@ class Remote(val app: AkkaApplication) {
class RemoteSystemDaemon(remote: Remote) extends Actor {
import remote._
import remote.app._
override def preRestart(reason: Throwable, msg: Option[Any]) {
eventHandler.debug(this, "RemoteSystemDaemon failed due to [%s] - restarting...".format(reason))
log.debug("RemoteSystemDaemon failed due to [{}] - restarting...", reason)
}
def receive: Actor.Receive = {
case message: RemoteSystemDaemonMessageProtocol
eventHandler.debug(this, "Received command [\n%s] to RemoteSystemDaemon on [%s]".format(message.getMessageType, nodename))
log.debug("Received command [\n{}] to RemoteSystemDaemon on [{}]", message.getMessageType, nodename)
message.getMessageType match {
case USE handleUse(message)
@ -121,7 +124,7 @@ class RemoteSystemDaemon(remote: Remote) extends Actor {
//TODO: should we not deal with unrecognized message types?
}
case unknown eventHandler.warning(this, "Unknown message to RemoteSystemDaemon [%s]".format(unknown))
case unknown log.warning("Unknown message to RemoteSystemDaemon [{}]", unknown)
}
def handleUse(message: RemoteSystemDaemonMessageProtocol) {
@ -132,14 +135,14 @@ class RemoteSystemDaemon(remote: Remote) extends Actor {
if (shouldCompressData) LZF.uncompress(message.getPayload.toByteArray) else message.getPayload.toByteArray
val actorFactory =
serialization.deserialize(actorFactoryBytes, classOf[() Actor], None) match {
app.serialization.deserialize(actorFactoryBytes, classOf[() Actor], None) match {
case Left(error) throw error
case Right(instance) instance.asInstanceOf[() Actor]
}
app.actorOf(Props(creator = actorFactory), message.getActorAddress)
} else {
eventHandler.error(this, "Actor 'address' for actor to instantiate is not defined, ignoring remote system daemon command [%s]".format(message))
log.error("Actor 'address' for actor to instantiate is not defined, ignoring remote system daemon command [{}]", message)
}
sender ! Success(app.defaultAddress)
@ -213,7 +216,7 @@ class RemoteSystemDaemon(remote: Remote) extends Actor {
}
private def payloadFor[T](message: RemoteSystemDaemonMessageProtocol, clazz: Class[T]): T = {
serialization.deserialize(message.getPayload.toByteArray, clazz, None) match {
app.serialization.deserialize(message.getPayload.toByteArray, clazz, None) match {
case Left(error) throw error
case Right(instance) instance.asInstanceOf[T]
}
@ -244,7 +247,7 @@ class RemoteMessage(input: RemoteMessageProtocol, remote: RemoteSupport, classLo
.newInstance(exception.getMessage).asInstanceOf[Throwable]
} catch {
case problem: Exception
remote.app.eventHandler.error(problem, remote, problem.getMessage)
remote.app.mainbus.publish(Logging.Error(problem, remote, problem.getMessage))
CannotInstantiateRemoteExceptionDueToRemoteProtocolParsingErrorException(problem, classname, exception.getMessage)
}
}

View file

@ -12,7 +12,7 @@ import akka.routing._
import akka.dispatch._
import akka.util.duration._
import akka.config.ConfigurationException
import akka.event.{ DeathWatch, EventHandler }
import akka.event.{ DeathWatch, Logging }
import akka.serialization.{ Serialization, Serializer, Compression }
import akka.serialization.Compression.LZF
import akka.remote.RemoteProtocol._
@ -31,6 +31,8 @@ import java.util.concurrent.atomic.AtomicBoolean
*/
class RemoteActorRefProvider(val app: AkkaApplication) extends ActorRefProvider {
val log = Logging(app, this)
import java.util.concurrent.ConcurrentHashMap
import akka.dispatch.Promise
@ -171,7 +173,7 @@ class RemoteActorRefProvider(val app: AkkaApplication) extends ActorRefProvider
local.actorFor(actor.address)
} else {
val remoteInetSocketAddress = new InetSocketAddress(actor.hostname, actor.port) //FIXME Drop the InetSocketAddresses and use RemoteAddress
app.eventHandler.debug(this, "%s: Creating RemoteActorRef with address [%s] connected to [%s]".format(app.defaultAddress, actor.address, remoteInetSocketAddress))
log.debug("{}: Creating RemoteActorRef with address [{}] connected to [{}]", app.defaultAddress, actor.address, remoteInetSocketAddress)
Some(RemoteActorRef(remote.server, remoteInetSocketAddress, actor.address, None)) //Should it be None here
}
}
@ -180,7 +182,7 @@ class RemoteActorRefProvider(val app: AkkaApplication) extends ActorRefProvider
* Using (checking out) actor on a specific node.
*/
def useActorOnNode(remoteAddress: InetSocketAddress, actorAddress: String, actorFactory: () Actor) {
app.eventHandler.debug(this, "[%s] Instantiating Actor [%s] on node [%s]".format(app.defaultAddress, actorAddress, remoteAddress))
log.debug("[{}] Instantiating Actor [{}] on node [{}]", app.defaultAddress, actorAddress, remoteAddress)
val actorFactoryBytes =
app.serialization.serialize(actorFactory) match {
@ -208,20 +210,20 @@ class RemoteActorRefProvider(val app: AkkaApplication) extends ActorRefProvider
val f = connection ? (command, remote.remoteSystemDaemonAckTimeout)
(try f.await.value catch { case _: FutureTimeoutException None }) match {
case Some(Right(receiver))
app.eventHandler.debug(this, "Remote system command sent to [%s] successfully received".format(receiver))
log.debug("Remote system command sent to [{}] successfully received", receiver)
case Some(Left(cause))
app.eventHandler.error(cause, this, cause.toString)
log.error(cause, cause.toString)
throw cause
case None
val error = new RemoteException("Remote system command to [%s] timed out".format(connection.address))
app.eventHandler.error(error, this, error.toString)
log.error(error, error.toString)
throw error
}
} catch {
case e: Exception
app.eventHandler.error(e, this, "Could not send remote system command to [%s] due to: %s".format(connection.address, e.toString))
log.error(e, "Could not send remote system command to [{}] due to: {}", connection.address, e.toString)
throw e
}
} else {

View file

@ -7,6 +7,7 @@ package akka.remote
import akka.actor._
import akka.routing._
import akka.AkkaApplication
import akka.event.Logging
import scala.collection.immutable.Map
import scala.annotation.tailrec
@ -25,6 +26,8 @@ class RemoteConnectionManager(
initialConnections: Map[InetSocketAddress, ActorRef] = Map.empty[InetSocketAddress, ActorRef])
extends ConnectionManager {
val log = Logging(app, this)
// FIXME is this VersionedIterable really needed? It is not used I think. Complicates API. See 'def connections' etc.
case class State(version: Long, connections: Map[InetSocketAddress, ActorRef])
extends VersionedIterable[ActorRef] {
@ -62,7 +65,7 @@ class RemoteConnectionManager(
@tailrec
final def failOver(from: InetSocketAddress, to: InetSocketAddress) {
app.eventHandler.debug(this, "Failing over connection from [%s] to [%s]".format(from, to))
log.debug("Failing over connection from [{}] to [{}]", from, to)
val oldState = state.get
var changed = false
@ -113,7 +116,7 @@ class RemoteConnectionManager(
if (!state.compareAndSet(oldState, newState)) {
remove(faultyConnection) // recur
} else {
app.eventHandler.debug(this, "Removing connection [%s]".format(faultyAddress))
log.debug("Removing connection [{}]", faultyAddress)
}
}
}
@ -140,7 +143,7 @@ class RemoteConnectionManager(
putIfAbsent(address, newConnectionFactory) // recur
} else {
// we succeeded
app.eventHandler.debug(this, "Adding connection [%s]".format(address))
log.debug("Adding connection [{}]", address)
newConnection // return new connection actor
}
}

View file

@ -23,6 +23,7 @@ import java.util.concurrent._
import java.util.concurrent.atomic._
import akka.AkkaException
import akka.AkkaApplication
import akka.event.Logging
class RemoteClientMessageBufferException(message: String, cause: Throwable = null) extends AkkaException(message, cause) {
def this(msg: String) = this(msg, null)
@ -126,6 +127,8 @@ abstract class RemoteClient private[akka] (
val module: NettyRemoteClientModule,
val remoteAddress: InetSocketAddress) extends RemoteMarshallingOps {
val log = Logging(app, this)
val name = simpleName(this) + "@" +
remoteAddress.getAddress.getHostAddress + "::" +
remoteAddress.getPort
@ -134,7 +137,7 @@ abstract class RemoteClient private[akka] (
private[remote] def isRunning = runSwitch.isOn
protected def notifyListeners(msg: Any): Unit
protected def notifyListeners(msg: RemoteLifeCycleEvent): Unit
protected def currentChannel: Channel
@ -154,9 +157,8 @@ abstract class RemoteClient private[akka] (
*/
def send(request: RemoteMessageProtocol) {
if (isRunning) { //TODO FIXME RACY
app.eventHandler.debug(this, "Sending message: " + new RemoteMessage(request, remoteSupport))
log.debug("Sending message: " + new RemoteMessage(request, remoteSupport))
// tell
try {
val payload = createMessageSendEnvelope(request);
currentChannel.write(payload).addListener(
@ -188,21 +190,21 @@ class PassiveRemoteClient(_app: AkkaApplication,
module: NettyRemoteClientModule,
remoteAddress: InetSocketAddress,
val loader: Option[ClassLoader] = None,
notifyListenersFun: ( Any) Unit)
notifyListenersFun: RemoteLifeCycleEvent Unit)
extends RemoteClient(_app, remoteSupport, module, remoteAddress) {
def notifyListeners(msg: Any): Unit = notifyListenersFun(msg)
override def notifyListeners(msg: RemoteLifeCycleEvent) { app.mainbus.publish(msg) }
def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = runSwitch switchOn {
notifyListeners(RemoteClientStarted(module, remoteAddress))
app.eventHandler.debug(this, "Starting remote client connection to [%s]".format(remoteAddress))
log.debug("Starting remote client connection to [{}]", remoteAddress)
}
def shutdown() = runSwitch switchOff {
app.eventHandler.debug(this, "Shutting down remote client [%s]".format(name))
log.debug("Shutting down remote client [{}]", name)
notifyListeners(RemoteClientShutdown(module, remoteAddress))
app.eventHandler.debug(this, "[%s] has been shut down".format(name))
log.debug("[{}] has been shut down", name)
}
}
@ -213,12 +215,12 @@ class PassiveRemoteClient(_app: AkkaApplication,
*/
class ActiveRemoteClient private[akka] (
_app: AkkaApplication,
remoteSupport: RemoteSupport,
module: NettyRemoteClientModule,
remoteAddress: InetSocketAddress,
_remoteSupport: RemoteSupport,
_module: NettyRemoteClientModule,
_remoteAddress: InetSocketAddress,
val loader: Option[ClassLoader] = None,
notifyListenersFun: ( Any) Unit)
extends RemoteClient(_app, remoteSupport, module, remoteAddress) {
notifyListenersFun: (RemoteLifeCycleEvent) Unit)
extends RemoteClient(_app, _remoteSupport, _module, _remoteAddress) {
val settings = new RemoteClientSettings(app)
import settings._
@ -235,7 +237,7 @@ class ActiveRemoteClient private[akka] (
@volatile
private var reconnectionTimeWindowStart = 0L
def notifyListeners(msg: Any): Unit = notifyListenersFun(msg)
def notifyListeners(msg: RemoteLifeCycleEvent): Unit = notifyListenersFun(msg)
def currentChannel = connection.getChannel
@ -258,7 +260,7 @@ class ActiveRemoteClient private[akka] (
}
def attemptReconnect(): Boolean = {
app.eventHandler.debug(this, "Remote client reconnecting to [%s]".format(remoteAddress))
log.debug("Remote client reconnecting to [{}]", remoteAddress)
val connection = bootstrap.connect(remoteAddress)
openChannels.add(connection.awaitUninterruptibly.getChannel) // Wait until the connection attempt succeeds or fails.
@ -281,7 +283,7 @@ class ActiveRemoteClient private[akka] (
bootstrap.setOption("tcpNoDelay", true)
bootstrap.setOption("keepAlive", true)
app.eventHandler.debug(this, "Starting remote client connection to [%s]".format(remoteAddress))
log.debug("Starting remote client connection to [{}]", remoteAddress)
connection = bootstrap.connect(remoteAddress)
@ -301,7 +303,7 @@ class ActiveRemoteClient private[akka] (
case false if reconnectIfAlreadyConnected
closeChannel(connection)
app.eventHandler.debug(this, "Remote client reconnecting to [%s]".format(remoteAddress))
log.debug("Remote client reconnecting to [{}]", remoteAddress)
attemptReconnect()
case false false
@ -310,7 +312,7 @@ class ActiveRemoteClient private[akka] (
// Please note that this method does _not_ remove the ARC from the NettyRemoteClientModule's map of clients
def shutdown() = runSwitch switchOff {
app.eventHandler.debug(this, "Shutting down remote client [%s]".format(name))
log.debug("Shutting down remote client [{}]", name)
notifyListeners(RemoteClientShutdown(module, remoteAddress))
timer.stop()
@ -321,7 +323,7 @@ class ActiveRemoteClient private[akka] (
bootstrap = null
connection = null
app.eventHandler.debug(this, "[%s] has been shut down".format(name))
log.debug("[{}] has been shut down", name)
}
private[akka] def isWithinReconnectionTimeWindow: Boolean = {
@ -331,7 +333,7 @@ class ActiveRemoteClient private[akka] (
} else {
val timeLeft = (RECONNECTION_TIME_WINDOW - (System.currentTimeMillis - reconnectionTimeWindowStart)) > 0
if (timeLeft)
app.eventHandler.debug(this, "Will try to reconnect to remote server for another [%s] milliseconds".format(timeLeft))
log.info("Will try to reconnect to remote server for another [{}] milliseconds", timeLeft)
timeLeft
}
@ -459,6 +461,8 @@ class NettyRemoteSupport(_app: AkkaApplication) extends RemoteSupport(_app) with
class NettyRemoteServer(val app: AkkaApplication, serverModule: NettyRemoteServerModule, val loader: Option[ClassLoader]) extends RemoteMarshallingOps {
val log = Logging(app, this)
val settings = new RemoteServerSettings(app)
import settings._
@ -504,6 +508,8 @@ class NettyRemoteServer(val app: AkkaApplication, serverModule: NettyRemoteServe
trait NettyRemoteServerModule extends RemoteServerModule {
self: RemoteSupport
val log = Logging(app, this)
def app: AkkaApplication
def remoteSupport = self
@ -595,6 +601,8 @@ class RemoteServerHandler(
val applicationLoader: Option[ClassLoader],
val server: NettyRemoteServerModule) extends SimpleChannelUpstreamHandler with RemoteMarshallingOps {
val log = Logging(app, this)
import settings._
implicit def app = server.app

View file

@ -6,16 +6,15 @@ package akka.event.slf4j
import org.slf4j.{ Logger SLFLogger, LoggerFactory SLFLoggerFactory }
import akka.event.EventHandler
import akka.event.Logging._
import akka.actor._
import Actor._
/**
* Base trait for all classes that wants to be able use the SLF4J logging infrastructure.
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
trait Logging {
trait SLF4JLogging {
@transient
lazy val log = Logger(this.getClass.getName)
}
@ -31,8 +30,7 @@ object Logger {
*
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
class Slf4jEventHandler extends Actor with Logging {
import EventHandler._
class Slf4jEventHandler extends Actor with SLF4JLogging {
def receive = {
case event @ Error(cause, instance, message)
@ -51,10 +49,11 @@ class Slf4jEventHandler extends Actor with Logging {
logger(instance).debug("[{}] [{}]",
event.thread.getName, message.asInstanceOf[AnyRef])
case event log.debug("[{}]", event.toString)
case InitializeLogger(_) log.info("Slf4jEventHandler started")
}
def logger(instance: AnyRef): SLFLogger = instance match {
// TODO make sure that this makes sense (i.e. should be the full path after Peters changes)
case a: ActorRef Logger(a.address)
case _ Logger(instance.getClass)
}

View file

@ -14,7 +14,6 @@ import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.UntypedActorFactory;
import akka.dispatch.Future;
import akka.event.EventHandler;
import akka.testkit.EventFilter;
import akka.testkit.ErrorFilter;
import akka.testkit.TestEvent;
@ -72,7 +71,7 @@ public class UntypedCoordinatedIncrementTest {
EventFilter expectedFailureFilter = (EventFilter) new ErrorFilter(ExpectedFailureException.class);
EventFilter coordinatedFilter = (EventFilter) new ErrorFilter(CoordinatedTransactionException.class);
Seq<EventFilter> ignoreExceptions = seq(expectedFailureFilter, coordinatedFilter);
application.eventHandler().notify(new TestEvent.Mute(ignoreExceptions));
application.mainbus().publish(new TestEvent.Mute(ignoreExceptions));
CountDownLatch incrementLatch = new CountDownLatch(numCounters);
List<ActorRef> actors = new ArrayList<ActorRef>(counters);
actors.add(failer);
@ -85,7 +84,7 @@ public class UntypedCoordinatedIncrementTest {
Future future = counter.ask("GetCount", askTimeout);
assertEquals(0, ((Integer)future.get()).intValue());
}
application.eventHandler().notify(new TestEvent.UnMute(ignoreExceptions));
application.mainbus().publish(new TestEvent.UnMute(ignoreExceptions));
}
public <A> Seq<A> seq(A... args) {

View file

@ -11,7 +11,6 @@ import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.UntypedActorFactory;
import akka.dispatch.Future;
import akka.event.EventHandler;
import akka.testkit.EventFilter;
import akka.testkit.ErrorFilter;
import akka.testkit.TestEvent;
@ -76,7 +75,7 @@ public class UntypedTransactorTest {
EventFilter expectedFailureFilter = (EventFilter) new ErrorFilter(ExpectedFailureException.class);
EventFilter coordinatedFilter = (EventFilter) new ErrorFilter(CoordinatedTransactionException.class);
Seq<EventFilter> ignoreExceptions = seq(expectedFailureFilter, coordinatedFilter);
application.eventHandler().notify(new TestEvent.Mute(ignoreExceptions));
application.mainbus().publish(new TestEvent.Mute(ignoreExceptions));
CountDownLatch incrementLatch = new CountDownLatch(numCounters);
List<ActorRef> actors = new ArrayList<ActorRef>(counters);
actors.add(failer);
@ -97,7 +96,7 @@ public class UntypedTransactorTest {
}
}
}
application.eventHandler().notify(new TestEvent.UnMute(ignoreExceptions));
application.mainbus().publish(new TestEvent.UnMute(ignoreExceptions));
}
public <A> Seq<A> seq(A... args) {

View file

@ -7,7 +7,6 @@ import akka.transactor.Coordinated
import akka.actor._
import akka.stm.{ Ref, TransactionFactory }
import akka.util.duration._
import akka.event.EventHandler
import akka.transactor.CoordinatedTransactionException
import akka.testkit._
@ -83,20 +82,20 @@ class CoordinatedIncrementSpec extends AkkaSpec with BeforeAndAfterAll {
"increment no counters with a failing transaction" in {
val ignoreExceptions = Seq(
EventFilter[ExpectedFailureException],
EventFilter[CoordinatedTransactionException],
EventFilter[ActorTimeoutException])
app.eventHandler.notify(TestEvent.Mute(ignoreExceptions))
val (counters, failer) = actorOfs
val coordinated = Coordinated()
counters(0) ! Coordinated(Increment(counters.tail :+ failer))
coordinated.await
for (counter counters) {
(counter ? GetCount).as[Int].get must be === 0
EventFilter[ExpectedFailureException](),
EventFilter[CoordinatedTransactionException](),
EventFilter[ActorTimeoutException]())
filterEvents(ignoreExceptions) {
val (counters, failer) = actorOfs
val coordinated = Coordinated()
counters(0) ! Coordinated(Increment(counters.tail :+ failer))
coordinated.await
for (counter counters) {
(counter ? GetCount).as[Int].get must be === 0
}
counters foreach (_.stop())
failer.stop()
}
counters foreach (_.stop())
failer.stop()
app.eventHandler.notify(TestEvent.UnMute(ignoreExceptions))
}
}
}

View file

@ -9,7 +9,6 @@ import akka.transactor.Coordinated
import akka.actor._
import akka.stm._
import akka.util.duration._
import akka.event.EventHandler
import akka.transactor.CoordinatedTransactionException
import akka.testkit._
@ -116,21 +115,21 @@ class FickleFriendsSpec extends AkkaSpec with BeforeAndAfterAll {
"Coordinated fickle friends" should {
"eventually succeed to increment all counters by one" in {
val ignoreExceptions = Seq(
EventFilter[ExpectedFailureException],
EventFilter[CoordinatedTransactionException],
EventFilter[ActorTimeoutException])
app.eventHandler.notify(TestEvent.Mute(ignoreExceptions))
val (counters, coordinator) = actorOfs
val latch = new CountDownLatch(1)
coordinator ! FriendlyIncrement(counters, latch)
latch.await // this could take a while
(coordinator ? GetCount).as[Int].get must be === 1
for (counter counters) {
(counter ? GetCount).as[Int].get must be === 1
EventFilter[ExpectedFailureException](),
EventFilter[CoordinatedTransactionException](),
EventFilter[ActorTimeoutException]())
filterEvents(ignoreExceptions) {
val (counters, coordinator) = actorOfs
val latch = new CountDownLatch(1)
coordinator ! FriendlyIncrement(counters, latch)
latch.await // this could take a while
(coordinator ? GetCount).as[Int].get must be === 1
for (counter counters) {
(counter ? GetCount).as[Int].get must be === 1
}
counters foreach (_.stop())
coordinator.stop()
}
counters foreach (_.stop())
coordinator.stop()
app.eventHandler.notify(TestEvent.UnMute(ignoreExceptions))
}
}
}

View file

@ -8,7 +8,6 @@ import akka.transactor.Transactor
import akka.actor._
import akka.stm._
import akka.util.duration._
import akka.event.EventHandler
import akka.transactor.CoordinatedTransactionException
import akka.testkit._
@ -106,20 +105,20 @@ class TransactorSpec extends AkkaSpec {
"increment no counters with a failing transaction" in {
val ignoreExceptions = Seq(
EventFilter[ExpectedFailureException],
EventFilter[CoordinatedTransactionException],
EventFilter[ActorTimeoutException])
app.eventHandler.notify(TestEvent.Mute(ignoreExceptions))
val (counters, failer) = createTransactors
val failLatch = TestLatch(numCounters)
counters(0) ! Increment(counters.tail :+ failer, failLatch)
failLatch.await
for (counter counters) {
(counter ? GetCount).as[Int].get must be === 0
EventFilter[ExpectedFailureException](),
EventFilter[CoordinatedTransactionException](),
EventFilter[ActorTimeoutException]())
filterEvents(ignoreExceptions) {
val (counters, failer) = createTransactors
val failLatch = TestLatch(numCounters)
counters(0) ! Increment(counters.tail :+ failer, failLatch)
failLatch.await
for (counter counters) {
(counter ? GetCount).as[Int].get must be === 0
}
counters foreach (_.stop())
failer.stop()
}
counters foreach (_.stop())
failer.stop()
app.eventHandler.notify(TestEvent.UnMute(ignoreExceptions))
}
}

View file

@ -3,7 +3,7 @@
*/
package akka.testkit
import akka.event.EventHandler
import akka.event.Logging.{ Warning, Error }
import java.util.concurrent.locks.ReentrantLock
import java.util.LinkedList
import java.util.concurrent.RejectedExecutionException
@ -104,7 +104,7 @@ private[testkit] object CallingThreadDispatcher {
* @author Roland Kuhn
* @since 1.1
*/
class CallingThreadDispatcher(_app: AkkaApplication, val name: String = "calling-thread", val warnings: Boolean = true) extends MessageDispatcher(_app) {
class CallingThreadDispatcher(_app: AkkaApplication, val name: String = "calling-thread") extends MessageDispatcher(_app) {
import CallingThreadDispatcher._
protected[akka] override def createMailbox(actor: ActorCell) = new CallingThreadMailbox(this, actor)
@ -211,12 +211,12 @@ class CallingThreadDispatcher(_app: AkkaApplication, val name: String = "calling
true
} catch {
case ie: InterruptedException
app.eventHandler.error(this, ie)
app.mainbus.publish(Error(this, ie))
Thread.currentThread().interrupt()
intex = ie
true
case e
app.eventHandler.error(this, e)
app.mainbus.publish(Error(this, e))
queue.leave
false
}

View file

@ -6,7 +6,6 @@ package akka.testkit
import akka.actor._
import akka.util.ReflectiveAccess
import akka.event.EventHandler
import com.eaio.uuid.UUID
import akka.actor.Props._
import akka.AkkaApplication

View file

@ -6,6 +6,7 @@ package akka.testkit
import akka.util.Duration
import java.util.concurrent.{ CyclicBarrier, TimeUnit, TimeoutException }
import akka.AkkaApplication
class TestBarrierTimeoutException(message: String) extends RuntimeException(message)
@ -24,14 +25,15 @@ object TestBarrier {
class TestBarrier(count: Int) {
private val barrier = new CyclicBarrier(count)
def await(): Unit = await(TestBarrier.DefaultTimeout)
def await()(implicit app: AkkaApplication): Unit = await(TestBarrier.DefaultTimeout)
def await(timeout: Duration) {
def await(timeout: Duration)(implicit app: AkkaApplication) {
try {
barrier.await(Testing.testTime(timeout.toNanos), TimeUnit.NANOSECONDS)
barrier.await(timeout.dilated.toNanos, TimeUnit.NANOSECONDS)
} catch {
case e: TimeoutException
throw new TestBarrierTimeoutException("Timeout of %s and time factor of %s" format (timeout.toString, Duration.timeFactor))
throw new TestBarrierTimeoutException("Timeout of %s and time factor of %s"
format (timeout.toString, app.AkkaConfig.TestTimeFactor))
}
}

View file

@ -1,11 +1,36 @@
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.testkit
import akka.event.EventHandler
import akka.event.EventHandler.{ Event, Error }
import akka.actor.Actor
import scala.util.matching.Regex
import akka.actor.Actor
import akka.event.Logging._
import akka.event.Logging
import akka.util.Duration
import akka.AkkaApplication
/**
* Implementation helpers of the EventFilter facilities: send `Mute`
* to the TestEventListener to install a filter, and `UnMute` to
* deinstall it.
*
* You should always prefer the filter methods in the package object
* (see [[akka.testkit]] `filterEvents` and `filterException`) or on the
* EventFilter implementations.
*/
sealed trait TestEvent
/**
* Implementation helpers of the EventFilter facilities: send <code>Mute</code>
* to the TestEventFilter to install a filter, and <code>UnMute</code> to
* deinstall it.
*
* You should always prefer the filter methods in the package object
* (see [[akka.testkit]] `filterEvents` and `filterException`) or on the
* EventFilter implementations.
*/
object TestEvent {
object Mute {
def apply(filter: EventFilter, filters: EventFilter*): Mute = new Mute(filter +: filters.toSeq)
@ -15,84 +40,416 @@ object TestEvent {
def apply(filter: EventFilter, filters: EventFilter*): UnMute = new UnMute(filter +: filters.toSeq)
}
case class UnMute(filters: Seq[EventFilter]) extends TestEvent
case object UnMuteAll extends TestEvent
}
trait EventFilter {
def apply(event: Event): Boolean
/**
* Facilities for selectively filtering out expected events from logging so
* that you can keep your test runs console output clean and do not miss real
* error messages.
*
* See the companion object for convenient factory methods.
*
* If the `occurrences` is set to Int.MaxValue, no tracking is done.
*/
abstract class EventFilter(occurrences: Int) {
@volatile // JMM does not guarantee visibility for non-final fields
private var todo = occurrences
/**
* This method decides whether to filter the event (<code>true</code>) or not
* (<code>false</code>).
*/
protected def matches(event: LogEvent): Boolean
final def apply(event: LogEvent): Boolean = {
if (matches(event)) {
if (todo != Int.MaxValue) todo -= 1
true
} else false
}
def awaitDone(max: Duration): Boolean = {
if (todo != Int.MaxValue && todo > 0) TestKit.awaitCond(todo == 0, max, noThrow = true)
todo == Int.MaxValue || todo == 0
}
/**
* Apply this filter while executing the given code block. Care is taken to
* remove the filter when the block is finished or aborted.
*/
def intercept[T](code: T)(implicit app: AkkaApplication): T = {
app.mainbus publish TestEvent.Mute(this)
try {
val result = code
if (!awaitDone(app.AkkaConfig.TestEventFilterLeeway))
if (todo > 0)
throw new AssertionError("Timeout waiting for " + todo + " messages on " + this)
else
throw new AssertionError("Received " + (-todo) + " messages too many on " + this)
result
} finally app.mainbus publish TestEvent.UnMute(this)
}
/*
* these default values are just there for easier subclassing
*/
protected val source: Option[AnyRef] = None
protected val message: Either[String, Regex] = Left("")
protected val complete: Boolean = false
/**
* internal implementation helper, no guaranteed API
*/
protected def doMatch(src: AnyRef, msg: Any) = {
val msgstr = if (msg != null) msg.toString else "null"
(source.isDefined && sourceMatch(src) || source.isEmpty) &&
(message match {
case Left(s) if (complete) msgstr == s else msgstr.startsWith(s)
case Right(p) p.findFirstIn(msgstr).isDefined
})
}
private def sourceMatch(src: AnyRef) = {
source.get match {
case c: Class[_] c isInstance src
case s src == s
}
}
}
/**
* Facilities for selectively filtering out expected events from logging so
* that you can keep your test runs console output clean and do not miss real
* error messages.
*
* '''Also have a look at the [[akka.testkit]] package objects `filterEvents` and
* `filterException` methods.'''
*
* The source filters do accept `Class[_]` arguments, matching any
* object which is an instance of the given class, e.g.
*
* {{{
* EventFilter.info(source = classOf[MyActor]) // will match Info events from any MyActor instance
* }}}
*
* The message object will be converted to a string before matching (`"null"` if it is `null`).
*/
object EventFilter {
def apply[A <: Throwable: Manifest](): EventFilter =
ErrorFilter(manifest[A].erasure)
/**
* Create a filter for Error events. Give up to one of <code>start</code> and <code>pattern</code>:
*
* {{{
* EventFilter[MyException]() // filter only on exception type
* EventFilter[MyException]("message") // filter on exactly matching message
* EventFilter[MyException](source = obj) // filter on event source
* EventFilter[MyException](start = "Expected") // filter on start of message
* EventFilter[MyException](source = obj, pattern = "weird.*message") // filter on pattern and message
* }}}
*
* ''Please note that filtering on the `source` being
* `null` does NOT work (passing `null` disables the
* source filter).''
*/
def apply[A <: Throwable: Manifest](message: String = null, source: AnyRef = null, start: String = "", pattern: String = null, occurrences: Int = Int.MaxValue): EventFilter =
ErrorFilter(manifest[A].erasure, Option(source),
if (message ne null) Left(message) else Option(pattern) map (new Regex(_)) toRight start,
message ne null)(occurrences)
def apply[A <: Throwable: Manifest](message: String): EventFilter =
ErrorMessageFilter(manifest[A].erasure, message)
/**
* Create a filter for Warning events. Give up to one of <code>start</code> and <code>pattern</code>:
*
* {{{
* EventFilter.warning() // filter only on exception type
* EventFilter.warning(source = obj) // filter on event source
* EventFilter.warning(start = "Expected") // filter on start of message
* EventFilter.warning(source = obj, pattern = "weird.*message") // filter on pattern and message
* }}}
*
* ''Please note that filtering on the `source` being
* `null` does NOT work (passing `null` disables the
* source filter).''
*/
def warning(message: String = null, source: AnyRef = null, start: String = "", pattern: String = null, occurrences: Int = Int.MaxValue): EventFilter =
WarningFilter(Option(source),
if (message ne null) Left(message) else Option(pattern) map (new Regex(_)) toRight start,
message ne null)(occurrences)
def apply[A <: Throwable: Manifest](source: AnyRef): EventFilter =
ErrorSourceFilter(manifest[A].erasure, source)
/**
* Create a filter for Info events. Give up to one of <code>start</code> and <code>pattern</code>:
*
* {{{
* EventFilter.info() // filter only on exception type
* EventFilter.info(source = obj) // filter on event source
* EventFilter.info(start = "Expected") // filter on start of message
* EventFilter.info(source = obj, pattern = "weird.*message") // filter on pattern and message
* }}}
*
* ''Please note that filtering on the `source` being
* `null` does NOT work (passing `null` disables the
* source filter).''
*/
def info(message: String = null, source: AnyRef = null, start: String = "", pattern: String = null, occurrences: Int = Int.MaxValue): EventFilter =
InfoFilter(Option(source),
if (message ne null) Left(message) else Option(pattern) map (new Regex(_)) toRight start,
message ne null)(occurrences)
def apply[A <: Throwable: Manifest](source: AnyRef, message: String): EventFilter =
ErrorSourceMessageFilter(manifest[A].erasure, source, message)
/**
* Create a filter for Debug events. Give up to one of <code>start</code> and <code>pattern</code>:
*
* {{{
* EventFilter.debug() // filter only on exception type
* EventFilter.debug(source = obj) // filter on event source
* EventFilter.debug(start = "Expected") // filter on start of message
* EventFilter.debug(source = obj, pattern = "weird.*message") // filter on pattern and message
* }}}
*
* ''Please note that filtering on the `source` being
* `null` does NOT work (passing `null` disables the
* source filter).''
*/
def debug(message: String = null, source: AnyRef = null, start: String = "", pattern: String = null, occurrences: Int = Int.MaxValue): EventFilter =
DebugFilter(Option(source),
if (message ne null) Left(message) else Option(pattern) map (new Regex(_)) toRight start,
message ne null)(occurrences)
def custom(test: (Event) Boolean): EventFilter =
CustomEventFilter(test)
/**
* Create a custom event filter. The filter will affect those events for
* which the supplied partial function is defined and returns
* `true`.
*
* {{{
* EventFilter.custom {
* case Warning(ref, "my warning") if ref == actor || ref == null => true
* }
* }}}
*/
def custom(test: PartialFunction[LogEvent, Boolean], occurrences: Int = Int.MaxValue): EventFilter =
CustomEventFilter(test)(occurrences)
}
case class ErrorFilter(throwable: Class[_]) extends EventFilter {
def apply(event: Event) = event match {
case Error(cause, _, _) throwable isInstance cause
case _ false
/**
* Filter which matches Error events, if they satisfy the given criteria:
* <ul>
* <li><code>throwable</code> applies an upper bound on the type of exception contained in the Error event</li>
* <li><code>source</code>, if given, applies a filter on the events origin</li>
* <li><code>message</code> applies a filter on the events message (either
* with String.startsWith or Regex.findFirstIn().isDefined); if the message
* itself does not match, the match is retried with the contained Exceptions
* message; if both are <code>null</code>, the filter always matches if at
* the same time the Exceptions stack trace is empty (this catches
* JVM-omitted fast-throw exceptions)</li>
* </ul>
* If you want to match all Error events, the most efficient is to use <code>Left("")</code>.
*/
case class ErrorFilter(
throwable: Class[_],
override val source: Option[AnyRef],
override val message: Either[String, Regex],
override val complete: Boolean)(occurrences: Int) extends EventFilter(occurrences) {
def matches(event: LogEvent) = {
event match {
case Error(cause, src, msg) if throwable isInstance cause
(msg == null && cause.getMessage == null && cause.getStackTrace.length == 0) ||
doMatch(src, msg) || doMatch(src, cause.getMessage)
case _ false
}
}
/**
* Java API
*
* @param source
* apply this filter only to events from the given source; do not filter on source if this is given as <code>null</code>
* @param message
* apply this filter only to events whose message matches; do not filter on message if this is given as <code>null</code>
* @param pattern
* if <code>false</code>, the message string must start with the given
* string, otherwise the <code>message</code> argument is treated as
* regular expression which is matched against the message (may match only
* a substring to filter)
* @param complete
* whether the events message must match the given message string or pattern completely
*/
def this(throwable: Class[_], source: AnyRef, message: String, pattern: Boolean, complete: Boolean, occurrences: Int) =
this(throwable, Option(source),
if (message eq null) Left("")
else if (pattern) Right(new Regex(message))
else Left(message),
complete)(occurrences)
/**
* Java API: filter only on the given type of exception
*/
def this(throwable: Class[_]) = this(throwable, null, null, false, false, Int.MaxValue)
}
/**
* Filter which matches Warning events, if they satisfy the given criteria:
* <ul>
* <li><code>source</code>, if given, applies a filter on the events origin</li>
* <li><code>message</code> applies a filter on the events message (either with String.startsWith or Regex.findFirstIn().isDefined)</li>
* </ul>
* If you want to match all Warning events, the most efficient is to use <code>Left("")</code>.
*/
case class WarningFilter(
override val source: Option[AnyRef],
override val message: Either[String, Regex],
override val complete: Boolean)(occurrences: Int) extends EventFilter(occurrences) {
def matches(event: LogEvent) = {
event match {
case Warning(src, msg) doMatch(src, msg)
case _ false
}
}
/**
* Java API
*
* @param source
* apply this filter only to events from the given source; do not filter on source if this is given as <code>null</code>
* @param message
* apply this filter only to events whose message matches; do not filter on message if this is given as <code>null</code>
* @param pattern
* if <code>false</code>, the message string must start with the given
* string, otherwise the <code>message</code> argument is treated as
* regular expression which is matched against the message (may match only
* a substring to filter)
* @param complete
* whether the events message must match the given message string or pattern completely
*/
def this(source: AnyRef, message: String, pattern: Boolean, complete: Boolean, occurrences: Int) =
this(Option(source),
if (message eq null) Left("")
else if (pattern) Right(new Regex(message))
else Left(message),
complete)(occurrences)
}
/**
* Filter which matches Info events, if they satisfy the given criteria:
* <ul>
* <li><code>source</code>, if given, applies a filter on the events origin</li>
* <li><code>message</code> applies a filter on the events message (either with String.startsWith or Regex.findFirstIn().isDefined)</li>
* </ul>
* If you want to match all Info events, the most efficient is to use <code>Left("")</code>.
*/
case class InfoFilter(
override val source: Option[AnyRef],
override val message: Either[String, Regex],
override val complete: Boolean)(occurrences: Int) extends EventFilter(occurrences) {
def matches(event: LogEvent) = {
event match {
case Info(src, msg) doMatch(src, msg)
case _ false
}
}
/**
* Java API
*
* @param source
* apply this filter only to events from the given source; do not filter on source if this is given as <code>null</code>
* @param message
* apply this filter only to events whose message matches; do not filter on message if this is given as <code>null</code>
* @param pattern
* if <code>false</code>, the message string must start with the given
* string, otherwise the <code>message</code> argument is treated as
* regular expression which is matched against the message (may match only
* a substring to filter)
* @param complete
* whether the events message must match the given message string or pattern completely
*/
def this(source: AnyRef, message: String, pattern: Boolean, complete: Boolean, occurrences: Int) =
this(Option(source),
if (message eq null) Left("")
else if (pattern) Right(new Regex(message))
else Left(message),
complete)(occurrences)
}
/**
* Filter which matches Debug events, if they satisfy the given criteria:
* <ul>
* <li><code>source</code>, if given, applies a filter on the events origin</li>
* <li><code>message</code> applies a filter on the events message (either with String.startsWith or Regex.findFirstIn().isDefined)</li>
* </ul>
* If you want to match all Debug events, the most efficient is to use <code>Left("")</code>.
*/
case class DebugFilter(
override val source: Option[AnyRef],
override val message: Either[String, Regex],
override val complete: Boolean)(occurrences: Int) extends EventFilter(occurrences) {
def matches(event: LogEvent) = {
event match {
case Debug(src, msg) doMatch(src, msg)
case _ false
}
}
/**
* Java API
*
* @param source
* apply this filter only to events from the given source; do not filter on source if this is given as <code>null</code>
* @param message
* apply this filter only to events whose message matches; do not filter on message if this is given as <code>null</code>
* @param pattern
* if <code>false</code>, the message string must start with the given
* string, otherwise the <code>message</code> argument is treated as
* regular expression which is matched against the message (may match only
* a substring to filter)
* @param complete
* whether the events message must match the given message string or pattern completely
*/
def this(source: AnyRef, message: String, pattern: Boolean, complete: Boolean, occurrences: Int) =
this(Option(source),
if (message eq null) Left("")
else if (pattern) Right(new Regex(message))
else Left(message),
complete)(occurrences)
}
/**
* Custom event filter when the others do not fit the bill.
*
* If the partial function is defined and returns true, filter the event.
*/
case class CustomEventFilter(test: PartialFunction[LogEvent, Boolean])(occurrences: Int) extends EventFilter(occurrences) {
def matches(event: LogEvent) = {
test.isDefinedAt(event) && test(event)
}
}
case class ErrorMessageFilter(throwable: Class[_], message: String) extends EventFilter {
def apply(event: Event) = event match {
case Error(cause, _, _) if !(throwable isInstance cause) false
case Error(cause, _, null) if cause.getMessage eq null cause.getStackTrace.length == 0
case Error(cause, _, null) cause.getMessage startsWith message
case Error(cause, _, msg)
(msg.toString startsWith message) || (cause.getMessage startsWith message)
case _ false
}
}
case class ErrorSourceFilter(throwable: Class[_], source: AnyRef) extends EventFilter {
def apply(event: Event) = event match {
case Error(cause, instance, _) (throwable isInstance cause) && (source eq instance)
case _ false
}
}
case class ErrorSourceMessageFilter(throwable: Class[_], source: AnyRef, message: String) extends EventFilter {
def apply(event: Event) = event match {
case Error(cause, instance, _) if !((throwable isInstance cause) && (source eq instance)) false
case Error(cause, _, null) if cause.getMessage eq null cause.getStackTrace.length == 0
case Error(cause, _, null) cause.getMessage startsWith message
case Error(cause, _, msg)
(msg.toString startsWith message) || (cause.getMessage startsWith message)
case _ false
}
}
case class CustomEventFilter(test: (Event) Boolean) extends EventFilter {
def apply(event: Event) = test(event)
}
class TestEventListener extends EventHandler.DefaultListener {
/**
* EventListener for running tests, which allows selectively filtering out
* expected messages. To use it, include something like this into
* <code>akka.test.conf</code> and run your tests with system property
* <code>"akka.mode"</code> set to <code>"test"</code>:
*
* <pre><code>
* akka {
* event-handlers = ["akka.testkit.TestEventListener"]
* }
* </code></pre>
*/
class TestEventListener extends Logging.DefaultLogger {
import TestEvent._
var filters: List[EventFilter] = Nil
override def receive: Actor.Receive = ({
case Mute(filters) filters foreach addFilter
case UnMute(filters) filters foreach removeFilter
case UnMuteAll filters = Nil
case event: Event if filter(event)
}: Actor.Receive) orElse super.receive
override def receive = {
case InitializeLogger(bus) Seq(classOf[Mute], classOf[UnMute]) foreach (bus.subscribe(context.self, _))
case Mute(filters) filters foreach addFilter
case UnMute(filters) filters foreach removeFilter
case event: LogEvent if (!filter(event)) print(event)
}
def filter(event: Event): Boolean = filters exists (f try { f(event) } catch { case e: Exception false })
def filter(event: LogEvent): Boolean = filters exists (f try { f(event) } catch { case e: Exception false })
def addFilter(filter: EventFilter): Unit = filters ::= filter

View file

@ -99,7 +99,8 @@ class TestKit(_app: AkkaApplication) {
* ActorRef of the test actor. Access is provided to enable e.g.
* registration as message target.
*/
val testActor: ActorRef = new LocalActorRef(app, Props(new TestActor(queue)).copy(dispatcher = new CallingThreadDispatcher(app)), app.guardian, "testActor" + TestKit.testActorId.incrementAndGet(), true)
val testActor: ActorRef = app.systemActorOf(Props(new TestActor(queue)).copy(dispatcher = new CallingThreadDispatcher(app)),
"testActor" + TestKit.testActorId.incrementAndGet)
private var end: Duration = Duration.Inf
@ -451,12 +452,6 @@ class TestKit(_app: AkkaApplication) {
lastWasNoMsg = true
}
/**
* Same as `receiveWhile(remaining)(f)`, but correctly treating the timeFactor.
*/
@deprecated("insert empty first parameter list", "1.2")
def receiveWhile[T](f: PartialFunction[AnyRef, T]): Seq[T] = receiveWhile(remaining / Duration.timeFactor)(f)
/**
* Receive a series of messages until one does not match the given partial
* function or the idle timeout is met (disabled by default) or the overall
@ -476,7 +471,7 @@ class TestKit(_app: AkkaApplication) {
* </pre>
*/
def receiveWhile[T](max: Duration = Duration.MinusInf, idle: Duration = Duration.Inf, messages: Int = Int.MaxValue)(f: PartialFunction[AnyRef, T]): Seq[T] = {
val stop = now + (if (max == Duration.MinusInf) remaining else max.dilated)
val stop = now + (if (max eq Duration.MinusInf) remaining else max.dilated)
var msg: Message = NullMessage
@tailrec
@ -554,6 +549,41 @@ class TestKit(_app: AkkaApplication) {
object TestKit {
private[testkit] val testActorId = new AtomicInteger(0)
/**
* Block until the given condition evaluates to `true` or the timeout
* expires, whichever comes first.
*
* If no timeout is given, take it from the innermost enclosing `within`
* block.
*
* Note that the timeout is scaled using Duration.timeFactor.
*/
def awaitCond(p: Boolean, max: Duration, interval: Duration = 100.millis, noThrow: Boolean = false): Boolean = {
val stop = now + max
@tailrec
def poll(): Boolean = {
if (!p) {
val toSleep = stop - now
if (toSleep <= Duration.Zero) {
if (noThrow) false
else throw new AssertionError("timeout " + max + " expired")
} else {
Thread.sleep((toSleep min interval).toMillis)
poll()
}
} else true
}
poll()
}
/**
* Obtain current timestamp as Duration for relative measurements (using System.nanoTime).
*/
def now: Duration = System.nanoTime().nanos
}
/**

View file

@ -6,6 +6,7 @@ package akka.testkit
import akka.util.Duration
import java.util.concurrent.{ CountDownLatch, TimeUnit }
import akka.AkkaApplication
class TestLatchTimeoutException(message: String) extends RuntimeException(message)
class TestLatchNoTimeoutException(message: String) extends RuntimeException(message)
@ -20,10 +21,10 @@ class TestLatchNoTimeoutException(message: String) extends RuntimeException(mess
object TestLatch {
val DefaultTimeout = Duration(5, TimeUnit.SECONDS)
def apply(count: Int = 1) = new TestLatch(count)
def apply(count: Int = 1)(implicit app: AkkaApplication) = new TestLatch(count)
}
class TestLatch(count: Int = 1) {
class TestLatch(count: Int = 1)(implicit app: AkkaApplication) {
private var latch = new CountDownLatch(count)
def countDown() = latch.countDown()
@ -33,9 +34,9 @@ class TestLatch(count: Int = 1) {
def await(): Boolean = await(TestLatch.DefaultTimeout)
def await(timeout: Duration): Boolean = {
val opened = latch.await(Testing.testTime(timeout.toNanos), TimeUnit.NANOSECONDS)
val opened = latch.await(timeout.dilated.toNanos, TimeUnit.NANOSECONDS)
if (!opened) throw new TestLatchTimeoutException(
"Timeout of %s with time factor of %s" format (timeout.toString, Duration.timeFactor))
"Timeout of %s with time factor of %s" format (timeout.toString, app.AkkaConfig.TestTimeFactor))
opened
}
@ -43,9 +44,9 @@ class TestLatch(count: Int = 1) {
* Timeout is expected. Throws exception if latch is opened before timeout.
*/
def awaitTimeout(timeout: Duration = TestLatch.DefaultTimeout) = {
val opened = latch.await(Testing.testTime(timeout.toNanos), TimeUnit.NANOSECONDS)
val opened = latch.await(timeout.dilated.toNanos, TimeUnit.NANOSECONDS)
if (opened) throw new TestLatchNoTimeoutException(
"Latch opened before timeout of %s with time factor of %s" format (timeout.toString, Duration.timeFactor))
"Latch opened before timeout of %s with time factor of %s" format (timeout.toString, app.AkkaConfig.TestTimeFactor))
opened
}

View file

@ -1,21 +0,0 @@
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.testkit
import akka.util.Duration
import Duration.timeFactor
/**
* Multiplying numbers used in test timeouts by a factor, set by system property.
* Useful for Jenkins builds (where the machine may need more time).
*/
object Testing {
def testTime(t: Int): Int = (timeFactor * t).toInt
def testTime(t: Long): Long = (timeFactor * t).toLong
def testTime(t: Float): Float = (timeFactor * t).toFloat
def testTime(t: Double): Double = timeFactor * t
def sleepFor(duration: Duration) = Thread.sleep(testTime(duration.toMillis))
}

View file

@ -1,18 +1,28 @@
package akka
import akka.event.EventHandler
import akka.util.Duration
import java.util.concurrent.TimeUnit.MILLISECONDS
package object testkit {
def filterEvents[T](eventFilters: Iterable[EventFilter])(block: T)(implicit app: AkkaApplication): T = {
app.eventHandler.notify(TestEvent.Mute(eventFilters.toSeq))
def now = System.currentTimeMillis
app.mainbus.publish(TestEvent.Mute(eventFilters.toSeq))
try {
block
val result = block
val stop = now + app.AkkaConfig.TestEventFilterLeeway.toMillis
val failed = eventFilters filterNot (_.awaitDone(Duration(stop - now, MILLISECONDS))) map ("Timeout waiting for " + _)
if (failed.nonEmpty)
throw new AssertionError("Filter completion error:\n" + failed.mkString("\n"))
result
} finally {
app.eventHandler.notify(TestEvent.UnMute(eventFilters.toSeq))
app.mainbus.publish(TestEvent.UnMute(eventFilters.toSeq))
}
}
def filterEvents[T](eventFilters: EventFilter*)(block: T)(implicit app: AkkaApplication): T = filterEvents(eventFilters.toSeq)(block)
def filterException[T <: Throwable](block: Unit)(implicit app: AkkaApplication, m: Manifest[T]): Unit = filterEvents(Seq(EventFilter[T]))(block)
def filterException[T <: Throwable](block: Unit)(implicit app: AkkaApplication, m: Manifest[T]): Unit = EventFilter[T]() intercept (block)
}

View file

@ -9,16 +9,24 @@ import org.scalatest.matchers.MustMatchers
import akka.AkkaApplication
import akka.actor.{ Actor, ActorRef, Props }
import akka.dispatch.MessageDispatcher
import akka.event.{ Logging, LoggingAdapter }
import akka.util.duration._
import akka.dispatch.FutureTimeoutException
abstract class AkkaSpec(_application: AkkaApplication = AkkaApplication())
extends TestKit(_application) with WordSpec with MustMatchers with BeforeAndAfterAll {
val log: LoggingAdapter = Logging(app.mainbus, this)
final override def beforeAll {
atStartup()
}
final override def afterAll {
app.stop()
try app.terminationFuture.await(5 seconds) catch {
case _: FutureTimeoutException app.log.warning("failed to stop within 5 seconds")
}
atTermination()
}
@ -40,3 +48,21 @@ abstract class AkkaSpec(_application: AkkaApplication = AkkaApplication())
actorOf(Props(ctx { case "go" try body finally ctx.self.stop() }).withDispatcher(dispatcher)) ! "go"
}
}
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class AkkaSpecSpec extends WordSpec with MustMatchers {
"An AkkaSpec" must {
"terminate all actors" in {
import AkkaApplication.defaultConfig
val app = AkkaApplication("test", defaultConfig ++ Configuration(
"akka.actor.debug.lifecycle" -> true, "akka.loglevel" -> "DEBUG"))
val spec = new AkkaSpec(app) {
val ref = Seq(testActor, app.actorOf(Props.empty, "name"))
}
spec.ref foreach (_ must not be 'shutdown)
app.stop()
spec.awaitCond(spec.ref forall (_.isShutdown), 2 seconds)
}
}
}

View file

@ -6,7 +6,7 @@ package akka.testkit
import org.scalatest.matchers.MustMatchers
import org.scalatest.{ BeforeAndAfterEach, WordSpec }
import akka.actor._
import akka.event.EventHandler
import akka.event.Logging.Warning
import akka.dispatch.{ Future, Promise }
import akka.util.duration._
import akka.AkkaApplication
@ -77,7 +77,6 @@ object TestActorRefSpec {
}
class Logger extends Actor {
import EventHandler._
var count = 0
var msg: String = _
def receive = {
@ -154,7 +153,7 @@ class TestActorRefSpec extends AkkaSpec with BeforeAndAfterEach {
}
"stop when sent a poison pill" in {
filterEvents(EventFilter[ActorKilledException]) {
EventFilter[ActorKilledException]() intercept {
val a = TestActorRef(Props[WorkerActor])
testActor startsMonitoring a
a.!(PoisonPill)(testActor)
@ -167,7 +166,7 @@ class TestActorRefSpec extends AkkaSpec with BeforeAndAfterEach {
}
"restart when Kill:ed" in {
filterEvents(EventFilter[ActorKilledException]) {
EventFilter[ActorKilledException]() intercept {
counter = 2
val boss = TestActorRef(Props(new TActor {
@ -190,9 +189,10 @@ class TestActorRefSpec extends AkkaSpec with BeforeAndAfterEach {
"support futures" in {
val a = TestActorRef[WorkerActor]
val f = a ? "work" mapTo manifest[String]
val f = a ? "work"
// CallingThreadDispatcher means that there is no delay
f must be('completed)
f.get must equal("workDone")
f.as[String] must equal(Some("workDone"))
}
}

View file

@ -4,7 +4,6 @@ import org.scalatest.WordSpec
import org.scalatest.matchers.MustMatchers
import org.scalatest.{ BeforeAndAfterEach, WordSpec }
import akka.actor._
import akka.event.EventHandler
import akka.dispatch.Future
import akka.util.duration._

View file

@ -3,23 +3,10 @@ package akka.testkit
import org.scalatest.matchers.MustMatchers
import org.scalatest.{ BeforeAndAfterEach, WordSpec }
import akka.util.Duration
import akka.config.Configuration
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class TestTimeSpec extends AkkaSpec with BeforeAndAfterEach {
val tf = Duration.timeFactor
override def beforeEach {
val f = Duration.getClass.getDeclaredField("timeFactor")
f.setAccessible(true)
f.setDouble(Duration, 2.0)
}
override def afterEach {
val f = Duration.getClass.getDeclaredField("timeFactor")
f.setAccessible(true)
f.setDouble(Duration, tf)
}
class TestTimeSpec extends AkkaSpec(Configuration("akka.test.timefactor" -> 2.0)) with BeforeAndAfterEach {
"A TestKit" must {

View file

@ -5,7 +5,7 @@
package akka.tutorial.second
import akka.actor.Actor._
import akka.event.EventHandler
import akka.event.Logging
import System.{ currentTimeMillis now }
import akka.routing.Routing.Broadcast
import akka.routing._
@ -15,6 +15,7 @@ import akka.actor.{ ActorRef, Timeout, Actor, PoisonPill }
object Pi extends App {
val app = AkkaApplication()
val log = Logging(app, this)
calculate(nrOfWorkers = 4, nrOfElements = 10000, nrOfMessages = 10000)
@ -109,9 +110,9 @@ object Pi extends App {
master.?(Calculate, Timeout(60000)).
await.resultOrException match { //wait for the result, with a 60 seconds timeout
case Some(pi)
app.eventHandler.info(this, "\n\tPi estimate: \t\t%s\n\tCalculation time: \t%s millis".format(pi, (now - start)))
log.info("\n\tPi estimate: \t\t{}\n\tCalculation time: \t{} millis", pi, now - start)
case None
app.eventHandler.error(this, "Pi calculation did not complete within the timeout.")
log.error("Pi calculation did not complete within the timeout.")
}
}
}

View file

@ -14,8 +14,11 @@ akka {
time-unit = "seconds" # Time unit for all timeout properties throughout the config
event-handlers = ["akka.event.EventHandler$DefaultListener"] # Event handlers to register at boot time (EventHandler$DefaultListener logs to STDOUT)
event-handler-level = "INFO" # Options: ERROR, WARNING, INFO, DEBUG
event-handlers = ["akka.event.Logging$DefaultLogger"] # Event handlers to register at boot time (Logging$DefaultLogger logs to STDOUT)
loglevel = "INFO" # Options: ERROR, WARNING, INFO, DEBUG
# this level is used by the configured loggers (see "event-handlers") as soon
# as they have been started; before that, see "stdout-loglevel"
stdout-loglevel = "WARNING" # Loglevel for the very basic logger activated during AkkaApplication startup
event-handler-dispatcher {
type = "Dispatcher" # Must be one of the following

View file

@ -6,7 +6,7 @@ include "akka-reference.conf"
akka {
event-handlers = ["akka.testkit.TestEventListener"]
event-handler-level = "WARNING"
loglevel = "WARNING"
actor {
default-dispatcher {
core-pool-size = 4