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.Â
Let’s dive in.
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.