I've been working on a library in C# and would like to offer capability for it automatically log all exceptions. Ideally, I'd like it to use log4net, thus allowing the client to configure the log however they like (i.e. they can redirect it to the EventLog or a database or what have you).
However, I would like to avoid having the logging dependency if they chose not to use the logging feature. Is this doable?
In other words, is there a way I can optionally have a log4net dependency, depending on what the client sets in config file?
The obvious answer is to use the System.Diagnostics.Trace subsystem with a custom TraceSource. That way you can set up, in the configuration file, any TraceListener you'd like, including log4net, EventLog, text files, Console, or XML files.
If you added a log4net TraceListener then the dependency would be loaded at runtime, and not compiled in. The Trace subsystem has become quite powerful since its inception, and I recommend you look into it.
You can use the tracing sub-system that is already built into .NET - it is configuration controlled.
I wouldn't add a dependency myself - simply emit messages through the tracing API - the client can decide how to log them if they so wish.
Personally I prefer the Log4Net API to that provided by System.Diagnostics.Trace.
So I have my own abstraction layer that uses a provider-model design pattern, and exposes an API similar to log4net. I can then plug in a log4net provider, but am free to replace it with a different provider (e.g. System.Diagnostics.Trace; EntLib) in the future.
The implementation is very similar to this one.
By doing this, applications have no direct dependency on the underlying logging provider, and you can easily switch to a different provider if you (or your customers) have other preferences.
Related
Currently depending on a library which utilizes the Castle.Core Logging abstraction. I've dug through both that library's docs, and Castle's, and can't seem to find clear explanation of how to capture log output to pipe to our logging framework of choice (NLog, in this instance). I've also dug through a few posts which touch on the topic, but dismissed as not applicable to this situation.
It should be noted that NLog works fine for the rest of the application. No errors seen in the internal logs. Just no output from this third party library.
I see the Castle.Core NLog integration, but that looks to be something to be utilized by the library depending on Castle, not one depending on the library.
So is it possible to capture log output from this library? Or do I need to reach out to the project for support?
If you own the process hosting the library, it is your responsibility to tell Castle.Core.Log which log provider to use.
Configure NLog in your application, then register NLog as the Castle Log Provider as explained in the documentation by calling
container.AddFacility<LoggingFacility>(f => f.LogUsing(LoggerImplementation.NLog) when creating your container
For your library (white) you should provide the logger factory by either setting it on the CoreAppXmlConfiguration instance, or supply your own subclass instance when initializing the library's Application object.
See https://github.com/TestStack/White/blob/master/src/TestStack.White/Configuration/CoreAppXmlConfiguration.cs#L53
I'm creating a logger for a company that has several types of .NET projects (Windows Services, ASP.NET, etc), and I was considering using log4net as my logger, but I don't want to be married to log4net, so I was thinking of wrapping it in my own assembly. I realize some developers don't recommend wrapping log4net because that would be an anti-pattern, but assuming I was going that route anyway, I had some questions:
I am planning to use the design principles mentioned in this article to design my wrapper (using factory method, interfaces, and reflection, I can simply decide which logger I want to use (whether log4net, elmah or something else) by specifying in the config file:
https://www.simple-talk.com/dotnet/.net-framework/designing-c-software-with-interfaces/
Question is:
Should I create this logger project in a separate Visual Studio solution and just use the dll in my client applications? If so, where would the configuration details for log4net go? Would that be supplied by the client application's config file? If so, is that good design? For instance, if I decided to switch away from log4net to a different logging framework, I would not only have to change the config setting to specify the new concrete logger's assembly/class name, but would also have to remove the log4net config entries (and perhaps add the new logger's config entries). Is this considered as an acceptable design approach?
Oh my goodness your timing is awesome. And that article is very relevant to me so thanks! I am doing this very same thing right now. I realized that log4net is a decent logger, but a terrible library for making a logger.
I agree with the article, in that you should not directly expose to log4net. Unless this is a small app it would be too difficult to switch later. And log4net is showing age so that may happen. I like the interface approach overall.
But, wrapping log4net it is a pain in the butt. So in doing my prototype wrapper I feel like I rewrote 50% of log4net, and discarded 25%. Some issues I found:
log4net will grab the "caller information" for you. Normally that is great. But if you wrap log4net, the caller information will point to your logger. So you will have to explicitly grab it yourself. But log4net doesn't provide a way for you to override the caller information. So now you will have to create your own fields for the caller's file, line number, class, and package. Thus, not only do you not gain the benefit here, but it is actually more work than just doing it yourself.
Log4net uses the old pre C#-4.0 method of grabbing the caller information which is slow.
Your will be unable to completely wrap log4net without wrapping the configuration. The caller has to configure the loggers either in code or in their app.config. If they do it in their app.config then they are putting log4net specific stuff in their app, so you failed to hide it with your wrapper. But if you have your wrapper code automatically perform the configuration, you just lost the flexibility of log4net. The third option is to make your own configuration, but then what good did log4net do for you? You just rewrote another piece of it.
You are stuck with the log levels that come with log4net. In our app, we want "categories" instead of "levels" which I then have to map to the log4net "levels" under the hood. Now, all the predefined log4net filters are of no use to me.
Anyone using your wrapper still has to reference log4net in their project anyway.
If your wrapper needs a way to handle errors, or pass them back to the caller, you will have trouble. log4net has its own internal error handling and you will need to hook into that and provide your own. Otherwise, errors (like a misconfigured appender) will just go out to the console. If it was designed as a library for making loggers, it would just throw the exception back up or provide a simple event.
One thing we wanted to get out of log4net is the ability to write to different outputs without us us having to write that code ourselves. Ex: I've never written to the event log, and I think log4net can do that. But it might be easier for me to rip out the Event logging code, rather than to try and wrap that. Same thing with filters.
There are some other problems I had with log4net that aren't directly related to trying to wrap it necessarily.
The code is old. The interfaces don't use generics where they should. Lots of object.
They use the old System.Collections collections. Similar to #1.
It has ifdefs for .NET 1 versus 2, and ifdefs for the obsolete compact framework. ugh.
It is designed to log strings, not structured objects. I made my own code to do so, and so did these people: http://stephenjamescode.blogspot.com/2014/01/logging-custom-objects-and-fields-with.html and http://element533.blogspot.com/2010/05/mapping-message-object-properties-to.html but this feels like basic functionality.
It doesn't support CSV and it is cumbersome to add. http://element533.blogspot.com/2010/05/writing-to-csv-using-log4net.html
It doesn't have any kind of logging "service"
It doesn't provide a way to read or parse the log.
I found it was more effort to configure the appenders than to write your own. Ex: I mapped a bunch of fields to the AdoNetAppender, but it would have taken me less time to just rewrite AdoNetAppender. Debugging a database field mapping in XML is harder than trying to debug the equivalent C# + ADO.NET code. The XML is more verbose and less type safe. This might be specific to me because I had a very structured set of data and a lot of fields.
Sorry for the really long post, I have lots and lots of thoughts on this topic. I don't really dislike log4net, I just think it is out of date and if you are wrapping it, you might be better off writing your own.
I am the author of a C# open-source wrapper for a 3rd party service. I need to expose an ILogger facility (such as https://logging.apache.org/log4net/release/sdk/log4net.Core.ILogger.html) to log specific events and errors.
I could just go on and add a major logger such as Log4Net, but I don't want the wrapper to be tied to a specific logger.
I could just add an IoC container to easily solve this with a constructor dependecy injection but then again I don't want my wrapper to be tied to any specific IoC.
On the other hand it would be great if I could somehow expose the logging events to the consuming app (which is the one responsible for logging anyway) with the wrapper being agnostic towards its consumer.
Any thoughts on how to achieve this?
Projects will often provide their own abstraction. A default logger is bundled so things work out of the box, but you can easily configure the logging provider, as seen in ServiceStack logging and NServiceBus logging. For example:
LogManager.LogFactory = new Log4NetFactory(true);
There is also Common.Logging, which was designed to address the logging framework dependency issue. However, I have not seen it used extensively in major open source projects even though it's been around a while.
I'm working on a project where I'm required to use Enterprise Library v.3.1.1.0 Logging block (wish it was log4net or nlog, but I don't get a choice). We have an IIS application where several WCF webservices are hosted, and they share a single web.config file. This is also something I'm not at liberty to change.
None of these services had any logging implemented previously.
So it's pretty straight forward to use the Ent Lib Config utility to set up a rolling flat file listener, and log to a text file the way I want. The problem I'm having is configuring it properly though so each service can have their own separate log file, while they still all share the same web.config.
I've gone through several tutorials, but I'm not understanding how to do this.
Any tips?
The configuration in the web.config is static so there will be one file per configured trace listener. One approach to achieve one file per service is to have each service log to a different category and each category uses a different trace listener. This could even be done programmatically so that services can add their own trace listener's at runtime although this is a bit more advanced than updating the configuration file manually (e.g. ensure service is added only once as well as ensuring that when the configuration is updated it is thread-safe).
Enterprise Library does not have anything analogous to log4net's hierarchical loggers so there is no out of the box way to use reflection to route log messages based on the originating class. It might be possible but you will have to write some code. You could write a Logger facade class to set the category based on the callers namespace. (Also note that there is no namespace wildcard matching like log4net.)
Using a configuration file I want to enable myself to turn on and off things like (third party) logging and using a cache in a C# website. The solution should not be restricted to logging and caching in particular but more general, so I can use it for other things as well.
I have a configuration xml file in which I can assert that logging and caching should be turned on or off (it could also be in the Web.Config, that's not the point right now) which will result in for example a bool logging and a bool caching that are true or false.
The question is about this part:
What I can do is prepend every logging/caching related statement with if (logging) and if (caching).
What is better way of programming this? Is there also a programming term for this kind of problem? Maybe attributes are also a way to go?
Why not just use the web.config and the System.Configuration functionality that already exists?
Your web app is going to parse web.config on every page load anyway, so the overhead involved in having yet another XML config file seems overkill when you can just define your own section on the existing configuration.
I'm curious what kind of logging/caching statements you have? If you have some class that is doing WriteLog or StoreCahce or whatever... why not just put the if(logging) in the WriteLog method. It seems like if you put all of your logging caching related methods into once class and that class knew whether logging/caching was on, then you could save your self a bunch of If statements at each instance.
You could check out the Microsoft Enterprise Library. It features stuff like logging and caching. The logging is made easy by the fact you always include the logging code but the actual logging beneath it is controlled by the settings.
http://msdn.microsoft.com/en-us/library/cc467894.aspx
You can find other cool stuff in the patterns and practices group.
Consult http://msdn.microsoft.com/en-us/library/ms178606.aspx for specifics regarding configuring cache.
I agree with foxxtrot, you want to use the web.config and add in a appsetting or two to hold the values.
Then for the implementation on checking, yes, simply use an if to see if you need to do the action. I highly recommend centralizing your logging classes to prevent duplication of code.
You could use a dependency injection container and have it load different logging and caching objects based on configuration. If you wanted to enable logging, you would specify an active Logging object/provider in config; if you wanted to then disable it, you could have the DI inject a "dummy" logging provider that did not log anything but returned right away.
I would lean toward a simpler design such as the one proposed by #foxxtrot, but runtime swapping out of utility components is one of the things that DI can do for you that is kind of nice.