1
votes

I need to develop custom logger fro ASP.NET Core WEB API. I'd like to use the standard logging infrastructure, however, what I need is little bit different, because log records shouldn't be written to the destination media immediately, but I need

  1. create new logger per request
  2. collect log records of this request in memory
  3. save all records of the request as one record to the database at the end of that action or when the exception appears.

I'm quite new to ASP.NET Core, so I followed several tutorials, created the DBLogger (implementing ILogger and saving records to internal StringBuilder + one additional method Save), configuration, provider, extensions, I registered it in Startup and it works, but without the last step, which is the saving to the database. In the controller, I use the DI to get the logger, so it looks like this

    public class ValuesController : Controller

{
    private readonly ILogger<ValuesController> _logger;

    public ValuesController(ILogger<ValuesController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IEnumerable<string> Get()
    {
        _logger.LogWarning("TestWarning");
        _logger.LogInformation("TestInfo");

        return new string[] { "value1", "value2" };
    }

So I can now write log records, but how can I call the additional (custom) functionality of a specific Logger (in this case Save() method of my DBLogger)? The _logger property in my controller holds references to all loggers used in application internally, but the collection is not accessible from code.

The question, in general, could even be: How can I use the custom functionality of custom ILogger in the code. Or maybe - how can I get the reference to the custom logger?

[Edit] This is not my type (DBlogger), what i receive by DI, but i get the Microsoft.Extensions.Logging.Logger, containing non public property _logger of type Microsoft.Extensions.Logging.Logger containing non public collection of loggers containing my logger (see pic bellow). So that's why I feel it complicated

1]

Thanks

Filip

2

2 Answers

2
votes

//Write an extension method Save for ILogger and pass any params to StateInfo

public static void Save(this ILogger logger, string param) {

var state = new List<KeyValuePair<string, dynamic>>
{
    new KeyValuePair<string, dynamic>("Myparam", param),

};

logger.Log(level,999, state, null, null);
}

public class DBLogger:ILogger{
public void Log<TState>(LogLevel logLevel, Microsoft.Extensions.Logging.EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
      if (eventId.Id == 999) //Save Event
      {
            if (state is IReadOnlyList<KeyValuePair<string, object>> stateInfo )
            {
                foreach (var property in stateInfo)
                {
                  if (property.Key == "Myparam")
                        {
                            var value = (string)property.Value;//do something with value
                        }
                }
            }
     }
}
0
votes

You could either declare your logger as dynamic:

    private readonly dynamic _logger;

In this case however, you need to ensure that the specific implementation of ILogger has a method called Save when you do that call.

OR

Use reflection to invoke the save method. You would surround this with a try catch to handle the case when your specific ILogger implementation does not include a method called Save.