-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Betterize Hosting Log #10102
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
Betterize Hosting Log #10102
Conversation
This comment was made automatically. If there is a problem contact aspnetcore-build@microsoft.com. I've triaged the above build. I've created/commented on the following issue(s) |
} | ||
|
||
// Get or create the _loggingContext | ||
private LogContext LoggingContext => _loggingContext ??= new LogContext(); |
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.
??=
@pranavkm How many points for that?
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.
🥇
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.
My remaining question is how often a Context is constructed without setting any of these properties to a non-default value.
This does seem like a ton of work to turn six properties into one lazy-allocated field with six properties.
Also, does this need to be thread safe? I hope not because new LogContext()
could run multiple times if LoggingContext is accessed and initialized twice in a parallel.
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.
My remaining question is how often a Context is constructed without setting any of these properties to a non-default value.
If you don't want an Activity
(152 bytes), 4 ExecutionContext
s (160 bytes), 2 string
s (76+66 bytes), 4 AsyncLocalMaps (160 bytes) and 3 Logging scope objects (144 bytes); => 758 bytes
per request; when you aren't outputting any of it because you aren't at Information
level; you might set "Microsoft.AspNetCore.Hosting.Diagnostics": "None"
which will do it.
e.g.
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.AspNetCore.Hosting.Diagnostics": "None"
},
"EventLog": {
"LogLevel": {
"Microsoft.AspNetCore.Hosting.Diagnostics": "None"
}
}
},
And if you are picking up that extra 758 bytes per request, what's an extra object ;)
Also if you have no logging as per the TE benchmarks; which also benefits from the struct being 64 bytes rather than 82 bytes when passed.
Also, does this need to be thread safe?
No, its contained to before and after the request in hosting and not exposed to the user code in the application
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.
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 completely forgot that the Context itself was a struct. Too bad it's public. It would have been sooo much easier to turn the Context into a class, but that's breaking.
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.
And if Logging is off for Hosting then the Activity and the LogContext will never be allocated as they are guarded by the Log Enabled check
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 completely forgot that the Context itself was a struct. Too bad it's public. It would have been sooo much easier to turn the Context into a class, but that's breaking.
Well LogContext
is now a class if you can work out where to hang it rather than allocating it per request? (when logging or diagnostics is enabled)
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.
And if Logging is off for Hosting then the Activity and the LogContext will never be allocated as they are guarded by the Log Enabled check
I figured, but that's unrelated to the LogContext.
Well LogContext is now a class if you can work out where to hang it rather than allocating it per request? (when logging or diagnostics is enabled)
Pooling is an interesting idea. If Context itself was a class, could we pool that instead?
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 HttpContext
is "pooled" via IHttpContextFactory
(lives on connection); but the HostingApplication.Context
is side-car'd over it and avoids allocation by living in the stack and being passed around by value.
|
||
namespace Microsoft.AspNetCore.Hosting.Internal | ||
{ | ||
using static HostingRequestStartingLog; |
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.
More @pranavkm points 😄 I see this was introduced "way back" in C# 6, but I haven't seen this used much.
public IDisposable Scope | ||
{ | ||
// Get set value or return null | ||
get => _loggingContext?.Scope; |
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 was going to make this readonly get
but the version of C# AspNetCore uses is too old.
I think updating it will make Code Check unhappy as every auto-property getter gets the [Readonly]
attribute
Actually, would it really be too breaking to make HostingApplication.Context a class? Context seems to have turned into an overly-long, overly-complicated class anyway with almost everything being stored via LogContext reference. This PR changes the struct layout anyway which is why the reference assembly needed updating. |
Would need to introduce a service that the server implemented to not allocated it per request (as per HttpContext); so would be a lot more motion? And since it also contains the Could go with a double interface; if server implements HostContext pooling use that, otherwise use only HttpContext pooling and allocate the HostContext? |
Only removes the attributes |
Something like:
|
Though... that might be part of a bigger issue. Like are some routing structures connection orientated rather than request; can scopes be reset and reused etc..? |
With pooling the HostContext #10180 |
I'd like to review this before merging. I haven't kept up to date with the changes. |
@davidfowl @halter73 what's the situation here? Are we ready to merge? Unfortunately it'll probably need another rebase :(. |
I'm fine with merging this. We'll want to keep a close eye on the benchmarks. |
With master targeting 5.0 now, I'm totally fine with that. I'll re-kick the build to force it to run against the latest master. If that works, I'm OK with merging without a rebase (since we'll rebase as it's merged). |
/azp run |
Azure Pipelines successfully started running 2 pipeline(s). |
Imagine if we could run benchmarks before committing 😬 |
Someday... someday our dreams will come true :). @halter73 the rebuild looks to be fine, merge when you're ready. |
Rebased |
/azp run AspNetCore-ci |
Azure Pipelines successfully started running 1 pipeline(s). |
Didn't seem to restart the |
Doesn't look to be related to this change. The failure isn't related to the contents of the logs, but the |
/azp run |
Commenter does not have sufficient privileges for PR 10102 in repo aspnet/AspNetCore |
Output something more useful for
HostingRequestFinishedLog
(which can get intermixed when multiple parallel requests); so it becomes the more interesting event given context; since its kinda junky currently unless you are also outputting full scopes (even then you need to do matching).Before
After
Also improve the more detailed semantic logged output
Before

After

Resolves #10097
Resolves #10556
Resolves #10557
/cc @davidfowl