My solutions has several projects which includes several libraries and one project for UI. Currently it is a windows forms application and I use log4net for logging. This UI project has only reference to log4net and this project maintains the configuration files. But I would like to log from my libraries as well.
Usual method for doing this is to wrap the logging calls behind an interface. Create a common project something called utilities and add this interface to this project. Now this project can be used in all the projects and can use this interface for logging.
I am thinking about an alternative design which involves passing delegates and reducing coupling and avoiding unnecessary interfaces.
Consider following class is one from my library.
public sealed class Foo
{
Action<string> log;
Action<string, Exception> logException;
public Foo(Action<string> log, Action<string,Exception> logException)
{
this.log = log;
this.logException = logException;
}
public void Work()
{
WL("Starting work");
WL("Completed step1");
.........
}
void WL(string message)
{
if(log != null) log(message);
}
void WL(string message, Exception exception)
{
if(logException != null) logException(message, exception);
}
}
Now from the calling code, I can easily pass the logging method. Something like
Foo foo = new Foo(message => Console.WriteLine(message),
(message, exception) => Console.WriteLine("{0},{1}", message, exception));
foo.Work();
Used a console for explaining, in reality I will use the logging code here.
1 - Do you think this as a better solution? I think this is better as this is more loosely coupled.
2 - Is there any other better solutions available?
This is the only related question I have found here
Any thoughts...?
Don't use delegates if there are multiple signatures flying in close formation. All you're doing is avoiding defining classes and interfaces that would be meaningful. log4net provides an ILog interface which is an excellent example of a simple wrapper interface you can pass in.
If you're going to use a logging framework, especially log4net, don't wrap it and don't create a single global (static OR singleton) entry point. I've written about this before, and you may be interested in the question about best practices as well.
I have a thin layer that exposes a logging API very similar to Log4Net, that uses a provider-model design pattern to allow you to plug in any suitable logging framework. I've implemented providers for:
System.Diagnostics.Trace
log4net
EntLib
This means I can use logging throughout all my apps without any direct dependency on a specific logging framework, and users of my components can plug in their own favorite logging framework.
My advice is to add a reference to log4net to all your projects but leave the logger configuration in the UI project. This still leaves you with the flexibility to define different logging levels on a per assembly basis. Logging is such a low level activity and log4net is such a mature product that I wouldn't spend any time trying to come up with a clever solution just to satisfy "best practices". I might even argue, over a beer or two, that referencing log4net is no different than referencing System.Core.
Unless you have different pieces of code using different logging frameworks, I'd have a singleton LogDispatcher or something similar that all code which would try and log would call into, perhaps passing in a message level to determine the correct logging method. This prevents the delegates for logging from needing to be passed around the entire codebase, and centralizes all of the code which is responsible for the logging policy.
Another approach is to use a framework like Log4Net. Even if you don't end up using it, their design is a good one to base your own logging on.
Google for "AOP logging".
Here's some chat about this from Ayende.
Quoting Jon S. "Simple is almost always better than clever" - IMHO your use of delegates looks more of the latter.
If you want the library projects to log, they should setup-and-use their own logger. I'd not ask clients to pass in a logger (object or interface) - which then travels all the way deep down the type dependency graph. It just pollutes the interface a bit with unnecessary logger object/interface/delegate etc. parameters.
If you're using Log4XXX frameworks, I believe it emphasises the concept of "hierarchical logging architecture" (the names they come up with in s/w ;), where each type/class can maintain and write to its own log file. If the ctor of Foo creates a logger internally, I'd like that. And since it is configurable, specific clients may change the configuration files to redirect the output elsewhere too.
So your problem is one I will soon have to commit to a solution for. The defacto answer is "Use Injection" but in this case it's less inversion of control and more expansion of dependencies. I think your close, so here are my thoughts.
The Pros of your solution
There is no need for additional references by your class or the assembly it's in. Because your using Actions with common types, those references are likely already present.
The benefit of that is that is that 100% of the implementation of logging is left to the assembly that injects your actions. So if you add log4Net of nLog the only reference to it will be where it is implemented. So if you wanted switch later, only that assembly would have to be updated.
The converse of that is if you just inject a chosen logger into each class. That means you have to add a reference in every project to the logger. Even if the interfaces are named and implemented the same, you have to have the reference for it to resolve. In solutions where you have more than 3 projects that can be costly, and you have the same cost any time you would switch loggers.
Possible Improvement
In that lies the beauty of your solution. However it could be improved. I find that when injecting things of similar function or "aspect" it can make sense to put them into an object and inject that instead. You could create interface with both of your actions and inject concretes that implement whatever library you want. This would, again, leave the only reference to the logging library to one project/assembly with only the cost of having to add a reference to your interface to the rest.
Hope this helps and good luck.
Related
In my app I'm creating an auditing package that obtains various information, one such type of information should provide different information regarding what method is executed (time it took to execute, method name, method class, assembly, etc).
I'm not looking to use an existing package or framework, but to create my own.
I can imagine that this is a complicated thing to do, but I'm looking for some pointers to get me started .
One option you may be interested in is DI-level interception. Since container is responsible for your objects instantiation, sometimes it can be configured with proxy generators to enable call interception.
You can choose between Autofac, or Unity.
The most popular tasks to solve with this approach are cross-cutting concerns, like: logging, measurements, run-time application structure analysis. If you don't want to pollute your code base with repetitive diagnostic code, just delegate this task to an interceptor.
Similiar idea is AOP. I havn't seen popular AOP packages for a long time, and havn't used them, but it's worth to do a research on this topic too:
What is the best implementation for AOP in .Net?
DI Interception vs. AOP
I am facing the challenge of logging implementation in my C# class library, which is a domain model. My main goal is to keep logging functionality as canonical and decoupled as possible. Usually logging messages will be written to files, and perhaps output window while debugging.
Currently I use log4net, and I have written a static Logger class which implements the logging methods themselves. So, when methods in the domain objects are executed, they call static Logger.Log() methods.
While this wrapping is enough to sooth my purity urges, I wonder if it would be a good idea to implement all this logging calls via events, and remove logging implementation details from the class library altogether. Then, client code would optionally listen to them and extract useful information from some LogEventArgs.
So the question is:
Event-based logging in general, and specifically in class libraries, is a good idea or not? And why?
Thanks for reading.
Using events for logging also introduces a lot of memory leak possibilities!
I would use Dependency Injection for cross cutting concerns like logging.
With DI you have the possibility to either inject it, or use interception.
I've got to the point in my design, where I am seriously considering a singleton.
As we all know, the "common" argument is "Never do it! It's terrible!", as if we'd littered our code with a bunch of goto statements.
ServiceStack is a wonderful framework. Myself and my team are sold on it, and we have a complicated web-service based infrastructure to implement. I have been encouraging an asynchronous design, and where possible - using SendAsync on the service-stack clients.
Given we have all these different systems doing different things, it occurred to me I'd like to have a common logger, (A web service in itself actually, with a fall-back to a local text file if the web service is not available - e.g. some demons are stalking the building). Whilst I am a big fan of Dependency Injection, it doesn't seem clean (at least, to me) to be passing a reference to a "use this logger client" to every single asynchronous request.
Given that ServiceStack's failure signature is a Func<TRESPONSE, Exception> (and I have no fault with this), I am not even sure that if the enclosing method that made the call in the first place would have a valid handle.
However, if we had a singleton logger at this point, it doesn't matter where we are in the world, what thread we are on, and what part of a myriad of anonymous functions we are in.
Is this an accepted valid case, or is it a non-argument - down with singletons?
Logging is one of the areas which makes sense to be a singleton, it should never have any side-effects to your code and you will almost always want the same logger to be used globally. The primary thing you should be concerned with when using Singletons is ThreadSafety, which in the case of most Loggers, they're ThreadSafe by default.
ServiceStack's Logging API allows you to both provide a substitutable Logging implementation by configuring it globally on App_Start with:
LogManager.LogFactory = new Log4NetFactory(configureLog4Net:true);
After this point every class now has access to Log4Net's logger defined in the Factory above:
class Any
{
static ILog log = LogManager.GetLogger(typeof(Any));
}
In all Test projects I prefer everything to be logged to the Console, so I just need to set it once with:
LogManager.LogFactory = new ConsoleLogFactory();
By default ServiceStack.Logging, logs to a benign NullLogger which ignores each log entry.
There's only one problem with classic implementation of a singleton -
it is easily accessible, and provokes direct use, which leads to strong coupling,
god objects, etc.
under classic implementation I mean this:
class Singleton
{
public static readonly Singleton Instance = new Singleton();
private Singleton(){}
public void Foo(){}
public void Bar(){}
}
If you use singleton only in terms of an object lifecycle strategy,
and let IoC framework manage this for you, maintaining loose coupling -
there is nothing wrong with having 'just one' instance of a class
for entire lifetime of application, as long as you make sure it is thread-safe.
If you are placing that common logging behind a static facade that application code calls, ask yourself how you would actually unit test that code. This is a problem that Dependency Injection tries to solve, but you are reintroducing it by letting application logic depend on a static class.
There are two other problems you might be having. To question I have for you is: Are you sure you don't log too much, and are you sure you aren't violating the SOLID principles.
I've written an SO answer a year back that discusses those two questions. I advice you to read it.
As always, I prefer to have a factory. This way I can change the implementation in future and maintain the client contract.
You could say that singleton's implmenentation could also change but factories are just more general. For example, the factory could implement arbitrary lifetime policy and change this policy over time or according to your needs. On the other hand, while this is technically possible to implement different lifetime policies for a singleton, what you get then should probably not be considered a "singleton" but rather a "singleton with specific lifetime policy". And this is probably just as bad as it sounds.
Whenever I am to use a singleton, I first consider a factory and most of the times, the factory just wins over singleton. If you really don't like factories, create a static class - a stateless class with static methods only. Chances are, you just don't need an object, just a set of methods.
I'm using Log4Net to handle logging in my WPF application.
Currently, the logger is configured with the rest of the front-end code. I have to pass a reference to the Service layer and the Repository layer if I want to be able to use the logger in these layers (I'll actually be using StructureMap for this). This means the back-end has a dependency on the front-end and I don't like that.
I'm wondering how best to handle this? Should I configure the logger in the Repository layer?
log4net LogManager.GetLogger(string name) will return an existing logger instance if it has already been created (e.g., in another layer), so there is no need to pass logger objects around.
You do need to be aware of multiple threads/processes trying to write to the same log file at the same time. You can use the log4net MinimalLock, or try this third party solution. Neither is ideal (the codeproject one is inefficient and still hits concurrency problems). I have ended up writing my own (which unfortunately is not publicly available).
Logging is a common cross-cutting concern that I have seen handled in several different ways. The simplest method is to create a static class that lives in a common assembly that is shared by all the layers.
However, since you are using StructureMap for your IoC, a better solution would be to configure StructureMap to inject your logger class (which might be configured as a singleton, depending on your needs) into each instance created. I personally prefer property injection for such cross-cutting concern classes, so that constructors don't get cluttered, but that's a matter of preference.
I have an .net assembly at C#. I have both: binary and source which has no logger, for example.
All I need is to insert property which will be initialised specific logger. Then I need to introduce logger invoker in all methods. The first way - is manually write property and their invokes. And the second way - is to write another class\method (I suppose in the same assembly) which will do it automatically.
Is it possible? Any suggestions?
I think it is possible, cause it was one of the questions at the interview. But there is no proof that this is possible, and they wanted to hear "no, do this manually".
This is what we call in architectural terms a 'cross cutting concern'. Logging is something that straddles many aspects of an application.
There are features to take care of it in the Microsoft Enterprise Library. The part you want is the Policy Injection library. You can then specify, in the config, methods to match (based on method name/structure) and a function to be called. In this way you can include logging as a proper cross-cutting concern of your app, rather than something which must be manually coded into every method.
It is not possible to alter the execution of a method without altering the source code and recompiling. You could write a wrapper class that would expose all classes and methods which would first call your logger and then the methods, but that's not what they asked.
So the answer to their question is 1. is possible, 2. isn't possible, and if you would have to add logging support, you would need to add it to each method manually.