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
Execution time reported for HTTP request by logger is lower than in reality #1121
Comments
That's interesting, do you have ability to profile this and see where the time is spent? |
I can try, but I assume the reporting happens right after the header is received, and it takes some time to receive everything. But I don't really know, and probably profiling won't help either since it's not CPU usage |
Most profilers have an option to profile 'thread time' instead of 'cpu time'. In particular I know that the timeline mode of JetBrains If you're to provide some profiler data, or a simple repro I'd be happy to investigate this. One other question - are you running in an environment with a sync context? Does it make a difference if you do The log messages that you're reporting are from our outer logging handler, so I would expect them to be as accurate as possible. Message handlers also act like middleware, and this one is the one that surrounds all of the pipeline. https://github.com/aspnet/Extensions/blob/master/src/HttpClientFactory/Http/src/Logging/LoggingScopeHttpMessageHandler.cs#L66 I would expect |
FYI @karelz @stephentoub |
OK I can definitely reproduce this with a "slow" server and The reason why this is the case is that the support for So when our logging code runs, it's always going to be just after the headers of the response have been read. I'm not sure that there's anything we can or should do about this - but there's definitely a reasonable explanation for it. If for some reason you really want the body to be totally read during the message handler chain, you can write your own handler to force this earlier. Example: public class MyBufferingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
await response.Content.LoadIntoBufferAsync();
return response;
}
}
|
Thanks for the explanation, that is pretty much what I expected to happen that logging code runs right after the headers are being read. It's not that critical for me to write a special handler, since I can rely on my logging that is made on top instead. A little problem here is that it is a bit misleading to say "End processing HTTP request", since it is actually not quite "ended", depending of course on what we mean by that word. So maybe some different wording can be applied, though I can't quite come up with a good sentence here. So it does mean additionally if one wants to know how much time it takes end to end, it's better to have a logging on top yourself, rather than rely on internal logging that will always be off (with the delta depending on the size of the content, bandwidth, etc.) |
I think you're right about that - do you have a suggestion about what this log message should say? |
I am a bit confused in your example about this log message that comes before end receive:
Ideally though it's best to have both messages
But it seems it's not that easy from the current architecture, and I guess changing architecture because of logging is not going to happen :) Perhaps HttpClient can fire some additional event that can somehow be intercepted by logging as well |
In my example, I wrote a handler to force downloading of the request body. Since a call to HttpClient can trigger multiple actual requests, we have logging at both ends of the pipeline. In between is where the download of the message body occurs. It's academic though because we're not going to put this handler in the product code. I was just demonstrating that it's possible. |
I hit this problem too. When a call is made to GetAsync with content buffering option (which is the default if the completion option parameter is not specified), it is possible that the developer expects the operation to be very fast. If it turns out that it takes a significant time to complete on average, he might want to act on that by doing something after the headers have been received, before proceeding to load the content. In order to diagnose this need, he requires proper instrumentation. There does seem to be a lack of opportunity to intercept the content buffering, specifically to log its duration separately from the duration of getting just the response headers. Since the completion option is not passed to the message handlers, there's no way to know if the time of buffering should be taken into consideration. Perhaps the ideal solution is to allow interception of the content buffering in HttpClient separately from the chain of message handlers.
|
There's a possible workaround that I'm going to investigate: adding a message handler that replaces the response content object (HttpContent) with a decorator over the original content object. |
Fixes: #1121 Just a small tweak to logging to make it clear that this is the elapsed time to get the response headers.
I'm sending a small pr to adjust this logging message to be more clear. All of the real solutions to this problem seem like things that are either:
|
Fixes: #1121 Just a small tweak to logging to make it clear that this is the elapsed time to get the response headers.
Fixes: dotnet/extensions#1121 Just a small tweak to logging to make it clear that this is the elapsed time to get the response headers. Commit migrated from dotnet/extensions@846de6f
Fixes: dotnet/extensions#1121 Just a small tweak to logging to make it clear that this is the elapsed time to get the response headers. Commit migrated from dotnet/extensions@846de6f
Fixes: dotnet/extensions#1121 Just a small tweak to logging to make it clear that this is the elapsed time to get the response headers. Commit migrated from dotnet/extensions@846de6f
Fixes: dotnet/extensions#1121 Just a small tweak to logging to make it clear that this is the elapsed time to get the response headers. \n\nCommit migrated from dotnet/extensions@846de6f
Describe the bug
I make an HTTP requests to REST API that returns quite a lot of data. I have now used HttpClientFactory from .Net Core to get the data and it works fine. But what has puzzled me is a discrepancy between my timing and internal timing that comes from the library itself.
Here is an example message from the library:
End processing HTTP request after 130311.0094ms - OK
The thing is: it really takes 20-30 more seconds to really download all the data even though the library has written it's all finished (To execute
client.GetAsync()
method).I assume what happens here is that library is very eager to report right after the header is received without waiting for the body to get downloaded.
This really sound like a bug, but I am not sure if it is. Maybe someone has a better explanation on why this is happening?
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Library should log the end request when it is really finished, that is all the data is received.
Additional context
I am not 100% sure this is a bug, but would like at least to have som explanation on why this is happening then.
P.S. Here is an example of my code:
Elapsed time in my log is way higher than in the system message
P.P.S I have tried running with HttpCompletionOption.ResponseContentRead but it really did not change the outcome, it's still a big difference.
The text was updated successfully, but these errors were encountered: