Log4net - optimal strategy when using inheritance - c#

I have integrated log4net in my app. I have a few helper methods to assist in logging which call log4net. When refactoring, I plan to move these methods to base class so that the code is not repeated in other derived classes.
Without the inheritance model, following worked correctly in each class
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Placing the above in the base class will return the declaring type as base class and not derived class.
What is an optimal way to move this declaration to the base class?
At present, I can think of a few ways to achieve this but don't find them optimal.

I think I would do this:
LogManager.GetLogger(this.GetType());

Based on Sefan's answer here's how I declared it in the base class
/// <summary>
/// This is delay loaded to allow us to capture the class type of the inherited class on request
/// </summary>
private ILog log = null;
protected ILog Log
{
get
{
if (log == null)
{
log = LogManager.GetLogger(this.GetType());
}
return log;
}
}

We just redeclare it in each class that needs a logger (the point of it being a private static) and use a code snippet to make that as simple as typing log<tab><tab> if you wanted to get extra fancy though you could do something like:
public class Loggable<T> where T : Loggable<T>
{
private static readonly ILog log = LogManager.GetLogger(typeof(T));
protected static ILog Log
{
get
{
return log;
}
}
}
And punch T through your inheritance hierarchy so that it is the most derived class.
The problem with all of the answers here is that you lose information about where log messages are coming from, so I would personally stick to your original code despite the added boilerplate.

Related

How can I wire StructureMap with 2 different objects (log4net loggers) of the same interface

I have a class named MyClass, which uses two different loggers named Logger1 and Logger2. I use log4net for logging, and want to use StructureMap for DI.
Without StructureMap, my class would look like this:
public class MyClass
{
private static readonly ILog Logger1 = LogManager.GetLogger("Logger1"); // Loggers are configured in a config file
private static readonly ILog Logger2 = LogManager.GetLogger("Logger2");
public void DoSomething()
{
...
Logger1.Info("did something");
...
Logger2.Info("need to log this elsewhere");
}
}
Introducing DI, with StructureMap (using v3.0.3), I would make the loggers instance members, and inject them into the constructor, like this:
public class MyClass
{
private readonly ILog Logger1;
private readonly ILog Logger2;
myClass(ILog logger1, ILog logger2)
{
this.Logger1 = logger1;
this.Logger2 = logger2;
}
public void DoSomething()
{
...
Logger1.Info("did something");
...
Logger2.Info("need to log this elsewhere");
}
}
The thing is, I cannot get StructureMap to wire this up for me properly. I tried wiring the loggers like this:
For<ILog>.Use(()=> LogManager.GetLogger("Logger1")).Named("Logger1");
For<ILog>.Use(()=> LogManager.GetLogger("Logger2")).Named("Logger2");
Doing this Gets me empty (unconfigured) loggers). Replacing Use() with Add() gives my an exception due to not having a default instance registered for ILog.
Does anybody know how I can do this?
If the loggers perform different roles then I would create two interfaces inheriting from ILog to reflect this. That way you would have no problem configuring StructureMap to handle them.
I ended up doing the following: I created two interfaces as per Rob's advice: ILogger1 and ILogger2. Since the both have the same API, as I need the same kind of functionality from them, they both inherit from the same interface - though not log4net.ILog as per Steven's advice:
interface IMyLog
{
void Info(object message);
void Info(string format, params object[] args);
}
interface ILogger1 : IMyLog { }
interface ILogger2 : IMyLog { }
Also, since the implementation of this API is the same for my needs, I have one concrete class MyLogger, implementing both ILogger1 and ILogger2. If I ever need the implementations to be different it will be easy for me to have explicit interface implementation, or separate classes. Only My Logger takes a dependency on log4net, as it uses it for its implementation:
enum LoggerType { Logger1, Logger2 }
internal class MyLogger : ILogger1, ILogger2
{
private readonly ILog _log;
public MyLogger(LoggerType loggerName)
{
switch (loggerName)
{
case LoggerType.Logger1:
_log = LogManager.GetLogger("first-log");
break;
case LoggerType.Logger2:
_log = LogManager.GetLogger("second-log");
break;
default:
throw new ArgumentException("Invalid logger name", "loggerName");
}
}
public void Info(object message)
{
_log.Info(message);
}
public void Info(string format, params object[] args)
{
_log.InfoFormat(format, args);
}
}
In order to register it with StructureMap, I used the following code in the registry:
For<ILogger1>().Use<MyLogger>().Ctor<LoggerType>("loggerName").Is(LoggerType.Logger1).Singleton(); // I want only one logger per type
For<ILogger2>().Use<MyLogger>().Ctor<LoggerType>("loggerName").Is(LoggerType.Logger2).Singleton();
It all works wonderfully. So, thanks to Steven and Rob for their advice. I really learned something. I wish I could upvote an answer and a response more than once.
So, to summarize, I:
Created a separate interface for each kind of logger (even saying it now sounds intuitive).
Created a base interface for the logger interfaces, because for my needs they have the same API (YMMV)
Created one concrete logger adapter that implements both interfaces because that suits my needs (YMMV again)
Share the implementation of the interfaces' API, for the above reasons
Registered each interface to create a concrete logger with a different type passed in the constructor
configured the concrete logger with log4net using a Factory Method to determine which logger to use
As an alterative to the answers above, this can be solved exclusively in StructureMap (and I believe works for the SM version used in the question). You can tell StructureMap exactly how to build MyClass by also including the following in a Registry.
For<MyClass>().Use(x => new MyClass(x.GetInstance<ILog>("Logger1"), x.GetInstance<ILog>("Logger2")));

