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
Akka.Event: add log filtering system to prevent Akka.NET logs from being emitted in first place #7179
Akka.Event: add log filtering system to prevent Akka.NET logs from being emitted in first place #7179
Conversation
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.
Detailed my changes
@@ -1725,6 +1725,7 @@ namespace Akka.Actor | |||
public int LogDeadLetters { get; } | |||
public bool LogDeadLettersDuringShutdown { get; } | |||
public System.TimeSpan LogDeadLettersSuspendDuration { get; } | |||
public Akka.Event.LogFilterEvaluator LogFilter { get; } |
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.
New setting - this is where the log filter actually lives. Any custom logging plugin can access it this way.
// ReSharper disable once ClassNeverInstantiated.Global | ||
public class LogFilterEvaluatorSpecs | ||
{ | ||
public class LogFilterSetupSpecs : AkkaSpec |
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.
End to end specs - I can't easily intercept the default output from the StandardOutWriter
so I'm swapping in my own MinimalLogger
implementation and testing the results using that at the end. Not 100% clean, but close enough.
loggingAdapter2.Warning("baz"); | ||
|
||
// expect only the last message to be received | ||
ReceiveN(3); |
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.
Log events will still hit the EventStream
- the filter runs at the layer beneath this. AND THAT IS IMPORTANT: if we have the log filter layer running at this layer, at the point where LogEvent
s are EMITTED, this WILL KILL PERFORMANCE.
Instead, we make the decision about whether or not to keep / include a log at the layer right before the log is rendered. This is the correct place to do this.
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.
Anyway, that's why we still receive all 3 log events.
ReceiveN(3); | ||
|
||
// check that the last message was the one that was allowed through | ||
_logger.Events.Count.Should().Be(1); |
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.
The real logger should only have recorded the 1 log that passes both filters.
} | ||
} | ||
|
||
public class LogSourceCases |
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.
The rest of these test cases are really just testing the default Regex
used by the LogFilterBuilder
.
src/core/Akka/Event/LogFilter.cs
Outdated
{ | ||
switch (filter.FilterType) | ||
{ | ||
case LogFilterType.Source: |
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.
A single vote cast for LogFilterDecision.Drop
is all it takes for us to bail out.
// expand the message if we haven't already | ||
// NOTE: might result in duplicate allocations in third party logging libraries. They'll have to adjust their | ||
// code accordingly after this feature ships. | ||
expandedLogMessage = (string.IsNullOrEmpty(expandedLogMessage) ? evt.Message.ToString() : expandedLogMessage)!; |
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.
Have to expand the log down here, since we're keeping it.
|
||
namespace Akka.Event | ||
{ | ||
public abstract class MinimalLogger : MinimalActorRef | ||
{ | ||
public LogFilterEvaluator Filter { get; internal set; } = LogFilterEvaluator.NoFilters; |
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.
Default setting, which maintains previous behavior.
{ | ||
try | ||
{ | ||
// short circuit if we're not going to print this message | ||
if (!filter.ShouldTryKeepMessage(logEvent, out var expandedLogMessage)) | ||
return; |
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.
Self-explanatory.
@@ -144,7 +149,7 @@ internal static void PrintLogEvent(LogEvent logEvent) | |||
} | |||
} | |||
|
|||
StandardOutWriter.WriteLine(logEvent.ToString(), color); | |||
StandardOutWriter.WriteLine(expandedLogMessage, color); |
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.
Avoid expanding the log a second time.
Going to leave this PR open for comments for a while before it gets merged in |
Also: documentation. Will add it once I get review comments. |
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
I still need to do API approvals here |
Changes
Fixes #7097 and probably lots of other usability issues.
The goal behind this system is to prevent Akka.NET
LogEvent
s from being emitted in the first place in the event that their data is not useful. This should allow developers to do things likeakka.LOGLEVEL=DEBUG
without getting absolutely flooded with noise from busy parts of the system like Akka.Remote, Akka.Streams, and so on.The general idea is to pass in a new
Setup
class:These
LogFilterBase
types are intended to be simple functions, but while taking into account some easy performance considerations:I'm even including a
LogFilterBuilder
that should make it easy to construct these using a simple builder pattern. For a log to be printed, all filters must evaluate totrue
. Will include some examples of this below.Checklist
For significant changes, please ensure that the following have been completed (delete if not relevant):