I am using log4net in which I am obtaining a reference to the logger within a static class like so:
internal static class Constants
{
public static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
}
and using that reference throughout the app like so:
Constants.Log.Info(_message);
However I've got the feeling that this may cause problems and I realise that constant (global?) variables can be a bad thing.
You can use dependency injection in a static class using method or property injection. However, you cannot use constructor injection in a static class because the constructor of a static class cannot accept any parameters.
Loggers should be declared to be static and final. It is good programming practice to share a single logger object between all of the instances of a particular class and to use the same logger for the duration of the program.
A Singleton can implement interfaces, inherit from other classes and allow inheritance. While a static class cannot inherit their instance members. So Singleton is more flexible than static classes and can maintain state. A Singleton can be initialized lazily or asynchronously and loaded automatically by the .
You are correct, that is not the best approach, if you want to be able to easily differentiate log levels and use different log targets ("appenders") for each class.
It's usually recommended that each class has a static ILog
instance, named after it's fully qualified type:
namespace Animals
{
public class Dog
{
private static readonly ILog Log = LogManager.GetLogger(typeof(Dog));
}
public class Cat
{
private static readonly ILog Log = LogManager.GetLogger(typeof(Cat));
}
}
While this looks like more work compared to having a singleton, it proves very handy in the long term. Once you've done this, it is easy to differentiate Dog
and Cat
log levels through your configuration file (example shown with log4net syntax):
<log4net>
<!-- appender definitions ommited -->
<!-- default for all loggers in Animals namespace -->
<logger name="Animals">
<level value="WARN"/>
</logger>
<!-- ...but we need full debug for Dogs -->
<logger name="Animals.Dog">
<level value="DEBUG"/>
</logger>
<!-- ...and we want to send Cat messages over e-mail -->
<logger name="Animals.Cat">
<level value="INFO"/>
<appender-ref ref="SmtpAppender"/>
</logger>
</log4net>
Logging frameworks like log4net also use the notion of hierarchical logging: a logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. To make use of this feature, it's best to avoid naming loggers manually (using hardcoded string
s), but rather use type information to include the entire namespace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With