In Serilog, logs are stored sequentially in a file or in Elasticsearch. These logs are stored randomly (per user request) in Elasticsearch or text file as the number of site users increases and the number increases. For example, one user is registering an order and another user is performing a return operation, and the logs of these two users are sent simultaneously to your desired destination (Elasticsearch or text file) and the logs take an irregular shape and you can not Follow the order. As the number of users and requests increases, it becomes almost impossible or impossible to find logs related to an action or api. But with Serilog.Context.LogContext.PushProperty you can define a scope that contains a name and a value, and all the logs within that scope contain the same name and value that you created them.

public IActionResult ConfirmOrder(Order order)
{
    using (Serilog.Context.LogContext.PushProperty("OrderId", order.Id))
    {
        _logger.LogInformation("Check order validation");
        //DoSomething
        _logger.LogInformation("Order validation successfully");
        //DoSomething
        _orderService.ConfirmOrder(order);
        _logger.LogInformation("Order confirmed successfully");
    }
    return Ok();
}

This will include all logs registered in the OrderId scope, including a property called OrderId and the order value. Id, which allows you to find all the requisites related to a particular action with the order ID. Even if you used ILogger in the ConfirmOrder method for orderService, all logs for orderService include the OrderId property. An example of a log:  

{
   "Timestamp":"2020-10-20T23:01:01.0492132+03:30",
   "Level":"Information",
   "MessageTemplate":"Order Confirmed successfully",
   "Properties":{
      "SourceContext":"SerilogExamlpe.WebApplication.Controllers.WeatherForecastController",
      "ActionId":"870582be-312f-4065-88eb-5675e2df4928",
      "ActionName":"SerilogExamlpe.WebApplication.Controllers.WeatherForecastController.Get (SerilogExamlpe.WebApplication)",
      "RequestId":"0HM3L5QM34E6K:00000001",
      "RequestPath":"/weatherforecast",
      "SpanId":"|da92fcac-4169ab4e937de2ae.",
      "TraceId":"da92fcac-4169ab4e937de2ae",
      "ParentId":"",
      "OrderId":12345,//<-- NOTE THIS
      "MachineName":"FARHAD-PC",
      "Environment":"Development"
   }
}

The registered log corresponds to the last log written; With the value "Order Confirmed successfully". In this log, you see the OrderId property with a value of 12345; While we have only recorded one text, in the log, it has added additional information to the log. By doing this, you can easily find all the logs related to the order with ID 12345.

If you do not use Serilog and use your .NET ILogger to register logs, you can use the BeginScope method instead of PushProperty as follows:

using (_logger.BeginScope("OrderId : {orderId}", 12345))

You can also create a middleware that stores the user's ID and IP in all logs:  

app.Use(async (httpContext, next) =>
{
    //Get username
    var username = httpContext.User.Identity.IsAuthenticated ? httpContext.User.Identity.Name : "anonymous";
    LogContext.PushProperty("User", username);

    //Get remote IP address
    var ip = httpContext.Connection.RemoteIpAddress.ToString();
    LogContext.PushProperty("IP", !String.IsNullOrWhiteSpace(ip) ? ip : "unknown");

    await next.Invoke();
});

:)

Powered by Froala Editor