Interface implementation with only empty methods

I'm using log4net in an application for logging.
I want to avoid a discussion about implementing a logging facade, but essentially, I'm creating some classes which will allow an ILog implementation to be injected via the constructor. Eg:
abstract class MigratorBase<T> : IMigrator<T>
{
private ILog logger;
public MigratorBase(ILog logger)
{
this.logger = logger;
}
}
I also would like to provide a default constructor on the class, which if called, essentially disables logging (or logs to nothing). Instead of scattering fragments of code that check if the logger is null, such as this:
if (this.logger != null)
Log.DebugFormat("Connecting to {0}", this.href);
I thought a better way to accomplish this functionality would be to assign an implementation of ILog that was purely empty methods. I could call it a NullLog, and would look similar to this:
class NullLog : ILog
{
public void Debug(object message, Exception exception) { }
public void Debug(object message) { }
public void DebugFormat(IFormatProvider provider, string format, params object[] args) { }
...
...
}
and then in the default constructor I could assign an object of this type to the class's private member, as such:
abstract class MigratorBase<T> : IMigrator<T>
{
private ILog logger;
public MigratorBase(ILog logger)
{
this.logger = logger;
}
public MigratorBase()
{
this.logger = new NullLog();
}
}
This approach seems more object oriented to me, so I think I like it, but googling seems to reveal people suggesting that it's a bad idea to implement an interface with empty methods.
Can anyone suggest why the above might be a bad idea? Or is it in fact an ok idea?
What you describe is called the Null Object pattern. Martin Fowler coined this term and explains it thoroughly in the book Patterns of Enterprise Application Architecture.
I think this is a great pattern to remove all the if-conditions in the code to check for not null. A downside could be that you have to explain a pattern in you development team and maybe add a comment about not adding functionality inside your NullLog class. Otherwise I couldn’t find a downside with this pattern.

instance class->static class->instance class in C#

