|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
Introduction:XQuiSoft Logging is an open source component for logging support in .net applications. It is part of the XQuiSoft application framework, which is entirely open source. It goes beyond what can be done in the built in .net framework http://sourceforge.net/projects/xqs-logging This logging component has a dependency on two other open source projects in the xquisoft framework. The xquisoft provider component is the first. It is basically an implementation of the provider pattern for the 1.1 framework similar to that in the 2.0 framework. The second is the xquisoft data component, used for database abstraction. This component is only required if you use the DbLogProvider. These two open source projects can be found at: http://sourceforge.net/projects/xqs-provider The documentation is available on XQuiSoft Developer Network (xqsdn). Use the index page to find help on any of the class names http://www.xquisoft.com/xqsdn/documentation/index.html Demo Code Notice:When you unzip the demo project you'll need to do one of two things.
On my test machine I had the solution in a working folder on my C:\ drive which I use for all projects. Then when I added the web projects they were added to inetpub\wwwroot. That made it a little hard to zip the solution. Basic Features:Ease of use: All you have to do to write a message to the log is call a single static method on the Extensibility: The logging component is based on the provider pattern. This means that the Multiple configuration methods: You can configure your application to use logging in two ways. The first is to create a configuration section in your application configuration file. The section would define the logger(s) to use, and any filters to apply to the logger(s). The second method is to initialize a new logger and add it to the Log's provider collection at run time. you can also configure the log provider at any point in the application life cycle, or remove a logger from the main Stability: The Flexibly filtering: The filtering is also based on the provider pattern. There is a base Composition: Logs can be configured to have child loggers. For example the Event makeup: A single log event consists of a Level, Source, Category, Message, Details, and Timestamp. The level is an integer scale of importance. There are built in levels named as Error(256), Warning(512), Info(1024), and Verbose(2048). You can use those levels or make up custom levels in between those levels. The source is who invoke the message. Category is what it seems, a way for the source to categorize one message over another. message and details are informational fields of differing length. Note, filters can be based on any of these fields. Performant: The framework itself does not slow down an application to any noticable effect. The overhead is in the required operations to write to the destination datasource. For instance, Writing to a file has the overhead of opening and closing a file. However, with a combination of the Built in LogProviders:
If the Built in Filters:
All filters can be configured to be either
Why use XQuiSoft Logging instead of log4net, Nspring, and enterprise library?These other logging frameworks are satisfactory. If you are using one of these frameworks in an application you may not want to switch. However, I belive that you write less code using the xquisoft logging component. So on your next project take the following into consideration. Here are a few points of differentiation that I have noticed. If you find that any of this is incorrect, please let me know and I will correct the article. Are the others hard to use? No. But they aren't all AS easy to use. Take for instance NSpring. I didn't see anywhere in NSpring that you can create a logging configuration. You also have to instantiate a logger in your application, open it, write to it, and then close it. Why do you have to do so much work? If you write a component for others to use, and you want to log something how do you know what your client(s) wants to log to? Do you have them pass a logger to you? That just sucks. NSpring code:Logger log = Logger.CreateConsoleLogger(); log.Open(); log.Log("my message", "my category"); log.Close(); In log4Net, you apparently have two options. You either have to know the name of the destination logger, or you have to get it based on reflection. Log4net (option 1):ILog Log = LogManager.GetLogger("BufferingForwardingAppender"); Log.Debug("Test log message"); Log4net (option 2): private static readonly ILog Log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); Log.Debug("Test log message"); In XQuiSoft you just need one line. The Log class has all static methods, and each is delegated to the providers as configured. Enterprise library is very similar in usage from your code. XQuiSoft Logging: Enterprise library: Logger.Write("Message To Log", "Category Name", 0); // 0 is the message level, you can also use an enum All of these logging packages are extensible. They all give you an abstract base class to derive from. The base class offers overloads that call another abstract method overload that must be implemented in your custom provider. XQuiSoft refers to them as "providers", nspring refers to them as "loggers", log4net refers to them as "appenders", and enterprise library refers to them as "sinks". Finally, I tested the relative performance of each logging package. I created a single solution. Each test was contained in it's own web project so that test results would not be affected by one log packages configuration and/or memory overhead. Each project contained a single web page that does not display anything, but the Page_Load method enters something into the log. Another web application that does nothing is also included as a baseline of maximum performance. Then I used Microsoft Application Center Test for load testing. I simulated 30 simultaneous browser connections, a 5 second warm up time, and a duration of 5 minutes. here are the results of each test, with the most performant at the top:
Oddly, the xquisoft file logger was the fastest possible way to log. The reason it is faster than the xquisoft console logger is that the console logger was not sent through a buffer. But I don't think buffering a write to the console would improve speed since each Console.Write does not open a resource, or if it did there is no way to request that it stays open between calls. I used a The log4net file logger actually was buffered, although it appeared as if it wasn't. I used a BufferingForwardingAppender with size 100, that wrote to a RollingFileAppender. So it should have tried to keep the file open for a series of 100 events at a time. however, when I look at the MACT test the graph does not show low points at a regular interval to indicate that the buffer worked that well. I cannot explain how the nspring file logger was faster than both the nspring console logger and the log4net file logger. Overall the nspring loggers had very erractic performance levels according to the MACT test result graph. It may be because the nspring logger does not support configuration files, and I had to recreate a logger on each page_load. Much of the overhead can be attributed to not being able to cache instances of a logger between page calls. If anyone can update my test code with an improved usage of nspring, please let me know. I did not run the performance tests the enterprise library for a few reasons. First, I couldn't get them to run. Apparently you can't just xcopy the ent lib dll's and use them. You have to install the performance counters. An error on the web page is related to performace counters, and not being able to open the registry. In order to disable them you have to edit and recompile the library! Why can't they just supply a config setting to not attempt writing to the performance counter? I didn't want to bother with all that. The second reason I didn't test it is because there are already performance comparisions between log4net and ent lib which show that ent lib is much slower than log4net. XQuiSoft Logging is faster than log4net, so that makes XQuiSoft Logging faster than ent lib. Microsoft Enterprise Library Logging Block compared to Log4net follow up (Loren Halvorson) Exception Handling:As of June 12th a new version of the Logging component has been released. The earlier version initialily took a different approach to exception handling. First, I generally have two major rules in exeption handling 1) don't swallow and ignore exceptions! Always report it either to a log, and/or to the application user. The only 'exception' (pun intended) to this rule is if you can successfully mitigate the problem. For instance, maybe you have fallback logic to try if the first method does not work. 2) Don't catch and propagate exceptions that you do not have explicit logic to handle. No catch (Exception ex){}. This rule applies to data and business layers in an application, and also to standalone components. The only time you should catch Exception is in the Application_Exception or equivalent. You catch it at this top level to prevent an all-out crash. This handler usually log's the problem and displays a warning to the user. In the logging component (pre 1.5) an exception in logging swallowed the exception if logging failed. My reasoning was that a failure in logging should not crash your application. The business layer exception that occured is really what you'll display to the user. To handle exceptions in loggers the component has always supplied a property on the base LogProvider called ExceptionProviderName. It determines the name of a backup logger to send exceptions from the main logger. You can 'chain' failover loggers ending with a logger that should never fail, maybe the system log. However, if the final logger failed, it was ignored. I've re-considered this position to align with my exception handling rule #1. Now the final logger in the chain will throw a LogException to the caller of the logging component. However, if an attempt is made to log a LogException it is ignored, since if it was possible to ignore it would have been logged already. This prevents an endless loop of exceptions being thrown. If you still want to ignore logging exceptions you can. Create a new LogProvider that does nothing, and make it the last logger in your exception chain. Don't swallow LogExceptions in your app code. That way you can configure the last log exception failover to be a DebugLogProvider and have the page output the fatal logging error without having to remove that exception swallow code.. Conclusion:I've covered the basics features and usage of the XQuiSoft Logging component. I've also compared XQuiSoft Logging to the other major logging components / frameworks on the market. From what I have seen, XQuiSoft Logging is a much better component. But then again I am biased since I wrote XQuiSoft Logging. I would like to see others make a similar comparision and see what the results are? If you already extensively use another logging component are are very happy with it, then keep using it. However, if you start a new project, consider the benefits of XQuiSoft Logging over the others. Evaluate it, and see if it fits into your toolbox. History:April 19, 2006: Initial submission of article. June 12, 2006: Added new exception handling policy. Updated to component version 1.5.5000.0. Get it from source forge. The sample code was not updated since no API changes were made.
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||