title: How to push custom properties to Serilog’s LogContext without adding other context properties?
body: <p>In a .Net Core 2.2 API, I am trying to use Serilog for logging to SQL Server to take advantage of its structured logging capabilities. Besides the standard fields (Id, Timestamp, Level, Message, MessageTemplate, LogEvent), I need to capture the user’s name and IP address with every log entry. I have seen <a href="https://stackoverflow.com/questions/30915733/serilog-forcontext-and-custom-properties">this post</a> but I’d like to do this in one place so the developers don’t have to add it manually with each log statement. I have the following snippet in my <code>Startup.cs</code> ctor:</p>
  
  <pre class="lang-cs prettyprint-override"><code>    public Startup(IConfiguration configuration)
      {
          _configuration = configuration;
  
          Log.Logger = new LoggerConfiguration()
              .ReadFrom.Configuration(configuration)
              .Enrich.FromLogContext()
              .Enrich.With&lt;SerilogContextEnricher&gt;()
              .CreateLogger();
      }
  </code></pre>
  
  <p>The <code>.Enrich.FromLogContext()</code> call makes the static LogContext available for me to add my custom properties (username and IP address) in a custom middleware like so:</p>
  
  <pre class="lang-cs prettyprint-override"><code>    public class SerilogMiddleware
      {
          private static readonly ILogger Log = Serilog.Log.ForContext&lt;SerilogMiddleware&gt;();
          private readonly RequestDelegate _next;
  
          public SerilogMiddleware(RequestDelegate next)
          {
              this._next = next ?? throw new ArgumentNullException(nameof(next));
          }
  
          public async Task Invoke(HttpContext httpContext)
          {
              if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
  
              // Get user info
              var user = httpContext.User.FindFirst(ClaimTypes.Name)?.Value ?? "anonymous";
  
              // Get client info
              var client = httpContext.Connection.RemoteIpAddress.ToString() ?? "unknown";
  
              // enrich LogContext with user info
              using (LogContext.PushProperty("User", user))
              using (LogContext.PushProperty("Client", client))
              {
                  try
                  {
                      await _next(httpContext);
                  }
  
                  // Never caught, because LogException() returns false.
                  catch (Exception ex) when (LogException(httpContext, ex)) { }
              }
          }
  
          private static bool LogException(HttpContext httpContext, Exception ex)
          {
              var logForContext = Log.ForContext("StackTrace", ex.StackTrace);
  
              logForContext.Error(ex, ex.Message);
  
              return false;
          }
      }
  </code></pre>
  
  <p>However, the <code>.Enrich.FromLogContext()</code> call also adds ActionId, ActionName, RequestId, RequestPath and CorrelationId properties to the LogEvent field. I don’t want to bloat my log table with these 5 properties. My current solution is to enrich my logger with the below custom enricher that removes these properties from EventLog.</p>
  
  <pre class="lang-cs prettyprint-override"><code>    public class SerilogContextEnricher : ILogEventEnricher
      {
          public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
          {
              logEvent.RemovePropertyIfPresent("ActionId");
              logEvent.RemovePropertyIfPresent("ActionName");
              logEvent.RemovePropertyIfPresent("RequestId");
              logEvent.RemovePropertyIfPresent("RequestPath");
              logEvent.RemovePropertyIfPresent("CorrelationId");
          }
      }
  </code></pre>
  
  <p>This all works fine but it seems silly to initially add these properties to the logger and then remove them afterwards. Does anyone know of a way to push custom properties to all log entries universally without this game of adding and removing unwanted properties?</p>