LogCallHandler

Topics: Logging Application Block, Policy Injection Application Block, Pre-release discussions
Mar 16, 2010 at 8:56 PM
Edited Mar 16, 2010 at 8:57 PM

Hi,

I would like to configure my app to log before and after a every virtual method call. To do this I've configured my logging application block, registered my class for VirtualMethodInterception and PolicyInjection

_Container.RegisterType<TestLib.TestClass>(new Interceptor<VirtualMethodInterceptor>(),new InterceptionBehavior<PolicyInjectionBehavior>());

_TestClass = _Container.Resolve<TestLib.TestClass>();

I then add [LogCallHandler] above those virtual methods I want to write before and after to the log.

This is all working, but it does not write the method name to the log, just a line with all the default values. I have 2 questions about this.

1. Is it possible to move all of this to the app.config file in EntLib 5.0? I currently have Beta2, but haven't figured out how to do this. I was trying with Beta 1 as well.

2. Is it possible to configure the LogCallHandler to log the method name before and after without actually specifying in code. ie I want to write this ->

[

LogCallHandler] not this ->

[LogCallHandler(BeforeMessage = "Enter TestMethod", AfterMessage = "Exit TestMethod", IncludeParameters = true)]

thanks for any suggestions or links to samples. Remember I am using Ent Lib 5.0.

Beezler

 

Mar 17, 2010 at 7:32 AM

Hi,

Yes. Its possible. You would need to configure a policy in the policy injection app block section, add a matching rule of your choice and add a logging handler. To make the logging of the method name work, you would need to edit the formatter of the logging handler, to add Method Name: {property(MethodName)} . Here is a sample:

I have this interface and class:

    public interface IMockClass
    {
        string SayName(string name);
    }

 

    public class MockClass : IMockClass
    {
        public string SayName(string name)
        {
            return string.Format("Your name is : {0}", name);
        }
    }
 
Here is my client code:
 
        static void Main(string[] args)
        {
            IMockClass mock = PolicyInjection.Create<MockClass, IMockClass>();
            mock.SayName("MyName");
            Console.WriteLine("Done ...");
            Console.ReadLine();
        }
And my config:
 
<configuration>
    <configSections>
        <section name="policyInjection" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration.PolicyInjectionSettings, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.315.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
        <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.315.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    </configSections>
    <policyInjection>
        <policies>
            <add name="Default">
                <matchingRules>
                    <add type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.AssemblyMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=5.0.315.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                        match="EL5beta2piab" name="Assembly Matching Rule" />
                </matchingRules>
                <handlers>
                    <add type="Microsoft.Practices.EnterpriseLibrary.Logging.PolicyInjection.LogCallHandler, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.315.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                        beforeMessage="*** BEFORE {method} ***" afterMessage="*** AFTER {MethodName} ***"
                        includeCallStack="true" name="Logging Call Handler">
                        <categories>
                            <add name="General" />
                        </categories>
                    </add>
                </handlers>
            </add>
        </policies>
    </policyInjection>
    <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
        <listeners>
            <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.315.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.315.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                source="Enterprise Library Logging" formatter="Text Formatter"
                log="" machineName="." traceOutputOptions="None" />
        </listeners>
        <formatters>
            <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.315.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}&#xA;Method Name: {property(MethodName)}"
                name="Text Formatter" />
        </formatters>
        <categorySources>
            <add switchValue="All" name="General">
                <listeners>
                    <add name="Event Log Listener" />
                </listeners>
            </add>
        </categorySources>
        <specialSources>
            <allEvents switchValue="All" name="All Events" />
            <notProcessed switchValue="All" name="Unprocessed Category" />
            <errors switchValue="All" name="Logging Errors &amp; Warnings">
                <listeners>
                    <add name="Event Log Listener" />
                </listeners>
            </errors>
        </specialSources>
    </loggingConfiguration>
</configuration>

I could also send you my sample solution. Just send us a mail.

Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Mar 17, 2010 at 12:20 PM

Thank you very much. What I did was added the {property(MethodName)} to my formatter. Then I place [LogCallHandler] declaration above my class definition. This in conjunction with Registering my type provides the results I need. 

Jun 21, 2011 at 4:49 PM

Hi,

I'm trying to use {method} and {MethodName} as beforeMessage and afterMessage in EntLib 5.0.505 but looks like these tokens are not recognized.

I'm getting following output

21.06.2011 19:43:53 [ExecutionTrace, IUserRepository] 0 [752 ] Verbose     00000000-0000-0000-0000-000000000000    >> {method}
Extended Properties: email - @param

----------------------------------------
21.06.2011 19:43:53 [ExecutionTrace, IUserRepository] 0 [752 ] Verbose     00000000-0000-0000-0000-000000000000    << {MethodName}
Extended Properties: email - @param

Jun 21, 2011 at 5:08 PM

BTW, the same thing applied to CallTime. I cannot log it in AfterMessage.

below is my policyInjection//handlers section

        <handlers>
          <add type="Microsoft.Practices.EnterpriseLibrary.Logging.PolicyInjection.LogCallHandler, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            beforeMessage="enter" afterMessage="exit {CallTime} {property(CallTime)}" includeCallTime="true"
            priority="1" severity="Verbose" name="LogCallHandler">
            <categories>
              <add name="ExecutionTrace" />
              <add name="{type}" />
            </categories>
          </add>
        </handlers>

