How do I pass a ILogger<T> into a object created with new?

Viewed 2598

I want to pass a logger into a constructor of an object. Normally, the logger is dependency injected into a class, but I want to log inside a class that is not dependency injected.

I have a .NET Core worker service. In that service, I have 0-many instances of a class that are created at runtime. I also want to be able to log messages to the logger inside that class.

In my example, I can pass the ILogger that I get from inside the TimedWorker, but the type is wrong.

Currently, I have:

    class TimedWorker : BackgroundService
    {
        private List<Dog> m_dogs;
        private ILogger<TimedWorker> m_logger;
        private IConfiguration m_configuration;

        public TimedWorker(ILogger<TimedWorker> logger, IConfiguration configuration)
        {
            m_logger = logger;
            m_configuration = configuration;
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            m_dogs= new List<Dogs>();
            List<DogOption> dogOptions= new List<DogOption>();
            m_configuration.GetSection("Dogs").Bind(dogOptions);

            foreach(DogOption option in dogOptions)
            {
                m_dogs.Add(new Dog(option, m_logger));
            }
        } 

    ///...

    }

    class Dog {
        public string Name { get; }
        private int Age;
        private ILogger m_logger;

        public Dog(DogOption option, ILogger logger)
        {
            m_logger = logger;

            Name = option.Name;
            Age = option.Age;

            m_logger.LogInformation($"Dog '{Name}' created");
        }
    }

The problem is that when it logs, the logger is of type TimedWorker, not Dog. So when I look at the logs, they are labeled under TimedWorker instead of Dog. I do not know how to pass in a ILogger into the Dog class. Any advice?

2 Answers

You can inject the IServiceProvider and resolve the dependency manually.

You can do it like this:

public class Worker
{
    private readonly IServiceProvider _serviceProvider;

    public Worker(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public void Start()
    {
        var specificLogger = _serviceProvider.GetService(typeof(ILogger<Dog>)) as ILogger<Dog>;

        var dog = new Dog(specificLogger);
    }
}
public class Dog
{
    public Dog(ILogger<Dog> logger)
    {
        logger.LogInformation("Hello");
    }
}

This creates the specific log based on the class.

2020-11-18 18:41:58.1275||INFO|ConsoleApp.Dog|Hello

You can create a logger directly. For example:

var logger = LoggerFactory.Create(options => {}).Create<Worker>();
Related