Un patrón común para localizar un error sigue este script:
- Observe la rareza, por ejemplo, sin salida o un programa colgado.
- Localice el mensaje relevante en el registro o la salida del programa, por ejemplo, "No se pudo encontrar Foo". (Lo siguiente solo es relevante si esta es la ruta tomada para localizar el error. Si un seguimiento de la pila u otra información de depuración está disponible, esa es otra historia).
- Busque el código donde se imprime el mensaje.
- Depure el código entre el primer lugar donde Foo ingresa (o debería ingresar) la imagen y dónde se imprime el mensaje.
El tercer paso es donde el proceso de depuración a menudo se detiene porque hay muchos lugares en el código donde Could not find {name}
se imprime "No se pudo encontrar Foo" (o una cadena con plantilla ). De hecho, varias veces un error de ortografía me ayudó a encontrar la ubicación real mucho más rápido de lo que lo haría de otra manera: hizo que el mensaje fuera único en todo el sistema y, a menudo, en todo el mundo, lo que resultó en un golpe de motor de búsqueda relevante de inmediato.
La conclusión obvia de esto es que deberíamos usar ID de mensaje únicos a nivel mundial en el código, codificándolo como parte de la cadena del mensaje y posiblemente verificando que solo haya una aparición de cada ID en la base del código. En términos de mantenibilidad, ¿cuáles cree esta comunidad que son los pros y los contras más importantes de este enfoque, y cómo implementaría esto o de lo contrario se aseguraría de que la implementación nunca sea necesaria (suponiendo que el software siempre tenga errores)?
Respuestas:
En general, esta es una estrategia válida y valiosa. Aquí hay algunos pensamientos.
Esta estrategia también se conoce como "telemetría" en el sentido de que cuando se combina toda esa información, ayudan a "triangular" la traza de ejecución y permiten que un solucionador de problemas tenga sentido de lo que el usuario / aplicación está tratando de lograr y lo que realmente sucedió .
Algunos datos esenciales que deben recopilarse (que todos sabemos) son:
Muchas veces, los enfoques de registro tradicionales se quedan cortos, debido a la falla en rastrear un mensaje de registro de bajo nivel hasta el comando de nivel más alto que lo activa. Un seguimiento de pila solo captura los nombres de las funciones superiores que ayudaron a manejar el comando de nivel más alto, no los detalles (datos) que a veces se necesitan para caracterizar ese comando.
Normalmente el software no fue escrito para implementar este tipo de requisitos de trazabilidad. Esto hace que la correlación del mensaje de bajo nivel con el comando de alto nivel sea más difícil. El problema es particularmente peor en los sistemas de subprocesos múltiples libremente, donde muchas solicitudes y respuestas pueden superponerse, y el procesamiento puede descargarse a un subproceso diferente que el subproceso de recepción de solicitud original.
Por lo tanto, para obtener el mayor valor de la telemetría, se necesitarán cambios en la arquitectura general del software. La mayoría de las interfaces y las llamadas a funciones deberán modificarse para aceptar y propagar un argumento "trazador".
Incluso las funciones de utilidad necesitarán agregar un argumento "trazador", de modo que si falla, el mensaje de registro permitirá correlacionarse con un cierto comando de alto nivel.
Otra falla que dificultará el rastreo de telemetría es la falta de referencias de objetos (punteros nulos o referencias). Cuando falta algún dato crucial, puede ser imposible informar algo útil para la falla.
En términos de escribir los mensajes de registro:
fuente
Imagine que tiene una función de utilidad trivial que se utiliza en cientos de lugares en su código:
Si tuviéramos que hacer lo que sugieres, podríamos escribir
Un error que podría ocurrir es si la entrada fuera cero; esto daría como resultado una excepción dividir por cero.
Digamos que ve 27349262 en su salida o en sus registros. ¿Dónde busca el código que pasó el valor cero? Recuerde, la función, con su ID única, se usa en cientos de lugares. Entonces, si bien puede saber que se produjo la división por cero, no tiene idea de quién
0
es.Me parece que si vas a molestarte en registrar las ID de los mensajes, también puedes registrar el seguimiento de la pila.
Si la verbosidad del seguimiento de la pila es lo que te molesta, no tienes que volcarlo como una cadena de la forma en que el tiempo de ejecución te lo da. Puedes personalizarlo. Por ejemplo, si desea un seguimiento de pila abreviado que vaya solo a
n
niveles, puede escribir algo como esto (si usa c #):Y úsalo así:
Salida:
Tal vez más fácil que mantener identificaciones de mensajes y más flexible.
Robar mi código de DotNetFiddle
fuente
SAP NetWeaver ha estado haciendo esto por décadas.
Ha demostrado ser una herramienta valiosa cuando se solucionan errores en el gigantesco código masivo que es el típico sistema SAP ERP.
Los mensajes de error se administran en un repositorio central donde cada mensaje se identifica por su clase de mensaje y número de mensaje.
Cuando desee emitir un mensaje de error, solo debe indicar la clase, el número, la gravedad y las variables específicas del mensaje. La representación de texto del mensaje se crea en tiempo de ejecución. Por lo general, ve la clase y el número de mensaje en cualquier contexto donde aparecen los mensajes. Esto tiene varios efectos geniales:
Puede encontrar automáticamente cualquier línea de código en la base de código ABAP que cree un mensaje de error específico.
Puede establecer puntos de interrupción del depurador dinámico que se activan cuando se genera un mensaje de error específico.
Puede buscar errores en los artículos de la base de conocimiento de SAP y obtener resultados de búsqueda más relevantes que si busca "No se pudo encontrar Foo".
Las representaciones de texto de los mensajes son traducibles. Entonces, al alentar el uso de mensajes en lugar de cadenas, también obtienes capacidades i18n.
Un ejemplo de una ventana emergente de error con número de mensaje:
Buscando ese error en el repositorio de errores:
Encuéntralo en la base de código:
Sin embargo, hay inconvenientes. Como puede ver, estas líneas de código ya no se documentan por sí mismas. Cuando lee el código fuente y ve una
MESSAGE
declaración como las de la captura de pantalla anterior, solo puede inferir del contexto lo que realmente significa. Además, a veces las personas implementan controladores de errores personalizados que reciben la clase y el número de mensaje en tiempo de ejecución. En ese caso, el error no se puede encontrar automáticamente o no se puede encontrar en la ubicación donde realmente ocurrió el error. La solución para el primer problema es acostumbrarse a agregar siempre un comentario en el código fuente que le dice al lector lo que significa el mensaje. El segundo se resuelve agregando un código muerto para asegurarse de que la búsqueda automática de mensajes funcione. Ejemplo:Pero hay algunas situaciones en las que esto no es posible. Hay, por ejemplo, algunas herramientas de modelado de procesos empresariales basadas en la interfaz de usuario en las que puede configurar mensajes de error para que aparezcan cuando se infrinjan las reglas empresariales. La implementación de esas herramientas está completamente basada en datos, por lo que estos errores no se mostrarán en la lista donde se usan. Eso significa que confiar demasiado en la lista donde se usa cuando se trata de encontrar la causa de un error puede ser una pista falsa.
fuente
El problema con ese enfoque es que conduce a un registro cada vez más detallado. 99.9999% del cual nunca mirarás.
En cambio, recomiendo capturar el estado al comienzo de su proceso y el éxito / fracaso del proceso.
Esto le permite reproducir el error localmente, recorrer el código y limita su registro a dos lugares por proceso. p.ej.
Ahora puedo usar exactamente el mismo estado en mi máquina de desarrollo para reproducir el error, revisando el código en mi depurador y escribiendo una nueva prueba unitaria para confirmar la corrección.
Además, si es necesario, puedo evitar más registros solo registrando fallas o manteniendo el estado en otro lugar (¿base de datos? ¿Cola de mensajes?)
Obviamente tenemos que tener mucho cuidado al registrar datos confidenciales. Entonces, esto funciona particularmente bien si su solución está usando colas de mensajes o el patrón de almacén de eventos. Como el registro solo necesita decir "Mensaje xyz falló"
fuente
Sugeriría que iniciar sesión no es la forma de hacerlo, sino que esta circunstancia se considera excepcional (bloquea su programa) y se debe lanzar una excepción. Digamos que su código era:
Parece que su código de llamada no está configurado para lidiar con el hecho de que Foo no existe y que podría ser:
Y esto devolverá un seguimiento de la pila junto con la excepción que se puede usar para ayudar a la depuración.
Alternativamente, si esperamos que Foo pueda ser nulo cuando se recupere y eso está bien, necesitamos corregir los sitios de llamadas:
El hecho de que su software se cuelgue o actúe "extrañamente" en circunstancias inesperadas me parece incorrecto: si necesita un Foo y no puede manejar que no esté allí, entonces parece mejor bloquearse que intentar avanzar por un camino que puede corrompe su sistema.
fuente
Las bibliotecas de registro adecuadas proporcionan mecanismos de extensión, por lo que si desea conocer el método donde se originó un mensaje de registro, pueden hacerlo de forma inmediata. Tiene un impacto en la ejecución ya que el proceso requiere generar un seguimiento de la pila y recorrerlo hasta que esté fuera de la biblioteca de registro.
Dicho esto, realmente depende de lo que quieras que haga tu ID por ti:
Todas estas cosas se pueden hacer de fábrica con el software de registro adecuado (es decir, no
Console.WriteLine()
oDebug.WriteLine()
).Personalmente, lo que es más importante es la capacidad de reconstruir rutas de ejecución. Para eso están diseñadas herramientas como Zipkin . Una ID para rastrear el comportamiento de una acción del usuario en todo el sistema. Al colocar sus registros en un motor de búsqueda central, no solo puede encontrar las acciones más largas, sino que también llama los registros que se aplican a esa acción (como la pila ELK ).
Las ID opacas que cambian con cada mensaje no son muy útiles. Una identificación coherente utilizada para rastrear el comportamiento a través de un conjunto completo de microservicios ... inmensamente útil.
fuente