In this article, we are going to discuss how we can use the logging API in a .NET application and the three important interfaces of this API – ILogger, ILoggerFactory, and ILoggerProvider.

Logging is an important part of every application. It helps us identify the issues in our application when we face any problems in production. 

To download the source code for this article, you can visit our GitHub repository.

Let’s dive in.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

What is Logging API?

Microsoft provides a logging API under the Microsoft.Extensions package. This logging API can work with various built-in logging providers to write logs to various outputs like the Console or Debug window.

Microsoft.Extensions.Logging has various classes and interfaces that are necessary for logging in .NET. We are going to cover the most important ones – ILogger, ILoggerFactory, and ILoggingProvider. 

ILoggerFactory Interface

ILoggerFactory is a factory interface that we can use to create instances of the ILogger type and register logging providers. It acts as a wrapper for all the logger providers registered to it and a logger it creates can write to all the logger providers at once.

That said, let’s inspect the ILoggerFactory definition:

public interface ILoggerFactory : IDisposable
{
    ILogger CreateLogger(string categoryName);
    void AddProvider(ILoggerProvider provider);
}

As we can see, it has two methods, the CreateLogger() method, and the AddProvider() method.

As the name suggests, the CreateLogger() method is responsible for creating a new logger instance. It takes the name of the category as its input. The AddProvider() method is responsible for adding new providers to the logger factory. The LoggerFactory class is an in-built implementation of the ILoggerFactory interface.

ILoggerProvider Interface

ILoggerProvider is responsible for creating logger instances specified by the logger category:

public interface ILoggerProvider : IDisposable
{
    ILogger CreateLogger(string categoryName);
}

There are various built-in logging providers in .NET. The most important providers are:

  • Console Provider
  • Debug Provider
  • EventSource Provider
  • EventLog Provider (Windows)
  • TraceSource Provider

We can even create our own logging providers by implementing the ILoggerProvider interface.

ILogger Interface

The ILogger interface is responsible for writing the log to the actual storage. ILogger<T> is used for injecting in the constructor for logging:

public interface ILogger
{
    void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter);
    bool IsEnabled(LogLevel logLevel);
    IDisposable BeginScope<TState>(TState state);
}

Now that we’re familiar with what these interfaces are for, let’s see them in action.

Demo Application 

For this example, let’s use a simple console application and the console and debug providers for logging.

First, let’s create an instance of ILoggerFactory and then add these two providers to it:

ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddConsole();
    builder.AddDebug();
});

Once we register the provider, it’s time to implement a logger.

Let’s create a Student class that uses the logger to log information every time a new instance of the class is created:

public Student(string name, string department, ILogger<Student> logger)
{
    Name = name;
    Department = department;
    _logger = logger;

    _logger.LogInformation("Name of student is " + Name +" and his department is " + Department);
}

In this code, we include the ILogger<Student> interface as a parameter in the constructor.

Now that we have a class, let’s create an instance of it in the main method and see the logger in action:

ILogger<Student> logger = loggerFactory.CreateLogger<Student>();
var student = new Student("John", "IT", logger);

First, we create an instance of ILogger using the loggerFactory called logger. Then we pass it as an argument to the student constructor.

Once we create a student instance the logger is going to write a message to our console output:

info: LoggingAPI.Student[0]
      Name of student is John and his department is IT

However, there is another way to do this.

Instead of injecting the ILogger interface, we inject an instance of ILoggerFactory. Let’s create another class called Department and inject the ILoggerFactory to it:

public Department(string name, string description, ILoggerFactory factory)
{
    Name = name;
    Description = description;

    _logger = factory.CreateLogger<Department>();
    _logger.LogInformation("Department is " + Name + " " + Description);
}

Now let’s create an instance of this class and see the output:

var department = new Department("IT", "Information Technology", loggerFactory);

This time around our output is a bit different:

info: LoggingAPI.Department[0]
      Department is IT Information Technology

As we can see this approach yields the same result as injecting the logger. However, this is not a recommended approach as it is not a constructor’s responsibility to create the instances of loggers.

That’s it for this short article. Let’s sum it up.

Conclusion

In this article, we have discussed three main interfaces of Logging API in C# – ILogger, ILoggerFactory, and ILoggerProvider. These are very important and yet simple to use interfaces that help us implement logging in any kind of application.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!