From a702713cd4a8f9f7f0ce802284a4837054677a1b Mon Sep 17 00:00:00 2001 From: BrennanConroy Date: Thu, 24 Aug 2017 08:37:05 -0700 Subject: [PATCH] SignalR C# Client logging (#752) --- SignalR.sln | 3 +- .../HubConnection.cs | 67 ++--- .../Internal/SignalRClientLoggerExtensions.cs | 256 ++++++++++++++++++ .../InvocationRequest.cs | 20 +- 4 files changed, 298 insertions(+), 48 deletions(-) create mode 100644 src/Microsoft.AspNetCore.SignalR.Client/Internal/SignalRClientLoggerExtensions.cs diff --git a/SignalR.sln b/SignalR.sln index d47a0472dd..6f89370fc0 100644 --- a/SignalR.sln +++ b/SignalR.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26706.0 +VisualStudioVersion = 15.0.26730.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DA69F624-5398-4884-87E4-B816698CDE65}" EndProject @@ -55,6 +55,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{6CEC3D test\Common\ChannelExtensions.cs = test\Common\ChannelExtensions.cs test\Common\ServerFixture.cs = test\Common\ServerFixture.cs test\Common\TaskExtensions.cs = test\Common\TaskExtensions.cs + test\Common\TestHelpers.cs = test\Common\TestHelpers.cs EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client-ts", "client-ts", "{3A76C5A2-79ED-49BC-8BDC-6A3A766FFA1B}" diff --git a/src/Microsoft.AspNetCore.SignalR.Client/HubConnection.cs b/src/Microsoft.AspNetCore.SignalR.Client/HubConnection.cs index bd7a819fec..bc87ffedf2 100644 --- a/src/Microsoft.AspNetCore.SignalR.Client/HubConnection.cs +++ b/src/Microsoft.AspNetCore.SignalR.Client/HubConnection.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Channels; +using Microsoft.AspNetCore.SignalR.Client.Internal; using Microsoft.AspNetCore.SignalR.Internal; using Microsoft.AspNetCore.SignalR.Internal.Encoders; using Microsoft.AspNetCore.SignalR.Internal.Protocol; @@ -155,14 +156,14 @@ namespace Microsoft.AspNetCore.SignalR.Client private Task InvokeCore(string methodName, InvocationRequest irq, object[] args, bool nonBlocking) { - ThrowIfConnectionTerminated(); + ThrowIfConnectionTerminated(irq.InvocationId); if (nonBlocking) { - _logger.LogTrace("Preparing invocation of '{target}' and {argumentCount} args", methodName, irq.ResultType.AssemblyQualifiedName, args.Length); + _logger.PreparingNonBlockingInvocation(irq.InvocationId, methodName, args.Length); } else { - _logger.LogTrace("Preparing invocation of '{target}', with return type '{returnType}' and {argumentCount} args", methodName, irq.ResultType.AssemblyQualifiedName, args.Length); + _logger.PreparingBlockingInvocation(irq.InvocationId, methodName, irq.ResultType.FullName, args.Length); } // Create an invocation descriptor. Client invocations are always blocking @@ -172,17 +173,13 @@ namespace Microsoft.AspNetCore.SignalR.Client if (!nonBlocking) { // I just want an excuse to use 'irq' as a variable name... - _logger.LogDebug("Registering Invocation ID '{invocationId}' for tracking", invocationMessage.InvocationId); + _logger.RegisterInvocation(invocationMessage.InvocationId); AddInvocation(irq); } - // Trace the full invocation, but only if that logging level is enabled (because building the args list is a bit slow) - if (_logger.IsEnabled(LogLevel.Trace)) - { - var argsList = string.Join(", ", args.Select(a => a.GetType().FullName)); - _logger.LogTrace("Issuing Invocation '{invocationId}': {returnType} {methodName}({args})", invocationMessage.InvocationId, irq.ResultType.FullName, methodName, argsList); - } + // Trace the full invocation + _logger.IssueInvocation(invocationMessage.InvocationId, irq.ResultType.FullName, methodName, args); // We don't need to wait for this to complete. It will signal back to the invocation request. return SendInvocation(invocationMessage, irq); @@ -193,14 +190,14 @@ namespace Microsoft.AspNetCore.SignalR.Client try { var payload = _protocolReaderWriter.WriteMessage(invocationMessage); - _logger.LogInformation("Sending Invocation '{invocationId}'", invocationMessage.InvocationId); + _logger.SendInvocation(invocationMessage.InvocationId); await _connection.SendAsync(payload, irq.CancellationToken); - _logger.LogInformation("Sending Invocation '{invocationId}' complete", invocationMessage.InvocationId); + _logger.SendInvocationCompleted(invocationMessage.InvocationId); } catch (Exception ex) { - _logger.LogError(0, ex, "Sending Invocation '{invocationId}' failed", invocationMessage.InvocationId); + _logger.SendInvocationFailed(invocationMessage.InvocationId, ex); irq.Fail(ex); TryRemoveInvocation(invocationMessage.InvocationId, out _); } @@ -216,17 +213,13 @@ namespace Microsoft.AspNetCore.SignalR.Client switch (message) { case InvocationMessage invocation: - if (_logger.IsEnabled(LogLevel.Trace)) - { - var argsList = string.Join(", ", invocation.Arguments.Select(a => a.GetType().FullName)); - _logger.LogTrace("Received Invocation '{invocationId}': {methodName}({args})", invocation.InvocationId, invocation.Target, argsList); - } + _logger.ReceivedInvocation(invocation.InvocationId, invocation.Target, invocation.Arguments); await DispatchInvocationAsync(invocation, _connectionActive.Token); break; case CompletionMessage completion: if (!TryRemoveInvocation(completion.InvocationId, out irq)) { - _logger.LogWarning("Dropped unsolicited Completion message for invocation '{invocationId}'", completion.InvocationId); + _logger.DropCompletionMessage(completion.InvocationId); return; } DispatchInvocationCompletion(completion, irq); @@ -236,7 +229,7 @@ namespace Microsoft.AspNetCore.SignalR.Client // Complete the invocation with an error, we don't support streaming (yet) if (!TryGetInvocation(streamItem.InvocationId, out irq)) { - _logger.LogWarning("Dropped unsolicited Stream Item message for invocation '{invocationId}'", streamItem.InvocationId); + _logger.DropStreamMessage(streamItem.InvocationId); return; } DispatchInvocationStreamItemAsync(streamItem, irq); @@ -250,10 +243,10 @@ namespace Microsoft.AspNetCore.SignalR.Client private Task Shutdown(Exception ex = null) { - _logger.LogTrace("Shutting down connection"); + _logger.ShutdownConnection(); if (ex != null) { - _logger.LogError(ex, "Connection is shutting down due to an error"); + _logger.ShutdownWithError(ex); } lock (_pendingCallsLock) @@ -265,7 +258,7 @@ namespace Microsoft.AspNetCore.SignalR.Client foreach (var outstandingCall in _pendingCalls.Values) { - _logger.LogTrace("Removing pending call {invocationId}", outstandingCall.InvocationId); + _logger.RemoveInvocation(outstandingCall.InvocationId); if (ex != null) { outstandingCall.Fail(ex); @@ -282,7 +275,7 @@ namespace Microsoft.AspNetCore.SignalR.Client // Find the handler if (!_handlers.TryGetValue(invocation.Target, out InvocationHandler handler)) { - _logger.LogWarning("Failed to find handler for '{target}' method", invocation.Target); + _logger.MissingHandler(invocation.Target); return Task.CompletedTask; } @@ -295,25 +288,25 @@ namespace Microsoft.AspNetCore.SignalR.Client // and there's nobody to actually wait for us to finish. private async void DispatchInvocationStreamItemAsync(StreamItemMessage streamItem, InvocationRequest irq) { - _logger.LogTrace("Received StreamItem for Invocation #{invocationId}", streamItem.InvocationId); + _logger.ReceivedStreamItem(streamItem.InvocationId); if (irq.CancellationToken.IsCancellationRequested) { - _logger.LogTrace("Canceling dispatch of StreamItem message for Invocation {invocationId}. The invocation was cancelled.", irq.InvocationId); + _logger.CancelingStreamItem(irq.InvocationId); } else if (!await irq.StreamItem(streamItem.Item)) { - _logger.LogWarning("Invocation {invocationId} received stream item after channel was closed.", irq.InvocationId); + _logger.ReceivedStreamItemAfterClose(irq.InvocationId); } } private void DispatchInvocationCompletion(CompletionMessage completion, InvocationRequest irq) { - _logger.LogTrace("Received Completion for Invocation #{invocationId}", completion.InvocationId); + _logger.ReceivedInvocationCompletion(completion.InvocationId); if (irq.CancellationToken.IsCancellationRequested) { - _logger.LogTrace("Cancelling dispatch of Completion message for Invocation {invocationId}. The invocation was cancelled.", irq.InvocationId); + _logger.CancelingCompletion(irq.InvocationId); } else { @@ -328,11 +321,11 @@ namespace Microsoft.AspNetCore.SignalR.Client } } - private void ThrowIfConnectionTerminated() + private void ThrowIfConnectionTerminated(string invocationId) { if (_connectionActive.Token.IsCancellationRequested) { - _logger.LogError("Invoke was called after the connection was terminated"); + _logger.InvokeAfterTermination(invocationId); throw new InvalidOperationException("Connection has been terminated."); } } @@ -343,10 +336,10 @@ namespace Microsoft.AspNetCore.SignalR.Client { lock (_pendingCallsLock) { - ThrowIfConnectionTerminated(); + ThrowIfConnectionTerminated(irq.InvocationId); if (_pendingCalls.ContainsKey(irq.InvocationId)) { - _logger.LogCritical("Invocation ID '{invocationId}' is already in use.", irq.InvocationId); + _logger.InvocationAlreadyInUse(irq.InvocationId); throw new InvalidOperationException($"Invocation ID '{irq.InvocationId}' is already in use."); } else @@ -360,7 +353,7 @@ namespace Microsoft.AspNetCore.SignalR.Client { lock (_pendingCallsLock) { - ThrowIfConnectionTerminated(); + ThrowIfConnectionTerminated(invocationId); return _pendingCalls.TryGetValue(invocationId, out irq); } } @@ -369,7 +362,7 @@ namespace Microsoft.AspNetCore.SignalR.Client { lock (_pendingCallsLock) { - ThrowIfConnectionTerminated(); + ThrowIfConnectionTerminated(invocationId); if (_pendingCalls.TryGetValue(invocationId, out irq)) { _pendingCalls.Remove(invocationId); @@ -395,7 +388,7 @@ namespace Microsoft.AspNetCore.SignalR.Client { if (!_connection._pendingCalls.TryGetValue(invocationId, out InvocationRequest irq)) { - _connection._logger.LogError("Unsolicited response received for invocation '{invocationId}'", invocationId); + _connection._logger.ReceivedUnexpectedResponse(invocationId); return null; } return irq.ResultType; @@ -405,7 +398,7 @@ namespace Microsoft.AspNetCore.SignalR.Client { if (!_connection._handlers.TryGetValue(methodName, out InvocationHandler handler)) { - _connection._logger.LogWarning("Failed to find handler for '{target}' method", methodName); + _connection._logger.MissingHandler(methodName); return Type.EmptyTypes; } return handler.ParameterTypes; diff --git a/src/Microsoft.AspNetCore.SignalR.Client/Internal/SignalRClientLoggerExtensions.cs b/src/Microsoft.AspNetCore.SignalR.Client/Internal/SignalRClientLoggerExtensions.cs new file mode 100644 index 0000000000..dc94a1b381 --- /dev/null +++ b/src/Microsoft.AspNetCore.SignalR.Client/Internal/SignalRClientLoggerExtensions.cs @@ -0,0 +1,256 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.SignalR.Client.Internal +{ + internal static class SignalRClientLoggerExtensions + { + // Category: HubConnection + private static readonly Action _preparingNonBlockingInvocation = + LoggerMessage.Define(LogLevel.Trace, 0, "Preparing non-blocking invocation '{invocationId}' of '{target}', with {argumentCount} argument(s)."); + + private static readonly Action _preparingBlockingInvocation = + LoggerMessage.Define(LogLevel.Trace, 1, "Preparing blocking invocation '{invocationId}' of '{target}', with return type '{returnType}' and {argumentCount} argument(s)."); + + private static readonly Action _registerInvocation = + LoggerMessage.Define(LogLevel.Debug, 2, "Registering Invocation ID '{invocationId}' for tracking."); + + private static readonly Action _issueInvocation = + LoggerMessage.Define(LogLevel.Trace, 3, "Issuing Invocation '{invocationId}': {returnType} {methodName}({args})."); + + private static readonly Action _sendInvocation = + LoggerMessage.Define(LogLevel.Information, 4, "Sending Invocation '{invocationId}'."); + + private static readonly Action _sendInvocationCompleted = + LoggerMessage.Define(LogLevel.Information, 5, "Sending Invocation '{invocationId}' completed."); + + private static readonly Action _sendInvocationFailed = + LoggerMessage.Define(LogLevel.Error, 6, "Sending Invocation '{invocationId}' failed."); + + private static readonly Action _receivedInvocation = + LoggerMessage.Define(LogLevel.Trace, 7, "Received Invocation '{invocationId}': {methodName}({args})."); + + private static readonly Action _dropCompletionMessage = + LoggerMessage.Define(LogLevel.Warning, 8, "Dropped unsolicited Completion message for invocation '{invocationId}'."); + + private static readonly Action _dropStreamMessage = + LoggerMessage.Define(LogLevel.Warning, 9, "Dropped unsolicited StreamItem message for invocation '{invocationId}'."); + + private static readonly Action _shutdownConnection = + LoggerMessage.Define(LogLevel.Trace, 10, "Shutting down connection."); + + private static readonly Action _shutdownWithError = + LoggerMessage.Define(LogLevel.Error, 11, "Connection is shutting down due to an error."); + + private static readonly Action _removeInvocation = + LoggerMessage.Define(LogLevel.Trace, 12, "Removing pending invocation {invocationId}."); + + private static readonly Action _missingHandler = + LoggerMessage.Define(LogLevel.Warning, 13, "Failed to find handler for '{target}' method."); + + private static readonly Action _receivedStreamItem = + LoggerMessage.Define(LogLevel.Trace, 14, "Received StreamItem for Invocation {invocationId}."); + + private static readonly Action _cancelingStreamItem = + LoggerMessage.Define(LogLevel.Trace, 15, "Canceling dispatch of StreamItem message for Invocation {invocationId}. The invocation was canceled."); + + private static readonly Action _receivedStreamItemAfterClose = + LoggerMessage.Define(LogLevel.Warning, 16, "Invocation {invocationId} received stream item after channel was closed."); + + private static readonly Action _receivedInvocationCompletion = + LoggerMessage.Define(LogLevel.Trace, 17, "Received Completion for Invocation {invocationId}."); + + private static readonly Action _cancelingCompletion = + LoggerMessage.Define(LogLevel.Trace, 18, "Canceling dispatch of Completion message for Invocation {invocationId}. The invocation was canceled."); + + private static readonly Action _invokeAfterTermination = + LoggerMessage.Define(LogLevel.Error, 19, "Invoke for Invocation '{invocationId}' was called after the connection was terminated."); + + private static readonly Action _invocationAlreadyInUse = + LoggerMessage.Define(LogLevel.Critical, 20, "Invocation ID '{invocationId}' is already in use."); + + private static readonly Action _receivedUnexpectedResponse = + LoggerMessage.Define(LogLevel.Error, 21, "Unsolicited response received for invocation '{invocationId}'."); + + // Category: Streaming and NonStreaming + private static readonly Action _invocationCreated = + LoggerMessage.Define(LogLevel.Trace, 0, "Invocation {invocationId} created."); + + private static readonly Action _invocationDisposed = + LoggerMessage.Define(LogLevel.Trace, 1, "Invocation {invocationId} disposed."); + + private static readonly Action _invocationCompleted = + LoggerMessage.Define(LogLevel.Trace, 2, "Invocation {invocationId} marked as completed."); + + private static readonly Action _invocationFailed = + LoggerMessage.Define(LogLevel.Trace, 3, "Invocation {invocationId} marked as failed."); + + // Category: Streaming + private static readonly Action _receivedUnexpectedComplete = + LoggerMessage.Define(LogLevel.Error, 4, "Invocation {invocationId} received a completion result, but was invoked as a streaming invocation."); + + private static readonly Action _errorWritingStreamItem = + LoggerMessage.Define(LogLevel.Error, 5, "Invocation {invocationId} caused an error trying to write a stream item."); + + // Category: NonStreaming + private static readonly Action _streamItemOnNonStreamInvocation = + LoggerMessage.Define(LogLevel.Error, 4, "Invocation {invocationId} received stream item but was invoked as a non-streamed invocation."); + + public static void PreparingNonBlockingInvocation(this ILogger logger, string invocationId, string target, int count) + { + _preparingNonBlockingInvocation(logger, invocationId, target, count, null); + } + + public static void PreparingBlockingInvocation(this ILogger logger, string invocationId, string target, string returnType, int count) + { + _preparingBlockingInvocation(logger, invocationId, target, returnType, count, null); + } + + public static void RegisterInvocation(this ILogger logger, string invocationId) + { + _registerInvocation(logger, invocationId, null); + } + + public static void IssueInvocation(this ILogger logger, string invocationId, string returnType, string methodName, object[] args) + { + if (logger.IsEnabled(LogLevel.Trace)) + { + var argsList = string.Join(", ", args.Select(a => a.GetType().FullName)); + _issueInvocation(logger, invocationId, returnType, methodName, argsList, null); + } + } + + public static void SendInvocation(this ILogger logger, string invocationId) + { + _sendInvocation(logger, invocationId, null); + } + + public static void SendInvocationCompleted(this ILogger logger, string invocationId) + { + _sendInvocationCompleted(logger, invocationId, null); + } + + public static void SendInvocationFailed(this ILogger logger, string invocationId, Exception exception) + { + _sendInvocationFailed(logger, invocationId, exception); + } + + public static void ReceivedInvocation(this ILogger logger, string invocationId, string methodName, object[] args) + { + if (logger.IsEnabled(LogLevel.Trace)) + { + var argsList = string.Join(", ", args.Select(a => a.GetType().FullName)); + _receivedInvocation(logger, invocationId, methodName, argsList, null); + } + } + + public static void DropCompletionMessage(this ILogger logger, string invocationId) + { + _dropCompletionMessage(logger, invocationId, null); + } + + public static void DropStreamMessage(this ILogger logger, string invocationId) + { + _dropStreamMessage(logger, invocationId, null); + } + + public static void ShutdownConnection(this ILogger logger) + { + _shutdownConnection(logger, null); + } + + public static void ShutdownWithError(this ILogger logger, Exception exception) + { + _shutdownWithError(logger, exception); + } + + public static void RemoveInvocation(this ILogger logger, string invocationId) + { + _removeInvocation(logger, invocationId, null); + } + + public static void MissingHandler(this ILogger logger, string target) + { + _missingHandler(logger, target, null); + } + + public static void ReceivedStreamItem(this ILogger logger, string invocationId) + { + _receivedStreamItem(logger, invocationId, null); + } + + public static void CancelingStreamItem(this ILogger logger, string invocationId) + { + _cancelingStreamItem(logger, invocationId, null); + } + + public static void ReceivedStreamItemAfterClose(this ILogger logger, string invocationId) + { + _receivedStreamItemAfterClose(logger, invocationId, null); + } + + public static void ReceivedInvocationCompletion(this ILogger logger, string invocationId) + { + _receivedInvocationCompletion(logger, invocationId, null); + } + + public static void CancelingCompletion(this ILogger logger, string invocationId) + { + _cancelingCompletion(logger, invocationId, null); + } + + public static void InvokeAfterTermination(this ILogger logger, string invocationId) + { + _invokeAfterTermination(logger, invocationId, null); + } + + public static void InvocationAlreadyInUse(this ILogger logger, string invocationId) + { + _invocationAlreadyInUse(logger, invocationId, null); + } + + public static void ReceivedUnexpectedResponse(this ILogger logger, string invocationId) + { + _receivedUnexpectedResponse(logger, invocationId, null); + } + + public static void InvocationCreated(this ILogger logger, string invocationId) + { + _invocationCreated(logger, invocationId, null); + } + + public static void InvocationDisposed(this ILogger logger, string invocationId) + { + _invocationDisposed(logger, invocationId, null); + } + + public static void InvocationCompleted(this ILogger logger, string invocationId) + { + _invocationCompleted(logger, invocationId, null); + } + + public static void InvocationFailed(this ILogger logger, string invocationId) + { + _invocationFailed(logger, invocationId, null); + } + + public static void ReceivedUnexpectedComplete(this ILogger logger, string invocationId) + { + _receivedUnexpectedComplete(logger, invocationId, null); + } + + public static void ErrorWritingStreamItem(this ILogger logger, string invocationId, Exception exception) + { + _errorWritingStreamItem(logger, invocationId, exception); + } + + public static void StreamItemOnNonStreamInvocation(this ILogger logger, string invocationId) + { + _streamItemOnNonStreamInvocation(logger, invocationId, null); + } + } +} diff --git a/src/Microsoft.AspNetCore.SignalR.Client/InvocationRequest.cs b/src/Microsoft.AspNetCore.SignalR.Client/InvocationRequest.cs index e40dd8feda..61f4b12b44 100644 --- a/src/Microsoft.AspNetCore.SignalR.Client/InvocationRequest.cs +++ b/src/Microsoft.AspNetCore.SignalR.Client/InvocationRequest.cs @@ -5,6 +5,7 @@ using System; using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Channels; +using Microsoft.AspNetCore.SignalR.Client.Internal; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.SignalR.Client @@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.SignalR.Client ResultType = resultType; Logger = logger; - Logger.LogTrace("Invocation {invocationId} created", InvocationId); + Logger.InvocationCreated(InvocationId); } public static InvocationRequest Invoke(CancellationToken cancellationToken, Type resultType, string invocationId, ILoggerFactory loggerFactory, out Task result) @@ -54,7 +55,7 @@ namespace Microsoft.AspNetCore.SignalR.Client public virtual void Dispose() { - Logger.LogTrace("Invocation {invocationId} disposed", InvocationId); + Logger.InvocationDisposed(InvocationId); // Just in case it hasn't already been completed Cancel(); @@ -75,10 +76,10 @@ namespace Microsoft.AspNetCore.SignalR.Client public override void Complete(object result) { - Logger.LogTrace("Invocation {invocationId} marked as completed.", InvocationId); + Logger.InvocationCompleted(InvocationId); if (result != null) { - Logger.LogError("Invocation {invocationId} received a completion result, but was invoked as a streaming invocation.", InvocationId); + Logger.ReceivedUnexpectedComplete(InvocationId); _channel.Out.TryComplete(new InvalidOperationException("Server provided a result in a completion response to a streamed invocation.")); } else @@ -89,7 +90,7 @@ namespace Microsoft.AspNetCore.SignalR.Client public override void Fail(Exception exception) { - Logger.LogTrace("Invocation {invocationId} marked as failed.", InvocationId); + Logger.InvocationFailed(InvocationId); _channel.Out.TryComplete(exception); } @@ -97,7 +98,6 @@ namespace Microsoft.AspNetCore.SignalR.Client { try { - Logger.LogTrace("Invocation {invocationId} received stream item.", InvocationId); while (!_channel.Out.TryWrite(item)) { if (!await _channel.Out.WaitToWriteAsync()) @@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.SignalR.Client } catch (Exception ex) { - Logger.LogError(ex, "Invocation {invocationId} caused an error trying to write a stream item.", InvocationId); + Logger.ErrorWritingStreamItem(InvocationId, ex); } return true; } @@ -132,19 +132,19 @@ namespace Microsoft.AspNetCore.SignalR.Client public override void Complete(object result) { - Logger.LogTrace("Invocation {invocationId} marked as completed.", InvocationId); + Logger.InvocationCompleted(InvocationId); _completionSource.TrySetResult(result); } public override void Fail(Exception exception) { - Logger.LogTrace("Invocation {invocationId} marked as failed.", InvocationId); + Logger.InvocationFailed(InvocationId); _completionSource.TrySetException(exception); } public override ValueTask StreamItem(object item) { - Logger.LogError("Invocation {invocationId} received stream item but was invoked as a non-streamed invocation.", InvocationId); + Logger.StreamItemOnNonStreamInvocation(InvocationId); _completionSource.TrySetException(new InvalidOperationException("Streaming methods must be invoked using HubConnection.Stream")); // We "delivered" the stream item successfully as far as the caller cares