Click here to Skip to main content
15,886,033 members
Articles / Web Development / ASP.NET

Automatic Logging with Policy Injection Application Block, Structure Map, and log4net

Rate me:
Please Sign up or sign in to vote.
4.71/5 (13 votes)
9 May 2010CPOL7 min read 60.1K   1.2K   50  
Log the entrance and exit of all methods in a project with minimal code clutter
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
using log4net;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;
using StructureMap;

namespace LoggingDemo.DependencyInjection
{
    [ConfigurationElementType(typeof(CustomCallHandlerData))]//this decorator is needed to make the call handler show up in the Configuration Manager tool
    public class MethodLoggingCallHandler : ICallHandler
    {
        public MethodLoggingCallHandler()
        {
        }

        /// <summary>
        /// Required by the interface, but we don't use the parameter
        /// </summary>
        /// <param name="ignore"></param>
        public MethodLoggingCallHandler(NameValueCollection ignore)
        {
        }


        /// <summary>
        /// NOTE: Only use Tag Attribute Matching Rule, do not use Custom Attribute Matching Rule, there is a confirmed bug in the Policy Injection block where this Invoke method will be called twice if you use Custom Attribute Matching Rule.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="getNext"></param>
        /// <returns></returns>
        public IMethodReturn Invoke(IMethodInvocation input,
                                    GetNextHandlerDelegate getNext)
        {
            ILog log = LogManager.GetLogger("MyLog");

            // Perform any pre-processing tasks required in the custom handler here.
            // This code executes before control passes to the next handler.
            log.Debug("Entering " + input.MethodBase.DeclaringType.FullName + "." + input.MethodBase.Name + "() Parameters: [" + GetParameters(input.Inputs) + "]");

            // Use the following line of code in any handler to invoke the next 
            // handler that the application block should execute. This code gets
            // the current return message that you must pass back to the caller:
            IMethodReturn result = getNext()(input, getNext);

            // Perform any post-processing tasks required in the custom handler here.
            // This code executes after the invocation of the target object method or
            // property accessor, and before control passes back to the previous
            // handler as the Invoke call stack unwinds. You can modify the return 
            // message if required.
            string returnValue;
            if (result.ReturnValue != null)
            {
                returnValue = GetObjectPropertiesString(result.ReturnValue, result.ReturnValue.GetType(), null);
            }
            else
            {
                returnValue = " None ";
            }
            log.Debug("Leaving " + input.MethodBase.DeclaringType.FullName + "." + input.MethodBase.Name + "() Return Value: [" + returnValue + "]");

            // Return the message to the calling code, which may be the previous 
            // handler or, if this is the first handler in the chain, the client.   
            return result;
        }

        public int Order { get; set; }

        private static string GetParameters(IParameterCollection parameters)
        {
            StringBuilder parameterString = new StringBuilder();

            if (parameters.Count == 0)
            {
                return " None ";
            }
            else
            {
                // foreach doesnt work with parameters collection, must use old fashioned for loop
                for (int i = 0; i < parameters.Count; i++)
                {
                    ParameterInfo parameter = parameters.GetParameterInfo(i);

                    parameterString.Append(
                        "[" +
                        GetObjectPropertiesString(parameters[i], parameter.ParameterType, parameter.Name) +
                        "]; ");
                }

                // remove last semicolon
                if (parameterString.Length > 0)
                {
                    parameterString.Remove(parameterString.Length - 2, 2);
                }

                return parameterString.ToString();
            }
        }

        /// <summary>
        /// Get the object's properties and their values
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="objectType"></param>
        /// <returns></returns>
        private static string GetObjectProperties(object obj, Type objectType)
        {
            StringBuilder propertiesString = new StringBuilder();
            PropertyInfo[] properties = objectType.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                propertiesString.Append("[(" + property.PropertyType.Name + ") "
                                        + property.Name + " = '" + property.GetValue(obj, null) + "'], ");
            }
            // remove last comma
            if (propertiesString.Length > 0)
            {
                propertiesString.Remove(propertiesString.Length - 2, 2);
            }

            return propertiesString.ToString();
        }

        private static string GetObjectPropertiesString(object obj, Type type, string objName)
        {
            if (obj != null)
            {
                StringBuilder propertyString = new StringBuilder();
                string objNameSegment = (objName != null) ? objName + " = " : "";
                if (Convert.GetTypeCode(obj) == TypeCode.Object && !(obj is IEnumerable))
                {
                    // if object, get all properties
                    propertyString.Append(
                        "(" + type.FullName + ") " + objNameSegment +
                        " Properties: [" + GetObjectProperties(obj, type) + "]");
                }
                else
                {
                    // for primitive types, just show the type and value
                    // for collection types, just show the collection type and item type (e.g. [(List`1)  'System.Collections.Generic.List`1[JCDCHelper.CV.DDLDispValueCV]'])
                    propertyString.Append(
                        "(" + type.Name + ") " + objNameSegment +
                        " '" + obj + "'");
                }

                return propertyString.ToString();
            }
            else
            {
                return " None ";
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions