title: ASP.NET Core: Building Thread-Safe Logging Into Database
body: <p>In the <code>Startup.cs</code> of my ASP.NET Core application I want to configure the <code>LoggingFactory</code> so that it logs into the database.
  Therefore I create following <code>DBLoggerExtensions</code> class to add a context:</p>
  
  <pre><code>public static class DBLoggerExtensions
  {
      public static ILoggerFactory AddContext(this ILoggerFactory factory, Func&lt;string, LogLevel, bool&gt; filter = null)
      {
          factory.AddProvider(new DBLoggerProvider(filter));
          return factory;
      }
  
      public static ILoggerFactory AddContext(this ILoggerFactory factory, LogLevel minLevel)
      {
          return AddContext(
              factory,
              (_, logLevel) =&gt; logLevel &gt;= minLevel);
      }
  }
  </code></pre>
  
  <p>This will be called in the Configure method of the Startup.cs like this:</p>
  
  <pre><code>loggerFactory.AddConsole(Configuration.GetSection("Logging"));
          loggerFactory.AddDebug();
          loggerFactory.AddContext(LogLevel.Information);
  </code></pre>
  
  <p>The AddContext method add my custom LoggerProvider:</p>
  
  <pre><code>public class DBLoggerProvider : ILoggerProvider
  {
      private readonly Func&lt;string, LogLevel, bool&gt; _filter;
  
      public DBLoggerProvider(Func&lt;string, LogLevel, bool&gt; filter)
      {
          _filter = filter;
      }
      public ILogger CreateLogger(string categoryName)
      {
          return new DBLogger(categoryName, _filter);
      }
  
      public void Dispose()
      {
  
      }
  }
  </code></pre>
  
  <p>Which logs into the database:</p>
  
  <pre><code>public class DBLogger : ILogger
  {
      private string _categoryName;
      private Func&lt;string, LogLevel, bool&gt; _filter;
      private LoggerContext _context;
      private bool _selfException = false;
  
      public DBLogger(string categoryName, Func&lt;string, LogLevel, bool&gt; filter)
      {
          _categoryName = categoryName;
          _filter = filter;
          _context = new LoggerContext();
      }
  
      public void Log&lt;TState&gt;(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func&lt;TState, Exception, string&gt; formatter)
      {
          if (!IsEnabled(logLevel))
          {
              return;
          }
          if (_selfException)
          {
              _selfException = false;
              return;
          }
          _selfException = true;
          if (formatter == null)
          {
              throw new ArgumentNullException(nameof(formatter));
          }
          var message = formatter(state, exception);
          if (string.IsNullOrEmpty(message))
          {
              return;
          }
  
          if (exception != null)
          {
              message += "\n" + exception.ToString();
          }
  
          try
          {
              var maxMessageLength = 2000;
              message = maxMessageLength != null &amp;&amp; message.Length &gt; maxMessageLength ? message.Substring(0, (int)maxMessageLength) : message;
              _context.EventLogs.Add(new EventLog { Message = message, EventId = eventId.Id, LogLevel = logLevel.ToString(), CreatedTime = DateTime.UtcNow });
              _context.SaveChanges();
              _selfException = false;
          }
          catch (Exception ex)
          {
              var test = ex;
          }
      }
  
      public bool IsEnabled(LogLevel logLevel)
      {
          return (_filter == null || _filter(_categoryName, logLevel));
      }
  
      public IDisposable BeginScope&lt;TState&gt;(TState state)
      {
          return null;
      }
  
  }
  </code></pre>
  
  <p>But my problem is that this is not thread safe.
  How do I accomplish logging into the database where the LoggingFactory does not share the DbContext within different threads?</p>
  
  <p>Thanks</p>