This question is related to Steven’s answer - here. He proposed a very good logger wrapper. I will paste his code below:
public interface ILogger
{
void Log(LogEntry entry);
}
public static class LoggerExtensions
{
public static void Log(this ILogger logger, string message)
{
logger.Log(new LogEntry(LoggingEventType.Information,
message, null));
}
public static void Log(this ILogger logger, Exception exception)
{
logger.Log(new LogEntry(LoggingEventType.Error,
exception.Message, exception));
}
// More methods here.
}
So, my question is what is the proper way to create implementation that proxies to log4net? Should I just add another Log extension method with type parameter and then create a switch inside? Use different log4net method in case of LoggingEventType ?
And second question, what is the best way to use it later in the code?
Because he wrote:
(…) you can easily create an ILogger implementation (…) and configure
your DI container to inject it in classes that have a ILogger in their
constructor.
Does that mean that every class that will log sth (so basically every), should have ILogger in its constructor?
So, my question is what is the proper way to create implementation that proxies to log4net?
you should create something like:
public class Log4netAdapter : ILogger
{
private readonly log4net.ILog m_Adaptee;
public Log4netAdapter(log4net.ILog adaptee)
{
m_Adaptee = adaptee;
}
public void Log(LogEntry entry)
{
//Here invoke m_Adaptee
if(entry.Severity == LoggingEventType.Debug)
m_Adaptee.Debug(entry.Message, entry.Exception);
else if(entry.Severity == LoggingEventType.Information)
m_Adaptee.Info(entry.Message, entry.Exception);
else if(entry.Severity == LoggingEventType.Warning)
m_Adaptee.Warn(entry.Message, entry.Exception);
else if(entry.Severity == LoggingEventType.Error)
m_Adaptee.Error(entry.Message, entry.Exception);
else
m_Adaptee.Fatal(entry.Message, entry.Exception);
}
}
Does that mean that every class that will log sth (so basically every), should have ILogger in its constructor?
As I understand from Stevens answer: Yes, you should do this.
what is the best way to use it later in the code?
If you are using a DI container, then just use the DI container to map ILogger to Log4netAdapter. You also need to register log4net.ILog, or just give an instance of log4net logger to the DI container to inject it to the Log4netAdapter constructor.
If you don't use a DI container, i.e., you use Pure DI, then you do something like this:
ILog log = log4net.LogManager.GetLogger("MyClass");
ILogger logging_adapter = new Log4netAdapter(log);
var myobject = new MyClass(other_dependencies_here, logging_adapter);
Related
So the way I usually do it (with DI) is to add the extension to my container:
unityContainer.AddNewExtension<Log4NetExtension>();
and then at the constructor of the class where I need to call the logger I use something like this:
public class test
{
private ILog logger;
public test (ILog logger)
{
this.logger =logger;
}
}
Now my problem is, in one of my classes, I don't want to pass anything to the constructor and I was wondering how can I assign my logger (since im using unity I thought of calling resolve but it's not working)
public class test
{
private ILog logger;
public test()
{
logger = unityContainer.Resolve<ILog>(); //I edited this for simplicity
}
}
Error is something like the container didn't know how to resolve ILog.
EDIT:
The class that didn't let me pass anything through its constructor is a Job (implements IJob) class, in the end I ended up using a job listener instead of logging in each job.
Some tips if you still want to pass something for the constructor is by implementation a Job Factory which should help you inject parameters. And I saw a nuget you can add to help you with Quartz integration with Unity.
Log4net allows you create a logger using a name in your class, no need to pass it via a constructor.
Add this as a class member
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger("MyAppLog");
Of course, this does not use your DIContainer.
You can use property injection:
public class test
{
[Dependency]
public ILog Logger { get; set; }
public test()
{
}
}
Two drawbacks, though:
the logger's a public writable property now, so anyone could technically use or overwrite your logger
property injection is meant for optional dependencies, so you might be confusing others who look at the class
While registering components in Castle Windsor, how do we bind specific implementation of an interface to a component that has a dependency on that interface. I know in advance which implementation needs to be used by the component.
For example i created a sample console application based on code from several blogs and tutorials.
Following is the code.
public interface IReport
{
void LogReport();
}
public interface ILogger
{
string Log();
}
public class FileLogger : ILogger
{
public string Log()
{
return "Logged data to a file";
}
}
public class DatabaseLogger : ILogger
{
public string Log()
{
return "Logged data to a database";
}
}
public class McAfeeService : IReport
{
private readonly ILogger _logger;
public McAfeeService(ILogger logger)
{
this._logger = logger;
}
public void LogReport()
{
string getLogResult = this._logger.Log();
Console.WriteLine("McAfee Scan has " + getLogResult);
}
}
public class NortonService : IReport
{
private readonly ILogger _logger;
public NortonService(ILogger logger)
{
this._logger = logger;
}
public void LogReport()
{
string getLogResult = this._logger.Log();
Console.WriteLine("Norton Scan has " + getLogResult);
}
}
class Program
{
private static IWindsorContainer container;
static void Main(string[] args)
{
// Register components
container = new WindsorContainer();
container.Register(Component.For<IReport>().ImplementedBy<NortonService>());
container.Register(Component.For<ILogger>().ImplementedBy<FileLogger>());
IReport service = container.Resolve<IReport>();
service.LogReport();
Console.ReadLine();
}
}
I would like NortonService to always use a Filelogger and McAfeeService to use a Database Logger.
In the above program i am unable to bind NortonService to FileLogger.
How to do it?
The above answers lead me to inline dependencies and the feature service override
Here is the registration code:
container.Register(Component.For<IReport>().ImplementedBy<NortonService>().Named("nortonService"));
container.Register(Component.For<ILogger>().ImplementedBy<FileLogger>());
container.Register(Component.For<ILogger>().ImplementedBy<DatabaseLogger>());
container.Register(
Component.For<IReport>().ImplementedBy<McAfeeService>().Named("mcafeeService")
.DependsOn(Dependency.OnComponent<ILogger, DatabaseLogger>())
);
IReport mcafeescan = container.Resolve<IReport>("mcafeeService");
mcafeescan.LogReport();
IReport nortonscan = container.Resolve<IReport>("nortonService");
nortonscan.LogReport();
Output:
McAfee Scan has Logged data to a database
Norton Scan has Logged data to a file
I had a problem very like this, two implementation of one interface and two implementation of another interface. I wanted to force usage of particular implementations of those interfaces.
My class structure looked like this -
I looked at the naming convention, but didn't really like it. Instead I used the following -
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IMessageLoader>().ImplementedBy<MessageLoaderDatabase>()
,Component.For<IMessageLoader>().ImplementedBy<MessageLoaderFile>()
,Component.For<IMessageOfTheDayService>().ImplementedBy<MessageOfTheDayServiceDatabase>()
.DependsOn(Dependency.OnComponent<IMessageLoader, MessageLoaderDatabase>())
,Component.For<IMessageOfTheDayService>().ImplementedBy<MessageOfTheDayServiceFile>()
.DependsOn(Dependency.OnComponent<IMessageLoader, MessageLoaderFile>())
,Component.For<MessageOfTheDayController>().LifestyleTransient()
.DependsOn(Dependency.OnComponent<IMessageOfTheDayService, MessageOfTheDayServiceFile>())
);
Full info about this approach is here. In the source code provided with that post I show two other ways of achieving the same result.
If you want to do it at runtime, This can be acheived through IHandlerSelector. Write a class that implements IHandlerSelector. It provides a method SelectHandler which will let you define the condition for binding conditionally at runtime. A Handler in this case is a component in Windsor that participates in instance construction. Refer here for more details.
My answer maybe not the best one, you can use naming method to resolve multi implementation:
container.Register(Component.For(typeof(ILogger))
.ImplementedBy(typeof(FileLogger))
.Named("FileLoggerIoC")
.LifestylePerWebRequest() ,
Component.For(typeof(ILogger))
.ImplementedBy(typeof(DatabaseLogger))
.Named("DatabaseLoggerIoC")
.LifestylePerWebRequest());
In your calling functions, you need to resolve it by name :-
var fileLog = container.Resolve("FileLoggerIoC", typeof(ILogger));
var DbLog = container.Resolve("DatabaseLoggerIoC", typeof(ILogger));
Mine method maybe not the best one as people don't like service locator to get the components, you can use this as temporary solution.
I have 2 projects
App (WindosForms used only as UI for starting components )
Components
Components has all interfaces and default implementation that I inject through StructureMap (Registry).
In this project i introduce a interface for Logging and default implementation for all classes (Log2Cnsole) and register with StructureMap.
What i need is that if some one wants to use his own UI app and remove default one I want that user of component DLL can override the default Log2Console with his, only if hi implement his (example LogToDB override Log2Console if he implement interface in his own project and register through StructureMap).
Sorry for my bad English.
The way to do this is offer a default constructor that calls another constructor with a specific implementation:
public interface ILogger
{
void Log(string text);
}
public class ConsoleLogger
{
public void Log(string text) { Console.WriteLine(text); }
}
public class TraceWriter
{
private ILogger log;
// Default behaviour
public TraceWriter () :
this(new ConsoleLogger()) { }
// User specified implementation
public TraceWriter ( ILogger logger )
{
this.log = logger;
}
}
Ultimately this has to do with setting up log4Net but generically the problem is not logging specific.
Generically what I am trying to figure out is how to do, in Microsoft Unity 2.0, something equivalent to what one gets with the Castle.Facilities.Logging.LoggingFacility. Namely the ability to declare a dependency on a logger and have the logger initialized with the Type of the object into which it is being injected.
In the spirit of a test is worth a thousand words, here is what I need:
class Logger_IOC_Tests
{
//[Test]
public void Logger_should_be_initialized_with_the_type_of_the_object_that_is_using_it()
{
var container = new UnityContainer();
/* Configuration Magic probably involiving registering either
* a custom IDependencyResolverPolicy or BuilderStrategy
* goes here...
*/
container.RegisterType<LoggerUser>(new ContainerControlledLifetimeManager());
var user = container.Resolve<LoggerUser>();
Assert.True(user.Logger.GetUserType() == user.GetType());
}
}
interface ILogger
{
Type GetUserType();
}
class Logger : ILogger
{
private readonly Type _type;
public Logger(Type type)
{
_type = type;
}
public Type GetUserType()
{
return _type;
}
}
class LoggerUser
{
public readonly ILogger Logger;
public LoggerUser(ILogger logger)
{
Logger = logger;
}
}
I don't know if this what you are looking for, but I saw it a few months ago and was reminded of it when I saw your question. I have not used Unity, so I can't really compare what you have posted with what is at the link. Hopefully it will be useful to you:
http://davidkeaveny.blogspot.com/2011/03/unity-and-log4net.html
I've been trying to achieve the same result of being able to insert correctly configured ILog instances into a dependency using constructor injection with Unity.
In the end, I wrote my own "log4net" unity extension to do exactly this (in part inspired by a blog post that another answerer, Kenneth Baltrinic, wrote).
This allows you to register the extension once with Unity:
var container = new UnityContainer();
container.AddNewExtension<Log4NetExtension>();
and then have the correct ILog logger instance passed in:
public class MyClass
{
private readonly ILog logger;
public MyClass(ILog logger)
{
this.logger = logger;
}
}
The extension can be found here:
https://github.com/roblevine/UnityLoggingExtensions
More info here: http://blog.roblevine.co.uk/net/using-log4net-with-unity/
EDIT this is now available as a NuGet package
After hours of digging around in the Unity source code, I came up with the following solution. However, I would prefer to find a way to set the appropriate dependency resolver based on the type being resolved rather than overriding the default constructor selector policy. For one, because I previously overrode the default constructor selector for other purposes. For another, this solution only handles dependencies that are injected via constructor. For full coverage one would have to override the default property and method selectors as well I presume. For myself, I only need constructors.
class Logger_IOC_Tests
{
[Test]
public void Logger_should_be_initialized_with_the_type_of_the_object_that_is_using_it()
{
var container = new UnityContainer();
container.AddNewExtension<LoggingExtension>();
container.RegisterType<LoggerUser>(new ContainerControlledLifetimeManager());
var user = container.Resolve<LoggerUser>();
Assert.True(user.Logger.GetUserType() == user.GetType());
}
}
class LoggingExtension : UnityContainerExtension
{
protected override void Initialize()
{
Context.Policies.SetDefault(typeof(IConstructorSelectorPolicy), new LoggingConstructorSelectorPolicy());
}
}
public class LoggingConstructorSelectorPolicy : DefaultUnityConstructorSelectorPolicy
{
protected override IDependencyResolverPolicy CreateResolver(ParameterInfo parameter)
{
return parameter.ParameterType == typeof(ILogger)
? new LoggerResolverPolicy(parameter.Member.DeclaringType)
: base.CreateResolver(parameter);
}
}
class LoggerResolverPolicy : IDependencyResolverPolicy
{
private readonly Type _dependantType;
public LoggerResolverPolicy(Type dependantType)
{
_dependantType = dependantType;
}
public object Resolve(IBuilderContext context)
{
return new Logger(_dependantType);
}
}
The above extension works well but more configuration information is needed for MVC5 users. Here are the steps using unity.
Add the following line to the top of your startup.cs class above the namespace.
[assembly: log4net.Config.XmlConfigurator(ConfigFile ="Web.config", Watch = true)]
In your global.asax application_startup method add the following information:
log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));
The rest of the configuration to the unity container should be as is:
container.AddNewExtension<Log4NetExtension>();
Ensure you have an appender added to your web.config. That should be about it to get this working correctly. Good Luck
With Unity 5 and above, you can now use Unity's own Log4Net extension from https://github.com/unitycontainer/log4net.
All you have to do is install the Nuget and add the extension to your container:
container.AddNewExtension<Log4NetExtension>();
And it will work automatically with any classes that use ILog as a dependency.
You can use the following code to inject Log4Net
log4net.Config.BasicConfigurator.Configure();
container.RegisterType<ILog>(new InjectionFactory(x => LogManager.GetLogger(typeof(Program))));
typeof(Program) is used since I'm registering in program class. Use can use the class name or this keyword
Then you can inject ILog into the class
public class MyClass
{
private readonly ILog logger;
public MyClass(ILog logger)
{
this.logger = logger;
}
}
I have an interface for logging the exceptions, i.e. IExceptionLogger.
This interface has 3 implementations: DBExceptionLogger, XMLExceptionLogger, CSVExceptionLogger.
I have an application that will make a use of DBExceptionLogger.
The application references only IExceptionLogger. How do I create an instance of DBExceptionLogger within the application.
I can't reference the DBExceptionLogger directly since it will break the purpose of having IExceptionLogger interface.
You should look at the concepts of inversion of control and dependency injection. These will help you to inject a particular instance of an object that implements your interface, with your code needing to be aware of exactly what it is beyond that fact. There are many libraries to help you in .NET: Unity, Spring.NET, Autofac, LinFu to name but a few.
//Usage of logger with factory
IExceptionLogger logger = ExceptionLoggerFactory.GetLogger();
public static class ExceptionLoggerFactory
{
public static IExceptionLogger GetLogger()
{
//logic to choose between the different exception loggers
//e.g.
if (someCondition)
return new DBExceptionLogger();
//else etc etc
}
}
You can use the Factory pattern (a class whose responsibility is creating an IExceptionLogger class), or more generally, an Inversion of Control framework.
IExceptionLogger logger = new DBExceptionLogger();
then pass logger variable to all your classes which write logging information.
you can use Poor Man's DI with a static factory like this:
public class ExceptionLoggerFactory
{
public static IExceptionLogger GetDBLogger()
{
return new DBExceptionLogger();
}
}
public class MyClass
{
private IExceptionLogger _logger;
public MyClass() : this(ExceptionLoggerFactory.GetDBLogger())
{
}
public MyClass(IExceptionLogger logger)
{
_logger = logger;
}
}