-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Enabling console logger queue length and mode to be configurable #70186
Conversation
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Tagging subscribers to this area: @dotnet/area-extensions-logging Issue DetailsDescriptionAdds configuration for console logger's queue length and mode
Performance testingComparing original
|
Author: | maryamariyan |
---|---|
Assignees: | maryamariyan |
Labels: |
|
Milestone: | - |
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerQueueFullMode.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Show resolved
Hide resolved
...ing.Console/tests/Microsoft.Extensions.Logging.Console.Tests/ConsoleLoggerExtensionsTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
Still a few more feedback left to apply. Marked resolved the ones that are done with the new commit. |
ce492c7
to
e4c6f97
Compare
} | ||
} | ||
|
||
internal const int DefaultMaxQueueLengthValue = 1024 * 1024; |
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.
I think this is way too big. Previously we were discussing a 1MB limit on the buffer with the assumption that an average message might be 400 bytes and the goal was only to do a modest increase in buffer size. I proposed 400KB (~1000 messages) and Fowler counter-proposed 1MB (~2500 messages). I'm OK if we want to bump from 1000 messages to 2500 as a default, but I don't think we should jump to 1 million. As-is I expect this will create OOM or huge memory increases for apps that log aggressively.
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.
2500 is not enough for a default value.
e.g. with
for (int i = 0; i < 10000; i++)
{
logger.LogInformation(_1000Chars);
}
When testing to set the max size for the above for
loop, the max size increase to 2500
won't be enough but for the same use case setting to 10,000 arbitrarily, makes sure we don't hit the lock contention and the speed jump that we want happens too.
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.
I'm not sure I follow your rationale? If that 10,000 comes from some of our perf tests it was picked arbitrarily as a 'big enough' number to amortize the influence of outliers and the start/finish code in the benchmark. It was never intended as an estimate of how many log calls are likely to be made in a bursty logging scenario so I wouldn't use it to tune default buffer sizes.
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.
I have no strong opinion of value default. Just sharing my observation here in case it helps decide on the best number to choose. Changed default from 1024*1024 to 2500 in latest commit.
cc @davidfowl
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProvider.cs
Outdated
Show resolved
Hide resolved
Thanks for reviews. The PR is ready for another look. |
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
// Assert | ||
if (okToDrop) | ||
{ | ||
Assert.True(errorConsole.TimesWriteCalled > 0); |
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.
If the thread dequeing messages runs fast enough then nothing will be dropped and the test will fail. To make the test deterministic regardless of dequeue thread speed you would need to block at some point in the test console or console sink.
Looking pretty good, just a few more things I spotted above. |
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Show resolved
Hide resolved
b883e00
to
50f021e
Compare
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
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.
@noahfalk @davidfowl I'll switch the default to some number in the middle. I'd like this to be able to merge for the upcoming preview to give contributors a chance to try out and let us know how it fits in their solutions. that might influence a better default number prior to our final previews.
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
ee406ed
to
60f5f3b
Compare
PR is ready for review again |
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 to me in terms of diagnostic functionality : )
src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/Resources/Strings.resx
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerQueueFullMode.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerQueueFullMode.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerQueueFullMode.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/Resources/Strings.resx
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs
Outdated
Show resolved
Hide resolved
{ | ||
// _fullMode is used inside the lock and is safer to guard setter with lock as well | ||
// this set is not expected to happen frequently | ||
_fullMode = value; |
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.
Why don't we need a Monitor.PulseAll(_messageQueue);
here?
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.
no thread would be waiting on full mode to change
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.
what about my comment here #70186 (comment)?
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.
oh seems like this comment is related, #70186 (comment)
updated.
Co-authored-by: Eric Erhardt <[email protected]>
… into cloud-console
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. Thanks for the great work here, @maryamariyan!
Monitor.Wait(_messageQueue); | ||
} | ||
|
||
if (_messageQueue.Count > 0 && !_isAddingCompleted) |
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.
So after the Dispose
is called - we won't log any messages that are still in buffer?
@vlada-shubina as FYI
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.
To elaborate more
Dispose
callsCompleteAdding
which tries to lock_messageQueue
and then marks_isAddingCompleted
withtrue
ProcessLogQueue
callsTryDequeue
in a loop, per single item. For each call it needs to lock_messageQueue
to be able to return item to be logged byProcessLogQueue
- If
_isAddingCompleted
istrue
theTryDequeue
will return false - even if_messageQueue.Count
is nonempty
Those facts bring the following concerns:
- The
CompleteAdding
andTryDequeue
races for same lock. OnceCompleteAdding
wins, nothing more is logged, even if items are still queued - this seems to be a bug. TryDequeue
tries to acquire lock for each single item being logged - I'm surprised this ends up being faster then using low-lockBlockingCollection
. If it really is - should theBlockingCollection
be actualy revised?
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.
@JanKrivanek if you can provide a sample code to demonstrate the concerns, you may open a new issue and we can track looking at that there. Thanks for your feedback.
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.
I am seeing you already logged #79812. We'll try to look at that at some point.
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.
Sample repro: https://github.com/JanKrivanek/ConsoleLogging
Showing that messages are being dropped in 7.0 version of logging.
Description
Adds configuration for console logger's queue length and mode
ThreadStateException
case in Dispose andGetQueueSize
metrics logic)Performance testing
Comparing original
BlockingCollection
with newQueue
implementationUsing a custom log formatter which only writes the string in message template, with no padding or prefix, using the snippet below:
Table below shows the perf numbers comparing
BlockingCollection
vs. newQueue
implementation given different max length sizes, running:This shows there's no time regression caused by using the queue approach. All of the cases above would hit the max queue length limit and they all have a perf hit because of hitting that limit.
The other test involves setting max queue length to a value that the logging load would not hit.
At this higher max value (making sure it wont hit max for looping 100_000 logs, total of 190 MB), both
BlockingCollection
andQueue
approaches get a big performance boost when logging the same amount of logs:Note: Given that these numbers are from manually using stopwatch, it doesn't cover the standard deviation error between using BlockingCollection and Queue. Overall both approaches remain in the same range in performance.
Fixes #65264