Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: ILogger vs static Log instance

This is more an architectural question: Do you use ILogger (and pass it in the constructor via DI) or do you prefer a static class Log?

We use ILogger a lot but it really seems to clatter the code especially when it is passed via constructor. If not passed via constructor and just every time created, then I really do not see a benefit if using the interface.

So how do you handle this? I am especially interested in the arguments behind it - not just saying "static" or "interface".

Thx

like image 663
Michael Wagner Avatar asked Jun 25 '26 11:06

Michael Wagner


2 Answers

Using a static instance of anything is a bad idea for different reasons, depending on your use case.
- They are difficult to mock in a unit test so your logger is always writing logs even when they are not needed.
- Lack of mocking also means you cannot write tests to ensure an error log is written in appropriate situations. - They cannot be replaced at runtime to allow injection of different loggers. This can be important if you are releasing a library for others to use. I define a standard logger interface and log everything to that, then allow clients to inject their own logger as long as it implements my interface.
- If you use the default static Log implementation provided by the vendor, you are locked into their interface meaning you cannot hide or change the surface area of the logger. Changing loggers becomes a MUCH bigger effort if the syntax of the new logger changes.

So that leaves you with some kind of injection. Personally I prefer having all dependencies in the constructor, even if it becomes verbose, because it’s easy to see all dependencies a particular class has. If you are trying to avoid a big constructor you can look into Property Injection. This requires an attribute on a property of the class, but still gives you all the advantages of injecting the dependencies. If you put the injected property on a base class it will be available for all children automatically.

BTW, I’m not a fan of the Ambient Context described above because it’s basically a single purpose DI container, and you must have a concrete reference to multiple ambient service containers. If the easy access of this pattern appeals to you, look into Service Location which is the same idea but more flexible.

like image 199
Brad Irby Avatar answered Jun 27 '26 00:06

Brad Irby


If ILogger is really a cross-cutting concern, which is used everywhere and thus just causes to pollute every instance with a new constructor parameter, then what you need is to you use a special way of dependency injection called AmbientContext.

Basically it provides you a singleton Context property, which can be accessed from anywhere in the business scope and contains the "global" dependencies such as logging, time service, etc., whatever you need.

But please note that it doesn't mean you can throw out your ILogger and use a static Log class with a hardcoded implementation. Ambient context is also a way of dependency injection so its dependencies should be resolved.

like image 34
György Kőszeg Avatar answered Jun 27 '26 01:06

György Kőszeg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!