2011-12-13 14:46:15 +01:00
|
|
|
|
.. _logging-scala:
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2011-12-13 14:46:15 +01:00
|
|
|
|
#################
|
2013-04-19 13:21:15 +02:00
|
|
|
|
Logging
|
2011-12-13 14:46:15 +01:00
|
|
|
|
#################
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2013-02-22 15:16:53 +01:00
|
|
|
|
Logging in Akka is not tied to a specific logging backend. By default
|
|
|
|
|
|
log messages are printed to STDOUT, but you can plug-in a SLF4J logger or
|
|
|
|
|
|
your own logger. Logging is performed asynchronously to ensure that logging
|
|
|
|
|
|
has minimal performance impact. Logging generally means IO and locks,
|
|
|
|
|
|
which can slow down the operations of your code if it was performed
|
|
|
|
|
|
synchronously.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
|
|
|
|
|
How to Log
|
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
|
|
Create a ``LoggingAdapter`` and use the ``error``, ``warning``, ``info``, or ``debug`` methods,
|
2011-12-13 14:46:15 +01:00
|
|
|
|
as illustrated in this example:
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2012-05-24 22:23:36 +02:00
|
|
|
|
.. includecode:: code/docs/event/LoggingDocSpec.scala
|
2011-12-13 12:33:29 +01:00
|
|
|
|
:include: my-actor
|
|
|
|
|
|
|
2011-12-13 13:32:58 +01:00
|
|
|
|
For convenience you can mixin the ``log`` member into actors, instead of defining it as above.
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: scala
|
|
|
|
|
|
|
2011-12-14 15:12:40 +01:00
|
|
|
|
class MyActor extends Actor with akka.actor.ActorLogging {
|
2012-01-13 13:50:42 +01:00
|
|
|
|
...
|
|
|
|
|
|
}
|
2011-12-13 13:32:58 +01:00
|
|
|
|
|
2011-12-13 14:46:15 +01:00
|
|
|
|
The second parameter to the ``Logging`` is the source of this logging channel.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
The source object is translated to a String according to the following rules:
|
|
|
|
|
|
|
|
|
|
|
|
* if it is an Actor or ActorRef, its path is used
|
|
|
|
|
|
* in case of a String it is used as is
|
|
|
|
|
|
* in case of a class an approximation of its simpleName
|
2012-01-13 13:50:42 +01:00
|
|
|
|
* and in all other cases a compile error occurs unless and implicit
|
|
|
|
|
|
:class:`LogSource[T]` is in scope for the type in question.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2012-02-22 11:00:00 +01:00
|
|
|
|
The log message may contain argument placeholders ``{}``, which will be
|
|
|
|
|
|
substituted if the log level is enabled. Giving more arguments as there are
|
|
|
|
|
|
placeholders results in a warning being appended to the log statement (i.e. on
|
|
|
|
|
|
the same line with the same severity). You may pass a Java array as the only
|
|
|
|
|
|
substitution argument to have its elements be treated individually:
|
|
|
|
|
|
|
2012-05-24 22:23:36 +02:00
|
|
|
|
.. includecode:: code/docs/event/LoggingDocSpec.scala#array
|
2012-02-22 11:00:00 +01:00
|
|
|
|
|
|
|
|
|
|
The Java :class:`Class` of the log source is also included in the generated
|
|
|
|
|
|
:class:`LogEvent`. In case of a simple string this is replaced with a “marker”
|
|
|
|
|
|
class :class:`akka.event.DummyClassForStringSources` in order to allow special
|
|
|
|
|
|
treatment of this case, e.g. in the SLF4J event listener which will then use
|
|
|
|
|
|
the string instead of the class’ name for looking up the logger instance to
|
|
|
|
|
|
use.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2013-06-19 18:28:51 +02:00
|
|
|
|
Logging of Dead Letters
|
|
|
|
|
|
-----------------------
|
|
|
|
|
|
|
|
|
|
|
|
By default messages sent to dead letters are logged at info level. Existence of dead letters
|
|
|
|
|
|
does not necessarily indicate a problem, but it might be, and therefore they are logged by default.
|
|
|
|
|
|
After a few messages this logging is turned off, to avoid flooding the logs.
|
|
|
|
|
|
You can disable this logging completely or adjust how many dead letters that are
|
|
|
|
|
|
logged. During system shutdown it is likely that you see dead letters, since pending
|
|
|
|
|
|
messages in the actor mailboxes are sent to dead letters. You can also disable logging
|
|
|
|
|
|
of dead letters during shutdown.
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
log-dead-letters = 10
|
|
|
|
|
|
log-dead-letters-during-shutdown = on
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
To customize the logging further or take other actions for dead letters you can subscribe
|
|
|
|
|
|
to the :ref:`event-stream-scala`.
|
|
|
|
|
|
|
2012-01-23 13:54:11 +01:00
|
|
|
|
Auxiliary logging options
|
|
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
|
|
|
|
Akka has a couple of configuration options for very low level debugging, that makes most sense in
|
|
|
|
|
|
for developers and not for operations.
|
|
|
|
|
|
|
2012-01-23 14:35:01 +01:00
|
|
|
|
You almost definitely need to have logging set to DEBUG to use any of the options below:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
2013-02-19 11:29:17 +01:00
|
|
|
|
loglevel = "DEBUG"
|
2012-01-23 14:35:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-01-23 13:54:11 +01:00
|
|
|
|
This config option is very good if you want to know what config settings are loaded by Akka:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
# Log the complete configuration at INFO level when the actor system is started.
|
|
|
|
|
|
# This is useful when you are uncertain of what configuration is used.
|
2012-02-09 20:40:09 +01:00
|
|
|
|
log-config-on-start = on
|
2012-01-23 13:54:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-02-25 11:39:08 +13:00
|
|
|
|
If you want very detailed logging of user-level messages then wrap your actors' behaviors with
|
|
|
|
|
|
``akka.event.LoggingReceive`` and enable the ``receive`` option:
|
2012-01-23 13:54:11 +01:00
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
2012-04-08 01:10:19 +02:00
|
|
|
|
actor {
|
|
|
|
|
|
debug {
|
|
|
|
|
|
# enable function of LoggingReceive, which is to log any received message at
|
|
|
|
|
|
# DEBUG level
|
|
|
|
|
|
receive = on
|
|
|
|
|
|
}
|
2012-01-23 13:54:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
If you want very detailed logging of all automatically received messages that are processed
|
|
|
|
|
|
by Actors:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
2012-04-08 01:10:19 +02:00
|
|
|
|
actor {
|
|
|
|
|
|
debug {
|
2012-10-01 20:35:19 +02:00
|
|
|
|
# enable DEBUG logging of all AutoReceiveMessages (Kill, PoisonPill et.c.)
|
2012-04-08 01:10:19 +02:00
|
|
|
|
autoreceive = on
|
|
|
|
|
|
}
|
2012-01-23 13:54:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
If you want very detailed logging of all lifecycle changes of Actors (restarts, deaths etc):
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
2012-04-08 01:10:19 +02:00
|
|
|
|
actor {
|
|
|
|
|
|
debug {
|
|
|
|
|
|
# enable DEBUG logging of actor lifecycle changes
|
|
|
|
|
|
lifecycle = on
|
|
|
|
|
|
}
|
2012-01-23 13:54:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-09-08 14:34:20 +02:00
|
|
|
|
If you want unhandled messages logged at DEBUG:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
actor {
|
|
|
|
|
|
debug {
|
|
|
|
|
|
# enable DEBUG logging of unhandled messages
|
|
|
|
|
|
unhandled = on
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-01-23 13:54:11 +01:00
|
|
|
|
If you want very detailed logging of all events, transitions and timers of FSM Actors that extend LoggingFSM:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
2012-04-08 01:10:19 +02:00
|
|
|
|
actor {
|
|
|
|
|
|
debug {
|
|
|
|
|
|
# enable DEBUG logging of all LoggingFSMs for events, transitions and timers
|
|
|
|
|
|
fsm = on
|
|
|
|
|
|
}
|
2012-01-23 13:54:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
If you want to monitor subscriptions (subscribe/unsubscribe) on the ActorSystem.eventStream:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
2012-04-08 01:10:19 +02:00
|
|
|
|
actor {
|
|
|
|
|
|
debug {
|
|
|
|
|
|
# enable DEBUG logging of subscription changes on the eventStream
|
|
|
|
|
|
event-stream = on
|
|
|
|
|
|
}
|
2012-01-23 13:54:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Auxiliary remote logging options
|
|
|
|
|
|
--------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
If you want to see all messages that are sent through remoting at DEBUG log level:
|
|
|
|
|
|
(This is logged as they are sent by the transport layer, not by the Actor)
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
remote {
|
2012-10-01 20:35:19 +02:00
|
|
|
|
# If this is "on", Akka will log all outbound messages at DEBUG level,
|
|
|
|
|
|
# if off then they are not logged
|
2012-01-23 14:14:39 +01:00
|
|
|
|
log-sent-messages = on
|
2012-01-23 13:54:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
If you want to see all messages that are received through remoting at DEBUG log level:
|
|
|
|
|
|
(This is logged as they are received by the transport layer, not by any Actor)
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
remote {
|
2012-10-01 20:35:19 +02:00
|
|
|
|
# If this is "on", Akka will log all inbound messages at DEBUG level,
|
|
|
|
|
|
# if off then they are not logged
|
2012-01-23 14:14:39 +01:00
|
|
|
|
log-received-messages = on
|
2012-01-23 13:54:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-04-28 08:32:58 +02:00
|
|
|
|
If you want to see message types with payload size in bytes larger than
|
|
|
|
|
|
a specified limit at INFO log level:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
remote {
|
|
|
|
|
|
# Logging of message types with payload size in bytes larger than
|
|
|
|
|
|
# this value. Maximum detected size per message type is logged once,
|
|
|
|
|
|
# with an increase threshold of 10%.
|
|
|
|
|
|
# By default this feature is turned off. Activate it by setting the property to
|
|
|
|
|
|
# a value in bytes, such as 1000b. Note that for all messages larger than this
|
|
|
|
|
|
# limit there will be extra performance and scalability cost.
|
|
|
|
|
|
log-frame-size-exceeding = 1000b
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-08-14 11:29:54 +02:00
|
|
|
|
Also see the logging options for TestKit: :ref:`actor.logging-scala`.
|
2012-01-23 14:35:01 +01:00
|
|
|
|
|
2012-01-13 13:50:42 +01:00
|
|
|
|
Translating Log Source to String and Class
|
|
|
|
|
|
------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
The rules for translating the source object to the source string and class
|
|
|
|
|
|
which are inserted into the :class:`LogEvent` during runtime are implemented
|
|
|
|
|
|
using implicit parameters and thus fully customizable: simply create your own
|
|
|
|
|
|
instance of :class:`LogSource[T]` and have it in scope when creating the
|
|
|
|
|
|
logger.
|
|
|
|
|
|
|
2012-05-24 22:23:36 +02:00
|
|
|
|
.. includecode:: code/docs/event/LoggingDocSpec.scala#my-source
|
2012-01-13 13:50:42 +01:00
|
|
|
|
|
|
|
|
|
|
This example creates a log source which mimics traditional usage of Java
|
|
|
|
|
|
loggers, which are based upon the originating object’s class name as log
|
|
|
|
|
|
category. The override of :meth:`getClazz` is only included for demonstration
|
|
|
|
|
|
purposes as it contains exactly the default behavior.
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
You may also create the string representation up front and pass that in as
|
|
|
|
|
|
the log source, but be aware that then the :class:`Class[_]` which will be
|
|
|
|
|
|
put in the :class:`LogEvent` is
|
|
|
|
|
|
:class:`akka.event.DummyClassForStringSources`.
|
|
|
|
|
|
|
|
|
|
|
|
The SLF4J event listener treats this case specially (using the actual string
|
|
|
|
|
|
to look up the logger instance to use instead of the class’ name), and you
|
2012-02-14 19:50:01 +07:00
|
|
|
|
might want to do this also in case you implement your own logging adapter.
|
2012-01-13 13:50:42 +01:00
|
|
|
|
|
2013-02-19 11:29:17 +01:00
|
|
|
|
Turn Off Logging
|
|
|
|
|
|
----------------
|
|
|
|
|
|
|
|
|
|
|
|
To turn off logging you can configure the log levels to be ``OFF`` like this.
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
|
|
|
|
|
stdout-loglevel = "OFF"
|
|
|
|
|
|
loglevel = "OFF"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
The ``stdout-loglevel`` is only in effect during system startup and shutdown, and setting
|
|
|
|
|
|
it to ``OFF`` as well, ensures that nothing gets logged during system startup or shutdown.
|
|
|
|
|
|
|
2013-02-01 08:02:53 +01:00
|
|
|
|
Loggers
|
|
|
|
|
|
=======
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2013-02-22 15:16:53 +01:00
|
|
|
|
Logging is performed asynchronously through an event bus. Log events are processed by an event handler actor
|
|
|
|
|
|
and it will receive the log events in the same order as they were emitted.
|
|
|
|
|
|
|
2015-09-21 14:43:57 +02:00
|
|
|
|
.. note::
|
|
|
|
|
|
The event handler actor does not have a bounded inbox and is run on the default dispatcher. This means
|
|
|
|
|
|
that logging extreme amounts of data may affect your application badly. It can be somewhat mitigated by
|
|
|
|
|
|
making sure to use an async logging backend though. (See :ref:`slf4j-directly-scala`)
|
|
|
|
|
|
|
2013-02-22 15:16:53 +01:00
|
|
|
|
You can configure which event handlers are created at system start-up and listen to logging events. That is done using the
|
|
|
|
|
|
``loggers`` element in the :ref:`configuration`.
|
2014-06-19 11:33:08 +02:00
|
|
|
|
Here you can also define the log level. More fine grained filtering based on the log source
|
|
|
|
|
|
can be implemented in a custom ``LoggingFilter``, which can be defined in the ``logging-filter``
|
|
|
|
|
|
configuration property.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
|
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
2013-02-01 08:02:53 +01:00
|
|
|
|
# Loggers to register at boot time (akka.event.Logging$DefaultLogger logs
|
|
|
|
|
|
# to STDOUT)
|
|
|
|
|
|
loggers = ["akka.event.Logging$DefaultLogger"]
|
2013-02-19 11:29:17 +01:00
|
|
|
|
# Options: OFF, ERROR, WARNING, INFO, DEBUG
|
2011-12-14 15:12:40 +01:00
|
|
|
|
loglevel = "DEBUG"
|
2011-12-13 12:33:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-01-13 13:50:42 +01:00
|
|
|
|
The default one logs to STDOUT and is registered by default. It is not intended
|
|
|
|
|
|
to be used for production. There is also an :ref:`slf4j-scala`
|
2013-02-01 08:02:53 +01:00
|
|
|
|
logger available in the 'akka-slf4j' module.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2011-12-13 14:46:15 +01:00
|
|
|
|
Example of creating a listener:
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2012-05-24 22:23:36 +02:00
|
|
|
|
.. includecode:: code/docs/event/LoggingDocSpec.scala
|
2011-12-13 12:33:29 +01:00
|
|
|
|
:include: my-event-listener
|
|
|
|
|
|
|
2014-02-05 10:26:54 +01:00
|
|
|
|
Logging to stdout during startup and shutdown
|
|
|
|
|
|
=============================================
|
|
|
|
|
|
|
|
|
|
|
|
When the actor system is starting up and shutting down the configured ``loggers`` are not used.
|
|
|
|
|
|
Instead log messages are printed to stdout (System.out). The default log level for this
|
|
|
|
|
|
stdout logger is ``WARNING`` and it can be silenced completely by setting
|
|
|
|
|
|
``akka.stdout-loglevel=OFF``.
|
|
|
|
|
|
|
2014-06-19 11:33:08 +02:00
|
|
|
|
.. _slf4j-scala:
|
|
|
|
|
|
|
2011-12-13 12:33:29 +01:00
|
|
|
|
SLF4J
|
|
|
|
|
|
=====
|
|
|
|
|
|
|
2013-02-01 08:02:53 +01:00
|
|
|
|
Akka provides a logger for `SL4FJ <http://www.slf4j.org/>`_. This module is available in the 'akka-slf4j.jar'.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
It has one single dependency; the slf4j-api jar. In runtime you also need a SLF4J backend, we recommend `Logback <http://logback.qos.ch/>`_:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: scala
|
|
|
|
|
|
|
2015-05-08 16:35:29 +02:00
|
|
|
|
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.1.3"
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
2014-06-19 11:33:08 +02:00
|
|
|
|
You need to enable the Slf4jLogger in the ``loggers`` element in
|
2011-12-14 15:12:40 +01:00
|
|
|
|
the :ref:`configuration`. Here you can also define the log level of the event bus.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
More fine grained log levels can be defined in the configuration of the SLF4J backend
|
2014-06-19 11:33:08 +02:00
|
|
|
|
(e.g. logback.xml). You should also define ``akka.event.slf4j.Slf4jLoggingFilter`` in
|
|
|
|
|
|
the ``logging-filter`` configuration property. It will filter the log events using the backend
|
|
|
|
|
|
configuration (e.g. logback.xml) before they are published to the event bus.
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2015-09-08 14:14:17 +02:00
|
|
|
|
.. warning::
|
|
|
|
|
|
If you set the ``loglevel`` to a higher level than "DEBUG", any DEBUG events will be filtered
|
|
|
|
|
|
out already at the source and will never reach the logging backend, regardless of how the backend
|
|
|
|
|
|
is configured.
|
|
|
|
|
|
|
2011-12-13 12:33:29 +01:00
|
|
|
|
.. code-block:: ruby
|
|
|
|
|
|
|
|
|
|
|
|
akka {
|
2013-02-01 08:02:53 +01:00
|
|
|
|
loggers = ["akka.event.slf4j.Slf4jLogger"]
|
2011-12-13 12:33:29 +01:00
|
|
|
|
loglevel = "DEBUG"
|
2014-06-19 11:33:08 +02:00
|
|
|
|
logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
|
2011-12-13 12:33:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-02-05 10:26:54 +01:00
|
|
|
|
One gotcha is that the timestamp is attributed in the event handler, not when actually doing the logging.
|
|
|
|
|
|
|
2012-02-03 10:47:56 +01:00
|
|
|
|
The SLF4J logger selected for each log event is chosen based on the
|
|
|
|
|
|
:class:`Class[_]` of the log source specified when creating the
|
|
|
|
|
|
:class:`LoggingAdapter`, unless that was given directly as a string in which
|
|
|
|
|
|
case that string is used (i.e. ``LoggerFactory.getLogger(c: Class[_])`` is used in
|
|
|
|
|
|
the first case and ``LoggerFactory.getLogger(s: String)`` in the second).
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
2012-06-04 23:35:52 +02:00
|
|
|
|
Beware that the actor system’s name is appended to a :class:`String` log
|
2012-02-03 10:47:56 +01:00
|
|
|
|
source if the LoggingAdapter was created giving an :class:`ActorSystem` to
|
|
|
|
|
|
the factory. If this is not intended, give a :class:`LoggingBus` instead as
|
|
|
|
|
|
shown below:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: scala
|
|
|
|
|
|
|
|
|
|
|
|
val log = Logging(system.eventStream, "my.nice.string")
|
|
|
|
|
|
|
2015-09-21 14:43:57 +02:00
|
|
|
|
.. _slf4j-directly-scala:
|
|
|
|
|
|
|
|
|
|
|
|
Using the SLF4J API directly
|
|
|
|
|
|
----------------------------
|
|
|
|
|
|
If you use the SLF4J API directly in your application, remember that the logging operations will block
|
|
|
|
|
|
while the underlying infrastructure writes the log statements.
|
|
|
|
|
|
|
|
|
|
|
|
This can be avoided by configuring the logging implementation to use
|
|
|
|
|
|
a non-blocking appender. Logback provides `AsyncAppender <http://logback.qos.ch/manual/appenders.html#AsyncAppender>`_
|
|
|
|
|
|
that does this. It also contains a feature which will drop ``INFO`` and ``DEBUG`` messages if the logging
|
|
|
|
|
|
load is high.
|
|
|
|
|
|
|
2015-01-12 21:03:42 +05:00
|
|
|
|
Logging Thread, Akka Source and Actor System in MDC
|
2015-01-22 23:15:44 +05:00
|
|
|
|
---------------------------------------------------
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
|
|
|
|
|
Since the logging is done asynchronously the thread in which the logging was performed is captured in
|
|
|
|
|
|
Mapped Diagnostic Context (MDC) with attribute name ``sourceThread``.
|
|
|
|
|
|
With Logback the thread name is available with ``%X{sourceThread}`` specifier within the pattern layout configuration::
|
|
|
|
|
|
|
2011-12-14 15:12:40 +01:00
|
|
|
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
2012-02-07 11:21:49 +01:00
|
|
|
|
<encoder>
|
2011-12-14 15:12:40 +01:00
|
|
|
|
<pattern>%date{ISO8601} %-5level %logger{36} %X{sourceThread} - %msg%n</pattern>
|
2012-02-07 11:21:49 +01:00
|
|
|
|
</encoder>
|
2011-12-14 15:12:40 +01:00
|
|
|
|
</appender>
|
2011-12-13 12:33:29 +01:00
|
|
|
|
|
2012-01-13 13:50:42 +01:00
|
|
|
|
.. note::
|
2012-02-09 20:40:09 +01:00
|
|
|
|
|
2012-01-13 13:50:42 +01:00
|
|
|
|
It will probably be a good idea to use the ``sourceThread`` MDC value also in
|
|
|
|
|
|
non-Akka parts of the application in order to have this property consistently
|
|
|
|
|
|
available in the logs.
|
|
|
|
|
|
|
2012-01-11 14:14:08 +01:00
|
|
|
|
Another helpful facility is that Akka captures the actor’s address when
|
|
|
|
|
|
instantiating a logger within it, meaning that the full instance identification
|
|
|
|
|
|
is available for associating log messages e.g. with members of a router. This
|
|
|
|
|
|
information is available in the MDC with attribute name ``akkaSource``::
|
|
|
|
|
|
|
|
|
|
|
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
2012-02-07 11:21:49 +01:00
|
|
|
|
<encoder>
|
2012-01-11 14:14:08 +01:00
|
|
|
|
<pattern>%date{ISO8601} %-5level %logger{36} %X{akkaSource} - %msg%n</pattern>
|
2012-02-07 11:21:49 +01:00
|
|
|
|
</encoder>
|
2012-01-11 14:14:08 +01:00
|
|
|
|
</appender>
|
|
|
|
|
|
|
2015-01-12 21:03:42 +05:00
|
|
|
|
Finally, the actor system in which the logging was performed
|
|
|
|
|
|
is available in the MDC with attribute name ``sourceActorSystem``::
|
|
|
|
|
|
|
|
|
|
|
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
|
|
|
|
|
<encoder>
|
|
|
|
|
|
<pattern>%date{ISO8601} %-5level %logger{36} %X{sourceActorSystem} - %msg%n</pattern>
|
|
|
|
|
|
</encoder>
|
|
|
|
|
|
</appender>
|
|
|
|
|
|
|
2012-01-11 14:14:08 +01:00
|
|
|
|
For more details on what this attribute contains—also for non-actors—please see
|
|
|
|
|
|
`How to Log`_.
|
2013-04-21 00:40:47 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
More accurate timestamps for log output in MDC
|
2015-01-22 23:15:44 +05:00
|
|
|
|
----------------------------------------------
|
2013-04-21 00:40:47 -07:00
|
|
|
|
|
|
|
|
|
|
Akka's logging is asynchronous which means that the timestamp of a log entry is taken from
|
|
|
|
|
|
when the underlying logger implementation is called, which can be surprising at first.
|
|
|
|
|
|
If you want to more accurately output the timestamp, use the MDC attribute ``akkaTimestamp``::
|
|
|
|
|
|
|
|
|
|
|
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
|
|
|
|
|
<encoder>
|
|
|
|
|
|
<pattern>%X{akkaTimestamp} %-5level %logger{36} %X{akkaSource} - %msg%n</pattern>
|
|
|
|
|
|
</encoder>
|
2013-10-18 01:10:10 -03:00
|
|
|
|
</appender>
|
|
|
|
|
|
|
|
|
|
|
|
MDC values defined by the application
|
|
|
|
|
|
-------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
One useful feature available in Slf4j is `MDC <http://logback.qos.ch/manual/mdc.html>`_,
|
|
|
|
|
|
Akka has a way for let the application specify custom values, you just need to get a
|
|
|
|
|
|
specialized :class:`LoggingAdapter`, the :class:`DiagnosticLoggingAdapter`. In order to
|
|
|
|
|
|
get it you will use the factory receiving an Actor as logSource:
|
|
|
|
|
|
|
|
|
|
|
|
.. code-block:: scala
|
|
|
|
|
|
|
|
|
|
|
|
// Within your Actor
|
|
|
|
|
|
val log: DiagnosticLoggingAdapter = Logging(this);
|
|
|
|
|
|
|
|
|
|
|
|
Once you have the logger, you just need to add the custom values before you log something.
|
|
|
|
|
|
This way, the values will be put in the SLF4J MDC right before appending the log and removed after.
|
|
|
|
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
|
|
|
|
The cleanup (removal) should be done in the actor at the end,
|
|
|
|
|
|
otherwise, next message will log with same mdc values,
|
|
|
|
|
|
if it is not set to a new map. Use ``log.clearMDC()``.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/event/LoggingDocSpec.scala#mdc
|
|
|
|
|
|
|
|
|
|
|
|
For convenience you can mixin the ``log`` member into actors, instead of defining it as above.
|
|
|
|
|
|
This trait also lets you override ``def mdc(msg: Any): MDC`` for specifying MDC values
|
|
|
|
|
|
depending on current message and lets you forget about the cleanup as well, since it already does it for you.
|
|
|
|
|
|
|
|
|
|
|
|
.. includecode:: code/docs/event/LoggingDocSpec.scala
|
|
|
|
|
|
:include: mdc-actor
|
|
|
|
|
|
|
|
|
|
|
|
Now, the values will be available in the MDC, so you can use them in the layout pattern::
|
|
|
|
|
|
|
|
|
|
|
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
|
|
|
|
|
<encoder>
|
|
|
|
|
|
<pattern>
|
|
|
|
|
|
%-5level %logger{36} [req: %X{requestId}, visitor: %X{visitorId}] - %msg%n
|
|
|
|
|
|
</pattern>
|
|
|
|
|
|
</encoder>
|
|
|
|
|
|
</appender>
|
|
|
|
|
|
|