-
Notifications
You must be signed in to change notification settings - Fork 11
Logging attributes
The Log attribute described here uses Castle Interceptors. You need to setup your application to use Contrib's Castle Windsor facilities before proceeding.
You will need to reference the following DLLs in any project that uses Log attribute:
SharpArchContrib.Castle.dll
Configurable diagnostic logging is one of those things that is very nice to have in your application. You don't use it all the time but when you face that oddball problem, especially in production, it sure is nice to be able to turn it on and figure out what is happening. Typically, you end up scattering code like the following where you assume it might be useful someday:
ILog logger = LogManager.GetLogger(this.GetType());
logger.Debug(string.format("Entering method x(parm1: {0}, parm2: {1}", parm1, parm2));
try {
<Application code>
logger.Debug(string.format("Exiting method x. Return {0}", returnValue));
catch (Exception err) {
logger.Error("Method x threw exception", err);
throw;
}
You probably follow the DRY principal and move the logging into a static helper method of some kind, but you still have to put it everywhere you think you'll need it. It clutters up the code and it is pretty difficult to put it everywhere you might actually need it in the future.
This is exactly the kind of scenario AOP was designed to solve. You really need logging everywhere but you do not want to go through the trouble of putting it everywhere in your code.
The easiest way to get started is to set up logging at the assembly level as outlined in the following steps:
-
Configure log4net The logging featues uses log4net. You will need to setup your application configuration file to work with log4net. Here's a simple example that sets up your application to log to a file. Note that the log level is set to the ERROR level:
<configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/> </configSections> <log4net> <appender name="LogToFile" type="log4net.Appender.FileAppender"> <file value="<Filename for Your Log>"/> <appendToFile value="false"/> <layout type="log4net.Layout.PatternLayout"> <!-- You can change the pattern to include caller information and other stuff. Do an Internet search on log4net pattern layout for more information. --> <conversionPattern value="%n%d %-5level %logger%n%m%n"/> </layout> </appender> <root> <!-- Value of priority may be ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF --> <level value="ERROR"/> <appender-ref ref="LogToFile"/> </root> </configuration>
-
Place Log Attribute in Assembly Place the following in a CommonAssemblyInfo.cs or some other file that is shared across all the projects in your solution that you want to have logging:
using System.Reflection; using log4net.Config; using log4net.Core; using SharpArchContrib.Core.Logging; using SharpArchContrib.PostSharp.Logging; <other assembly-level attributes such as AssemblyCompany and AssemblyCopyright (if using CommonAssemblyInfo.cs)> [assembly: Log(EntryLevel = LoggingLevel.Debug, SuccessLevel = LoggingLevel.Debug, ExceptionLevel = LoggingLevel.Error)] [assembly: XmlConfigurator(Watch = true)]
In this example, logging is enabled for all builds. Method entry, including the parameters passed to the method, will be logged if the logging level is at least DEBUG. The logger will write another log entry that includes the return value when the method exits if the logging level is at least DEBUG. Exceptions will be logged as long as the logging level is at least ERROR.
The levels shown in the example above are set by default. Therefore, the following code is equivalent:
using System.Reflection; using log4net.Config; using log4net.Core; using SharpArchContrib.Core.Logging; using SharpArchContrib.Castle.Logging; <other assembly-level attributes such as AssemblyCompany and AssemblyCopyright (if using CommonAssemblyInfo.cs> [assembly: Log()] [assembly: XmlConfigurator(Watch = true)]
Note also the use of the XmlConfigurator attribute to configure log4net based on the configuration found in the application configuration file. This is the easiest way to make sure log4net reads its configuration at application start up. If you configure log4net through code, you will want to do it as early as possible so that logging will work for all of the methods in your application.
The Log attribute may also be placed at the class level (sets logging for all methods in the class) or at the method level.
There is very little impact on the application when the log level is set such that nothing is logged. However, when you turn up the log level there is a significant overhead to logging. The amount of overhead will depend on the number of method calls logged and the logger. The file logger in log4net is quite fast. The trace logger is very slow.
If you place logging at the assembly level and also at the method level, the calls may be logged twice. Logging uses Castle Interceptors, so only methods that can be intercepted will be logged.
The ExceptionHandler attribute logs only exceptions. It also has optional parameters that allow you to catch the exception automatically and pass back a default return value when an exception occurs. For example, the following will log the exception, will not re-raise it and will cause the method to return false:
[Exception(IsSilent = true, ReturnValue = false)]
public bool DoIt() {
//do some stuff that could fail
return true;
}
It is most likely that you will place ExceptionHandler attributes at the method level. You may also place this attribute at the assembly or class levels.