Search Results for

    Show / Hide Table of Contents

    Logging

    ![NOTE] For information on how to use Serilog with Akka.NET, we have a dedicated page for that: "Using Serilog for Akka.NET Logging."

    How to Log

    To log in an actor, create a logger and assign it to a private field:

    private readonly ILoggingAdapter _log = Logging.GetLogger(Context);
    

    Use the Debug, Info, Warning and Error methods to log.

    _log.Debug("Some message");
    

    Standard Loggers

    Akka.NET comes with two built in loggers.

    • StandardOutLogger
    • BusLogging

    StandardOutLogger

    StandardOutLogger is considered as a minimal logger and implements the MinimalLogger abstract class. Its job is simply to output all LogEvents emitted by the EventBus onto the console. Since it is not an actual actor, ie. it doesn't need the ActorSystem to operate, it is also used to log other loggers activity at the very start and very end of the ActorSystem life cycle. You can change the minimal logger start and end life cycle behavior by changing the akka.stdout-loglevel HOCON settings to OFF if you do not need these feature in your application.

    Advanced MinimalLogger Setup

    You can also replace StandardOutLogger by making your own logger class with an empty constructor that inherits/implements the MinimalLogger abstract class and passing the fully qualified class name into the akka.stdout-logger-class HOCON settings.

    Warning

    Be aware that MinimalLogger implementations are NOT real actors and will NOT have any access to the ActorSystem and all of its extensions. All logging done inside a MinimalLogger have to be done in as simple as possible manner since it is used to log how other loggers are behaving at the very start and very end of the ActorSystem life cycle.

    Note that MinimalLogger are NOT interchangeable with other Akka.NET loggers and there can only be one MinimalLogger registered with the ActorSystem in the HOCON settings.

    Third Party Loggers

    These loggers are also available as separate nuget packages

    • Akka.Logger.Serilog which logs using serilog. See Detailed instructions on using Serilog.
    • Akka.Logger.NLog which logs using NLog
    • Microsoft.Extensions.Logging - which is built into Akka.Hosting.

    Note that you need to modify the config as explained below.

    NLog Configuration

    Example NLog configuration inside your app.config or web.config:

    akka {
        loggers = ["Akka.Logger.NLog.NLogLogger, Akka.Logger.NLog"]
    }
    

    The above NLog components can be found on Nuget (https://www.nuget.org/packages/Akka.Logger.NLog/)

    Configuring Custom Loggers

    To configure a custom logger inside your Akka.Config, you need to use a fully qualified .NET class name like this:

    akka {
        loggers = ["NameSpace.ClassName, AssemblyName"]
    }
    

    Or using Akka.Hosting, you can configure loggers programmatically using strongly typed references to the underlying logging classes:

    builder.Services.AddAkka("MyActorSystem", configurationBuilder =>
    {
        configurationBuilder
            .ConfigureLoggers(setup =>
            {
                // Example: This sets the minimum log level
                setup.LogLevel = LogLevel.DebugLevel;
                
                // Example: Clear all loggers
                setup.ClearLoggers();
                
                // Example: Add the default logger
                // NOTE: You can also use setup.AddLogger<DefaultLogger>();
                setup.AddDefaultLogger();
                
                // Example: Add the ILoggerFactory logger
                // NOTE:
                //   - You can also use setup.AddLogger<LoggerFactoryLogger>();
                //   - To use a specific ILoggerFactory instance, you can use setup.AddLoggerFactory(myILoggerFactory);
                setup.AddLoggerFactory();
                
                // Example: Adding a serilog logger
                setup.AddLogger<SerilogLogger>();
            })
            .WithActors((system, registry) =>
            {
                var echo = system.ActorOf(act =>
                {
                    act.ReceiveAny((o, context) =>
                    {
                        Logging.GetLogger(context.System, "echo").Info($"Actor received {o}");
                        context.Sender.Tell($"{context.Self} rcv {o}");
                    });
                }, "echo");
                registry.TryRegister<Echo>(echo); // register for DI
            });
    });
    

    Customizing the ILogMessageFormatter

    A new feature introduced in Akka.NET v1.5, you now have the ability to customize the ILogMessageFormatter - the component responsible for formatting output written to all Logger implementations in Akka.NET.

    The primary use case for this is supporting semantic logging across the board in your user-defined actors, which is something that Akka.Logger.Serilog supports quite well.

    However, maybe there are certain pieces of data you want to have injected into all of the log messages produced by Akka.NET internally - that's the sort of thing you can accomplish by customizing the ILogMessageFormatter:

    private class CustomLogFormatter : ILogMessageFormatter
    {
        public string Format(string format, params object[] args)
        {
            return string.Format("Custom: " + format, args);
        }
    
        public string Format(string format, IEnumerable<object> args)
        {
            return string.Format("Custom: " + format, args.ToArray());
        }
    }
    

    This class will be responsible for formatting all log messages when they're written out to your configured sinks - once we configure it in HOCON using the akka.logger-formatter setting:

    public static readonly Config Configuration = "akka.logger-formatter = \"Akka.Tests.Loggers.CustomLogFormatterSpec+CustomLogFormatter, Akka.Tests\"";
    

    Logging Unhandled Messages

    It is possible to configure akka so that Unhandled messages are logged as Debug log events for debug purposes. This can be achieved using the following configuration setting:

    akka {
        actor.debug.unhandled = on
    }
    

    Example Configuration

    akka {
      stdout-loglevel = DEBUG
      loglevel = DEBUG
      log-config-on-start = on
      actor {
        debug {
          receive = on
          autoreceive = on
          lifecycle = on
          event-stream = on
          unhandled = on
        }
      }
    }
    

    Logging All Received Messages

    It is possible to log all Receive'd messages, usually for debug purposes. This can be achieved by implementing the ILogReceive interface:

    public class MyActor : ReceiveActor, ILogReceive
    {
        public MyActor()
        {
            Receive<string>(s => Sender.Tell("ok"));
        }
    }
    
    ...
    
    // send a MyActor instance a string message
    myActor.Tell("hello");
    

    In your log, expect to see a line such as:

    [DEBUG]... received handled message hello from akka://test/deadLetters

    This logging can be toggled by configuring akka.actor.debug.receive.

    Filtering Log Messages

    Since v1.5.21, Akka.NET supports for filtering log messages based on the LogSource or the content of a log message.

    The goal of this feature is to allow users to run Akka.NET at more verbose logging settings (i.e. LogLevel.Debug) while not getting completely flooded with unhelpful noise from the Akka.NET logging system. You can use the LogFilterBuilder to exclude messages don't need while still keeping ones that you do.

    Configuring Log Filtering

    public static Setup LoggerSetup()
    {
        
        var builder = new LogFilterBuilder();
        builder.ExcludeSourceContaining("Akka.Tests")
            .ExcludeMessageContaining("foo-bar");
        return builder.Build();
    }
    

    We create a LogFilterBuilder prior to starting the ActorSystem and provide it with rules for which logs should be excluded from any of Akka.NET's logged output - this uses the ActorSystemSetup class functionality that Akka.NET supports for programmatic ActorSystem configuration:

    public static ActorSystemSetup CustomLoggerSetup()
    {
        var hocon = @$"akka.stdout-logger-class = ""{typeof(CustomLogger).AssemblyQualifiedName}""";
        var bootstrapSetup = BootstrapSetup.Create().WithConfig(ConfigurationFactory.ParseString(hocon));
        return ActorSystemSetup.Create(bootstrapSetup, LoggerSetup());
    }
    

    From there, we can create our ActorSystem with these rules enabled:

    ActorSystemSetup completeSetup = CustomLoggerSetup();
    
    // start the ActorSystem with the LogFilterBuilder rules enabled
    ActorSystem mySystem = ActorSystem.Create("MySys", completeSetup);
    

    Log Filtering Rules

    There are two built-in types of log filtering rules:

    • ExcludeSource___ - filters logs based on the LogSource; this type of filtering is very resource efficient because it doesn't require the log message to be expanded in order for filtering to work.
    • ExcludeMessage___ - filters logs based on the content of the message. More resource-intensive as it does require log messages to be fully expanded prior to filtering.
    Note

    For an Akka.NET log to be excluded from the output logs, only one filter rule has to return a LogFilterDecision.Drop.

    However, if that's not sufficient for your purposes we also support defining custom rules via the LogFilterBase class:

    /// <summary>
    /// Base class for all log filters
    /// </summary>
    /// <remarks>
    /// Worth noting: these run inside the Logging actors, so they're out of band
    /// from any high performance workloads already.
    ///
    /// In addition to this - all log filters will only run if the log level is enabled.
    ///
    /// i.e. if we're at INFO level and the filter is set to a lower level, i.e. filtering DEBUG
    /// logs, the filter won't even run.
    /// </remarks>
    public abstract class LogFilterBase : INoSerializationVerificationNeeded, IDeadLetterSuppression
    {
        /// <summary>
        /// Which part of the log message this filter is evaluating?
        /// </summary>
        /// <remarks>
        /// This actually has a performance implication - if we're filtering on the source, which
        /// is already fully "expanded" into its final string representation, we can try to fail fast
        /// on that without any additional allocations.
        ///
        /// If we're filtering on the message, we have to fully expand the log message first which
        /// involves allocations. Users on really tight performance budgets should be aware of this.
        /// </remarks>
        public abstract LogFilterType FilterType { get; }
    
        /// <summary>
        /// Fast path designed to avoid allocating strings if we're filtering on the message content.
        /// </summary>
        /// <param name="content">Usually the fully expanded message content.</param>
        /// <param name="expandedMessage">The fully expanded message, optional.</param>
        public abstract LogFilterDecision ShouldKeepMessage(LogEvent content, string? expandedMessage = null);
    }
    

    You can filter log messages based on any of the accessibly properties, and for performance reasons any LogFilterBase that looks at LogFilterType.Content will be passed in the fully expanded log message as a string? via the optional expandedMessage property. This is done in order to avoid allocating the log message every time for each possible rule that might be evaluated.

    In this article
    • githubEdit this page
    Back to top
    Contribute
    • Project Chat
    • Discussion Forum
    • Source Code
    Support
    • Akka.NET Support Plans
    • Akka.NET Observability Tools
    • Akka.NET Training & Consulting
    Maintained By
    • Petabridge - The Akka.NET Company
    • Learn Akka.NET