Pregunta

¿Debo detectar excepciones para fines de registro?

public foo(..)
{
   try
   {
     ...
   } catch (Exception ex) {
     Logger.Error(ex);
     throw;
   }
}

Si tengo esto implementado en cada una de mis capas (Acceso a datos, Negocios y Servicio web), significa que la excepción se registra varias veces.

¿Tiene sentido hacerlo si mis capas están en proyectos separados y solo las interfaces públicas tienen try/catch en ellas?¿Por qué?¿Por qué no?¿Existe algún enfoque diferente que pueda utilizar?

¿Fue útil?

Solución

Definitivamente no.Debes encontrar el lugar correcto para manejar la excepción (en realidad, haga algo, como capturar y no volver a lanzar), y luego regístrelo.Por supuesto, puede y debe incluir todo el seguimiento de la pila, pero seguir su sugerencia ensuciaría el código con bloques try-catch.

Otros consejos

A menos que vaya a cambiar la excepción, solo debe iniciar sesión en el nivel en el que va a manejar el error y no volver a generarlo.De lo contrario, su registro solo tendrá un montón de "ruido", 3 o más mensajes del mismo registrados, una vez en cada capa.

Mi mejor práctica es:

  1. Pruebe/capte únicamente en métodos públicos (en general;obviamente, si está detectando un error específico, deberá verificarlo allí)
  2. Solo inicie sesión en la capa de interfaz de usuario justo antes de suprimir el error y redirigir a una página/formulario de error.

La regla general es que sólo se detecta una excepción si realmente se puede hacer algo al respecto.Entonces, en la capa Empresarial o de Datos, solo detectará la excepción en situaciones como esta:

            try
            {
                this.Persist(trans);
            }
            catch(Exception ex)
            {
                trans.Rollback();
                throw ex;
            }

Mi capa empresarial/de datos intenta guardar los datos; si se genera una excepción, cualquier transacción se revierte y la excepción se envía a la capa de interfaz de usuario.

En la capa de UI, puedes implementar un controlador de excepciones común:

Application.ThreadException += nuevo ThreadExceptionEventHandler(Application_ThreadException);

Que luego maneja todas las excepciones.Podría registrar la excepción y luego mostrar una respuesta fácil de usar:

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        LogException(e.Exception);
    }
    static void LogException(Exception ex)
    {
        YYYExceptionHandling.HandleException(ex,
            YYYExceptionHandling.ExceptionPolicyType.YYY_Policy,
            YYYExceptionHandling.ExceptionPriority.Medium,
            "An error has occurred, please contact Administrator");
    } 

En el código de la interfaz de usuario real, puede detectar excepciones individuales si va a hacer algo diferente, como mostrar un mensaje amigable diferente o modificar la pantalla, etc.

Además, como recordatorio, intente siempre gestionar los errores (por ejemplo, dividir entre 0) en lugar de generar una excepción.

Una buena práctica es traducir las excepciones.No se limite a registrarlos.Si desea conocer el motivo específico por el que se lanzó una excepción, lance excepciones específicas:

public void connect() throws ConnectionException {
   try {
       File conf = new File("blabla");
       ...
   } catch (FileNotFoundException ex) {
       LOGGER.error("log message", ex);
       throw new ConnectionException("The configuration file was not found", ex);
   }
}

Utilice sus propias excepciones para ajustar la excepción incorporada.De esta manera puede distinguir entre errores conocidos y desconocidos al detectar una excepción.Esto es útil si tiene un método que llama a otros métodos que probablemente generen excepciones para reaccionar ante fallas esperadas e inesperadas.

Es posible que desee buscar estilos de manejo de excepciones estándar, pero según tengo entendido, esto es lo siguiente:maneje excepciones en el nivel donde puede agregar detalles adicionales a la excepción, o en el nivel donde presentará la excepción al usuario.

en su ejemplo, no está haciendo nada más que detectar la excepción, registrarla y lanzarla nuevamente.¿Por qué no capturarlo en el nivel más alto con un intento/captura en lugar de hacerlo dentro de cada método si todo lo que estás haciendo es registrarlo?