I have done a lot of reading on instance vs. static classes and have not found an answer to my question. Are there any perils to instancing a different class in a static class that was referenced by an instance class?
The current design I am working with is one in which instance classes call a static "Logger" method (passing a series of parameters) to log errors to a text file in the file system. I am refactoring the static "Logger" method to instantiate a parameter class (which is just a series of properties and a few helper methods to return itself as XML or a string) and a DBLogger class to log the error to the database rather than the file system, passing the parameter class as the sole parameter.
This model worked well in my legacy VB6 code, in which the Logger class was instanced, not static.
But now in the .NET code I am not sure if I should make my 2 new classes (parameter and DBLogger) static, or just make the DBLogger static and instance the parameter class. I am concerned about the potential for concurrency/multi-thread data issues with (or without) instances being created from a static class. Am I right to be concerned or am I worrying about nothing?
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
// all code truncated for illustration purposes
namespace ThisIs.A.Test
{
//INSTANCE
public class ErrorLogParameters
{
private int mThreadId = 0;
private int mErrorNumber = 0;
private string mServerDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
public int ThreadId
{
get { return mThreadId; }
set { mThreadId = value; }
}
public int ErrorNumber
{
get { return mErrorNumber; }
set { mErrorNumber = value; }
}
public string ServerDate
{
get { return mServerDate; }
}
}
//INSTANCE
public class ErrorLog
{
public void LogErrorToDatabase(ErrorLogParameters criteria)
{
//Log error to database here
}
}
//STATIC - Instantiates INSTANCE of ErrorLogParameters and ErrorLog
public class Logger
{
public static void WriteLog(string pstrObjectName, string pstrProcedureName, int plngErrNumber, string pstrErrDescription)
{
// create a new parameter object
ErrorLogParameters objParameters = new ErrorLogParameters();
// populate object properties
objParameters.ErrorNumber = mlngErrNumber;
objParameters.ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
ErrorLog objErrorLog = new ErrorLog();
objErrorLog.LogErrorToDatabase(objParameters);
}
}
//INSTANCE - Invokes STATIC method
public class SomeInstance
{
private void ErrorHandler_Log(Exception exception, string procedureName, string additonalDescription, string stackTrace)
{
// call from instance class to static class
Logger.WriteLog(mstrObjectName, procedureName, mlngErrNumber, mstrErrDescription);
}
}
}
No, that's absolutely fine - if you're creating an instance of any class within a method, it doesn't matter whether the class declaring that method is a static class or not.
Furthermore, unless you've got something "special" (e.g. a static variable counting the number of instances created) you're less likely to run into concurrency issues when creating new objects than when using existing objects. Basically, the tricky part of almost all concurrency is working out where mutable data is shared - it doesn't sound like you've got any here (although sample code would help to clarify that).
I would use a combination of the provider and singleton pattern for this.
Create an abstract class called Logger.
The Logger class contains abstract methods for writing to log. For example:
abstract void LogInfo(LogInfo info);
abstract void LogError(Exception exception);
etc
The Logger class contains a private instance of Logger object.
The Logger class contains a static property that returns the private instance.
The Logger class contains a static constructor that instantiate the private instance of Logger object. You would probably use Reflection and instantiate the object based on the configuration.
Implement a FileLogger that inherits from the Logger object. This logger writes to a file.
Implement a SQLLogger that inherits from the Logger object. This logger writes to a database.
Call the logger like so:
Logger.Instance.WriteInfo(info);
Logger.Instance.WriteError(exception);
There are a few advantages of using this design:
Your logging functionality is fully abstracted. This completely decouple the logging callers from the code that writes the logs. This allows you to write the log to any data stores.
You can change which logger to use without compiling the code. Just update the config file.
Singleton guarantees thread-safety
Testability. You can write Mock tests against abstract classes.
Hope this helps.
There are no concurrency issues with static methods.
Static variables are a different matter.

Use Singleton pattern for error logging class?

