-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make sure stdout-loglevel setting is honored through the whole actor system lifecycle #5251
Changes from 10 commits
0289b2b
3f962db
a2e2505
b36f917
38b93b2
a444df7
135ec8b
ba1d0d4
16db579
086a2bf
bdcb56d
bf5ea5a
926aab3
42d5d59
a09a755
c1a739a
fd223c3
52d5b3c
7babaf3
541d9dd
8e196c9
2108dfe
783d192
0d24266
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,57 +30,65 @@ public class TestEventListener : DefaultLogger | |
/// <returns>TBD</returns> | ||
protected override bool Receive(object message) | ||
{ | ||
if(message is InitializeLogger) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change if...then...else structure to switch |
||
switch (message) | ||
{ | ||
var initLogger = (InitializeLogger)message; | ||
var bus = initLogger.LoggingBus; | ||
var self = Context.Self; | ||
bus.Subscribe(self, typeof(Mute)); | ||
bus.Subscribe(self, typeof(Unmute)); | ||
bus.Subscribe(self, typeof(DeadLetter)); | ||
bus.Subscribe(self, typeof(UnhandledMessage)); | ||
Sender.Tell(new LoggerInitialized()); | ||
} | ||
else if(message is Mute) | ||
{ | ||
var mute = (Mute)message; | ||
foreach(var filter in mute.Filters) | ||
case InitializeLogger initLogger: | ||
{ | ||
AddFilter(filter); | ||
base.Receive(message); | ||
var bus = initLogger.LoggingBus; | ||
var self = Context.Self; | ||
bus.Subscribe(self, typeof(Mute)); | ||
bus.Subscribe(self, typeof(Unmute)); | ||
bus.Subscribe(self, typeof(DeadLetter)); | ||
bus.Subscribe(self, typeof(UnhandledMessage)); | ||
Sender.Tell(new LoggerInitialized()); | ||
break; | ||
} | ||
} | ||
else if(message is Unmute) | ||
{ | ||
var unmute = (Unmute)message; | ||
foreach(var filter in unmute.Filters) | ||
case Mute mute: | ||
{ | ||
RemoveFilter(filter); | ||
foreach(var filter in mute.Filters) | ||
{ | ||
AddFilter(filter); | ||
} | ||
|
||
break; | ||
} | ||
} | ||
else if(message is LogEvent) | ||
{ | ||
var logEvent = (LogEvent)message; | ||
if(!ShouldFilter(logEvent)) | ||
case Unmute unmute: | ||
{ | ||
Print(logEvent); | ||
foreach(var filter in unmute.Filters) | ||
{ | ||
RemoveFilter(filter); | ||
} | ||
|
||
break; | ||
} | ||
case LogEvent logEvent: | ||
{ | ||
if(!ShouldFilter(logEvent)) | ||
{ | ||
Print(logEvent); | ||
} | ||
|
||
break; | ||
} | ||
case DeadLetter letter: | ||
HandleDeadLetter(letter); | ||
break; | ||
|
||
case UnhandledMessage un: | ||
{ | ||
var rcp = un.Recipient; | ||
var warning = new Warning(rcp.Path.ToString(), rcp.GetType(), "Unhandled message from " + un.Sender + ": " + un.Message); | ||
if(!ShouldFilter(warning)) | ||
Print(warning); | ||
break; | ||
} | ||
|
||
default: | ||
Print(new Debug(Context.System.Name,GetType(),message)); | ||
break; | ||
} | ||
else if(message is DeadLetter) | ||
{ | ||
HandleDeadLetter((DeadLetter)message); | ||
} | ||
else if(message is UnhandledMessage) | ||
{ | ||
var un = (UnhandledMessage) message; | ||
var rcp = un.Recipient; | ||
var warning = new Warning(rcp.Path.ToString(), rcp.GetType(), "Unhandled message from " + un.Sender + ": " + un.Message); | ||
if(!ShouldFilter(warning)) | ||
Print(warning); | ||
} | ||
else | ||
{ | ||
Print(new Debug(Context.System.Name,GetType(),message)); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// //----------------------------------------------------------------------- | ||
// // <copyright file="ShutdownLoggerSpec.cs" company="Akka.NET Project"> | ||
// // Copyright (C) 2009-2021 Lightbend Inc. <http://www.lightbend.com> | ||
// // Copyright (C) 2013-2021 .NET Foundation <https://github.com/akkadotnet/akka.net> | ||
// // </copyright> | ||
// //----------------------------------------------------------------------- | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Threading.Tasks; | ||
using Akka.Actor; | ||
using Akka.Configuration; | ||
using Akka.Event; | ||
using Akka.TestKit; | ||
using FluentAssertions; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace Akka.Tests.Loggers | ||
{ | ||
public class ShutdownLoggerSpec: AkkaSpec | ||
{ | ||
private static readonly Config Config = ConfigurationFactory.ParseString(@" | ||
akka.loglevel = OFF | ||
akka.stdout-loglevel = OFF | ||
akka.stdout-logger-class = ""Akka.Tests.Loggers.ThrowingLogger, Akka.Tests"""); | ||
|
||
public ShutdownLoggerSpec(ITestOutputHelper output) : base(Config, output) | ||
{ | ||
} | ||
|
||
[Fact(DisplayName = "StandardOutLogger should not be called on shutdown when stdout-loglevel is set to OFF")] | ||
public async Task StandardOutLoggerShouldNotBeCalled() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM |
||
{ | ||
Sys.Settings.StdoutLogger.Should().BeOfType<ThrowingLogger>(); | ||
|
||
var probeRef = Sys.ActorOf(Props.Create(() => new LogProbe())); | ||
probeRef.Tell(new InitializeLogger(Sys.EventStream)); | ||
var probe = await probeRef.Ask<LogProbe>("hey"); | ||
|
||
await Sys.Terminate(); | ||
|
||
await Task.Delay(RemainingOrDefault); | ||
if (probe.Events.Any(o => o is Error err && err.Cause is ShutdownLogException)) | ||
throw new Exception("Test failed, log should not be called after shutdown."); | ||
} | ||
} | ||
|
||
internal class LogProbe : ReceiveActor | ||
{ | ||
public List<LogEvent> Events { get; } = new List<LogEvent>(); | ||
|
||
public LogProbe() | ||
{ | ||
Receive<string>(msg => Sender.Tell(this)); | ||
Receive<LogEvent>(Events.Add); | ||
Receive<InitializeLogger>(e => | ||
{ | ||
e.LoggingBus.Subscribe(Self, typeof (LogEvent)); | ||
Sender.Tell(new LoggerInitialized()); | ||
}); | ||
|
||
} | ||
} | ||
|
||
internal class ShutdownLogException : Exception | ||
{ | ||
public ShutdownLogException() | ||
{ } | ||
|
||
public ShutdownLogException(string msg) : base(msg) | ||
{ } | ||
} | ||
|
||
internal class ThrowingLogger : MinimalLogger | ||
{ | ||
protected override void Log(object message) | ||
{ | ||
throw new ShutdownLogException("This logger should never be called."); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
using Akka.Actor.Setup; | ||
using Akka.Configuration; | ||
using Akka.Dispatch; | ||
using Akka.Event; | ||
using Akka.Routing; | ||
using ConfigurationFactory = Akka.Configuration.ConfigurationFactory; | ||
|
||
|
@@ -109,6 +110,31 @@ public Settings(ActorSystem system, Config config, ActorSystemSetup setup) | |
|
||
LogLevel = Config.GetString("akka.loglevel", null); | ||
StdoutLogLevel = Config.GetString("akka.stdout-loglevel", null); | ||
|
||
var stdoutClassName = Config.GetString("akka.stdout-logger-class", null); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved the hard-wired StandardOutLogger instance from the Logging class to the Settings class. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this was @zbynek001's suggestion in one of those threads - we should document this inside https://getakka.net/articles/utilities/logging.html#standard-loggers |
||
if (string.IsNullOrWhiteSpace(stdoutClassName)) | ||
{ | ||
StdoutLogger = new StandardOutLogger(); | ||
} | ||
else | ||
{ | ||
var stdoutLoggerType = Type.GetType(stdoutClassName); | ||
if (stdoutLoggerType == null) | ||
throw new ArgumentException($"Could not load type of {stdoutClassName} for standard out logger."); | ||
if(!typeof(MinimalLogger).IsAssignableFrom(stdoutLoggerType)) | ||
throw new ArgumentException("Standard out logger type must inherit from the MinimalLogger abstract class."); | ||
|
||
try | ||
{ | ||
StdoutLogger = (MinimalLogger)Activator.CreateInstance(stdoutLoggerType); | ||
} | ||
catch (MissingMethodException) | ||
{ | ||
throw new MissingMethodException( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM |
||
"Standard out logger type must inherit from the MinimalLogger abstract class and have an empty constructor."); | ||
} | ||
} | ||
|
||
Loggers = Config.GetStringList("akka.loggers", new string[] { }); | ||
LoggersDispatcher = Config.GetString("akka.loggers-dispatcher", null); | ||
LoggerStartTimeout = Config.GetTimeSpan("akka.logger-startup-timeout", null); | ||
|
@@ -247,6 +273,11 @@ public Settings(ActorSystem system, Config config, ActorSystemSetup setup) | |
/// <value>The stdout log level.</value> | ||
public string StdoutLogLevel { get; private set; } | ||
|
||
/// <summary> | ||
/// Returns a singleton instance of the standard out logger. | ||
/// </summary> | ||
public MinimalLogger StdoutLogger { get; } | ||
|
||
/// <summary> | ||
/// Gets the loggers. | ||
/// </summary> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,10 @@ akka { | |
# Log level for the very basic logger activated during AkkaApplication startup | ||
# Options: OFF, ERROR, WARNING, INFO, DEBUG | ||
stdout-loglevel = "WARNING" | ||
|
||
# Fully qualified class name (FQCN) of the very basic logger used on startup and shutdown. | ||
# You can substitute the logger by supplying an FQCN to a custom class that implements Akka.Event.MinimumLogger | ||
stdout-logger-class = "Akka.Event.StandardOutLogger" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New HOCON setting to customize the standard out logger |
||
|
||
# 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. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add missing format exception catcher to Akka.TestKit.Xunit that was added to Akka.TestKit.Xunit2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM