Skip to content

Commit

Permalink
Merge pull request #69 from mhutch/more-logging-helpers
Browse files Browse the repository at this point in the history
Add helpers for logging enumeration exceptions
  • Loading branch information
mhutch committed Jul 8, 2023
2 parents e537224 + 012b261 commit ac2eadf
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 6 deletions.
96 changes: 96 additions & 0 deletions Core/Logging/LoggerExtensions.LoggedEnumerable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections;
using System.Collections.Generic;

using Microsoft.Extensions.Logging;

namespace MonoDevelop.Xml.Logging;

public static partial class LoggerExtensions
{
class LoggedEnumerable<T> : IEnumerable<T>
{
readonly IEnumerable<T> enumerable;
readonly ILogger logger;
readonly string? originMember;

public LoggedEnumerable (IEnumerable<T> enumerable, ILogger logger, string originMember)
{
this.enumerable = enumerable;
this.logger = logger;
this.originMember = originMember;
}

void Log (Exception ex) => logger.LogInternalError (ex, originMember);

public IEnumerator<T> GetEnumerator ()
{
try {
var enumerator = enumerable.GetEnumerator ();
return new LoggedEnumerator (this, enumerator);
} catch (Exception ex) {
Log (ex);
throw;
}
}

IEnumerator IEnumerable.GetEnumerator () => GetEnumerator ();

class LoggedEnumerator : IEnumerator<T>
{
readonly LoggedEnumerable<T> parent;
readonly IEnumerator<T> enumerator;

public LoggedEnumerator (LoggedEnumerable<T> parent, IEnumerator<T> enumerator)
{
this.parent = parent;
this.enumerator = enumerator;
}

public T Current {
get {
try {
return enumerator.Current;
} catch (Exception ex) {
parent.Log (ex);
throw;
}
}
}

object? IEnumerator.Current => Current;

public void Dispose ()
{
try {
enumerator.Dispose ();
} catch (Exception ex) {
parent.Log (ex);
throw;
}
}

public bool MoveNext ()
{
try {
return enumerator.MoveNext ();
} catch (Exception ex) {
parent.Log (ex);
return false;
}
}

public void Reset ()
{
try {
enumerator.Reset ();
} catch (Exception ex) {
parent.Log (ex);
}
}
}
}
}
28 changes: 22 additions & 6 deletions Core/Logging/LoggerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,37 @@ public static void LogExceptionsAndForget (this Task task, ILogger logger, [Call
task.CatchAndLogIfFaulted (logger, originMember);
}

public static Task<T> WithExceptionLogger<T> (this Task<T> task, ILogger logger, [CallerMemberName] string? originMember = default)
/// <summary>
/// Attaches a continution to the task that logs any exception thrown by the task, and returns the task.
/// </summary>
public static Task WithExceptionLogger (this Task task, ILogger logger, [CallerMemberName] string? originMember = default)
{
task.CatchAndLogIfFaulted (logger, originMember);
return task;
}

/// <summary>
/// Attaches a continution to the task that logs any exception thrown by the task, and returns the task.
/// </summary>
public static Task WithExceptionLogger (this Task task, ILogger logger, [CallerMemberName] string? originMember = default)
public static Task<T> WithExceptionLogger<T> (this Task<T> task, ILogger logger, [CallerMemberName] string? originMember = default)
{
task.CatchAndLogIfFaulted (logger, originMember);
return task;
}

public static Task<IEnumerable<T>> WithExceptionLogger<T> (this Task<IEnumerable<T>> task, ILogger logger, [CallerMemberName] string? originMember = default)
{
return task.ContinueWith (t => {
try {
return t.Result.WithExceptionLogger (logger, originMember);
} catch (Exception ex) {
LogInternalError (logger, ex, originMember);
throw;
}
},
TaskContinuationOptions.ExecuteSynchronously);
}

public static IEnumerable<T> WithExceptionLogger<T> (this IEnumerable<T> enumerable, ILogger logger, [CallerMemberName] string? originMember = default)
=> new LoggedEnumerable<T> (enumerable, logger, originMember ?? throw new ArgumentNullException (nameof (originMember)));

static Task CatchAndLogIfFaulted (this Task task, ILogger logger, string? originMember)
{
if (originMember is null) {
Expand All @@ -44,7 +60,7 @@ static Task CatchAndLogIfFaulted (this Task task, ILogger logger, string? origin
_ = task.ContinueWith (
t => LogExceptions (logger, originMember, t),
default,
TaskContinuationOptions.OnlyOnFaulted,
TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default
);

Expand Down

0 comments on commit ac2eadf

Please sign in to comment.