Un Framework para Programación Orientada a Aspectos (AOP) en C#    Parte 2: Un aspecto para registro de eventos

Esta publicación es la tercera parte (aunque diga parte dos) de una serie de cuatro publicaciones que estaré realizando sobre programación orientada a aspectos en .NET empleando el lenguaje de programación C#.

El que es quizás sea el ejemplo más sencillo de un aspecto es el registro de eventos de un sistema o aplicación. Así mismo, resulta ser el más significativo también.

El típico infierno al que se enfrenta un arquitecto o líder técnico a la hora de establecer la política de registro de eventos en su diseño es la gobernabilidad de dicho diseño, y la monitorización de su cumplimiento por parte del equipo de desarrollo, cosa que se torna excesivamente complicada por la creatividad de algunos miembros del equipo que rompe la homogeneidad de los mensajes que se ha establecido como parte del modelo de eventos.

Otro típico incidente es que los desarrolladores, muchas veces culpando a las restricciones de tiempo del proyecto o a la urgencia de la solicitud en la implementación de un determinado requerimiento, omiten agregar las líneas de código que generan el registro de eventos, lo cual a veces puede resultar incluso difícil de detectar en revisiones de código (a través de prácticas como los peer reviews.

A través del enfoque de AOP, es posible esconder el mensaje del evento y reducir su implementación a colocar un atributo que decore el método que se desea loggear, lo cual permitirá establacer el formato del mensaje e impedir que los miembros del equipo lo modifiquen, reforzando la arquitectura y la gobernabilidad del proyecto, a la vez que se simplifica el proceso de desarrollo y de verificación del código.

Un Apropiado Soporte

Al crear un sistema de registro de eventos, no deberíamos partir desde cero, ya que existe un montón de excelentes productos y frameworks que nos simplificarían esta tarea. Para este caso, emplearé los Microsoft Libraries, en particular el Logging Application Block; sin embargo el enfoque de AOP y de este framework que he venido presentado permite emplear cualquier otra librería como log4net o NLog.

Implementación

Es importante que si no han leido las primeras partes de esta serie de artículos, aprovechen este momento para hacerlo, sobre todo la parte 1. A partir de este momento mis explicaciones considerarán que el conocimiento y los detalles técnicos explicados en esa parte ya son conocidos.

El primer paso es crear el atributo (Attribute) que decorará las clases/interfaces para capturar su ejecución e inyectar el código de registro de eventos. Nuestro atributo se llamará LogAttribute y extiende de InterceptableAttribute, la clase base en el framework de AOP que sirve para definir atributos de intercepción.

    /// <summary>
    /// A custom attribute for logging purposes under an Aspect Oriented Programming paradigm.
    /// </summary>
    /// <remarks>
    /// It applies only to methods.
    /// </remarks>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class LogAttribute : InterceptableAttribute
    {
        /// <summary>
        /// A stopwatch to use then the verbority level is set to its highest value, in order to
        /// log the amount of time consumed by methods calls.
        /// </summary>
        private Stopwatch timer;

        /// <summary>
        /// The verbosity level to log.
        /// </summary>
        private VerbosityLevel verbosity;

        /// <summary>
        /// Initializes a new instance of the <see cref="LogAttribute" /> class.
        /// </summary>
        /// <param name="verbosity">The verbosity level to log.</param>        
        public LogAttribute(VerbosityLevel verbosity)
        {
            this.verbosity = verbosity;
            this.Processor = Activator.CreateInstance(typeof(LogProcessor)) as IProcessor;

            if (verbosity.Equals(VerbosityLevel.Full))
            {
                this.timer = new Stopwatch();
                this.timer.Reset();
            }
        }

        /// <summary>
        /// Gets the verbosity level to log.
        /// </summary>
        /// <value>The verbosity level of the log trace as defined in <see cref="VerbosityLevel"/>.</value>
        public VerbosityLevel Verbosity { get { return this.verbosity; } }

        /// <summary>
        /// Gets the this log timer.
        /// </summary>
        /// <remarks>
        /// If the <c>Verbosity</c> is different than <see cref="VerbosityLevel.Full"/> then this property will return <c>null</c>.
        /// </remarks>
        /// <value>
        /// An instance of a <see cref="Stopwatch"/> to retrieve execution time when logging with <see cref="VerbosityLevel.Full"/>.
        /// </value>
        /// <see cref="Stopwatch"/>
        /// <see cref="AOPLoggingApplicationBlock.VerbosityLevel"/>
        public Stopwatch Timer { get { return this.timer; } }
    }

Este atributo tiene dos (2) propiedades muy importantes. La primera, llamada VerbosityLevel permite establecer que tanta información se generará/almacenará cuando se registre eventos con cada intercepción. En principio para este ejemplo he definido cuatro (4) niveles de verbosidad:

  1. None: no se registrarán eventos.
  2. Light: una mínima, pero significativa cantidad de información será generada.
  3. Medium: una cantidad moderada de significante información será generada.
  4. Full: mucha información será generada, no necesariamente todoa ella significativa, pero sí útil.

La segunda propiedad se llama Timer no es más que un Stopwatch y que para el caso de VerbosityLevel.Full nos medirá cuanto ha tardado en ejecutarse un método interceptado (con lo cual podríamos identificar cuellos de botella en tiempos de producción por ejemplo).

Una vez establecido el atributo de intercepción, procedemos a crear el Processor que se encargará de manejar la inyección de código antes y después de la ejecución de los métodos interceptados. Para esto crearemos la clase LogProcessor que implementará la interfaz IProcessor del framework.

Esta clase es la que dependiento del VerbosityLevel y basado en el Microsoft Enterprise Library Logging Application Block procederá a escribir registros acorde a la configuración del mencionado Application Block. Los métodos ProcessCallMessage y ProcessReturnMessage se encargarán de crear el mensaje del evento de una manera estandard y pre-establecida (evitando que los desarrolladores decidan el mensaje y rompan con la gobernabilidad).

Lamentablemente la implementación de la clase LogProcessor es un tanto extensa como para ponerla en esta publicación, sin embargo está disponible para descargarse (y estudiarse) justo aquí.

Anuncios
Deja un comentario

8 comentarios

  1. Antonio

     /  noviembre 28, 2012

    Muy buenos los artículos Rodri. Me gustan. Voy a ver si saco un rato en lo pongo en práctica. A ver si quedamos pa unas cervezas.

    El enlace que has puesto al código sólo contiene el código del AOPFramework, no veo el del Log. No voy a poder dormir esta noche si no veo la implementación del LogProcessor!!

    ¿Pa cuándo el resto de artículos?
    Un abrazo

    Responder
    • Hola Antonio!

      Que bueno que te han gustado.

      BTW… gracias por comentarme lo del enlace. Estaba equivocado y ya lo he corregido. El enlace ahora te descargará el código del AOPLogging.

      Igual te dejo el enlace aquí para que lo tengas más a mano: https://www.box.com/s/zttkc69peuwapgxu016h.

      Por cierto, también lo puedes encontrar al final del sidebar derecho de mi blog, justo debajo de mi XBox Gamer Tag en una sección llamada “BOX”. Ahí estará apareciendo todo el código fuente que vaya montando.

      El resto de los artículos los tengo en Draft. A ver si la semana que viene que estoy de vacaciones los finalizo y programo su publicación.

      Un abrazo y de verdad… a ver cuando nos tomamos esas cervezas!!! Cuidate mucho!!!

      Responder
  2. Pablo

     /  abril 24, 2013

    Hola, bastante bueno esta este proyecto, tengo una pregunta, como se define la ruta del log a escribir o a utilizar.

    Responder
    • Hola Pablo,

      Pues personalmente convino el framework AOP con los Logging Application Block de las Enterprise Library de Microsoft. Dicho Application Block tiene en su configuración un parámetro para establecer la ruta del log a escribir.

      Responder
  3. Pedro

     /  abril 12, 2017

    Buenas Rodrigo!

    Ante todo, gracias por el aporte de conocimiento que das.

    Ahora bien, probando el ejemplo, me faltaría indicar la anotación sobre los métodos que vayan a trazarse.

    Teniendo en cuenta que utilo la extensión Log4Net, creo que no hay cambios aparentes en el código con respecto al ejemplo.

    ¿Podrías añadir un ejemplo de méotods con la anotación y que se muestre la traza en fichero/consola?

    Gracias de antemano,
    Un Saludo

    Responder
  1. Un Framework para Programación Orientada a Aspectos (AOP) en C#    Parte 1: Implementación « The Front End
  2. Un Framework para Programación Orientada a Aspectos (AOP) en C#    Parte 0: Introducción « The Front End
  3. Un Framework para Programación Orientada a Aspectos (AOP) en C#    Parte 3: Un aspecto para manejo de excepciones « The Front End

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s