Actualmente estoy refactorizando un subsistema grande con una arquitectura de varias capas, y estoy luchando por diseñar una estrategia efectiva de registro / manejo de errores.
Digamos que mi arquitectura consta de las siguientes tres capas:
- Interfaz pública (es decir, un controlador MVC)
- Capa de dominio
- Capa de acceso a datos
Mi fuente de confusión es donde debería implementar el registro de errores \ manejo:
La solución más fácil sería implementar el registro en el nivel superior (es decir, la Interfaz pública \ Controlador MVC). Sin embargo, esto se siente mal porque significa aumentar la excepción a través de las diferentes capas y luego iniciar sesión; en lugar de registrar la excepción en su origen.
Obviamente, registrar la excepción en su origen es la mejor solución porque tengo la mayor cantidad de información. Mi problema con esto es que no puedo capturar todas las excepciones en el origen sin capturar TODAS las excepciones, y en la capa de dominio / interfaz pública, esto conducirá a capturar excepciones que ya se han capturado, registrado y relanzado por la capa a continuación .
Otra posible estrategia es una combinación de # 1 y # 2; por el cual capturo excepciones específicas en la capa que tienen más probabilidades de ser lanzadas (IE Catching, logging y re-throwing
SqlExceptions
en Data Access Layer) y luego registro cualquier excepción no detectada en el nivel superior. Sin embargo, esto también requeriría que detecte y registre cada excepción en el nivel superior, porque no puedo distinguir entre los errores que ya se han registrado \ manejado y los que no.
Ahora, obviamente, este es un problema en la mayoría de las aplicaciones de software, por lo que debe haber una solución estándar para este problema que dé como resultado que las excepciones se detecten en el origen y se registren una vez; Sin embargo, no puedo ver cómo hacerlo yo mismo.
Tenga en cuenta que el título de esta pregunta es muy similar a ' Excepciones de registro en una aplicación de varios niveles " ', sin embargo, las respuestas en esa publicación carecen de detalles y no son suficientes para responder a mi pregunta.
fuente
The easiest solution would be to implement the logging at the top level
- hacer esto. Las excepciones de registro en su origen no son una buena idea y cada aplicación que he encontrado que hace esto fue una PITA para depurar. Debería ser responsabilidad de la persona que llama manejar las excepciones.try{ ... } catch(Exception ex) { Log(ex); }
resultado resultaría en la misma excepción que se registra en cada capa. (También parece una práctica bastante mala detectar todas las excepciones en cada capa de la base de código).Respuestas:
A sus preguntas:
Tener la burbuja de excepción hasta el nivel superior es un enfoque absolutamente correcto y plausible. Ninguno de los métodos de capa superior intenta continuar algún proceso después de la falla, que generalmente no puede tener éxito. Y una excepción bien equipada contiene toda la información necesaria para iniciar sesión. Y no hacer nada con respecto a las excepciones lo ayuda a mantener su código limpio y enfocado en la tarea principal en lugar de las fallas.
Eso es medio correcto. Sí, la información más útil está disponible allí. Pero recomendaría poner todo esto en el objeto de excepción (si aún no está allí) en lugar de registrarlo inmediatamente. Si inicia sesión en un nivel bajo, aún necesita lanzar una excepción para informar a las personas que llaman que no completó su trabajo. Esto termina en múltiples registros del mismo evento.
Excepciones
Mi directriz principal es capturar y registrar excepciones solo en el nivel superior. Y todas las capas a continuación deben asegurarse de que toda la información necesaria sobre fallas se transporte al nivel superior. Dentro de una aplicación de proceso único, por ejemplo, en Java, esto significa principalmente no intentar / capturar o iniciar sesión fuera del nivel superior.
A veces, desea que se incluya información de contexto en el registro de excepciones que no está disponible en la excepción original, por ejemplo, la instrucción SQL y los parámetros que se ejecutaron cuando se lanzó la excepción. Luego puede capturar la excepción original y volver a lanzar una nueva, que contenga la original más el contexto.
Por supuesto, la vida real a veces interfiere:
En Java, a veces debe capturar una excepción y envolverla en un tipo de excepción diferente solo para obedecer algunas firmas de métodos fijos. Pero si vuelve a lanzar una excepción, asegúrese de que la relanzada contenga toda la información necesaria para un registro posterior.
Si está cruzando un borde entre procesos, a menudo técnicamente no puede transferir el objeto de excepción completo, incluido el seguimiento de la pila. Y, por supuesto, la conexión podría perderse. Así que aquí hay un punto en el que un servicio debe registrar excepciones y luego hacer todo lo posible para transmitir la mayor cantidad posible de información de fallas a través de la línea a su cliente. El servicio debe asegurarse de que el cliente reciba un aviso de falla, ya sea al recibir una respuesta a la falla o al encontrarse con un tiempo de espera en caso de una conexión interrumpida. Por lo general, esto provocará que se registre la misma falla dos veces, una dentro del servicio (con más detalles) y otra en el nivel superior del cliente.
Inicio sesión
Estoy agregando algunas oraciones sobre el registro en general, no solo el registro de excepciones.
Además de situaciones excepcionales, también desea que las actividades importantes de su aplicación se registren en el registro. Entonces, use un marco de registro.
Tenga cuidado con los niveles de registro (¡leer registros donde la información de depuración y los errores graves no están marcados con diferentes en consecuencia es un dolor!). Los niveles de registro típicos son:
En producción, establezca el nivel de registro en INFO. Los resultados deberían ser útiles para un administrador del sistema para que sepa lo que está sucediendo. Espere que lo llame para pedir ayuda o corregir errores por cada ERROR en el registro y la mitad de las ADVERTENCIAS.
Habilite el nivel de DEPURACIÓN solo durante las sesiones de depuración reales.
Agrupe las entradas de registro en categorías apropiadas (por ejemplo, por el nombre de clase completo del código que genera la entrada), lo que le permite activar registros de depuración para partes específicas de su programa.
fuente
Me estoy preparando para los votos negativos, pero voy a ponerme nervioso y decir que no estoy seguro de poder estar de acuerdo con esto.
El aumento de las excepciones, mucho menos registrarlas nuevamente, es un esfuerzo adicional con poco beneficio. Capture la excepción en el origen (sí, lo más fácil), regístrela, pero luego no vuelva a lanzar la excepción, solo informe el "error" a la persona que llama. "-1", nulo, cadena vacía, alguna enumeración, lo que sea. La persona que llama solo necesita saber que la llamada falló, casi nunca los detalles horripilantes. Y esos estarán en su registro, ¿verdad? En el raro caso de que la persona que llama necesita los detalles, continúe y burbujee, pero no como un defecto automático irreflexivo.
fuente
null
o la cadena vacía? ¿Es -1 o algún número negativo? 2. Si a la persona que llama no le importa (es decir, no verifica), esto lleva a errores de seguimiento no relacionados con la causa original, por ejemplo aNullPointerException
. O peor: el cálculo continúa con valores incorrectos. 3. Si a la persona que llama le importaría pero el programador no piensa que este método está fallando, el compilador no se lo recuerda. Las excepciones no tienen este problema, ya sea que atrapes o vuelves a lanzar.