Sunday, October 14, 2018

TryCatcher: A Reusable Try-Catch Wrapper with Logging

Exception logging can be a tricky thing. With so many ways to log an application event, every developer has their own preferences and can change over time. This may not normally be a problem with small-to-medium applications, where it may be easy enough to update whole projects with new ways to log. For large solutions with multiple components, this can become tricky and at worst impractical.

Enforcing a common logging mechanism helps in code reuse in terms of logging exceptions. This can be extended to the exception handling itself, as the Try-Catch pattern tend to be the same in most cases. TryCatcher is a wrapper class to run a snippet of code within a Try-Catch block, and log any errors thrown if any.

Below is a sample function (StaticMethod()) and the regular way of calling it in void Main().

The RunMethod and RunFunction functions each accepts a delegate, and invokes that delegate within an internal Try-Catch. To execute the StaticMethod() call in the context of the TryCatcher Run-functions, pass them as a delegate to the appropriate function.

The RunMethod and RunFunction functions returns a ValueTuple indicating whether the execution was successful (RunSuccessful), the Exception object if it failed (Exception) and the returned value for functions for the case of RunFunction.

If the function succeeded, the RunSuccessful member is true and the Value member contains the return value of the function executed. If the execution failed due to an exception, RunSuccessful is false, and the Exception member contains the Exception object that was caught. Running the function in this context does not cause a runtime error, as the exception is absorbed and returned in Exception member for further optional processing.

Following are additional ways to use TryCatcher.

Extending the functions to support logging of any exceptions encountered while attempting to execute the delegates, version two adds logging functionalities.

If the Logger member is not defined (e.g. is null), then the logging functionality is ignored. If a valid logger that implements ICatchLogger interface is provided, then any exceptions encountered shall be logged as defined by the ICatchLogger implementation.

Given the errorFunction Action that throws and exception, the first RunMethod prior to registering the Logger absorbs the exception but does not trigger the logging functionality. The second RunMethod, after a simple Logger has been registered, displays the error encountered in the console. This ICatchLogger implementation may be extended to log the exception to a file log containing more information regarding the conditions of the exception.

1 comment: