Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log messages from .NET Standard class library

I have a solution with an ASP.NET Core (2.1.5) Web API project which references a couple of .NET Standard 2.0 class libraries projects.

I want to implement some logging to my application and I have already done this for the Web API project using NLog (in fact, it can be any provider implementing ILogger). To do this, I defined in Program.cs a static field which is initialized during the runtime and configured it with using WebHostBuilderExtensions.ConfigureLogging:

using Microsoft.Extensions.Logging;

public class Program
{
    private static readonly Logger logger = NLogBuilder.ConfigureNLog("NLog.config").GetCurrentClassLogger();
    // other content ...
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    var webHost = WebHost.CreateDefaultBuilder(args)
        .UseStartup(typeof(Startup).GetTypeInfo().Assembly.FullName)
        .ConfigureLogging(builder =>
        {
            builder.ClearProviders();
            builder.SetMinimumLevel(LogLevel.Information);
        })
        .UseNLog();
    // other content ...
}   

This allows me to use DI of ILogging in every class inside my ASP.NET Core application whenever I need it:

using Microsoft.Extensions.Logging;

public class Startup
{
    public IConfiguration Configuration { get; }
    private readonly ILogger<Startup> _logger;

    public Startup(IConfiguration configuration, ILogger<Startup> logger)
    {
        Configuration = configuration;
        _logger = logger;
    }
}

But now I am totally confused with setting up a logging for my class libraries. One of the options I can imagine is to use the DI mechanism to allow my libraries to call the same ILogger interface like this:

using Microsoft.Extensions.Logging;

public class MyLibraryClass
{
    private ILogger<MyLibraryClass> _logger;

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

    public void SomeLibraryMethod()
    {
        _logger.LogInformation("Some library method logging here...);
    }
}

But that looks to be quite awkward as I need to inject this dependency for all my libraries classes where I need logging (so to say, to all classes).

I also think of some static class for each library project where this dependency is injected just once and so that the static class can act as a wrapper around ILogger. Or even to move NLog from the WebAPI project to one of the libraries (or even make a separate library) and use it call this library from all other projects. But as advised here, it is better to have a separate instance of ILogger for each class to filter different loggers. Or maybe it is enough to create static loggers for a certain project?

My another concern is that such static wrappers around ILogger would require from me to define my own interface to work with log messages. But ILogger is itselt a well-designed interface and such attitude seems to be some kind of double work.

I have looked through a lot of step-by-step guides but most of them describe how to configure logging just for one ASP.NET Core web application (or most probably, I used wrong search keywords). Anyway, I am stuck at this moment and don't know the correct way to make my libraries use the same logging provider and file as for my main WebAPI application. Maybe, there are any well-known practices that I have missed?

like image 631
kreigan Avatar asked Nov 18 '18 17:11

kreigan


People also ask

What is .NET standard class library?

A class library defines types and methods that are called by an application. If the library targets . NET Standard 2.0, it can be called by any . NET implementation (including . NET Framework) that supports .

What is the difference between .NET Standard and .NET Framework class library?

NET standard is the set of API that is available on all . NET implementations, It will create some type of uniformness, a portability that supports.Net Core, Xamarin and . Net Framework. Basically, It is the set of Base class libraries (BCL) that support a wide range of technologies like .

Which dotnet function would you use to get a logger?

Log4net. Log4net is one of the most common external logging services available to . NET developers. The developers for log4net promise you can have logging integrated with your application within minutes, and it's true—setup is easy.


2 Answers

I think your Library project classes should have Microsoft.Extensions.Logging.ILogger injected in their CTOR like ILogger<T> logger = null. It is the responsibility of the project consuming it to configure the Logging providers like it is done OOTB by ASP.NET Generic Host in DotNet Core Apps. In case some one forgets to do it it won't throw an error(DI resolution error) as default value is null.

Be sure to use it like logger?.LogDebug() with null check.

like image 179
GPuri Avatar answered Sep 28 '22 02:09

GPuri


I don't think it's awkward Microsoft.Extensions.Logging.ILogger is a common interface that most logging libraries implement.

Using a singleton in this scenario would tie you to a specific logging library which is maybe fine for small project or POC projects, but imagine sharing your library across teams or publishing it. It is much more convenient to expect an interface.

As for, how to inject your logging library of choice to your class library, you don't really have to worry about it as it is taken care of by the DI system.

You just need to declare your class as a constructor dependency in one of your web project classes.

like image 30
areller Avatar answered Sep 28 '22 04:09

areller