I currently have a class written in C# which does some simple error logging stuff. It's been used quite extensively throughout my project.
class LogError
{
//constructor
public LogError() { }
//public methods
public void saveToTextFile() { }
//other similar methods...
}
But, it doesn't seems a good design of this class, as every time I have to create an instance of LogError class before saveToTextFile() method can be used.
So I am thinking of re-designing this class. Would this be a good case to apply Singleton pattern? What about making it static class instead? Any suggestions? Thanks.
The problem with Singleton is that it's hard to use different logging behaviour. Image you want to introduce a "Send an email instead of write to text file" later. It's basically the same if you have
new LogError().DoSomething();
or
LogError.Instance.DoSomething();
except for performance and/or implementation of the LogError class itself.
If you want to add flexibility, you'd better use Dependency Injection (which makes your code clearer than with the Singleton, in addition) or Dependency Lookup (which is somewhere in between).
I would look at Apache log4net. You don't have to worry about anything. You can configure it to log to multiple targets from your configuration file (or in code). The log message template is fully customizable. You can filter and route different log levels (debug/info/warning/error). It's really not worth reinventing the wheel here.
Yes make it singleton and also thread safe
If you are using , any container ( Autofac, Unity etc) then you can make use of the container.
Singleton can be broken ( By using Reflection so be informed )
one of the implementation would be ( this would not required explicit locking )
public class MySingleton
{
private static readonly MySingleton _singtonInstance = new MySingleton();
private MySingleton()
{
}
public static MySingleton SingtonInstance
{
get { return _singtonInstance; }
}
}
You can use interface as your log system facade, like
interface ILoggerFacade{
void Error(Exception e);
void Warning(Exception e);
....
}
after that you need to make interface implementation
class SimpleLogger:ILoggerFacade{
void Error(Exception e){//logging error};
...
}
and finnaly you need enter point to your logger. I ussually use static class but singleton is variant also.
static class sample:
class StaticLogger{
private ILoggerFacade _logger;
StaticLogger(){
//choose ILoggerFacade implementation
_logger=new SimpleLogger();
}
public static ILoggerFacade Logger{
get{ return _logger;}
}
}
If you will use facade interface you can easy change loggers in your project if it will be need.
There is a solution where you have a logging method that is being called once there are exceptions happen anywhere in your application. All you need to have is a general or common exception handler. Here's how.
On your Program.cs (inside your Main() method before the Application.Run) add this code.
Application.ThreadException += CommonExceptionHandler;
Create CommonExceptionHandler event on your Program.cs file let's say next to Main method.
private static void CommonExceptionHandler(object sender, ThreadExceptionEventArgs t)
{
LogError(t.Exception);
}
Create LogError Method on your Program.cs
public static void LogError(Exception ex)
{
var errMsg = ex.Message;
errMsg += ex.InnerException != null ? ex.InnerException.Message : string.Empty;
//TODO: Do what you want if an error occurs
}
This will catch all exceptions occur in your application. You don't need to worry anymore whether you would call your error log class for every catch block in all of your methods

should new behavior be introduced via composition or some other means?

I chose to expose some new behavior using composition vs. injecting a new object into my consumers code OR making the consumer provide their own implementation of this new behavior. Did I make a bad design decision?
I had new requirements that said that I needed to implement some special behavior in only certain circumstances. I chose to define a new interface, implement the new interface in a concrete class that was solely responsible for carrying out the behavior. Finally, in the concrete class that the consumer has a reference to, I implemented the new interface and delegate down to the class that does the work.
Here are the assumptions that I was working with...
I haven an interface, named IFileManager that allows implementors to manage various types of files
I have a factory that returns a concrete implementation of IFileManager
I have 3 implementations of IFileManager, these are (LocalFileManager, DfsFileManager, CloudFileManager)
I have a new requirements that says that I need to manage permissions for only the files being managed by the CloudFileManager, so the behavior for managing permissions is unique to the CloudFileManager
Here is the test that led me to the code that I wrote...
[TestFixture]
public class UserFilesRepositoryTest
{
public interface ITestDouble : IFileManager, IAclManager { }
[Test]
public void CreateResume_AddsPermission()
{
factory.Stub(it => it.GetManager("cloudManager")).Return(testDouble);
repository.CreateResume();
testDouble.AssertWasCalled(it => it.AddPermission());
}
[SetUp]
public void Setup()
{
testDouble = MockRepository.GenerateStub<ITestDouble>();
factory = MockRepository.GenerateStub<IFileManagerFactory>();
repository = new UserFileRepository(factory);
}
private IFileManagerFactory factory;
private UserFileRepository repository;
private ITestDouble testDouble;
}
Here is the shell of my design (this is just the basic outline not the whole shibang)...
public class UserFileRepository
{
// this is the consumer of my code...
public void CreateResume()
{
var fileManager = factory.GetManager("cloudManager");
fileManager.AddFile();
// some would argue that I should inject a concrete implementation
// of IAclManager into the repository, I am not sure that I agree...
var permissionManager = fileManager as IAclManager;
if (permissionManager != null)
permissionManager.AddPermission();
else
throw new InvalidOperationException();
}
public UserFileRepository(IFileManagerFactory factory)
{
this.factory = factory;
}
private IFileManagerFactory factory;
}
public interface IFileManagerFactory
{
IFileManager GetManager(string managerName);
}
public class FileManagerFactory : IFileManagerFactory
{
public IFileManager GetManager(string managerName)
{
IFileManager fileManager = null;
switch (managerName) {
case "cloudManager":
fileManager = new CloudFileManager();
break;
// other managers would be created here...
}
return fileManager;
}
}
public interface IFileManager
{
void AddFile();
void DeleteFile();
}
public interface IAclManager
{
void AddPermission();
void RemovePermission();
}
/// <summary>
/// this class has "special" behavior
/// </summary>
public class CloudFileManager : IFileManager, IAclManager
{
public void AddFile() {
// implementation elided...
}
public void DeleteFile(){
// implementation elided...
}
public void AddPermission(){
// delegates to the real implementation
aclManager.AddPermission();
}
public void RemovePermission() {
// delegates to the real implementation
aclManager.RemovePermission();
}
public CloudFileManager(){
aclManager = new CloudAclManager();
}
private IAclManager aclManager;
}
public class LocalFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
public class DfsFileManager : IFileManager
{
public void AddFile() { }
public void DeleteFile() { }
}
/// <summary>
/// this class exists to manage permissions
/// for files in the cloud...
/// </summary>
public class CloudAclManager : IAclManager
{
public void AddPermission() {
// real implementation elided...
}
public void RemovePermission() {
// real implementation elided...
}
}
Your approach to add your new behavior only saved you an initialization in the grand scheme of things because you to implemented CloudAclManager as separate from CloudFileManager anyways. I disagree with some things with how this integrates with your existing design (which isn't bad)...
What's Wrong With This?
You separated your file managers and made use of IFileManager, but you didn't do the same with IAclManager. While you have a factory to create various file managers, you automatically made CloudAclManager the IAclManager of CloudFileManager. So then, what's the point of having IAclManager?
To make matters worse, you
initialize a new CloudAclManager
inside of CloudFileManager every time you try to get its ACL
manager - you just gave factory
responsibilities to your
CloudFileManager.
You have CloudFileManager implement IAclManager on top of having it as a property. You just moved the rule that permissions are unique to CloudFileManager into your model layer rather than your business rule layer. This also results in supporting the unnecessary
potential of circular referencing between self and property.
Even if you wanted
CloudFileManager to delegate the
permission functionality to
CloudAclManager, why mislead other
classes into thinking that
CloudFileManager handles its own
permission sets? You just made your
model class look like a facade.
Ok, So What Should I Do Instead?
First, you named your class CloudFileManager, and rightly so because its only responsibility is to manage files for a cloud. Now that permission sets must also be managed for a cloud, is it really right for a CloudFileManager to take on these new responsibilities? The answer is no.
This is not to say that you can't have code to manage files and code to manage permissions in the same class. However, it would then make more sense for the class to be named something more general like CloudFileSystemManager as its responsibilities would not be limited to just files or permissions.
Unfortunately, if you rename your class it would have a negative effect on those currently using your class. So how about still using composition, but not changing CloudFileManager?
My suggestion would be to do the following:
1. Keep your IAclManager and create IFileSystemManager
public interface IFileSystemManager {
public IAclManager AclManager { get; }
public IFileManager FileManager { get; }
}
or
public interface IFileSystemManager : IAclManager, IFileManager {
}
2. Create CloudFileSystemManager
public class CloudFileSystemManager : IFileSystemManager {
// implement IFileSystemManager
//
// How each manager is set is up to you (i.e IoC, DI, simple setters,
// constructor parameter, etc.).
//
// Either way you can just delegate to the actual IAclManager/IFileManager
// implementations.
}
Why?
This will allow you to use your new behavior with minimal impact to your current code base / functionality without affecting those who are using your original code. File management and permission management can also coincide (i.e. check permissions before attempting an actual file action). It's also extensible if you need any other permission set manager or any other type of managers for that matter.
EDIT - Including asker's clarification questions
If I create IFileSystemManager : IFileManager, IAclManager, would the repository still use the FileManagerFactory and return an instance of CloudFileSystemManager?
No, a FileManagerFactory should not return a FileSystemManager. Your shell would have to update to use the new interfaces/classes. Perhaps something like the following:
private IAclManagerFactory m_aclMgrFactory;
private IFileManagerFactory m_fileMgrFactory;
public UserFileRepository(IAclManagerFactory aclMgrFactory, IFileManagerFactory fileMgrFactory) {
this.m_aclMgrFactory = aclMgrFactory;
this.m_fileMgrFactory = fileMgrFactory;
}
public void CreateResume() {
// I understand that the determination of "cloudManager"
// is non-trivial, but that part doesn't change. For
// your example, say environment = "cloudManager"
var environment = GetEnvMgr( ... );
var fileManager = m_fileMgrFactory.GetManager(environment);
fileManager.AddFile();
// do permission stuff - see below
}
As for invoking permission stuff to be done, you have a couple options:
// can use another way of determining that a "cloud" environment
// requires permission stuff to be done
if(environment == "cloudManager") {
var permissionManager = m_aclMgrFactory.GetManager(environment);
permissionManager.AddPermission();
}
or
// assumes that if no factory exists for the environment that
// no permission stuff needs to be done
var permissionManager = m_aclMgrFactory.GetManager(environment);
if (permissionManager != null) {
permissionManager.AddPermission();
}
I think that composition is exactly the right means to to this kind of trick. But I think you should keep it more simple (KISS) and just make an IAclManager property in the IFileManager and set it to null by default and set the SecurityManager implementation for the cloud service there.
This has different upsides:
You can check if permissions need to be checked by nullchecking the securityManager property. This way, if there doesn't need to be permissionsManaging done (as with localfile system), you don't have exceptions popping up. Like this:
if (fileManager.permissionsManager != null)
fileManager.permissionsManager.addPermission();
When you then carry out the task (to add or delete a file), you can check again if there's a permissionsManager and if the permission is given, if not throw exception (as you'll want to throw the exception when a permission to do an action is missing, not if a permission is missing in general if you're not going to add or delete files).
You can later on implement more IAclManagers for the other IFileManagers when your customer changes the requirements next time the same way as you would now.
Oh, and then you won't have such a confusing hierarchy when somebody else looks at the code ;-)
In general it looks good, but I do have a few suggestions. It seems that your CreateResume() method implementation demands a IFileManager that is also an IAclManager (or else it throws an exception).
If that is the case, you may want to consider adding an overload to your GetManager() method in which you can specify the interface that you require, and the factory can have the code that throws an exception if it doesn't find the right file manager. To accompolish this you can add another interface that is empty but implements both IAclManager and IFileManager:
public interface IAclFileManager : IFileManager, IAclManager {}
And then add the following method to the factory:
public T GetManager<T>(string name){ /* implementation */}
GetManager will throw an exception if the manager with the name given doesn't implement T (you can also check if it derives from or is of type T also).
All that being said, if AddPermissions doesn't take any parameters (not sure if you just did this for the post), why not just call AddPermissions() from CloudFileManager.AddFile() method and have it completely encapsulated from the user (removing the need for the new IAclManager interface)?
In any event, doesn't seem like a good idea to call AddFile in the CreateResume() method and only then throw the exception (since you now you have now created a file without the correct permissions which could be a security issue and also the consumer got an exception so he may assume that AddFile didn't succeed, as opposed to AddPermission).
Good luck!

Categories