Skip to content

Commit 1de2117

Browse files
committed
Improved exception logging to the console by making sure internal cancellations and timeout exceptions are logged
1 parent 2069085 commit 1de2117

File tree

4 files changed

+39
-10
lines changed

4 files changed

+39
-10
lines changed

RELEASE.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# 1.0.0-beta.68
22

33
- Improved the `HttpClient.SendWithRetryAsync()` extension to log retries at the information level since they may indicate other problems, and to retry during internal `HttpClient` timeouts.
4+
- Improved exception logging to the console by making sure internal cancellations and timeout exceptions are logged (previously they were silent, which could create the impression nothing went wrong).
45

56
# 1.0.0-beta.67
67

src/core/Statiq.App/Commands/EngineManager.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,16 @@ public async Task<ExitCode> ExecuteAsync(CancellationTokenSource cancellationTok
9292
}
9393
catch (Exception ex)
9494
{
95+
// If this was a cancellation, check if it was due to a timeout or an actual cancellation
9596
if (ex is OperationCanceledException)
9697
{
97-
// No log message for cancellation
98-
return ExitCode.OperationCanceled;
98+
// Was this a "true" cancellation of the engine?
99+
if (Engine.CancellationToken.IsCancellationRequested)
100+
{
101+
_logger.LogInformation("Exited due to engine cancellation request");
102+
return ExitCode.OperationCanceled;
103+
}
104+
_logger.LogCritical("Operation/task timeout occurred or internal cancellation was triggered, inner exception(s) follow (if available)");
99105
}
100106

101107
// Log exceptions not already logged (including those thrown by the engine directly)

src/core/Statiq.Common/Util/ExceptionExtensions.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Reflection;
5+
using System.Threading.Tasks;
56
using Microsoft.Extensions.Logging;
67

78
namespace Statiq.Common
@@ -20,6 +21,11 @@ public static IEnumerable<Exception> Unwrap(this Exception exception, bool unwra
2021
return invocationException.InnerException.Unwrap(unwrapLoggedExceptions);
2122
case LoggedException loggedException when unwrapLoggedExceptions:
2223
return loggedException.InnerException.Unwrap(true);
24+
case TaskCanceledException taskCanceledException:
25+
// Timeouts will throw this and may have an inner exception (I.e. https://stackoverflow.com/a/66694886)
26+
return taskCanceledException.InnerException is object
27+
? taskCanceledException.InnerException.Unwrap(unwrapLoggedExceptions)
28+
: new Exception[] { taskCanceledException };
2329
default:
2430
return new Exception[] { exception };
2531
}
@@ -28,4 +34,4 @@ public static IEnumerable<Exception> Unwrap(this Exception exception, bool unwra
2834
return Array.Empty<Exception>();
2935
}
3036
}
31-
}
37+
}

src/core/Statiq.Core/Execution/PipelinePhase.cs

+23-7
Original file line numberDiff line numberDiff line change
@@ -108,19 +108,35 @@ public async Task ExecuteAsync(
108108
catch (Exception ex)
109109
{
110110
Outputs = ImmutableArray<IDocument>.Empty;
111-
if (!(ex is OperationCanceledException))
111+
112+
// Report on the exception if it's not a "true" cancellation of the engine (I.e. a timeout or internal cancellation)
113+
if (!engine.CancellationToken.IsCancellationRequested)
112114
{
115+
string exceptionType = "Exception";
116+
Exception exceptionToLog = ex;
113117
LoggedException executeModulesException = ex as LoggedException;
114-
if (executeModulesException is object)
118+
119+
// Was this a timeout (already tested that IsCancellationRequested is false)
120+
if (ex is OperationCanceledException)
121+
{
122+
exceptionType = "Timeout/Cancellation";
123+
exceptionToLog = ex.InnerException ?? ex;
124+
}
125+
else if (executeModulesException is object)
115126
{
116-
ex = executeModulesException.InnerException;
127+
// ...or was it a logged exception
128+
exceptionToLog = executeModulesException.InnerException;
117129
}
118-
_logger.LogDebug($"Exception while executing pipeline {PipelineName}/{Phase}: {ex}");
119-
if (executeModulesException is object)
130+
131+
// Log the exception (or inner exception)
132+
_logger.LogDebug($"{exceptionType} while executing pipeline {PipelineName}/{Phase}: {exceptionToLog}");
133+
if (executeModulesException is object && exceptionToLog is object)
120134
{
121-
throw executeModulesException.InnerException;
135+
throw exceptionToLog;
122136
}
123137
}
138+
139+
// Always rethrow the exception
124140
throw;
125141
}
126142
finally
@@ -233,4 +249,4 @@ private static void DisposeModules(IEnumerable<IModule> modules)
233249
}
234250
}
235251
}
236-
}
252+
}

0 commit comments

Comments
 (0)