jueves, 17 de mayo de 2012

Fichero de Log Asíncrono

Hablando con algunos compañeros de trabajo, estábamos debatiendo sobre emplear ficheros de log. Soy firme defensor de ello, porque ante un error en producción, hay que conocer el porqué del fallo. El problema que nos encontrábamos era que al hacer uso de ficheros de log, la fvelocidad, disminuía muchísmo. así que buscando un poco he pensado que una buena solución es generar los ficheros de log de forma asíncrona. Se emplean las EnterPriseLibrary, porque para qué reinventar la rueda, por lo tanto no hay que olvidar la .dll.

using Microsoft.Practices.EnterpriseLibrary.Logging;

namespace ClassLibrary1
{
    public class Log
    {
        delegate void WriteLogDelegate(string message);

        public static void WriteLog(string message)
        {
            WriteLogDelegate logDelegate = new WriteLogDelegate(AsyncWriteLog);
            AsyncHelper.FireAndForget(logDelegate, message);
        }

        static void AsyncWriteLog(string message)
        {
            LogEntry log = new LogEntry();
            log.Message = message;

            Logger.Write(log);
        }      
      
    }
}
using System;

namespace ClassLibrary1
{
    /// <summary>
    /// This is asynchronous helper class from Jon Skeet
    /// http://www.yoda.arachsys.com/csharp/threads/threadpool.shtml
    /// </summary>
    public class AsyncHelper
    {
        /// <summary>
        /// Delegate to wrap another delegate and its arguments
        /// </summary>
        delegate void DelegateWrapper(Delegate d, object[] args);

        /// <summary>
        /// An instance of DelegateWrapper which calls InvokeWrappedDelegate,
        /// which in turn calls the DynamicInvoke method of the wrapped
        /// delegate.
        /// </summary>
        static DelegateWrapper wrapperInstance = new DelegateWrapper(InvokeWrappedDelegate);

        /// <summary>
        /// Callback used to call <code>EndInvoke</code> on the asynchronously
        /// invoked DelegateWrapper.
        /// </summary>
        static AsyncCallback callback = new AsyncCallback(EndWrapperInvoke);

        /// <summary>
        /// Executes the specified delegate with the specified arguments
        /// asynchronously on a thread pool thread.
        /// </summary>
        public static void FireAndForget(Delegate d, params object[] args)
        {
            // Invoke the wrapper asynchronously, which will then
            // execute the wrapped delegate synchronously (in the
            // thread pool thread)
            wrapperInstance.BeginInvoke(d, args, callback, null);
        }

        /// <summary>
        /// Invokes the wrapped delegate synchronously
        /// </summary>
        static void InvokeWrappedDelegate(Delegate d, object[] args)
        {
            d.DynamicInvoke(args);
        }

        /// <summary>
        /// Calls EndInvoke on the wrapper and Close on the resulting WaitHandle
        /// to prevent resource leaks.
        /// </summary>
        static void EndWrapperInvoke(IAsyncResult ar)
        {
            try
            {
                wrapperInstance.EndInvoke(ar);
                ar.AsyncWaitHandle.Close();
            }
            catch (Exception ex)
            {
                //Handle the exception.
            }
        }
    }
}


También hay que crear un fichero de configuración, que en este caso se llama: App.config y el contenido es:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </configSections>
  <loggingConfiguration name="Logging Application Block" tracingEnabled="true"
    defaultCategory="General" logWarningsWhenNoCategoriesMatch="true">
    <listeners>
      <add fileName="SVPBuildTool.log" rollSizeKB="0" timeStampPattern="yyyy-MM-dd"
        rollFileExistsBehavior="Increment" rollInterval="Day" formatter="Text Formatter"
        header="----------------------------------------" footer="----------------------------------------"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        name="Rolling Flat File Trace Listener" />
    </listeners>
    <formatters>
      <add template="Timestamp: {timestamp}&#xD;&#xA;Message: {message}&#xD;&#xA;Category: {category}&#xD;&#xA;Priority: {priority}&#xD;&#xA;EventId: {eventid}&#xD;&#xA;Severity: {severity}&#xD;&#xA;Title:{title}&#xD;&#xA;Machine: {machine}&#xD;&#xA;Application Domain: {appDomain}&#xD;&#xA;Process Id: {processId}&#xD;&#xA;Process Name: {processName}&#xD;&#xA;Win32 Thread Id: {win32ThreadId}&#xD;&#xA;Thread Name: {threadName}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"
        type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
        name="Text Formatter" />
    </formatters>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="Rolling Flat File Trace Listener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events">
        <listeners>
          <add name="Rolling Flat File Trace Listener" />
        </listeners>
      </allEvents>
      <notProcessed switchValue="All" name="Unprocessed Category" />
      <errors switchValue="All" name="Logging Errors &amp; Warnings" />
    </specialSources>
  </loggingConfiguration>
</configuration>

No hay comentarios:

Publicar un comentario