title: how to use serilog to log handled exceptions from anywhere/globally in a .NET Core 3.1 application (using serilog SQL Server sink)
body: <p>I'm developing a custom logging mechanism for an ASP.NET Core 3.1 app with angular front end. I'm using serilog to log errors and successful events in the MS SQL Server.</p>
  <p>So far so good, the logger works and everything is fine. This is achieved by a custom action filter used on the controllers to log (with attribute). In cases of unhandled exceptions the logger logs the error just fine.</p>
  <p>What I'm trying to achieve is to be able to log handled exceptions (within a try/catch block) due to the fact that there are nested try catch blocks inside functions called from EF Core repositories we use.</p>
  <p>One solution is to write an explicit logging method in each controller. This is not the best practice but it works.</p>
  <p>If I create a separate class and I call a logging method from that class anywhere in the controllers, the logger does not write to the database.
  Long story short, if there are 3 method calls, lets say, from other classes inside a method invoked, which they in turn contain a try/catch block, how can I log an exception, if raised ?</p>
  <p>I'm asking this because in case 2 out of N functions raise an exception, the application will continue to work, but I need to know what went wrong in order to fix it. Please let me know if you need a code sample or anything else that can help.</p>
  <p>I've tried a global exception handling mechanism with middleware as proposed after a search in google, but its the same as using an action filter from what I've seen so far and with the same results.</p>
  <p>Below I'm pasting some of the logic implemented on how to log and handle exceptions in a case of an error during POST/PUT/DELETE operations.</p>
  <p>in the base controller we use the attribute of the action filter implemented</p>
  <pre><code>    [ServiceFilter(typeof(LoggingActionFilter))]
      // POST: api/[controller]
      [HttpPost]
      public virtual async Task&lt;ActionResult&lt;TEntity&gt;&gt; Post(TViewEntity entity)
      {
          // do stuff...
      }
  </code></pre>
  <p>the <strong>LoggingActionFilter</strong> handles the request sent to the server and logs the action performed.</p>
  <p>In the <strong>Startup.cs</strong> file we have the following</p>
  <pre><code>    public void ConfigureServices(IServiceCollection services)
      {
          //services added....
          services.AddScoped&lt;LoggingActionFilter&gt;();
      }
  </code></pre>
  <p>The <strong>LoggingActionFilter</strong> class</p>
  <pre><code>public class LoggingActionFilter : IAsyncActionFilter
  {
      private readonly ILogger _logger;
      public LoggingActionFilter(ILoggerFactory loggerFactory)
      {
          _logger = loggerFactory.CreateLogger&lt;LoggingActionFilter&gt;();
      }
  
      public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
      {
          var userId = GetUserId(context.HttpContext);
          var isOnRequest = true;
          try
          {
              //before execution                
              var requestBody = GetRequestBodyAsString(context);
  
              _logger.LogInformation(/*params*/);
  
              var result = await next();
  
              //after execution
              isOnRequest = false;
  
              _logger.LogInformation(/*params*/);
          }
          catch (Exception ex)
          {
               _logger.LogError(/*params*/);
          }
      }
  
      private string GetUserId(HttpContext context)
      {
          var claimsIdentity = (ClaimsIdentity)context.User.Identity;
          var claim = claimsIdentity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
          return claim?.Value;
      }
  
      private string GetRequestBodyAsString(ActionExecutingContext context)
      {
          var result = string.Empty;
  
          foreach (var element in context.ActionArguments)
          {
              result += JsonConvert.SerializeObject(element.Value);
          }
  
          return result;
      }
  }
  </code></pre>
  <p>The logic above works as intended and the attributes decorate the REST actions in the base controller since they are overridden in the derived classes.</p>
  <p>It will catch the unhandled exceptions (without try/catch block).</p>
  <p>In a case of handled exceptions however, since there can be a method which calls, lets say 3 other methods that do have a try/catch block, in case one or more of the 3 methods stated above fail, the program will continue to respond but I need to log each error. Is there a proper way to do so with a global exception handler? Any tips ?</p>
  <p>Please let me know if you need any further information from me.</p>
  <p>Thank you in advance</p>