Solo lo manejaría en ese nivel si fuera a agregar información útil a la excepción antes de lanzarla nuevamente: envuelva la excepción en una nueva excepción que cree que tenga información útil más allá del texto de excepción de bajo nivel, que generalmente significa poco para cualquiera. sin algo de contexto..

A veces es necesario registrar datos que no están disponibles cuando se maneja la excepción.En ese caso, es apropiado iniciar sesión solo para obtener esa información.

Por ejemplo (pseudocódigo Java):

public void methodWithDynamicallyGeneratedSQL() throws SQLException {
    String sql = ...; // Generate some SQL
    try {
        ... // Try running the query
    }
    catch (SQLException ex) {
        // Don't bother to log the stack trace, that will
        // be printed when the exception is handled for real
        logger.error(ex.toString()+"For SQL: '"+sql+"'");
        throw ex;  // Handle the exception long after the SQL is gone
    }
}

Esto es similar al registro retroactivo (mi terminología), donde almacena un registro de eventos pero no los escribe a menos que haya un evento desencadenante, como por ejemplo una excepción.

Si debe registrar todas las excepciones, entonces es una idea fantástica.Dicho esto, registrar todas las excepciones sin otro motivo no es una buena idea.

Es posible que desee iniciar sesión en el nivel más alto, que suele ser su interfaz de usuario o código de servicio web.Registrar varias veces es una especie de desperdicio.Además, querrás saber toda la historia cuando mires el registro.

En una de nuestras aplicaciones, todas nuestras páginas se derivan de un objeto BasePage, y este objeto maneja el manejo de excepciones y el registro de errores.

Si eso es lo único que hace, creo que es mejor eliminar los try/catch de esas clases y dejar que la excepción se plantee a la clase responsable de manejarlos.De esa manera, obtendrá solo un registro por excepción, lo que le brindará registros más claros e incluso podrá registrar el seguimiento de la pila para no perderse dónde se originó la excepción.

Mi método consiste en registrar las excepciones sólo en el controlador.El "real" manejador, por así decirlo.De lo contrario, el registro será muy difícil de leer y el código estará menos estructurado.

Depende de la excepción:Si esto realmente no sucediera, definitivamente lo registraría.Por otro lado:Si espera esta excepción, debe pensar en el diseño de la aplicación.

De cualquier manera:al menos debería intentar especificar la excepción que desea volver a generar, capturar o registrar.

public foo(..)
{
   try
   {
     ...
   }
   catch (NullReferenceException ex) {
     DoSmth(e);
   }
   catch (ArgumentExcetion ex) {
     DoSmth(e);
   }
   catch (Exception ex) {
     DoSmth(e);
   }
}

Querrá iniciar sesión en un límite de nivel.Por ejemplo, si su nivel empresarial se puede implementar en una máquina físicamente separada en una aplicación de n niveles, entonces tiene sentido registrar y generar el error de esta manera.

De esta manera, tendrá un registro de excepciones en el servidor y no necesitará husmear en las máquinas cliente para descubrir qué sucedió.

Utilizo este patrón en niveles empresariales de aplicaciones que utilizan servicios web Remoting o ASMX.Con WCF puede interceptar y registrar una excepción utilizando un IErrorHandler adjunto a su ChannelDispatcher (otro tema completamente), por lo que no necesita el patrón try/catch/throw.

Necesita desarrollar una estrategia para manejar excepciones.No recomiendo atrapar y volver a lanzar.Además de las entradas de registro superfluas, hace que el código sea más difícil de leer.Considere escribir en el registro del constructor para la excepción.Esto reserva try/catch para excepciones de las que desea recuperarse;haciendo que el código sea más fácil de leer.Para hacer frente a excepciones inesperadas o irrecuperables, es posible que desee realizar un try/catch cerca de la capa más externa del programa para registrar información de diagnóstico.

Por cierto, si se trata de C++, su bloque catch está creando una copia del objeto de excepción, lo que puede ser una fuente potencial de problemas adicionales.Intente capturar una referencia al tipo de excepción:

  catch (const Exception& ex) { ... }

Este El podcast de Software Engineering Radio es una muy buena referencia para las mejores prácticas en el manejo de errores.En realidad son 2 conferencias.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top