-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Log error when exception occurs during streaming #42283
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
Log error when exception occurs during streaming #42283
Conversation
Thanks for your PR, @campersau. Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
error = ErrorMessageHelper.BuildErrorMessage("An error occurred on the server while streaming results.", ex.InnerException ?? ex, _enableDetailedErrors); | ||
} | ||
catch (Exception ex) | ||
{ | ||
// If the streaming method was canceled we don't want to send a HubException message - this is not an error case | ||
if (!(ex is OperationCanceledException && streamCts.IsCancellationRequested)) | ||
{ | ||
Log.FailedStreaming(_logger, invocationId, descriptor.MethodExecutor.MethodInfo.Name, ex); |
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.
Not sure should this one. cancellation failures shouldn't be logged as an error, maybe debug.
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.
It isn't see !
. Or do you mean other OperationCanceledException
s when !streamCts.IsCancellationRequested
?
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.
You're right, @campersau. There is an !
!!
It is surprising that this wasn't logged already. Are we sure this isn't logged anywhere else? This really should just be calling Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex)
if we observe that an Exception is thrown from a streaming hub method without the client cancelling the invocation.
I would assume the !streamCts.IsCancellationRequested
by itself is sufficient to ensure that. I'm not sure about the ChannelClosedException
. @BrennanConroy?
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.
Ah good catch @campersau! I missed the ! too.
For the ChannelClosedException
, we should have a test too right?
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 isn't currently any test for the ChannelClosedException
case, so I have added one which manually throws a ChannelClosedException
.
Because from looking at the Channels implementation in runtime it looks like these don't throw ChannelClosedException
from within WaitToReadAsync
/ TryRead
but instead always throw the users exception from TryComplete(Exception ex)
.
Only ReadAsync
would throw a ChannelClosedException
as far as I can tell.
For reference AsyncEnumerableAdapters
only uses WaitToReadAsync
/ TryRead
:
if (await _channel.WaitToReadAsync(_cancellationToken).ConfigureAwait(false) && _channel.TryRead(out var item)) |
Regarding: Log.FailedInvokingHubMethod
I can change it to use this instead, but maybe a different log might be better to distinguish between those two cases. The case where it would throw immediately vs. the case where it could throw mid reading. (The tests currently throw directly for the first read but it could also happen much later.)
Also Log.FailedInvokingHubMethod
does not include the invocationId
which might be useful as this exception might be logged much later.
In general the logs are quite inconsistent with the inclusion of the invocationId
.
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.
Looks like ChannelClosedException
was relevant many years ago in the first implementation of the feature: https://github.com/dotnet/aspnetcore/blame/1289636c3afa0e5f297df141359e4ba72dac6e70/src/SignalR/common/Shared/AsyncEnumerableAdapters.cs#L28
I'm not against a new log message, it's always helpful to have more specific logs when investigating issues (although you can argue here that the exception stack trace would give you enough information).
I would also be happy with adding the invocation ID to the FailedInvokingHubMethod
log.
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.
Should we remove the ChannelClosedException
case? I guess there could still be custom Channel implementations which do throw a ChannelClosedException
, so maybe no?
There are currently three proposed options for logging:
- Use a new logger message like
FailedStreaming
as currently proposed in the PR. - Use the existing logger message
FailedInvokingHubMethod
. - Use the existing logger message
FailedInvokingHubMethod
and add theinvocationId
.
I am fine with either of those, just wanted to bring up the discussion.
If we want to go with (3) then there are some other logger messages which currently don't have an invocationId
so we could add it to them too for consistentcy. Here are all of these:
Log.HubMethodNotAuthorized(_logger, hubMethodInvocationMessage.Target); |
Log.InvalidHubParameters(_logger, hubMethodInvocationMessage.Target, ex); |
Log.FailedInvokingHubMethod(logger, hubMethodInvocationMessage.Target, ex); |
Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex); |
Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex); |
Log.FailedInvokingHubMethod(_logger, hubMethodInvocationMessage.Target, ex); |
Log.InvalidReturnValueFromStreamingMethod(_logger, descriptor.MethodExecutor.MethodInfo.Name); |
Log.StreamingMethodCalledWithInvoke(_logger, hubMethodInvocationMessage); |
Log.NonStreamingMethodCalledWithStream(_logger, hubMethodInvocationMessage); |
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.
Should we remove the
ChannelClosedException
case?
I don't see any harm in keeping it.
There are currently three proposed options for logging:
I'm going to vote for adding a new log, it's more user friendly to see specific logs.
We can look at adding invocation IDs to existing logs in a separate change.
@@ -105,4 +105,7 @@ public static void ClosingStreamWithBindingError(ILogger logger, CompletionMessa | |||
|
|||
[LoggerMessage(24, LogLevel.Debug, "CompletionMessage for invocation ID '{InvocationId}' received unexpectedly.", EventName = "UnexpectedCompletion")] | |||
public static partial void UnexpectedCompletion(ILogger logger, string invocationId); | |||
|
|||
[LoggerMessage(25, LogLevel.Error, "InvocationId {InvocationId}: Failed during streaming '{HubMethod}'.", EventName = "FailedStreaming")] |
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.
nit:
[LoggerMessage(25, LogLevel.Error, "InvocationId {InvocationId}: Failed during streaming '{HubMethod}'.", EventName = "FailedStreaming")] | |
[LoggerMessage(25, LogLevel.Error, "InvocationId '{InvocationId}': Failed during streaming '{HubMethod}'.", EventName = "FailedStreaming")] |
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.
Some have quotes:
[LoggerMessage(23, LogLevel.Debug, "Invocation ID '{InvocationId}' is already in use.", EventName = "InvocationIdInUse")] |
[LoggerMessage(24, LogLevel.Debug, "CompletionMessage for invocation ID '{InvocationId}' received unexpectedly.", EventName = "UnexpectedCompletion")] |
And some have no quotes:
[LoggerMessage(6, LogLevel.Trace, "InvocationId {InvocationId}: Streaming result of type '{ResultType}'.", EventName = "StreamingResult", SkipEnabledCheck = true)] |
[LoggerMessage(7, LogLevel.Trace, "InvocationId {InvocationId}: Sending result of type '{ResultType}'.", EventName = "SendingResult", SkipEnabledCheck = true)] |
[LoggerMessage(10, LogLevel.Debug, "Canceling stream for invocation {InvocationId}.", EventName = "CancelStream")] |
I copied it from the ones without quotes :)
Let's wait if a new LoggerMessage
is even needed based on the ongoing discussion above.
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.
Bike-shed time.
"Invocation ID {InvocationId}: Failed while sending stream items from hub method {HubMethod}."
Thanks @campersau you're on a roll! |
Log error when exception occurs during streaming
Logs the exception when there is an exception during streaming on the server.
Fixes #42050