and log formatter section
      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        template="{timestamp(local)} [{category}] [TID:{win32ThreadId} {threadName}] {severity} {tab}{property(ActivityId)} {property(TypeName)}.{property(MethodName)} {message}{newline}Extended Properties: {dictionary({key} - {value}{newline})}"
        name="ExecutionTraceFormatter" />

 

Jun 22, 2011 at 1:21 AM

Hi,

Unfortunately, I wasn't able to reproduce your issue. Everything works fine at my side. If you don't mind, can you send a simple repro project at entlib.support@avanade.com?

 

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jul 17, 2011 at 12:20 PM

Hi,

 

Iam unable to create a log file using LogHandler. Here is the config.

 

<?xml version="1.0"?>
<configuration>
    <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=null" requirePermission="true" />
  </configSections>
  <!--<system.web>
    <compilation debug="true" targetFramework="4.0"/>
  </system.web>-->
    <system.diagnostics>
        <sources>
            <!--<source name="default" switchValue="All">
                <listeners>
                    <add name="file" initializeData="trace.log" traceOutputOptions="DateTime" type="System.Diagnostics.TextWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
                </listeners>
            </source>-->
        </sources>
    </system.diagnostics>
  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
    <listeners>
      <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=null"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=null"
        source="Enterprise Library Logging" formatter="Text Formatter"
        log="Log.log" machineName="." traceOutputOptions="None" />
    </listeners>
    <formatters>
      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=null"
        template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}&#xA;Method Name: {property(MethodName)}"
        name="Text Formatter" />
    </formatters>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="Event Log Listener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events" />
      <notProcessed switchValue="All" name="Unprocessed Category" />
      <errors switchValue="All" name="Logging Errors &amp; Warnings">
        <listeners>
          <add name="Event Log Listener" />
        </listeners>
      </errors>
    </specialSources>
  </loggingConfiguration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>

  <system.serviceModel>
       
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
     
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
    <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
    <namespace name="Logging" />
    <namespace name="testme" />
    <assembly name="JSONOrderService"/>
    <namespace name="JSONOrderService" />
    <assembly name="CoreService"/>
    <namespace name="OrderRoutingService" />
      <assembly name="JSONOrder"/>
    <namespace name="JSONOrder" />
   
        <container>
            <extension type="Interception"/>


      <!--<register type="Itestme" mapTo="testme" >
        <interceptor type="TransparentProxyInterceptor"/>
        <policyInjection/>
      </register>-->
     
      <register type="IOrder" mapTo="JSONOrderService" >
        <interceptor type="TransparentProxyInterceptor"/>
        <policyInjection/>
      </register>
     
      <interception>
       
       
      
        <!--<policy name="Logging">
          <matchingRule name="MatchService" type="NamespaceMatchingRule">
            <constructor>
              <param name="namespaceName"  value="testme" />
            </constructor>
          </matchingRule>
          <callHandler type="Logging.Log, JSONOrderService" name="Log">
            <constructor>
              --><!--<param name="Log" value="Service"/>--><!--
            </constructor>
          </callHandler>
        </policy>-->
        <policy name="Logging123">
          <matchingRule name="MatchService" type="NamespaceMatchingRule">
            <constructor>
              <param name="namespaceName"  value="JSONOrderService" />
            </constructor>
          </matchingRule>
          <!--<callHandler type="Logging.Log, JSONOrderService" name="Log">
        
            --><!--<constructor>
              <param name="Log" value="Service"/>
            </constructor>--><!--
          </callHandler>-->
          <callHandler type="Microsoft.Practices.EnterpriseLibrary.Logging.PolicyInjection.LogCallHandler, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=null"
         name="Logging Call Handler">
            <constructor>
              <param name="logWriter" />
              <param name="eventId" value="200" />
              <param name="logBeforeCall" value="false" />
              <param name="logAfterCall" value="true" />
              <param name="beforeMessage" value="method call started" />
              <param name="afterMessage" value="Method call completed" />
              <param name="includeParameters" value="true" />
              <param name="includeCallStack" value="true" />
              <param name="includeCallTime" value="true" />
              <param name="priority" value="-1" />
            </constructor>
          </callHandler>
         
        </policy>
      </interception>
        </container>
    </unity>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
 
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="Microsoft.Practices.Unity" publicKeyToken="31BF3856AD364E35" culture="neutral"/>
                <bindingRedirect oldVersion="0.0.0.0-2.0.414.0" newVersion="2.0.414.0"/>
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
</configuration>

Jul 18, 2011 at 2:20 AM

Hi,

You need to specify which category in Logging Settings the Log Call Handler will have to use. You need to add the property "Categories" to the config file. Since it accepts a collection of strings, you need create a type converter. Here is a sample code taken from this thread:

<property name="Categories">
         <value value="General, File" typeConverter="StringToListConverter" />
</property>

Sample code for the custom converter:

public class StringToListConverter : TypeConverter
{

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value != null)
            {
                string configValues = value.ToString();
                if (!string.IsNullOrEmpty(configValues))
                {
                    string[] categories = configValues.Split(',');
                    return categories.ToList();
                }
            }
            return new List<string>();
        }

}

 

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com