Skip to content

Commit 3176770

Browse files
committed
Add IDiagnosticContext.SetException()
1 parent 4d43531 commit 3176770

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContext.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,12 @@ public void Set(string propertyName, object value, bool destructureObjects = fal
5656
collector.AddOrUpdate(property);
5757
}
5858
}
59+
60+
/// <inheritdoc cref="IDiagnosticContext.SetException"/>
61+
public void SetException(Exception exception)
62+
{
63+
var collector = AmbientDiagnosticContextCollector.Current;
64+
collector?.SetException(exception);
65+
}
5966
}
6067
}

src/Serilog.Extensions.Hosting/Extensions/Hosting/DiagnosticContextCollector.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public sealed class DiagnosticContextCollector : IDisposable
1111
{
1212
readonly IDisposable _chainedDisposable;
1313
readonly object _propertiesLock = new object();
14+
Exception _exception;
1415
Dictionary<string, LogEventProperty> _properties = new Dictionary<string, LogEventProperty>();
1516

1617
/// <summary>
@@ -38,6 +39,28 @@ public void AddOrUpdate(LogEventProperty property)
3839
}
3940
}
4041

42+
/// <summary>
43+
/// Set an exception to include in the Serilog request log event.
44+
/// </summary>
45+
/// <example>
46+
/// Passing an exception to the diagnostic context is useful when unhandled exceptions are handled before reaching Serilog's
47+
/// RequestLoggingMiddleware. One example is using https://www.nuget.org/packages/Hellang.Middleware.ProblemDetails to transform
48+
/// exceptions to ProblemDetails responses.
49+
/// </example>
50+
/// <remarks>
51+
/// If an unhandled exception reaches Serilog's RequestLoggingMiddleware, then the unhandled exception takes precedence.<br/>
52+
/// If <c>null</c> is given, it clears any previously assigned exception.
53+
/// </remarks>
54+
/// <param name="exception">The exception to log.</param>
55+
public void SetException(Exception exception)
56+
{
57+
lock (_propertiesLock)
58+
{
59+
if (_properties == null) return;
60+
_exception = exception;
61+
}
62+
}
63+
4164
/// <summary>
4265
/// Complete the context and retrieve the properties added to it, if any. This will
4366
/// stop collection and remove the collector from the original execution context and
@@ -51,6 +74,36 @@ public bool TryComplete(out IEnumerable<LogEventProperty> properties)
5174
{
5275
properties = _properties?.Values;
5376
_properties = null;
77+
_exception = null;
78+
Dispose();
79+
return properties != null;
80+
}
81+
}
82+
83+
/// <summary>
84+
/// Complete the context and retrieve the properties added to it, if any. This will
85+
/// stop collection and remove the collector from the original execution context and
86+
/// any of its children.
87+
/// </summary>
88+
/// <param name="properties">The collected properties, or null if no collection is active.</param>
89+
/// <param name="exception">The collected exception, or null if none has been collected or if no collection is active.</param>
90+
/// <returns>True if properties could be collected.</returns>
91+
/// <example>
92+
/// This overload provides the exception collected by the diagnostic context, which is useful when unhandled exceptions are handled
93+
/// before reaching Serilog's RequestLoggingMiddleware. One example is using https://www.nuget.org/packages/Hellang.Middleware.ProblemDetails to transform
94+
/// exceptions to ProblemDetails responses.
95+
/// </example>
96+
/// <remarks>
97+
/// If an unhandled exception reaches Serilog's RequestLoggingMiddleware, then the unhandled exception should take precedence.<br/>
98+
/// </remarks>
99+
public bool TryComplete(out IEnumerable<LogEventProperty> properties, out Exception exception)
100+
{
101+
lock (_propertiesLock)
102+
{
103+
properties = _properties?.Values;
104+
exception = _exception;
105+
_properties = null;
106+
_exception = null;
54107
Dispose();
55108
return properties != null;
56109
}

src/Serilog.Extensions.Hosting/IDiagnosticContext.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using System;
16+
1517
namespace Serilog
1618
{
1719
/// <summary>
@@ -27,6 +29,21 @@ public interface IDiagnosticContext
2729
/// <param name="value">The property value.</param>
2830
/// <param name="destructureObjects">If true, the value will be serialized as structured
2931
/// data if possible; if false, the object will be recorded as a scalar or simple array.</param>
30-
void Set(string propertyName, object value, bool destructureObjects = false);
32+
void Set(string propertyName, object value, bool destructureObjects = false);
33+
34+
/// <summary>
35+
/// Set an exception to include in the Serilog request log event.
36+
/// </summary>
37+
/// <example>
38+
/// Passing an exception to the diagnostic context is useful when unhandled exceptions are handled before reaching Serilog's
39+
/// RequestLoggingMiddleware. One example is using https://www.nuget.org/packages/Hellang.Middleware.ProblemDetails to transform
40+
/// exceptions to ProblemDetails responses.
41+
/// </example>
42+
/// <remarks>
43+
/// If an unhandled exception reaches Serilog's RequestLoggingMiddleware, then the unhandled exception takes precedence.<br/>
44+
/// If <c>null</c> is given, it clears any previously assigned exception.
45+
/// </remarks>
46+
/// <param name="exception">The exception to log.</param>
47+
void SetException(Exception exception);
3148
}
3249
}

0 commit comments

Comments
 (0)