0

I have written a middleware for my web application.

The middleware handles special requests and writes multiple information from multiple sources to the log. For example like the following code snippet:

public class MyMiddleware
{
  public async Task Invoke(HttpContext context)
  {
    var dataToBeLogged = await context.Request.ReadFromJsonAsync<LogEntry[]>();
    foreach(var l in dataToBeLogged)
    {
      var loggerName = string.IsNullOrEmpty(l.LoggerName) ? "Default" : l.LoggerName;
      var logger = _loggerFactory.CreateLogger($"{env.ApplicationName}.Client.{loggerName}");
      logger.Log(l.Level, l.Exception, l.Message);
    }
  }
}

The loggerName and therefor the logger might be differ but it could also be that a logger with the same loggerName hast been created before.

My question is what is the best practice of handling the logger creation?

  • Should I always create a new logger? or
  • Should I create a Dictionary where I store loggers which has been created before in the Invoke method (Example 1)? or
  • Because the instance of the middleware doesn't change at runtime, should I create the dictionary a class level (Example 2)?

Example 1

public class MyMiddleware
{
  public async Task Invoke(HttpContext context)
  {
    var dataToBeLogged = await context.Request.ReadFromJsonAsync<LogEntry[]>();
    var dict = new Dictionary<string, ILogger>();
    foreach(var l in dataToBeLogged)
    {
      var loggerName = string.IsNullOrEmpty(l.LoggerName) ? "Default" : l.LoggerName;
      if (!dict.ContainsKey(loggerName))
        dict.Add(loggerName, _loggerFactory.CreateLogger($"{env.ApplicationName}.Client.{loggerName}"));
      var logger = dict[loggerName];
      logger.Log(l.Level, l.Exception, l.Message);
    }
  }
}

Example 2

public class MyMiddleware
{
  private readonly dict = new Dictionary<string, ILogger>();
  public async Task Invoke(HttpContext context)
  {
    var dataToBeLogged = await context.Request.ReadFromJsonAsync<LogEntry[]>();
    
    foreach(var l in dataToBeLogged)
    {
      var loggerName = string.IsNullOrEmpty(l.LoggerName) ? "Default" : l.LoggerName;
      if (!dict.ContainsKey(loggerName))
        dict.Add(loggerName, _loggerFactory.CreateLogger($"{env.ApplicationName}.Client.{loggerName}"));
      var logger = dict[loggerName];
      logger.Log(l.Level, l.Exception, l.Message);
    }
  }
}

LogEntry class

public class LogEntry
{
  public string LoggerName { get;set; }
  public int Level { get;set; }
  public Exception Exception { get;set; }
  public string Message { get;set; }
}

Example data

[
 { loggerName: "LoggerOne", level: 2, exception: null, message: "This is an information" },
 { loggerName: "LoggerTwo", level: 3, exception: null, message: "This is a warning" },
 { loggerName: "LoggerOne", level: 4, exception: { message: "A Exception message", stackTrace: "..." }, message: "This is an error" }
]

Expected log output

MyProject.Client.LoggerOne: Information: This is an information
MyProject.Client.LoggerTwo: Warning: This is a warning
MyProject.Client.LoggerOne: Error: This is an error
MyProject.Client.LoggerOne: Error: A Exception message
   at ...
   at ...
   at ...
NCC-2909-M
  • 709
  • 1
  • 7
  • 15
  • How about to create logs, use an ILogger object from dependency injection (DI)? You can read [Logging in .NET Core and ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-7.0) to know more. – Qing Guo Feb 07 '23 at 06:43
  • No I can't use DI because it would create a logger which has always the same `category name` for example `MyProject.Client.MyMiddleware: Error: ...` But I want logger with a dynamic category name depending on the `loggerName` of the `dataToBeLogged` I extended my example to make it clearer what I mean – NCC-2909-M Feb 08 '23 at 14:33

0 Answers0