Skip to content

Commit 7c68e77

Browse files
authored
Log error when exception occurs during streaming (#42283)
1 parent daaebbd commit 7c68e77

File tree

4 files changed

+48
-8
lines changed

4 files changed

+48
-8
lines changed

src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,13 +474,15 @@ private async Task StreamAsync(string invocationId, HubConnectionContext connect
474474
catch (ChannelClosedException ex)
475475
{
476476
// If the channel closes from an exception in the streaming method, grab the innerException for the error from the streaming method
477+
Log.FailedStreaming(_logger, invocationId, descriptor.MethodExecutor.MethodInfo.Name, ex.InnerException ?? ex);
477478
error = ErrorMessageHelper.BuildErrorMessage("An error occurred on the server while streaming results.", ex.InnerException ?? ex, _enableDetailedErrors);
478479
}
479480
catch (Exception ex)
480481
{
481482
// If the streaming method was canceled we don't want to send a HubException message - this is not an error case
482483
if (!(ex is OperationCanceledException && streamCts.IsCancellationRequested))
483484
{
485+
Log.FailedStreaming(_logger, invocationId, descriptor.MethodExecutor.MethodInfo.Name, ex);
484486
error = ErrorMessageHelper.BuildErrorMessage("An error occurred on the server while streaming results.", ex, _enableDetailedErrors);
485487
}
486488
}

src/SignalR/server/Core/src/Internal/DefaultHubDispatcherLog.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,7 @@ public static void ClosingStreamWithBindingError(ILogger logger, CompletionMessa
105105

106106
[LoggerMessage(24, LogLevel.Debug, "CompletionMessage for invocation ID '{InvocationId}' received unexpectedly.", EventName = "UnexpectedCompletion")]
107107
public static partial void UnexpectedCompletion(ILogger logger, string invocationId);
108+
109+
[LoggerMessage(25, LogLevel.Error, "Invocation ID {InvocationId}: Failed while sending stream items from hub method {HubMethod}.", EventName = "FailedStreaming")]
110+
public static partial void FailedStreaming(ILogger logger, string invocationId, string hubMethod, Exception exception);
108111
}

src/SignalR/server/SignalR/test/HubConnectionHandlerTestUtils/Hubs.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,15 @@ public async IAsyncEnumerable<string> CounterAsyncEnumerable(int count)
691691
}
692692
}
693693

694+
public async IAsyncEnumerable<string> ExceptionAsyncEnumerable()
695+
{
696+
await Task.Yield();
697+
throw new Exception("Exception from async enumerable");
698+
#pragma warning disable CS0162 // Unreachable code detected
699+
yield break;
700+
#pragma warning restore CS0162 // Unreachable code detected
701+
}
702+
694703
public async Task<IAsyncEnumerable<string>> CounterAsyncEnumerableAsync(int count)
695704
{
696705
await Task.Yield();
@@ -719,6 +728,20 @@ public ChannelReader<int> ExceptionStream()
719728
return channel.Reader;
720729
}
721730

731+
public ChannelReader<int> ChannelClosedExceptionStream()
732+
{
733+
var channel = Channel.CreateUnbounded<int>();
734+
channel.Writer.TryComplete(new ChannelClosedException("ChannelClosedException from channel"));
735+
return channel.Reader;
736+
}
737+
738+
public ChannelReader<int> ChannelClosedExceptionInnerExceptionStream()
739+
{
740+
var channel = Channel.CreateUnbounded<int>();
741+
channel.Writer.TryComplete(new ChannelClosedException(new Exception("ChannelClosedException from channel")));
742+
return channel.Reader;
743+
}
744+
722745
public ChannelReader<int> ThrowStream()
723746
{
724747
throw new Exception("Throw from hub method");

src/SignalR/server/SignalR/test/HubConnectionHandlerTests.cs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,16 +2066,28 @@ public async Task NonErrorCompletionSentWhenStreamCanceledFromClient()
20662066
}
20672067

20682068
[Theory]
2069-
[InlineData(true)]
2070-
[InlineData(false)]
2071-
public async Task ReceiveCorrectErrorFromStreamThrowing(bool detailedErrors)
2069+
[InlineData(nameof(StreamingHub.ExceptionAsyncEnumerable), "Exception: Exception from async enumerable")]
2070+
[InlineData(nameof(StreamingHub.ExceptionAsyncEnumerable), null)]
2071+
[InlineData(nameof(StreamingHub.ExceptionStream), "Exception: Exception from channel")]
2072+
[InlineData(nameof(StreamingHub.ExceptionStream), null)]
2073+
[InlineData(nameof(StreamingHub.ChannelClosedExceptionStream), "ChannelClosedException: ChannelClosedException from channel")]
2074+
[InlineData(nameof(StreamingHub.ChannelClosedExceptionStream), null)]
2075+
[InlineData(nameof(StreamingHub.ChannelClosedExceptionInnerExceptionStream), "Exception: ChannelClosedException from channel")]
2076+
[InlineData(nameof(StreamingHub.ChannelClosedExceptionInnerExceptionStream), null)]
2077+
public async Task ReceiveCorrectErrorFromStreamThrowing(string streamMethod, string detailedError)
20722078
{
2073-
using (StartVerifiableLog())
2079+
bool ExpectedErrors(WriteContext writeContext)
2080+
{
2081+
return writeContext.LoggerName == "Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher" &&
2082+
writeContext.EventId.Name == "FailedStreaming";
2083+
}
2084+
2085+
using (StartVerifiableLog(ExpectedErrors))
20742086
{
20752087
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(builder =>
20762088
builder.AddSignalR(options =>
20772089
{
2078-
options.EnableDetailedErrors = detailedErrors;
2090+
options.EnableDetailedErrors = detailedError != null;
20792091
}), LoggerFactory);
20802092
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<StreamingHub>>();
20812093

@@ -2085,14 +2097,14 @@ public async Task ReceiveCorrectErrorFromStreamThrowing(bool detailedErrors)
20852097

20862098
await client.Connected.DefaultTimeout();
20872099

2088-
var messages = await client.StreamAsync(nameof(StreamingHub.ExceptionStream));
2100+
var messages = await client.StreamAsync(streamMethod);
20892101

20902102
Assert.Equal(1, messages.Count);
20912103
var completion = messages[0] as CompletionMessage;
20922104
Assert.NotNull(completion);
2093-
if (detailedErrors)
2105+
if (detailedError != null)
20942106
{
2095-
Assert.Equal("An error occurred on the server while streaming results. Exception: Exception from channel", completion.Error);
2107+
Assert.Equal($"An error occurred on the server while streaming results. {detailedError}", completion.Error);
20962108
}
20972109
else
20982110
{

0 commit comments

Comments
 (0)