Logging for typed #23326
This commit is contained in:
parent
08b0d34a4c
commit
ac64a7bb98
28 changed files with 1449 additions and 307 deletions
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package akka.actor.typed.javadsl;
|
||||
|
||||
import akka.actor.typed.Behavior;
|
||||
import akka.event.Logging;
|
||||
import akka.japi.pf.PFBuilder;
|
||||
import akka.testkit.CustomEventFilter;
|
||||
import akka.testkit.typed.TestKit;
|
||||
import com.typesafe.config.ConfigFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.scalatest.junit.JUnitSuite;
|
||||
import scala.concurrent.duration.FiniteDuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ActorLoggingTest extends JUnitSuite {
|
||||
|
||||
private final static TestKit testKit = new TestKit("ActorLoggingTest",
|
||||
ConfigFactory.parseString(
|
||||
"akka.loglevel = INFO\n" +
|
||||
"akka.loggers = [\"akka.testkit.TestEventListener\"]"
|
||||
));
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
testKit.shutdown();
|
||||
}
|
||||
|
||||
interface Protocol {
|
||||
String getTransactionId();
|
||||
}
|
||||
|
||||
static class Message implements Protocol {
|
||||
public final String transactionId;
|
||||
public Message(String transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loggingProvidesMDC() {
|
||||
Behavior<Protocol> behavior = Behaviors.withMdc(
|
||||
Protocol.class,
|
||||
(msg) -> {
|
||||
Map<String, Object> mdc = new HashMap<>();
|
||||
mdc.put("txId", msg.getTransactionId());
|
||||
return mdc;
|
||||
},
|
||||
Behaviors.immutable(Protocol.class)
|
||||
.onMessage(Message.class, (ctx, msg) -> {
|
||||
ctx.getLog().info(msg.toString());
|
||||
return Behaviors.same();
|
||||
}).build()
|
||||
);
|
||||
|
||||
CustomEventFilter eventFilter = new CustomEventFilter(new PFBuilder<Logging.LogEvent, Object>()
|
||||
.match(Logging.LogEvent.class, (event) ->
|
||||
event.getMDC().containsKey("txId"))
|
||||
.build(),
|
||||
1);
|
||||
|
||||
testKit.spawn(behavior);
|
||||
eventFilter.awaitDone(FiniteDuration.create(3, TimeUnit.SECONDS));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -308,14 +308,15 @@ abstract class ActorContextSpec extends TypedAkkaSpec {
|
|||
import ActorContextSpec._
|
||||
|
||||
val config = ConfigFactory.parseString(
|
||||
"""|akka {
|
||||
| loglevel = WARNING
|
||||
| actor.debug {
|
||||
| lifecycle = off
|
||||
| autoreceive = off
|
||||
| }
|
||||
| typed.loggers = ["akka.testkit.typed.TestEventListener"]
|
||||
|}""".stripMargin)
|
||||
"""
|
||||
akka {
|
||||
loglevel = WARNING
|
||||
loggers = ["akka.testkit.TestEventListener"]
|
||||
actor.debug {
|
||||
lifecycle = off
|
||||
autoreceive = off
|
||||
}
|
||||
}""")
|
||||
|
||||
implicit lazy val system: ActorSystem[GuardianCommand] =
|
||||
ActorSystem(guardian(), AkkaSpec.getCallerName(classOf[ActorContextSpec]), config = Some(config withFallback AkkaSpec.testConf))
|
||||
|
|
@ -379,7 +380,8 @@ abstract class ActorContextSpec extends TypedAkkaSpec {
|
|||
pattern: String = null,
|
||||
occurrences: Int = Int.MaxValue)(implicit system: ActorSystem[GuardianCommand]): EventFilter = {
|
||||
val filter = EventFilter(message, source, start, pattern, occurrences)
|
||||
system.eventStream.publish(Mute(filter))
|
||||
import scaladsl.adapter._
|
||||
system.toUntyped.eventStream.publish(Mute(filter))
|
||||
filter
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,228 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package akka.actor.typed.scaladsl
|
||||
|
||||
import akka.actor.typed.{ LogMarker, TestException, TypedAkkaSpec, scaladsl }
|
||||
import akka.testkit.EventFilter
|
||||
import akka.testkit.typed.TestKit
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import akka.event.Logging
|
||||
import akka.event.Logging.{ LogEventWithCause, LogEventWithMarker }
|
||||
|
||||
import scala.util.control.NoStackTrace
|
||||
|
||||
class ActorLoggingSpec extends TestKit(ConfigFactory.parseString(
|
||||
"""
|
||||
akka.loglevel = DEBUG
|
||||
akka.loggers = ["akka.testkit.TestEventListener"]
|
||||
""")) with TypedAkkaSpec {
|
||||
|
||||
val marker = LogMarker("marker")
|
||||
val cause = new TestException("böö")
|
||||
|
||||
implicit val untyped = system.toUntyped
|
||||
|
||||
"Logging in a typed actor" must {
|
||||
|
||||
"be conveniently available from the ctx" in {
|
||||
val actor = EventFilter.info("Started", source = "akka://ActorLoggingSpec/user/the-actor", occurrences = 1).intercept {
|
||||
spawn(Behaviors.deferred[String] { ctx ⇒
|
||||
ctx.log.info("Started")
|
||||
|
||||
Behaviors.immutable { (ctx, msg) ⇒
|
||||
ctx.log.info("got message {}", msg)
|
||||
Behaviors.same
|
||||
}
|
||||
}, "the-actor")
|
||||
}
|
||||
|
||||
EventFilter.info("got message Hello", source = "akka://ActorLoggingSpec/user/the-actor", occurrences = 1).intercept {
|
||||
actor ! "Hello"
|
||||
}
|
||||
}
|
||||
|
||||
"pass markers to the log" in {
|
||||
EventFilter.custom({
|
||||
case event: LogEventWithMarker if event.marker == marker ⇒ true
|
||||
}, occurrences = 5).intercept(
|
||||
spawn(Behaviors.deferred[Any] { ctx ⇒
|
||||
ctx.log.debug(marker, "whatever")
|
||||
ctx.log.info(marker, "whatever")
|
||||
ctx.log.warning(marker, "whatever")
|
||||
ctx.log.error(marker, "whatever")
|
||||
ctx.log.error(marker, cause, "whatever")
|
||||
Behaviors.stopped
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
"pass cause with warning" in {
|
||||
EventFilter.custom({
|
||||
case event: LogEventWithCause if event.cause == cause ⇒ true
|
||||
}, occurrences = 2).intercept(
|
||||
spawn(Behaviors.deferred[Any] { ctx ⇒
|
||||
ctx.log.warning(cause, "whatever")
|
||||
ctx.log.warning(marker, cause, "whatever")
|
||||
Behaviors.stopped
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
"provide a whole bunch of logging overloads" in {
|
||||
|
||||
// Not the best test but at least it exercises every log overload ;)
|
||||
|
||||
EventFilter.custom({
|
||||
case _ ⇒ true // any is fine, we're just after the right count of statements reaching the listener
|
||||
}, occurrences = 72).intercept {
|
||||
spawn(Behaviors.deferred[String] { ctx ⇒
|
||||
ctx.log.debug("message")
|
||||
ctx.log.debug("{}", "arg1")
|
||||
ctx.log.debug("{} {}", "arg1", "arg2")
|
||||
ctx.log.debug("{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.debug("{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.debug("{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
ctx.log.debug(marker, "message")
|
||||
ctx.log.debug(marker, "{}", "arg1")
|
||||
ctx.log.debug(marker, "{} {}", "arg1", "arg2")
|
||||
ctx.log.debug(marker, "{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.debug(marker, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.debug(marker, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
|
||||
ctx.log.info("message")
|
||||
ctx.log.info("{}", "arg1")
|
||||
ctx.log.info("{} {}", "arg1", "arg2")
|
||||
ctx.log.info("{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.info("{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.info("{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
ctx.log.info(marker, "message")
|
||||
ctx.log.info(marker, "{}", "arg1")
|
||||
ctx.log.info(marker, "{} {}", "arg1", "arg2")
|
||||
ctx.log.info(marker, "{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.info(marker, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.info(marker, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
|
||||
ctx.log.warning("message")
|
||||
ctx.log.warning("{}", "arg1")
|
||||
ctx.log.warning("{} {}", "arg1", "arg2")
|
||||
ctx.log.warning("{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.warning("{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.warning("{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
ctx.log.warning(marker, "message")
|
||||
ctx.log.warning(marker, "{}", "arg1")
|
||||
ctx.log.warning(marker, "{} {}", "arg1", "arg2")
|
||||
ctx.log.warning(marker, "{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.warning(marker, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.warning(marker, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
|
||||
ctx.log.warning(cause, "message")
|
||||
ctx.log.warning(cause, "{}", "arg1")
|
||||
ctx.log.warning(cause, "{} {}", "arg1", "arg2")
|
||||
ctx.log.warning(cause, "{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.warning(cause, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.warning(cause, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
ctx.log.warning(marker, cause, "message")
|
||||
ctx.log.warning(marker, cause, "{}", "arg1")
|
||||
ctx.log.warning(marker, cause, "{} {}", "arg1", "arg2")
|
||||
ctx.log.warning(marker, cause, "{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.warning(marker, cause, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.warning(marker, cause, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
|
||||
ctx.log.error("message")
|
||||
ctx.log.error("{}", "arg1")
|
||||
ctx.log.error("{} {}", "arg1", "arg2")
|
||||
ctx.log.error("{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.error("{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.error("{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
ctx.log.error(marker, "message")
|
||||
ctx.log.error(marker, "{}", "arg1")
|
||||
ctx.log.error(marker, "{} {}", "arg1", "arg2")
|
||||
ctx.log.error(marker, "{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.error(marker, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.error(marker, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
|
||||
ctx.log.error(cause, "message")
|
||||
ctx.log.error(cause, "{}", "arg1")
|
||||
ctx.log.error(cause, "{} {}", "arg1", "arg2")
|
||||
ctx.log.error(cause, "{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.error(cause, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.error(cause, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
ctx.log.error(marker, cause, "message")
|
||||
ctx.log.error(marker, cause, "{}", "arg1")
|
||||
ctx.log.error(marker, cause, "{} {}", "arg1", "arg2")
|
||||
ctx.log.error(marker, cause, "{} {} {}", "arg1", "arg2", "arg3")
|
||||
ctx.log.error(marker, cause, "{} {} {} {}", "arg1", "arg2", "arg3", "arg4")
|
||||
ctx.log.error(marker, cause, "{} {} {} {} {}", Array("arg1", "arg2", "arg3", "arg4", "arg5"))
|
||||
|
||||
Behaviors.stopped
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
trait Protocol {
|
||||
def transactionId: Long
|
||||
}
|
||||
case class Message(transactionId: Long, message: String) extends Protocol
|
||||
|
||||
"Logging with MDC for a typed actor" must {
|
||||
|
||||
"provide the MDC values in the log" in {
|
||||
val behaviors = Behaviors.withMdc[Protocol](
|
||||
{ (msg) ⇒
|
||||
if (msg.transactionId == 1)
|
||||
Map(
|
||||
"txId" -> msg.transactionId,
|
||||
"first" -> true
|
||||
)
|
||||
else Map("txId" -> msg.transactionId)
|
||||
},
|
||||
Behaviors.deferred { ctx ⇒
|
||||
ctx.log.info("Starting")
|
||||
Behaviors.immutable { (ctx, msg) ⇒
|
||||
ctx.log.info("Got message!")
|
||||
Behaviors.same
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// mdc on defer is empty (thread and timestamp MDC is added by logger backend)
|
||||
val ref = EventFilter.custom({
|
||||
case logEvent if logEvent.level == Logging.InfoLevel ⇒
|
||||
logEvent.message should ===("Starting")
|
||||
logEvent.mdc shouldBe empty
|
||||
true
|
||||
case other ⇒ system.log.error(s"Unexpected log event: {}", other); false
|
||||
}, occurrences = 1).intercept {
|
||||
spawn(behaviors)
|
||||
}
|
||||
|
||||
// mdc on message
|
||||
EventFilter.custom({
|
||||
case logEvent if logEvent.level == Logging.InfoLevel ⇒
|
||||
logEvent.message should ===("Got message!")
|
||||
logEvent.mdc should ===(Map("txId" -> 1L, "first" -> true))
|
||||
true
|
||||
case other ⇒ system.log.error(s"Unexpected log event: {}", other); false
|
||||
}, occurrences = 1).intercept {
|
||||
ref ! Message(1, "first")
|
||||
}
|
||||
|
||||
// mdc does not leak between messages
|
||||
EventFilter.custom({
|
||||
case logEvent if logEvent.level == Logging.InfoLevel ⇒
|
||||
logEvent.message should ===("Got message!")
|
||||
logEvent.mdc should ===(Map("txId" -> 2L))
|
||||
true
|
||||
case other ⇒ system.log.error(s"Unexpected log event: {}", other); false
|
||||
}, occurrences = 1).intercept {
|
||||
ref ! Message(2, "second")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,9 +19,6 @@ object StashSpec {
|
|||
final case class GetProcessed(replyTo: ActorRef[Vector[String]]) extends Command
|
||||
final case class GetStashSize(replyTo: ActorRef[Int]) extends Command
|
||||
|
||||
// FIXME replace when we get the logging in place, #23326
|
||||
def log(ctx: ActorContext[_]): LoggingAdapter = ctx.system.log
|
||||
|
||||
def active(processed: Vector[String]): Behavior[Command] =
|
||||
Behaviors.immutable { (ctx, cmd) ⇒
|
||||
cmd match {
|
||||
|
|
@ -57,13 +54,13 @@ object StashSpec {
|
|||
case UnstashAll ⇒
|
||||
buffer.unstashAll(ctx, active(processed))
|
||||
case Unstash ⇒
|
||||
log(ctx).debug(s"Unstash ${buffer.size}")
|
||||
ctx.log.debug(s"Unstash ${buffer.size}")
|
||||
if (buffer.isEmpty)
|
||||
active(processed)
|
||||
else {
|
||||
ctx.self ! Unstash // continue unstashing until buffer is empty
|
||||
val numberOfMessages = 2
|
||||
log(ctx).debug(s"Unstash $numberOfMessages of ${buffer.size}, starting with ${buffer.head}")
|
||||
ctx.log.debug(s"Unstash $numberOfMessages of ${buffer.size}, starting with ${buffer.head}")
|
||||
buffer.unstash(ctx, unstashing(buffer.drop(numberOfMessages), processed), numberOfMessages, Unstashed)
|
||||
}
|
||||
case Stash ⇒
|
||||
|
|
@ -77,28 +74,28 @@ object StashSpec {
|
|||
Behaviors.immutable { (ctx, cmd) ⇒
|
||||
cmd match {
|
||||
case Unstashed(msg: Msg) ⇒
|
||||
log(ctx).debug(s"unstashed $msg")
|
||||
ctx.log.debug(s"unstashed $msg")
|
||||
unstashing(buffer, processed :+ msg.s)
|
||||
case Unstashed(GetProcessed(replyTo)) ⇒
|
||||
log(ctx).debug(s"unstashed GetProcessed")
|
||||
ctx.log.debug(s"unstashed GetProcessed")
|
||||
replyTo ! processed
|
||||
Behaviors.same
|
||||
case msg: Msg ⇒
|
||||
log(ctx).debug(s"got $msg in unstashing")
|
||||
ctx.log.debug(s"got $msg in unstashing")
|
||||
unstashing(buffer :+ msg, processed)
|
||||
case get: GetProcessed ⇒
|
||||
log(ctx).debug(s"got GetProcessed in unstashing")
|
||||
ctx.log.debug(s"got GetProcessed in unstashing")
|
||||
unstashing(buffer :+ get, processed)
|
||||
case Stash ⇒
|
||||
stashing(buffer, processed)
|
||||
case Unstash ⇒
|
||||
if (buffer.isEmpty) {
|
||||
log(ctx).debug(s"unstashing done")
|
||||
ctx.log.debug(s"unstashing done")
|
||||
active(processed)
|
||||
} else {
|
||||
ctx.self ! Unstash // continue unstashing until buffer is empty
|
||||
val numberOfMessages = 2
|
||||
log(ctx).debug(s"Unstash $numberOfMessages of ${buffer.size}, starting with ${buffer.head}")
|
||||
ctx.log.debug(s"Unstash $numberOfMessages of ${buffer.size}, starting with ${buffer.head}")
|
||||
buffer.unstash(ctx, unstashing(buffer.drop(numberOfMessages), processed), numberOfMessages, Unstashed)
|
||||
}
|
||||
case GetStashSize(replyTo) ⇒
|
||||
|
|
@ -147,15 +144,15 @@ object StashSpec {
|
|||
} else {
|
||||
ctx.self ! Unstash // continue unstashing until buffer is empty
|
||||
val numberOfMessages = 2
|
||||
log(ctx).debug(s"Unstash $numberOfMessages of ${buffer.size}, starting with ${buffer.head}")
|
||||
ctx.log.debug(s"Unstash $numberOfMessages of ${buffer.size}, starting with ${buffer.head}")
|
||||
buffer.unstash(ctx, this, numberOfMessages, Unstashed)
|
||||
}
|
||||
case Unstashed(msg: Msg) ⇒
|
||||
log(ctx).debug(s"unstashed $msg")
|
||||
ctx.log.debug(s"unstashed $msg")
|
||||
processed :+= msg.s
|
||||
this
|
||||
case Unstashed(GetProcessed(replyTo)) ⇒
|
||||
log(ctx).debug(s"unstashed GetProcessed")
|
||||
ctx.log.debug(s"unstashed GetProcessed")
|
||||
replyTo ! processed
|
||||
Behaviors.same
|
||||
case _: Unstashed ⇒
|
||||
|
|
|
|||
|
|
@ -4,14 +4,11 @@
|
|||
package docs.akka.typed
|
||||
|
||||
//#imports
|
||||
import akka.actor.typed.scaladsl.Behaviors
|
||||
import akka.actor.typed.{ ActorSystem, Logger, PostStop }
|
||||
|
||||
import scala.concurrent.Await
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import akka.actor.typed.ActorSystem
|
||||
import akka.actor.typed.PostStop
|
||||
import akka.actor.typed.scaladsl.Behaviors
|
||||
import akka.event.LoggingAdapter
|
||||
|
||||
//#imports
|
||||
|
||||
import akka.actor.typed.TypedAkkaSpecWithShutdown
|
||||
|
|
@ -27,16 +24,16 @@ object GracefulStopDocSpec {
|
|||
final case object GracefulShutdown extends JobControlLanguage
|
||||
|
||||
// Predefined cleanup operation
|
||||
def cleanup(log: LoggingAdapter): Unit = log.info("Cleaning up!")
|
||||
def cleanup(log: Logger): Unit = log.info("Cleaning up!")
|
||||
|
||||
val mcpa = Behaviors.immutable[JobControlLanguage] { (ctx, msg) ⇒
|
||||
msg match {
|
||||
case SpawnJob(jobName) ⇒
|
||||
ctx.system.log.info("Spawning job {}!", jobName)
|
||||
ctx.log.info("Spawning job {}!", jobName)
|
||||
ctx.spawn(Job.job(jobName), name = jobName)
|
||||
Behaviors.same
|
||||
case GracefulShutdown ⇒
|
||||
ctx.system.log.info("Initiating graceful shutdown...")
|
||||
ctx.log.info("Initiating graceful shutdown...")
|
||||
// perform graceful stop, executing cleanup before final system termination
|
||||
// behavior executing cleanup is passed as a parameter to Actor.stopped
|
||||
Behaviors.stopped {
|
||||
|
|
@ -49,7 +46,7 @@ object GracefulStopDocSpec {
|
|||
}
|
||||
}.onSignal {
|
||||
case (ctx, PostStop) ⇒
|
||||
ctx.system.log.info("MCPA stopped")
|
||||
ctx.log.info("MCPA stopped")
|
||||
Behaviors.same
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +59,7 @@ object GracefulStopDocSpec {
|
|||
|
||||
def job(name: String) = Behaviors.onSignal[JobControlLanguage] {
|
||||
case (ctx, PostStop) ⇒
|
||||
ctx.system.log.info("Worker {} stopped", name)
|
||||
ctx.log.info("Worker {} stopped", name)
|
||||
Behaviors.same
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
package akka.actor.typed
|
||||
|
||||
import akka.annotation.InternalApi
|
||||
import akka.event.typed.EventStream
|
||||
import akka.{ actor ⇒ a }
|
||||
|
||||
import scala.annotation.unchecked.uncheckedVariance
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import java.util.Optional
|
|||
|
||||
import akka.actor.BootstrapSetup
|
||||
import akka.actor.typed.receptionist.Receptionist
|
||||
import akka.event.typed.EventStream
|
||||
|
||||
/**
|
||||
* An ActorSystem is home to a hierarchy of Actors. It is created using
|
||||
|
|
@ -48,20 +47,12 @@ abstract class ActorSystem[-T] extends ActorRef[T] with Extensions {
|
|||
def logConfiguration(): Unit
|
||||
|
||||
/**
|
||||
* A reference to this system’s logFilter, which filters usage of the [[log]]
|
||||
* [[akka.event.LoggingAdapter]] such that only permissible messages are sent
|
||||
* via the [[eventStream]]. The default implementation will just test that
|
||||
* the message is suitable for the current log level.
|
||||
*/
|
||||
def logFilter: e.LoggingFilter
|
||||
|
||||
/**
|
||||
* A [[akka.event.LoggingAdapter]] that can be used to emit log messages
|
||||
* A [[akka.actor.typed.Logger]] that can be used to emit log messages
|
||||
* without specifying a more detailed source. Typically it is desirable to
|
||||
* construct a dedicated LoggingAdapter within each Actor from that Actor’s
|
||||
* [[ActorRef]] in order to identify the log messages.
|
||||
* use the dedicated `Logger` available from each Actor’s [[ActorContext]]
|
||||
* as that ties the log entries to the actor.
|
||||
*/
|
||||
def log: e.LoggingAdapter
|
||||
def log: Logger
|
||||
|
||||
/**
|
||||
* Start-up time in milliseconds since the epoch.
|
||||
|
|
@ -94,11 +85,6 @@ abstract class ActorSystem[-T] extends ActorRef[T] with Extensions {
|
|||
*/
|
||||
def scheduler: a.Scheduler
|
||||
|
||||
/**
|
||||
* Main event bus of this actor system, used for example for logging.
|
||||
*/
|
||||
def eventStream: EventStream
|
||||
|
||||
/**
|
||||
* Facilities for lookup up thread-pools from configuration.
|
||||
*/
|
||||
|
|
|
|||
559
akka-actor-typed/src/main/scala/akka/actor/typed/Logger.scala
Normal file
559
akka-actor-typed/src/main/scala/akka/actor/typed/Logger.scala
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package akka.actor.typed
|
||||
|
||||
import akka.annotation.{ DoNotInherit, InternalApi }
|
||||
|
||||
/**
|
||||
* A log marker is an additional metadata tag supported by some logging backends to identify "special" log events.
|
||||
* In the Akka internal actors for example the "SECURITY" marker is used for warnings related to security.
|
||||
*
|
||||
* Not for user extension, create instances using factory methods
|
||||
*/
|
||||
@DoNotInherit
|
||||
sealed trait LogMarker {
|
||||
def name: String
|
||||
}
|
||||
|
||||
/**
|
||||
* Factories for log markers
|
||||
*/
|
||||
object LogMarker {
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
@InternalApi
|
||||
private final class LogMarkerImpl(name: String) extends akka.event.LogMarker(name) with LogMarker
|
||||
|
||||
/**
|
||||
* Scala API: Create a new log marker with the given name
|
||||
*/
|
||||
def apply(name: String): LogMarker = new LogMarkerImpl(name)
|
||||
|
||||
/**
|
||||
* Scala API: Create a new log marker with the given name
|
||||
*/
|
||||
def create(name: String): LogMarker = apply(name)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Logging API provided inside of actors through the actor context.
|
||||
*
|
||||
* All log-level methods support simple interpolation templates with up to four
|
||||
* arguments placed by using <code>{}</code> within the template (first string
|
||||
* argument):
|
||||
*
|
||||
* {{{
|
||||
* ctx.log.error(exception, "Exception while processing {} in state {}", msg, state)
|
||||
* }}}
|
||||
*
|
||||
* More than four arguments can be defined by using an `Array` with the method with
|
||||
* one argument parameter.
|
||||
*
|
||||
* *Rationale for an Akka-specific logging API:*
|
||||
* Provided rather than a specific logging library logging API to not enforce a specific logging library on users but
|
||||
* still providing a convenient, performant, asynchronous and testable logging solution. Additionally it allows unified
|
||||
* logging for both user implemented actors and built in Akka actors where the actual logging backend can be selected
|
||||
* by the user. This logging facade is also used by Akka internally, without having to depend on specific logging frameworks.
|
||||
*
|
||||
* The [[Logger]] of an actor is tied to the actor path and should not be shared with other threads outside of the actor.
|
||||
*
|
||||
* Not for user extension
|
||||
*/
|
||||
@DoNotInherit
|
||||
abstract class Logger private[akka] () {
|
||||
|
||||
/**
|
||||
* Whether error logging is enabled on the actor system level, may not represent the setting all the way to the
|
||||
* logger implementation, but when it does it allows avoiding unnecessary resource usage for log entries that
|
||||
* will not actually end up in any logger output.
|
||||
*/
|
||||
def isErrorEnabled: Boolean
|
||||
|
||||
/**
|
||||
* Whether error logging is enabled on the actor system level, may not represent the setting all the way to the
|
||||
* logger implementation, but when it does it allows avoiding unnecessary resource usage for log entries that
|
||||
* will not actually end up in any logger output.
|
||||
*/
|
||||
def isWarningEnabled: Boolean
|
||||
|
||||
/**
|
||||
* Whether info logging is enabled on the actor system level, may not represent the setting all the way to the
|
||||
* logger implementation, but when it does it allows avoiding unnecessary resource usage for log entries that
|
||||
* will not actually end up in any logger output.
|
||||
*/
|
||||
def isInfoEnabled: Boolean
|
||||
|
||||
/**
|
||||
* Whether debug logging is enabled on the actor system level, may not represent the setting all the way to the
|
||||
* logger implementation, but when it does it allows avoiding unnecessary resource usage for log entries that
|
||||
* will not actually end up in any logger output.
|
||||
*/
|
||||
def isDebugEnabled: Boolean
|
||||
|
||||
// message only error logging
|
||||
|
||||
/**
|
||||
* Log message at error level, without providing the exception that caused the error.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
// exception error logging
|
||||
|
||||
/**
|
||||
* Log message at error level, including the exception that caused the error.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(cause: Throwable, message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(cause: Throwable, template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(cause: Throwable, template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
// marker error logging
|
||||
|
||||
/**
|
||||
* Log message at error level, including the exception that caused the error.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, cause: Throwable, message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, cause: Throwable, template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
/**
|
||||
* Log message at error level, without providing the exception that caused the error.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def error(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
// message only warning logging
|
||||
|
||||
/**
|
||||
* Log message at warning level.
|
||||
*/
|
||||
def warning(message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
/**
|
||||
* Log message at warning level.
|
||||
*/
|
||||
def warning(cause: Throwable, message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(cause: Throwable, template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(cause: Throwable, template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
// marker warning logging
|
||||
/**
|
||||
* Log message at warning level.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*/
|
||||
def warning(marker: LogMarker, message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
/**
|
||||
* Log message at warning level.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, cause: Throwable, message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, cause: Throwable, template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def warning(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
// message only info logging
|
||||
|
||||
/**
|
||||
* Log message at info level.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
// marker info logging
|
||||
|
||||
/**
|
||||
* Log message at info level.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(marker: LogMarker, message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(marker: LogMarker, template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def info(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
// message only debug logging
|
||||
|
||||
/**
|
||||
* Log message at debug level.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
// marker debug logging
|
||||
|
||||
/**
|
||||
* Log message at debug level.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(marker: LogMarker, message: String): Unit
|
||||
/**
|
||||
* Message template with 1 replacement argument.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* If `arg1` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(marker: LogMarker, template: String, arg1: Any): Unit
|
||||
/**
|
||||
* Message template with 2 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit
|
||||
/**
|
||||
* Message template with 3 replacement arguments.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit
|
||||
/**
|
||||
* Message template with 4 replacement arguments. For more parameters see the single replacement version of this method.
|
||||
*
|
||||
* The marker argument can be picked up by various logging frameworks such as slf4j to mark this log statement as "special".
|
||||
*
|
||||
* @see [[Logger]]
|
||||
*/
|
||||
def debug(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit
|
||||
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ import scala.util.Try
|
|||
|
||||
import akka.annotation.InternalApi
|
||||
import akka.util.OptionVal
|
||||
import akka.event.LoggingAdapter
|
||||
import akka.util.Timeout
|
||||
|
||||
/**
|
||||
|
|
@ -58,6 +59,8 @@ import akka.util.Timeout
|
|||
override def getSystem: akka.actor.typed.ActorSystem[Void] =
|
||||
system.asInstanceOf[ActorSystem[Void]]
|
||||
|
||||
override def getLog: Logger = log
|
||||
|
||||
override def spawn[U](behavior: akka.actor.typed.Behavior[U], name: String): akka.actor.typed.ActorRef[U] =
|
||||
spawn(behavior, name, Props.empty)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package akka.actor.typed.internal
|
||||
|
||||
import akka.actor.typed.Behavior
|
||||
import akka.actor.typed.internal.adapter.LoggerAdapterImpl
|
||||
import akka.annotation.InternalApi
|
||||
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*
|
||||
* Regular logging is supported directly on the ActorContext, but more advanced logging needs are covered here
|
||||
*/
|
||||
@InternalApi object LoggingBehaviorImpl {
|
||||
|
||||
/**
|
||||
* MDC logging support
|
||||
*
|
||||
* @param mdcForMessage Is invoked before each message is handled, allowing to setup MDC, MDC is cleared after
|
||||
* each message processing by the inner behavior is done.
|
||||
* @param behavior The actual behavior handling the messages, the MDC is used for the log entries logged through
|
||||
* `ActorContext.log`
|
||||
*/
|
||||
def withMdc[T: ClassTag](mdcForMessage: T ⇒ Map[String, Any], behavior: Behavior[T]): Behavior[T] =
|
||||
BehaviorImpl.intercept[T, T](
|
||||
beforeMessage = { (ctx, msg) ⇒
|
||||
ctx.log.asInstanceOf[LoggerAdapterImpl].mdc = mdcForMessage(msg)
|
||||
msg
|
||||
},
|
||||
beforeSignal = (_, _) ⇒ true,
|
||||
afterMessage = { (ctx, _, behavior) ⇒
|
||||
ctx.log.asInstanceOf[LoggerAdapterImpl].mdc = Map.empty
|
||||
behavior
|
||||
},
|
||||
afterSignal = (_, _, behavior) ⇒ behavior,
|
||||
behavior = behavior,
|
||||
toStringPrefix = "withMdc"
|
||||
)
|
||||
|
||||
}
|
||||
|
|
@ -70,8 +70,7 @@ import akka.actor.typed.scaladsl.Behaviors
|
|||
|
||||
protected def restart(ctx: ActorContext[T], initialBehavior: Behavior[T], startedBehavior: Behavior[T]): Supervisor[T, Thr] = {
|
||||
try Behavior.interpretSignal(startedBehavior, ctx, PreRestart) catch {
|
||||
case NonFatal(ex) ⇒ publish(ctx, Logging.Error(ex, ctx.asScala.self.path.toString, behavior.getClass,
|
||||
"failure during PreRestart"))
|
||||
case NonFatal(ex) ⇒ ctx.asScala.log.error(ex, "failure during PreRestart")
|
||||
}
|
||||
// no need to canonicalize, it's done in the calling methods
|
||||
wrap(Supervisor.initialUndefer(ctx, initialBehavior), afterException = true)
|
||||
|
|
@ -96,11 +95,8 @@ import akka.actor.typed.scaladsl.Behaviors
|
|||
|
||||
protected def log(ctx: ActorContext[T], ex: Thr): Unit = {
|
||||
if (loggingEnabled)
|
||||
publish(ctx, Logging.Error(ex, ctx.asScala.self.toString, behavior.getClass, ex.getMessage))
|
||||
ctx.asScala.log.error(ex, ex.getMessage)
|
||||
}
|
||||
|
||||
protected final def publish(ctx: ActorContext[T], e: Logging.LogEvent): Unit =
|
||||
try ctx.asScala.system.eventStream.publish(e) catch { case NonFatal(_) ⇒ }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -228,7 +224,8 @@ import akka.actor.typed.scaladsl.Behaviors
|
|||
|
||||
override def receiveSignal(ctx: ActorContext[Any], signal: Signal): Behavior[Any] = {
|
||||
if (blackhole) {
|
||||
ctx.asScala.system.eventStream.publish(Dropped(signal, ctx.asScala.self))
|
||||
import scaladsl.adapter._
|
||||
ctx.asScala.system.toUntyped.eventStream.publish(Dropped(signal, ctx.asScala.self))
|
||||
Behavior.same
|
||||
} else
|
||||
super.receiveSignal(ctx, signal)
|
||||
|
|
@ -249,7 +246,8 @@ import akka.actor.typed.scaladsl.Behaviors
|
|||
Behavior.same
|
||||
case _ ⇒
|
||||
if (blackhole) {
|
||||
ctx.asScala.system.eventStream.publish(Dropped(msg, ctx.asScala.self))
|
||||
import scaladsl.adapter._
|
||||
ctx.asScala.system.toUntyped.eventStream.publish(Dropped(msg, ctx.asScala.self))
|
||||
Behavior.same
|
||||
} else
|
||||
super.receiveMessage(ctx, msg)
|
||||
|
|
@ -261,8 +259,7 @@ import akka.actor.typed.scaladsl.Behaviors
|
|||
log(ctx, ex)
|
||||
// actual restart happens after the scheduled backoff delay
|
||||
try Behavior.interpretSignal(behavior, ctx, PreRestart) catch {
|
||||
case NonFatal(ex2) ⇒ publish(ctx, Logging.Error(ex2, ctx.asScala.self.path.toString, behavior.getClass,
|
||||
"failure during PreRestart"))
|
||||
case NonFatal(ex2) ⇒ ctx.asScala.log.error(ex2, "failure during PreRestart")
|
||||
}
|
||||
val restartDelay = calculateDelay(restartCount, strategy.minBackoff, strategy.maxBackoff, strategy.randomFactor)
|
||||
ctx.asScala.schedule(restartDelay, ctx.asScala.self, ScheduledRestart)
|
||||
|
|
|
|||
|
|
@ -41,8 +41,6 @@ import scala.reflect.ClassTag
|
|||
extends scaladsl.TimerScheduler[T] with javadsl.TimerScheduler[T] {
|
||||
import TimerSchedulerImpl._
|
||||
|
||||
// FIXME change to a class specific logger, see issue #21219
|
||||
private val log = ctx.system.log
|
||||
private var timers: Map[Any, Timer[T]] = Map.empty
|
||||
private val timerGen = Iterator from 1
|
||||
|
||||
|
|
@ -71,7 +69,7 @@ import scala.reflect.ClassTag
|
|||
}(ExecutionContexts.sameThreadExecutionContext)
|
||||
|
||||
val nextTimer = Timer(key, msg, repeat, nextGen, task)
|
||||
log.debug("Start timer [{}] with generation [{}]", key, nextGen)
|
||||
ctx.log.debug("Start timer [{}] with generation [{}]", key, nextGen)
|
||||
timers = timers.updated(key, nextTimer)
|
||||
}
|
||||
|
||||
|
|
@ -86,13 +84,13 @@ import scala.reflect.ClassTag
|
|||
}
|
||||
|
||||
private def cancelTimer(timer: Timer[T]): Unit = {
|
||||
log.debug("Cancel timer [{}] with generation [{}]", timer.key, timer.generation)
|
||||
ctx.log.debug("Cancel timer [{}] with generation [{}]", timer.key, timer.generation)
|
||||
timer.task.cancel()
|
||||
timers -= timer.key
|
||||
}
|
||||
|
||||
override def cancelAll(): Unit = {
|
||||
log.debug("Cancel all timers")
|
||||
ctx.log.debug("Cancel all timers")
|
||||
timers.valuesIterator.foreach { timer ⇒
|
||||
timer.task.cancel()
|
||||
}
|
||||
|
|
@ -103,12 +101,12 @@ import scala.reflect.ClassTag
|
|||
timers.get(timerMsg.key) match {
|
||||
case None ⇒
|
||||
// it was from canceled timer that was already enqueued in mailbox
|
||||
log.debug("Received timer [{}] that has been removed, discarding", timerMsg.key)
|
||||
ctx.log.debug("Received timer [{}] that has been removed, discarding", timerMsg.key)
|
||||
null.asInstanceOf[T] // message should be ignored
|
||||
case Some(t) ⇒
|
||||
if (timerMsg.owner ne this) {
|
||||
// after restart, it was from an old instance that was enqueued in mailbox before canceled
|
||||
log.debug("Received timer [{}] from old restarted instance, discarding", timerMsg.key)
|
||||
ctx.log.debug("Received timer [{}] from old restarted instance, discarding", timerMsg.key)
|
||||
null.asInstanceOf[T] // message should be ignored
|
||||
} else if (timerMsg.generation == t.generation) {
|
||||
// valid timer
|
||||
|
|
@ -117,7 +115,7 @@ import scala.reflect.ClassTag
|
|||
t.msg
|
||||
} else {
|
||||
// it was from an old timer that was enqueued in mailbox before canceled
|
||||
log.debug(
|
||||
ctx.log.debug(
|
||||
"Received timer [{}] from from old generation [{}], expected generation [{}], discarding",
|
||||
timerMsg.key, timerMsg.generation, t.generation)
|
||||
null.asInstanceOf[T] // message should be ignored
|
||||
|
|
|
|||
|
|
@ -5,20 +5,25 @@ package akka.actor.typed
|
|||
package internal
|
||||
package adapter
|
||||
|
||||
import akka.actor.ExtendedActorSystem
|
||||
import akka.actor.typed.Behavior.UntypedBehavior
|
||||
import akka.annotation.InternalApi
|
||||
import akka.util.OptionVal
|
||||
import akka.{ ConfigurationException, actor ⇒ a }
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContextExecutor
|
||||
import akka.annotation.InternalApi
|
||||
import akka.actor.typed.Behavior.UntypedBehavior
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
* INTERNAL API. Wrapping an [[akka.actor.ActorContext]] as an [[ActorContext]].
|
||||
*/
|
||||
@InternalApi private[akka] class ActorContextAdapter[T](val untyped: a.ActorContext) extends ActorContextImpl[T] {
|
||||
@InternalApi private[akka] final class ActorContextAdapter[T](val untyped: a.ActorContext) extends ActorContextImpl[T] {
|
||||
|
||||
import ActorRefAdapter.toUntyped
|
||||
|
||||
// lazily initialized
|
||||
private var actorLogger: OptionVal[Logger] = OptionVal.None
|
||||
|
||||
override def self = ActorRefAdapter(untyped.self)
|
||||
override val system = ActorSystemAdapter(untyped.system)
|
||||
override def mailboxCapacity = 1 << 29 // FIXME
|
||||
|
|
@ -65,6 +70,20 @@ import akka.actor.typed.Behavior.UntypedBehavior
|
|||
val ref = cell.addFunctionRef((_, msg) ⇒ untyped.self ! AdaptMessage[U, T](msg.asInstanceOf[U], f), _name)
|
||||
ActorRefAdapter[U](ref)
|
||||
}
|
||||
|
||||
override def log: Logger = {
|
||||
actorLogger match {
|
||||
case OptionVal.Some(logger) ⇒ logger
|
||||
case OptionVal.None ⇒
|
||||
import scala.language.existentials
|
||||
val logSource = self.path.toString
|
||||
val logClass = classOf[Behavior[_]] // FIXME figure out a better class somehow
|
||||
val system = untyped.system.asInstanceOf[ExtendedActorSystem]
|
||||
val logger = new LoggerAdapterImpl(system.eventStream, logClass, logSource, system.logFilter)
|
||||
actorLogger = OptionVal.Some(logger)
|
||||
logger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import akka.util.Timeout
|
|||
|
||||
import scala.concurrent.Future
|
||||
import akka.annotation.InternalApi
|
||||
import akka.event.typed.EventStream
|
||||
|
||||
import scala.compat.java8.FutureConverters
|
||||
|
||||
|
|
@ -57,11 +56,9 @@ import scala.compat.java8.FutureConverters
|
|||
override def shutdown(): Unit = () // there was no shutdown in untyped Akka
|
||||
}
|
||||
override def dynamicAccess: a.DynamicAccess = untyped.dynamicAccess
|
||||
override def eventStream: EventStream = new EventStreamAdapter(untyped.eventStream)
|
||||
implicit override def executionContext: scala.concurrent.ExecutionContextExecutor = untyped.dispatcher
|
||||
override def log: akka.event.LoggingAdapter = untyped.log
|
||||
override val log: Logger = new LoggerAdapterImpl(untyped.eventStream, getClass, name, untyped.logFilter)
|
||||
override def logConfiguration(): Unit = untyped.logConfiguration()
|
||||
override def logFilter: akka.event.LoggingFilter = untyped.logFilter
|
||||
override def name: String = untyped.name
|
||||
override def scheduler: akka.actor.Scheduler = untyped.scheduler
|
||||
override def settings: Settings = new Settings(untyped.settings)
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2016-2018 Lightbend Inc. <http://www.lightbend.com/>
|
||||
*/
|
||||
package akka.actor.typed
|
||||
package internal
|
||||
package adapter
|
||||
|
||||
import akka.{ event ⇒ e }
|
||||
import akka.annotation.InternalApi
|
||||
import akka.event.typed.EventStream
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
@InternalApi private[typed] class EventStreamAdapter(untyped: e.EventStream) extends EventStream {
|
||||
def logLevel: e.Logging.LogLevel = untyped.logLevel
|
||||
|
||||
def publish[T](event: T): Unit = untyped.publish(event.asInstanceOf[AnyRef])
|
||||
|
||||
def setLogLevel(loglevel: e.Logging.LogLevel): Unit = untyped.setLogLevel(loglevel)
|
||||
|
||||
def subscribe[T](subscriber: ActorRef[T], to: Class[T]): Boolean =
|
||||
subscriber match {
|
||||
case adapter: ActorRefAdapter[_] ⇒ untyped.subscribe(adapter.untyped, to)
|
||||
case _ ⇒
|
||||
throw new UnsupportedOperationException("Cannot subscribe native typed ActorRef")
|
||||
}
|
||||
|
||||
def unsubscribe[T](subscriber: ActorRef[T]): Unit =
|
||||
subscriber match {
|
||||
case adapter: ActorRefAdapter[_] ⇒ untyped.unsubscribe(adapter.untyped)
|
||||
case _ ⇒
|
||||
throw new UnsupportedOperationException("Cannot unsubscribe native typed ActorRef")
|
||||
}
|
||||
|
||||
def unsubscribe[T](subscriber: ActorRef[T], from: Class[T]): Boolean =
|
||||
subscriber match {
|
||||
case adapter: ActorRefAdapter[_] ⇒ untyped.unsubscribe(adapter.untyped, from)
|
||||
case _ ⇒
|
||||
throw new UnsupportedOperationException("Cannot unsubscribe native typed ActorRef")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,347 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package akka.actor.typed.internal.adapter
|
||||
|
||||
import akka.actor.typed.{ LogMarker, Logger }
|
||||
import akka.annotation.InternalApi
|
||||
import akka.event.Logging.{ Debug, Error, Info, Warning }
|
||||
import akka.event.{ LoggingBus, LoggingFilter, LogMarker ⇒ UntypedLM }
|
||||
import akka.util.OptionVal
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
@InternalApi
|
||||
private[akka] class LoggerAdapterImpl(bus: LoggingBus, logClass: Class[_], logSource: String, loggingFilter: LoggingFilter) extends Logger {
|
||||
|
||||
private[akka] var mdc: Map[String, Any] = Map.empty
|
||||
|
||||
override def isErrorEnabled = loggingFilter.isErrorEnabled(logClass, logSource)
|
||||
override def isWarningEnabled = loggingFilter.isWarningEnabled(logClass, logSource)
|
||||
override def isInfoEnabled = loggingFilter.isInfoEnabled(logClass, logSource)
|
||||
override def isDebugEnabled = loggingFilter.isDebugEnabled(logClass, logSource)
|
||||
|
||||
override def error(message: String): Unit = {
|
||||
if (isErrorEnabled) notifyError(message, OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(template: String, arg1: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1), OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2), OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3), OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3, arg4), OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(cause: Throwable, message: String): Unit = {
|
||||
if (isErrorEnabled) notifyError(message, OptionVal.Some(cause), OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(cause: Throwable, template: String, arg1: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1), OptionVal.Some(cause), OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(cause: Throwable, template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2), OptionVal.Some(cause), OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3), OptionVal.Some(cause), OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3, arg4), OptionVal.Some(cause), OptionVal.None)
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, cause: Throwable, message: String): Unit = {
|
||||
if (isErrorEnabled) notifyError(message, OptionVal.Some(cause), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, cause: Throwable, template: String, arg1: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1), OptionVal.Some(cause), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2), OptionVal.Some(cause), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3), OptionVal.Some(cause), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3, arg4), OptionVal.Some(cause), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, message: String): Unit = {
|
||||
if (isErrorEnabled) notifyError(message, OptionVal.None, OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, template: String, arg1: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1), OptionVal.None, OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2), OptionVal.None, OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3), OptionVal.None, OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def error(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3, arg4), OptionVal.None, OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def warning(message: String): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(message, OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(template: String, arg1: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1), OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2), OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3), OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3, arg4), OptionVal.None, OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(cause: Throwable, message: String): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(message, OptionVal.None, OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(cause: Throwable, template: String, arg1: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1), OptionVal.None, OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(cause: Throwable, template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2), OptionVal.None, OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3), OptionVal.None, OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3, arg4), OptionVal.None, OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, cause: Throwable, template: String, arg1: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1), OptionVal.Some(marker), OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2), OptionVal.Some(marker), OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3), OptionVal.Some(marker), OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3, arg4), OptionVal.Some(marker), OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, cause: Throwable, message: String): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(message, OptionVal.Some(marker), OptionVal.Some(cause))
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, message: String): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(message, OptionVal.Some(marker), OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, template: String, arg1: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1), OptionVal.Some(marker), OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2), OptionVal.Some(marker), OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3), OptionVal.Some(marker), OptionVal.None)
|
||||
}
|
||||
|
||||
override def warning(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3, arg4), OptionVal.Some(marker), OptionVal.None)
|
||||
}
|
||||
|
||||
override def info(message: String): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(message, OptionVal.None)
|
||||
}
|
||||
|
||||
override def info(template: String, arg1: Any): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(format(template, arg1), OptionVal.None)
|
||||
}
|
||||
|
||||
override def info(template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(format(template, arg1, arg2), OptionVal.None)
|
||||
}
|
||||
|
||||
override def info(template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3), OptionVal.None)
|
||||
}
|
||||
|
||||
override def info(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3, arg4), OptionVal.None)
|
||||
}
|
||||
|
||||
override def info(marker: LogMarker, message: String): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(message, OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def info(marker: LogMarker, template: String, arg1: Any): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(format(template, arg1), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def info(marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(format(template, arg1, arg2), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def info(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def info(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3, arg4), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def debug(message: String): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(message, OptionVal.None)
|
||||
}
|
||||
|
||||
override def debug(template: String, arg1: Any): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(format(template, arg1), OptionVal.None)
|
||||
}
|
||||
|
||||
override def debug(template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(format(template, arg1, arg2), OptionVal.None)
|
||||
}
|
||||
|
||||
override def debug(template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3), OptionVal.None)
|
||||
}
|
||||
|
||||
override def debug(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3, arg4), OptionVal.None)
|
||||
}
|
||||
|
||||
override def debug(marker: LogMarker, message: String): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(message, OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def debug(marker: LogMarker, template: String, arg1: Any): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(format(template, arg1), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def debug(marker: LogMarker, template: String, arg1: Any, arg2: Any): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(format(template, arg1, arg2), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def debug(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
override def debug(marker: LogMarker, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = {
|
||||
if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3, arg4), OptionVal.Some(marker))
|
||||
}
|
||||
|
||||
protected def notifyError(message: String, cause: OptionVal[Throwable], marker: OptionVal[LogMarker]): Unit = {
|
||||
val error = cause match {
|
||||
case OptionVal.Some(cause) ⇒
|
||||
marker match {
|
||||
case OptionVal.Some(m) ⇒ Error(cause, logSource, logClass, message, mdc, m.asInstanceOf[UntypedLM])
|
||||
case OptionVal.None ⇒ Error(cause, logSource, logClass, message, mdc)
|
||||
}
|
||||
case OptionVal.None ⇒
|
||||
marker match {
|
||||
case OptionVal.Some(m) ⇒ Error(logSource, logClass, message, mdc, m.asInstanceOf[UntypedLM])
|
||||
case OptionVal.None ⇒ Error(logSource, logClass, message, mdc)
|
||||
}
|
||||
}
|
||||
bus.publish(error)
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@deprecated("Use the 3 argument version instead", since = "2.5.10")
|
||||
protected def notifyWarning(message: String, marker: OptionVal[LogMarker]): Unit =
|
||||
notifyWarning(message, marker, OptionVal.None)
|
||||
|
||||
protected def notifyWarning(message: String, marker: OptionVal[LogMarker], cause: OptionVal[Throwable]): Unit = {
|
||||
val warning =
|
||||
if (cause.isDefined) Warning(cause.get, logSource, logClass, message, mdc, marker.orNull.asInstanceOf[UntypedLM])
|
||||
else marker match {
|
||||
case OptionVal.Some(m) ⇒ Warning(logSource, logClass, message, mdc, m.asInstanceOf[UntypedLM])
|
||||
case OptionVal.None ⇒ Warning(logSource, logClass, message, mdc)
|
||||
}
|
||||
bus.publish(warning)
|
||||
}
|
||||
|
||||
protected def notifyInfo(message: String, marker: OptionVal[LogMarker]): Unit = {
|
||||
val info = marker match {
|
||||
case OptionVal.Some(m) ⇒ Info(logSource, logClass, message, mdc, m.asInstanceOf[UntypedLM])
|
||||
case OptionVal.None ⇒ Info(logSource, logClass, message, mdc)
|
||||
}
|
||||
bus.publish(info)
|
||||
}
|
||||
|
||||
protected def notifyDebug(message: String, marker: OptionVal[LogMarker]): Unit = {
|
||||
val debug = marker match {
|
||||
case OptionVal.Some(m) ⇒ Debug(logSource, logClass, message, mdc, m.asInstanceOf[UntypedLM])
|
||||
case OptionVal.None ⇒ Debug(logSource, logClass, message, mdc)
|
||||
}
|
||||
bus.publish(debug)
|
||||
}
|
||||
|
||||
/**
|
||||
* If `arg` is an `Array` it will be expanded into replacement arguments, which is useful when
|
||||
* there are more than four arguments.
|
||||
*/
|
||||
private def format(t: String, arg1: Any): String = arg1 match {
|
||||
case a: Array[_] if !a.getClass.getComponentType.isPrimitive ⇒ formatArray(t, a: _*)
|
||||
case a: Array[_] ⇒ formatArray(t, (a map (_.asInstanceOf[AnyRef]): _*))
|
||||
case x ⇒ formatArray(t, x)
|
||||
}
|
||||
private def format(t: String, arg1: Any, arg2: Any): String = formatArray(t, arg1, arg2)
|
||||
private def format(t: String, arg1: Any, arg2: Any, arg3: Any): String = formatArray(t, arg1, arg2, arg3)
|
||||
private def format(t: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): String = formatArray(t, arg1, arg2, arg3, arg4)
|
||||
|
||||
private def formatArray(t: String, arg: Any*): String = {
|
||||
val sb = new java.lang.StringBuilder(64)
|
||||
var p = 0
|
||||
var startIndex = 0
|
||||
while (p < arg.length) {
|
||||
val index = t.indexOf("{}", startIndex)
|
||||
if (index == -1) {
|
||||
sb.append(t.substring(startIndex, t.length))
|
||||
.append(" WARNING arguments left: ")
|
||||
.append(arg.length - p)
|
||||
p = arg.length
|
||||
startIndex = t.length
|
||||
} else {
|
||||
sb.append(t.substring(startIndex, index))
|
||||
.append(arg(p))
|
||||
startIndex = index + 2
|
||||
p += 1
|
||||
}
|
||||
}
|
||||
sb.append(t.substring(startIndex, t.length)).toString
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ private[akka] object ReceptionistImpl extends ReceptionistBehaviorProvider {
|
|||
immutable[AllCommands] { (ctx, msg) ⇒
|
||||
msg match {
|
||||
case Register(key, serviceInstance, replyTo) ⇒
|
||||
ctx.system.log.debug("[{}] Actor was registered: {} {}", ctx.self, key, serviceInstance)
|
||||
ctx.log.debug("Actor was registered: {} {}", key, serviceInstance)
|
||||
watchWith(ctx, serviceInstance, RegisteredActorTerminated(key, serviceInstance))
|
||||
replyTo ! Registered(key, serviceInstance)
|
||||
externalInterface.onRegister(key, serviceInstance)
|
||||
|
|
@ -132,7 +132,7 @@ private[akka] object ReceptionistImpl extends ReceptionistBehaviorProvider {
|
|||
|
||||
case externalInterface.RegistrationsChangedExternally(changes, state) ⇒
|
||||
|
||||
ctx.system.log.debug("[{}] Registration changed: {}", ctx.self, changes)
|
||||
ctx.log.debug("Registration changed: {}", changes)
|
||||
|
||||
// FIXME: get rid of casts
|
||||
def makeChanges(registry: LocalServiceRegistry): LocalServiceRegistry =
|
||||
|
|
@ -144,7 +144,7 @@ private[akka] object ReceptionistImpl extends ReceptionistBehaviorProvider {
|
|||
updateRegistry(changes.keySet, makeChanges) // overwrite all changed keys
|
||||
|
||||
case RegisteredActorTerminated(key, serviceInstance) ⇒
|
||||
ctx.system.log.debug("[{}] Registered actor terminated: {} {}", ctx.self, key, serviceInstance)
|
||||
ctx.log.debug("Registered actor terminated: {} {}", key, serviceInstance)
|
||||
externalInterface.onUnregister(key, serviceInstance)
|
||||
updateRegistry(Set(key), _.removed(key)(serviceInstance))
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import akka.annotation.ApiMayChange
|
|||
import akka.actor.typed._
|
||||
import java.util.Optional
|
||||
|
||||
import akka.event.LoggingAdapter
|
||||
import akka.util.Timeout
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
|
@ -60,6 +61,11 @@ trait ActorContext[T] {
|
|||
*/
|
||||
def getSystem: ActorSystem[Void]
|
||||
|
||||
/**
|
||||
* An actor specific logger
|
||||
*/
|
||||
def getLog: Logger
|
||||
|
||||
/**
|
||||
* The list of child Actors created by this Actor during its lifetime that
|
||||
* are still alive, in no particular order.
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ import akka.actor.typed.Signal
|
|||
import akka.actor.typed.ActorRef
|
||||
import akka.actor.typed.SupervisorStrategy
|
||||
import akka.actor.typed.scaladsl.{ ActorContext ⇒ SAC }
|
||||
import akka.actor.typed.internal.{ BehaviorImpl, Supervisor, TimerSchedulerImpl }
|
||||
import akka.actor.typed.internal.{ BehaviorImpl, LoggingBehaviorImpl, Supervisor, TimerSchedulerImpl }
|
||||
import akka.annotation.ApiMayChange
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
/**
|
||||
* Factories for [[akka.actor.typed.Behavior]].
|
||||
*/
|
||||
|
|
@ -316,4 +316,19 @@ object Behaviors {
|
|||
def receiveMessage(msg: T): Behavior[T]
|
||||
def receiveSignal(msg: Signal): Behavior[T]
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a MDC ("Mapped Diagnostic Context") for logging from the actor.
|
||||
*
|
||||
* @param mdcForMessage Is invoked before each message to setup MDC which is then attachd to each logging statement
|
||||
* done for that message through the [[ActorContext.getLog]]. After the message has been processed
|
||||
* the MDC is cleared.
|
||||
* @param behavior The behavior that this should be applied to.
|
||||
*/
|
||||
def withMdc[T](
|
||||
`type`: Class[T],
|
||||
mdcForMessage: akka.japi.function.Function[T, java.util.Map[String, Object]],
|
||||
behavior: Behavior[T]): Behavior[T] =
|
||||
LoggingBehaviorImpl.withMdc[T](message ⇒ mdcForMessage.apply(message).asScala.toMap, behavior)(ClassTag(`type`))
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@
|
|||
*/
|
||||
package akka.actor.typed.scaladsl
|
||||
|
||||
import akka.actor.typed._
|
||||
import akka.annotation.{ ApiMayChange, DoNotInherit }
|
||||
import akka.event.LoggingAdapter
|
||||
import akka.util.Timeout
|
||||
|
||||
import scala.concurrent.ExecutionContextExecutor
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
import scala.reflect.ClassTag
|
||||
import scala.util.Try
|
||||
|
||||
import akka.actor.typed._
|
||||
import akka.annotation.ApiMayChange
|
||||
import akka.annotation.DoNotInherit
|
||||
import akka.annotation.InternalApi
|
||||
import akka.util.Timeout
|
||||
|
||||
/**
|
||||
* An Actor is given by the combination of a [[Behavior]] and a context in
|
||||
|
|
@ -58,6 +58,11 @@ trait ActorContext[T] { this: akka.actor.typed.javadsl.ActorContext[T] ⇒
|
|||
*/
|
||||
def system: ActorSystem[Nothing]
|
||||
|
||||
/**
|
||||
* An actor specific logger
|
||||
*/
|
||||
def log: Logger
|
||||
|
||||
/**
|
||||
* The list of child Actors created by this Actor during its lifetime that
|
||||
* are still alive, in no particular order.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ package akka.actor.typed
|
|||
package scaladsl
|
||||
|
||||
import akka.annotation.{ ApiMayChange, InternalApi }
|
||||
import akka.actor.typed.internal.{ BehaviorImpl, Supervisor, TimerSchedulerImpl }
|
||||
import akka.actor.typed.internal.{ BehaviorImpl, LoggingBehaviorImpl, Supervisor, TimerSchedulerImpl }
|
||||
|
||||
import scala.reflect.ClassTag
|
||||
import scala.util.control.Exception.Catcher
|
||||
|
|
@ -267,6 +267,19 @@ object Behaviors {
|
|||
def withTimers[T](factory: TimerScheduler[T] ⇒ Behavior[T]): Behavior[T] =
|
||||
TimerSchedulerImpl.withTimers(factory)
|
||||
|
||||
/**
|
||||
* Provide a MDC ("Mapped Diagnostic Context") for logging from the actor.
|
||||
*
|
||||
* @param mdcForMessage Is invoked before each message to setup MDC which is then attachd to each logging statement
|
||||
* done for that message through the [[ActorContext.log]]. After the message has been processed
|
||||
* the MDC is cleared.
|
||||
* @param behavior The behavior that this should be applied to.
|
||||
*/
|
||||
def withMdc[T: ClassTag](
|
||||
mdcForMessage: T ⇒ Map[String, Any],
|
||||
behavior: Behavior[T]): Behavior[T] =
|
||||
LoggingBehaviorImpl.withMdc(mdcForMessage, behavior)
|
||||
|
||||
// TODO
|
||||
// final case class Selective[T](timeout: FiniteDuration, selector: PartialFunction[T, Behavior[T]], onTimeout: () ⇒ Behavior[T])
|
||||
|
||||
|
|
|
|||
|
|
@ -1,87 +0,0 @@
|
|||
package akka.event.typed
|
||||
|
||||
import akka.actor.typed.ActorRef
|
||||
import akka.event.Logging.LogLevel
|
||||
|
||||
/**
|
||||
* An EventStream allows local actors to register for certain message types, including
|
||||
* their subtypes automatically. Publishing events will broadcast them to all
|
||||
* currently subscribed actors with matching subscriptions for the event type.
|
||||
*
|
||||
* IMPORTANT NOTICE
|
||||
*
|
||||
* This EventStream is local to the ActorSystem, it does not span a cluster. For
|
||||
* disseminating messages across a cluster please refer to the DistributedPubSub
|
||||
* module.
|
||||
*/
|
||||
trait EventStream {
|
||||
/**
|
||||
* Attempts to register the subscriber to the specified Classifier
|
||||
* @return true if successful and false if not (because it was already
|
||||
* subscribed to that Classifier, or otherwise)
|
||||
*/
|
||||
def subscribe[T](subscriber: ActorRef[T], to: Class[T]): Boolean
|
||||
|
||||
/**
|
||||
* Attempts to deregister the subscriber from the specified Classifier
|
||||
* @return true if successful and false if not (because it wasn't subscribed
|
||||
* to that Classifier, or otherwise)
|
||||
*/
|
||||
def unsubscribe[T](subscriber: ActorRef[T], from: Class[T]): Boolean
|
||||
|
||||
/**
|
||||
* Attempts to deregister the subscriber from all Classifiers it may be subscribed to
|
||||
*/
|
||||
def unsubscribe[T](subscriber: ActorRef[T]): Unit
|
||||
|
||||
/**
|
||||
* Publishes the specified Event to this bus
|
||||
*/
|
||||
def publish[T](event: T): Unit
|
||||
|
||||
/**
|
||||
* Query the current minimum log level.
|
||||
*/
|
||||
def logLevel: LogLevel
|
||||
|
||||
/**
|
||||
* Change the current minimum log level.
|
||||
*/
|
||||
def setLogLevel(loglevel: LogLevel): Unit
|
||||
}
|
||||
|
||||
import akka.actor.typed.{ ActorRef, Behavior, Settings }
|
||||
import akka.event.Logging.LogEvent
|
||||
import akka.{ event ⇒ e }
|
||||
|
||||
abstract class Logger {
|
||||
def initialBehavior: Behavior[Logger.Command]
|
||||
}
|
||||
|
||||
object Logger {
|
||||
sealed trait Command
|
||||
case class Initialize(eventStream: EventStream, replyTo: ActorRef[ActorRef[LogEvent]]) extends Command
|
||||
// FIXME add Mute/Unmute (i.e. the TestEventListener functionality)
|
||||
}
|
||||
|
||||
class DefaultLoggingFilter(settings: Settings, eventStream: EventStream) extends e.DefaultLoggingFilter(() ⇒ eventStream.logLevel)
|
||||
|
||||
/**
|
||||
* [[akka.event.LoggingAdapter]] that publishes [[akka.event.Logging.LogEvent]] to event stream.
|
||||
*/
|
||||
class BusLogging(val bus: EventStream, val logSource: String, val logClass: Class[_], loggingFilter: e.LoggingFilter)
|
||||
extends e.LoggingAdapter {
|
||||
|
||||
import e.Logging._
|
||||
|
||||
def isErrorEnabled = loggingFilter.isErrorEnabled(logClass, logSource)
|
||||
def isWarningEnabled = loggingFilter.isWarningEnabled(logClass, logSource)
|
||||
def isInfoEnabled = loggingFilter.isInfoEnabled(logClass, logSource)
|
||||
def isDebugEnabled = loggingFilter.isDebugEnabled(logClass, logSource)
|
||||
|
||||
protected def notifyError(message: String): Unit = bus.publish(Error(logSource, logClass, message, mdc))
|
||||
protected def notifyError(cause: Throwable, message: String): Unit = bus.publish(Error(cause, logSource, logClass, message, mdc))
|
||||
protected def notifyWarning(message: String): Unit = bus.publish(Warning(logSource, logClass, message, mdc))
|
||||
protected def notifyInfo(message: String): Unit = bus.publish(Info(logSource, logClass, message, mdc))
|
||||
protected def notifyDebug(message: String): Unit = bus.publish(Debug(logSource, logClass, message, mdc))
|
||||
}
|
||||
|
|
@ -739,17 +739,21 @@ object Logging {
|
|||
|
||||
}
|
||||
|
||||
trait LogEventWithCause {
|
||||
def cause: Throwable
|
||||
}
|
||||
|
||||
/**
|
||||
* For ERROR Logging
|
||||
*/
|
||||
case class Error(cause: Throwable, logSource: String, logClass: Class[_], message: Any = "") extends LogEvent {
|
||||
case class Error(override val cause: Throwable, logSource: String, logClass: Class[_], message: Any = "") extends LogEvent with LogEventWithCause {
|
||||
def this(logSource: String, logClass: Class[_], message: Any) = this(Error.NoCause, logSource, logClass, message)
|
||||
override def level = ErrorLevel
|
||||
}
|
||||
class Error2(cause: Throwable, logSource: String, logClass: Class[_], message: Any = "", override val mdc: MDC) extends Error(cause, logSource, logClass, message) {
|
||||
class Error2(override val cause: Throwable, logSource: String, logClass: Class[_], message: Any = "", override val mdc: MDC) extends Error(cause, logSource, logClass, message) {
|
||||
def this(logSource: String, logClass: Class[_], message: Any, mdc: MDC) = this(Error.NoCause, logSource, logClass, message, mdc)
|
||||
}
|
||||
class Error3(cause: Throwable, logSource: String, logClass: Class[_], message: Any, override val mdc: MDC, override val marker: LogMarker)
|
||||
class Error3(override val cause: Throwable, logSource: String, logClass: Class[_], message: Any, override val mdc: MDC, override val marker: LogMarker)
|
||||
extends Error2(cause, logSource, logClass, message, mdc) with LogEventWithMarker {
|
||||
def this(logSource: String, logClass: Class[_], message: Any, mdc: MDC, marker: LogMarker) = this(Error.NoCause, logSource, logClass, message, mdc, marker)
|
||||
}
|
||||
|
|
@ -784,9 +788,14 @@ object Logging {
|
|||
class Warning2(logSource: String, logClass: Class[_], message: Any, override val mdc: MDC) extends Warning(logSource, logClass, message)
|
||||
class Warning3(logSource: String, logClass: Class[_], message: Any, override val mdc: MDC, override val marker: LogMarker)
|
||||
extends Warning2(logSource, logClass, message, mdc) with LogEventWithMarker
|
||||
class Warning4(logSource: String, logClass: Class[_], message: Any, override val mdc: MDC, override val marker: LogMarker, override val cause: Throwable)
|
||||
extends Warning2(logSource, logClass, message, mdc) with LogEventWithMarker with LogEventWithCause
|
||||
object Warning {
|
||||
def apply(logSource: String, logClass: Class[_], message: Any, mdc: MDC) = new Warning2(logSource, logClass, message, mdc)
|
||||
def apply(logSource: String, logClass: Class[_], message: Any, mdc: MDC, marker: LogMarker) = new Warning3(logSource, logClass, message, mdc, marker)
|
||||
|
||||
def apply(cause: Throwable, logSource: String, logClass: Class[_], message: Any, mdc: MDC) = new Warning4(logSource, logClass, message, mdc, null, cause)
|
||||
def apply(cause: Throwable, logSource: String, logClass: Class[_], message: Any, mdc: MDC, marker: LogMarker) = new Warning4(logSource, logClass, message, mdc, marker, cause)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -72,7 +72,10 @@ class Slf4jLogger extends Actor with SLF4JLogging with RequiresMessageQueue[Logg
|
|||
|
||||
case event @ Warning(logSource, logClass, message) ⇒
|
||||
withMdc(logSource, event) {
|
||||
Logger(logClass, logSource).warn(markerIfPresent(event), "{}", message.asInstanceOf[AnyRef])
|
||||
event match {
|
||||
case e: LogEventWithCause ⇒ Logger(logClass, logSource).warn(markerIfPresent(event), if (message != null) message.toString else null, e.cause)
|
||||
case _ ⇒ Logger(logClass, logSource).warn(markerIfPresent(event), if (message != null) message.toString else null)
|
||||
}
|
||||
}
|
||||
|
||||
case event @ Info(logSource, logClass, message) ⇒
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ package internal
|
|||
import java.util.concurrent.{ CompletionStage, ThreadFactory }
|
||||
|
||||
import akka.annotation.InternalApi
|
||||
import akka.event.Logging
|
||||
import akka.event.typed.{ BusLogging, DefaultLoggingFilter, EventStream }
|
||||
import akka.event.{ BusLogging, DefaultLoggingFilter, Logging }
|
||||
import akka.testkit.typed.StubbedLogger
|
||||
import akka.util.Timeout
|
||||
import akka.{ actor ⇒ a, event ⇒ e }
|
||||
import com.typesafe.config.ConfigFactory
|
||||
|
|
@ -43,16 +43,7 @@ import scala.concurrent._
|
|||
}
|
||||
|
||||
override def dynamicAccess: a.DynamicAccess = new a.ReflectiveDynamicAccess(getClass.getClassLoader)
|
||||
override def eventStream: EventStream = new EventStream {
|
||||
override def subscribe[T](subscriber: ActorRef[T], to: Class[T]) = false
|
||||
override def setLogLevel(loglevel: Logging.LogLevel): Unit = {}
|
||||
override def logLevel = Logging.InfoLevel
|
||||
override def unsubscribe[T](subscriber: ActorRef[T], from: Class[T]) = false
|
||||
override def unsubscribe[T](subscriber: ActorRef[T]): Unit = {}
|
||||
override def publish[T](event: T): Unit = {}
|
||||
}
|
||||
override def logFilter: e.LoggingFilter = new DefaultLoggingFilter(settings, eventStream)
|
||||
override def log: e.LoggingAdapter = new BusLogging(eventStream, path.parent.toString, getClass, logFilter)
|
||||
|
||||
override def logConfiguration(): Unit = log.info(settings.toString)
|
||||
|
||||
override def scheduler: a.Scheduler = throw new UnsupportedOperationException("no scheduler")
|
||||
|
|
@ -84,4 +75,6 @@ import scala.concurrent._
|
|||
|
||||
def hasExtension(ext: ExtensionId[_ <: Extension]): Boolean =
|
||||
throw new UnsupportedOperationException("ActorSystemStub cannot register extensions")
|
||||
|
||||
def log: Logger = new StubbedLogger
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import java.util.concurrent.ConcurrentLinkedQueue
|
|||
|
||||
import akka.actor.typed.{ ActorRef, Behavior, PostStop, Props, Signal }
|
||||
import akka.annotation.{ ApiMayChange, InternalApi }
|
||||
import akka.event.LoggingAdapter
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.immutable
|
||||
import scala.util.control.Exception.Catcher
|
||||
import scala.util.control.NonFatal
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||
|
||||
import scala.language.existentials
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,14 +3,17 @@ package akka.testkit.typed
|
|||
import akka.actor.InvalidMessageException
|
||||
import akka.{ actor ⇒ untyped }
|
||||
import akka.actor.typed._
|
||||
import akka.util.Helpers
|
||||
import akka.util.{ Helpers, OptionVal }
|
||||
import akka.{ actor ⇒ a }
|
||||
|
||||
import scala.collection.immutable.TreeMap
|
||||
import scala.concurrent.ExecutionContextExecutor
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
import akka.annotation.InternalApi
|
||||
import akka.actor.typed.internal.{ ActorContextImpl, ActorRefImpl, ActorSystemStub, SystemMessage }
|
||||
import akka.actor.typed.internal._
|
||||
import akka.actor.typed.internal.adapter.LoggerAdapterImpl
|
||||
import akka.event.Logging.{ Info, LogEvent, LogLevel }
|
||||
import akka.event.{ Logging, LoggingAdapter }
|
||||
|
||||
/**
|
||||
* A local synchronous ActorRef that invokes the given function for every message send.
|
||||
|
|
@ -32,6 +35,39 @@ private[akka] final class FunctionRef[-T](
|
|||
override def isLocal = true
|
||||
}
|
||||
|
||||
final case class CapturedLogEvent(logLevel: LogLevel, message: String, cause: OptionVal[Throwable], marker: OptionVal[LogMarker])
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*
|
||||
* Captures log events for test inspection
|
||||
*/
|
||||
@InternalApi private[akka] final class StubbedLogger extends LoggerAdapterImpl(null, null, null, null) {
|
||||
|
||||
private var logBuffer: List[CapturedLogEvent] = Nil
|
||||
|
||||
override def isErrorEnabled: Boolean = true
|
||||
override def isWarningEnabled: Boolean = true
|
||||
override def isInfoEnabled: Boolean = true
|
||||
override def isDebugEnabled: Boolean = true
|
||||
|
||||
override protected def notifyError(message: String, cause: OptionVal[Throwable], marker: OptionVal[LogMarker]): Unit =
|
||||
logBuffer = CapturedLogEvent(Logging.ErrorLevel, message, cause, marker) :: logBuffer
|
||||
|
||||
override protected def notifyWarning(message: String, marker: OptionVal[LogMarker], cause: OptionVal[Throwable]): Unit =
|
||||
logBuffer = CapturedLogEvent(Logging.WarningLevel, message, OptionVal.None, marker) :: logBuffer
|
||||
|
||||
override protected def notifyInfo(message: String, marker: OptionVal[LogMarker]): Unit =
|
||||
logBuffer = CapturedLogEvent(Logging.InfoLevel, message, OptionVal.None, marker) :: logBuffer
|
||||
|
||||
override protected def notifyDebug(message: String, marker: OptionVal[LogMarker]): Unit =
|
||||
logBuffer = CapturedLogEvent(Logging.DebugLevel, message, OptionVal.None, marker) :: logBuffer
|
||||
|
||||
def logEntries: List[CapturedLogEvent] = logBuffer.reverse
|
||||
def clearLog(): Unit = logBuffer = Nil
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*
|
||||
|
|
@ -56,6 +92,7 @@ private[akka] final class FunctionRef[-T](
|
|||
|
||||
private var _children = TreeMap.empty[String, TestInbox[_]]
|
||||
private val childName = Iterator from 0 map (Helpers.base64(_))
|
||||
private val loggingAdapter = new StubbedLogger
|
||||
|
||||
override def children: Iterable[ActorRef[Nothing]] = _children.values map (_.ref)
|
||||
def childrenNames: Iterable[String] = _children.keys
|
||||
|
|
@ -138,4 +175,17 @@ private[akka] final class FunctionRef[-T](
|
|||
def removeChildInbox(child: ActorRef[Nothing]): Unit = _children -= child.path.name
|
||||
|
||||
override def toString: String = s"Inbox($self)"
|
||||
|
||||
override def log: Logger = loggingAdapter
|
||||
|
||||
/**
|
||||
* The log entries logged through ctx.log.{debug, info, warn, error} are captured and can be inspected through
|
||||
* this method.
|
||||
*/
|
||||
def logEntries: List[CapturedLogEvent] = loggingAdapter.logEntries
|
||||
|
||||
/**
|
||||
* Clear the log entries
|
||||
*/
|
||||
def clearLog(): Unit = loggingAdapter.clearLog()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package akka.testkit.typed
|
||||
|
||||
import akka.event.Logging.{ LogEvent, StdOutLogger }
|
||||
import akka.testkit.{ EventFilter, TestEvent ⇒ TE }
|
||||
import akka.event.typed.Logger.{ Command, Initialize }
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import akka.actor.typed.scaladsl.Behaviors
|
||||
import akka.actor.typed.Behavior
|
||||
import akka.event.typed.Logger
|
||||
|
||||
/**
|
||||
* EventListener for running tests, which allows selectively filtering out
|
||||
* expected messages. To use it, include something like this into
|
||||
* your config
|
||||
*
|
||||
* <pre><code>
|
||||
* akka.typed {
|
||||
* loggers = ["akka.testkit.typed.TestEventListener"]
|
||||
* }
|
||||
* </code></pre>
|
||||
*/
|
||||
class TestEventListener extends Logger with StdOutLogger {
|
||||
|
||||
override val initialBehavior: Behavior[Command] = {
|
||||
Behaviors.deferred[Command] { _ ⇒
|
||||
Behaviors.immutable[Command] {
|
||||
case (ctx, Initialize(eventStream, replyTo)) ⇒
|
||||
val log = ctx.spawn(Behaviors.deferred[AnyRef] { childCtx ⇒
|
||||
var filters: List[EventFilter] = Nil
|
||||
|
||||
def filter(event: LogEvent): Boolean = filters exists (f ⇒ try { f(event) } catch { case e: Exception ⇒ false })
|
||||
|
||||
def addFilter(filter: EventFilter): Unit = filters ::= filter
|
||||
|
||||
def removeFilter(filter: EventFilter) {
|
||||
@tailrec def removeFirst(list: List[EventFilter], zipped: List[EventFilter] = Nil): List[EventFilter] = list match {
|
||||
case head :: tail if head == filter ⇒ tail.reverse_:::(zipped)
|
||||
case head :: tail ⇒ removeFirst(tail, head :: zipped)
|
||||
case Nil ⇒ filters // filter not found, just return original list
|
||||
}
|
||||
filters = removeFirst(filters)
|
||||
}
|
||||
|
||||
Behaviors.immutable[AnyRef] {
|
||||
case (_, TE.Mute(filters)) ⇒
|
||||
filters foreach addFilter
|
||||
Behaviors.same
|
||||
case (_, TE.UnMute(filters)) ⇒
|
||||
filters foreach removeFilter
|
||||
Behaviors.same
|
||||
case (_, event: LogEvent) ⇒
|
||||
if (!filter(event)) print(event)
|
||||
Behaviors.same
|
||||
case _ ⇒ Behaviors.unhandled
|
||||
}
|
||||
}, "logger")
|
||||
|
||||
eventStream.subscribe(log, classOf[TE.Mute])
|
||||
eventStream.subscribe(log, classOf[TE.UnMute])
|
||||
ctx.watch(log) // sign death pact
|
||||
replyTo ! log
|
||||
|
||||
Behaviors.empty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue