What's the point of a logging facade? [closed]
I will speak mainly from the perspective of using the abstraction to insulate application code from a particular logging framework. There are other factors that can affect one's choice of logging framework or one's choice of (and requirements for) an abstraction.
I have spent a lot of time recently evaluating various logging frameworks as well as third party logging abstractions.
Some people feel there is value in insulating their application code from a specific logging framework. You will find many posts here on SO like this and this and this(and there are more) where logging is discussed and many people take it as a matter of course that the logging framework should be wrapped/abstracted.
Obviously, this allows you to not be tied to a specific framework. Is this important? Will you ever really switch out your logging framework? Well, there are also plenty of people who either don't mention wrapping or those who recommend against it. If you look at some of the examples of logging framework wrapping code that has been posted here, you can also see many examples of why at least some people should not wrap their logging framework!
If you had started a project recently, you might have examined logging frameworks and, perhaps, narrowed it down to two finalists: log4net and NLog. Each has arguments in its favor. log4net is clearly a favorite, probably THE favorite of those who have expressed an opinion. NLog provides very similar capabilities. Judged by popularity, log4net might be the clear choice. Based on capabilities, they seem very similar. Based on "recent activity" (as indicated by checkins to their source code repostories by blog activity or lack thereor), NLog be the clear choice. If you had to pick a year ago, you might go with log4net since it would be the "safe" choice. It was not clear when NLog would release. In the year since, NLog has gone through a pretty signifcant development cycle, releasing a beta version just a few days ago.
Which to choose a year ago? Which to choose now? Was one a clearly better choice then? Is one the better choice now?
One thing an abstraction gets you is the ability to put off the decision of which one to choose (you don't necessarily even HAVE to choose EVER, although you probably want to if you plan to deliver the logging framework with your product). You can test drive one and then the other and get a feel for how they work with your application, with your team, in your environment. Using something like Common.Logging or SLF allows you start writing code now, coding to some logging interface/API, and getting your logging code in place. If you believe that the interface/API is provided by the abstraction is sufficient for your work (and, why wouldn't it be since it is essentially the same as the interface/API provided by log4net and NLog), then there is not much danger in using the abstraction. As you go through the development cycle, you might find that one framework or the other better suits your needs. Having coded to the abstraction, you are free to make that choice at any point, up until the time your product goes out the door.
You might even be thinking, in the back of your mind, that you could possibly write a logging library from scratch. Again, if you believe that the interface/API of log4net and/or NLog is sufficient, you might implement your logging library with a similar API. If you believe that, that might be another reason to use an abstraction. Again, you can start writing code (for your product, not your logging library) today, logging with some other logging framework until such time that your "from scratch" logging library is ready. Maybe you really want to use System.Diagnostics.TraceSource and Ukadc.Diagnostics (to get output formatting capabilities similar to log4net or NLog) so that you can get "better" integration with the logging that Microsoft has implemented in some of their platforms using TraceSources. It could be pretty easy to write a "logger" in terms of TraceSources and then write the abstraction so that you could plug it into Common.Logging or SLF. (If the interface/API is sufficient, you could just write your "logger" in terms of the abstraction library's interface and not have to write an additional abstraction layer).
With such persuasive arguments as these, why would anyone ever NOT use an abstraction? Ha ha, just kidding!
If an abstraction is good, should you write your own or use an existing one? If you write one on your own, then you obviously have to write it. How does one do this? Well, you might just define an interface and wrap one framework (be careful and wrap it correctly!). Later, if you decide you want to switch, wrap that framework. If you are careful, you don't have to change any application code, except for maybe the place where you actually create the underlying framework's objects. Maybe this is good. You have avoided a dependency on some third party abstraction for the "small" price of implementing a single wrapper over a single framework. However, there is a cost. Until you have written your abstraction you cannot really write a lot of application code that has logging in it, unless you have a good strategy for changing it over to your abstraction. It also becomes more difficult to test drive two or more frameworks to decide which works better for your. Each framework that you want to "try" requires another wrap job. If you want to switch among frameworks easily (at least during development cycle), you have work to do to make it easy. The third party frameworks provide this out of the box.
Wow! Now I'm sold! Give me logging abstraction, or give me death!
Are logging abstractions all gravy? Is there a downside? They can't THAT great, can they?
Well, as always, when "buying" something or when getting something free, you get what is available. Logging abstractions are no different. Neither Common.Logging nor SLF expose at least one very important set of capabilities of log4net/NLog - the logging context capabilities (GDC, MDC, NDC). These can be key to getting adequate information logged and formatted to enable you to get the most value from your. SLF does not provide a TraceSource abstraction. It also does not provide IsXXXEnabled functions. Common.Logging provides a TraceSource abstraction. Castle.Logging DOES expose GDC/MDC/NDC for log4net and NLog. It also provides a TraceSource abstraction. Castle's TraceSource abstraction also enhances TraceSource logging by providing a "hierarchical" naming capability, similar to that provided by log4net and NLog. It looks pretty cool!
Also, these projects are all opensource of one form or another. So, depending on the abstraction, the developers might have more or less of a vested interest in keeping it up to date and adding new features. Common.Logging has been through a few versions and is used, AFAIK, in Spring.Net. Seems reasonbly active, at least historically. Castle.Logging is used in the Castle framework. So, they apparently have "real" customers and are getting "real world" usage, which will hopefully drive more feature implementation. SLF, as far as I can tell, is not used as part of a "real" development platform, so it is hard to tell how much it is exercised.
It is not clear what the roadmap is for these platforms. Common.Logging has some upcoming features listed on their website, but not clear indication when they will be available. The website says "June", but of what year? How often is the mailing list monitored? For SLF, how often is their codeplex monitored? Where does the priority of these "free" projects rate compared to the developers' paying jobs? Can you afford for some third party abstraction to implement a feature that you need? Will they be receptive if you implement something and then submit it back for consideration to be included in the product?
On the plus side, all of the source for all of these abstractions is available, so you could just assume responsibility for it and make any fixes or add any enhancements that you which, without having to go through time and energy of creating an abstraction from scratch. Do you like Common.Logging but really want log4net/NLog GDC/MDC/NDC? Get Castle's implementation and add it to Common.Logging. Voila! A logging abstraction that contains nearly 100% of the log4net/NLog logging API. Do you prefer SLF but wish it had IsXXXEnabled? Not much work to implement that. Go ahead and tack on the GDC/MDC/NDC while you are at it. Do you like Castle? (I'm not that familiar with it, not sure how easy it is to use outside of Castle, if that matters) Be careful, I haven't used it, but looking at the source on git, it looks like the NLog logger abstraction might not retain call site info.
Is it ethical to take parts of multiple open source projects and combining them to make one "super" project (for your own or your company's use)? Is it bad to take Common.Logging and augment it with Castle's GDC/MDC/NDC implementation? I don't know. I'll let someone else answer that.
I'm nearly finished...
Some third party logging abstractions provide other capabilities. You might use a library that is implemented in terms of, say log4net. You might not want to use log4net, or at least might not want to be tied to it. Common.Logging (and maybe SLF) makes it relatively easy for you to capture the log4net logging messages and reroute them through the abstraction so they are captured in the abstraction's underlying logging framework's logging stream. SLF might provide something similar. Of course, you might be able to do something similar with existing logging frameworks, either out of the box or by writing a custom log4net Appender, NLog Target, or System.Diagnostics TraceListener. These features have not bubbled up very high in my particular evaluation of whether or not to use a third party logging abstraction on my project because I am mainly interested simply in the abstraction aspect.
So, where do I stand? I think that there is value in keeping your application code insulated from a specific logging framework. To me, Common.Logging looks like a solid choice of abstraction, although some important features are missing (GDC/MDC/NDC) and it is not Silverlight compatible. It would great of those features became available soon. I am comfortable with implementing GDC/MDC/NDC if I have to. Making it Silverlight compatible would probably take more effort, primarily because I am not particularly experienced with C#/.NET/Silverlight. Until those issues are ironed out, we would be able to write plenty of application code with Common.Logging in place. We can spend our time developing our application rather than developing yet another logging library or abstraction library. If we end up having to add those missing features ourselves, well, we would have had to do a lot of that if we had implementing a logging library or abstraction library ourselves.
I think what makes One (level of abstraction) the magic number here is that Zero is too few and Two is too many.
Swapping a logger behind a logger facade (number of levels: 1) can possibly result in some user benefit, such as the new logger can do something that the old logger can't. I can imagine that it could be performance, supporting certain types of appenders, etc.
It's much harder to imagine the user benefit from swapping a logger facade (number of levels: 2).
(And if the number of levels is 0, then it's probably just bad object-oriented design: you'll have thousands of places in your code where the logger is referenced and what if there's a breaking change in the next version of the logger.)
The deal with logger facades appears to be that you have to pick one of the third-party options or to create your own and prepare to stick with it for a long time.