Registro y seguimiento en aplicaciones .NET
A medida que continúa desarrollando la aplicación y esta se vuelve más compleja, es posible que tenga que aplicar más diagnósticos de depuración a ella.
El seguimiento es una manera de supervisar la ejecución de la aplicación mientras se está ejecutando. Puede agregar instrumentación de seguimiento y depuración a la aplicación .NET al desarrollarla. Puede usar esa instrumentación mientras desarrolla la aplicación y después de implementarla.
Esta técnica sencilla es sorprendentemente poderosa. Se puede usar en situaciones en las que se necesita más de un depurador:
- Los problemas que se producen durante largos períodos de tiempo pueden ser difíciles de depurar con un depurador tradicional. Los registros permiten una revisión post mortem detallada que abarca largos períodos de tiempo. Por el contrario, los depuradores están restringidos al análisis en tiempo real.
- Las aplicaciones multiproceso y las aplicaciones distribuidas suelen ser difíciles de depurar. La asociación de un depurador tiende a modificar comportamientos. Puede analizar registros detallados según lo necesite para comprender los sistemas complejos.
- Los problemas en las aplicaciones distribuidas pueden surgir de una interacción compleja entre muchos componentes. No suele ser recomendable conectar un depurador a todas las partes del sistema.
- Muchos servicios no deben estar detenidos. La asociación de un depurador suele provocar errores de tiempo de espera.
- Los problemas no siempre se puede prever. El registro y el seguimiento están diseñados para una sobrecarga baja para que siempre se puedan grabar los programas en caso de que se produzca un problema.
Escritura de información en las ventanas de salida
Hasta este momento, hemos estado usando la consola para mostrar información al usuario de la aplicación. Hay otros tipos de aplicaciones creadas con .NET que tienen interfaces de usuario y ninguna consola visible, como aplicaciones móviles, web y de escritorio. En estas aplicaciones, se usa System.Console para registrar los mensajes "en segundo plano". Estos mensajes se pueden mostrar en una ventana de salida de Visual Studio o Visual Studio Code. También pueden generarse en un registro del sistema, como logcat de Android. Como resultado, debe tener gran consideración al usar System.Console.WriteLine en una aplicación que no sea de consola.
Esta situación es donde puede usar System.Diagnostics.Debug y System.Diagnostics.Trace además de System.Console. Tanto Debug como Trace forman parte de System.Diagnostics y solo escriben en los registros cuando se asocia un cliente de escucha adecuado.
La elección de la API de estilo de impresión que se va a usar depende de usted. Las principales diferencias son:
- System.Console
- Siempre habilitado y siempre escribe en la consola.
- Resulta útil para la información que el cliente pueda necesitar ver en la versión.
- Dado que es el enfoque más sencillo,
System.Consolea menudo se usa para la depuración temporal ad hoc. Este código de depuración a menudo nunca se comprueba en el control de código fuente.
- System.Diagnostics.Trace
- Solo se habilita cuando
TRACEse define. - Escribe en los agentes de escucha asociados, de forma predeterminada, DefaultTraceListener.
- Use esta API al crear registros que planee habilitar en la mayoría de las compilaciones.
- Solo se habilita cuando
- System.Diagnostics.Debug
- Solo se habilita cuando se define
DEBUG(en modo de depuración). - Escribe en un depurador asociado.
- Use esta API al crear registros que planee habilitar solo en compilaciones de depuración.
- Solo se habilita cuando se define
Console.WriteLine("This message is readable by the end user.")
Trace.WriteLine("This is a trace message when tracing the app.");
Debug.WriteLine("This is a debug message just for developers.");
Al diseñar su estrategia de seguimiento y depuración, piense en cómo quiere que sea la salida. Varias instrucciones Write rellenadas con información no relacionada crean un registro que es difícil de leer. Por otro lado, usar WriteLine para colocar instrucciones relacionadas en líneas independientes puede hacer que sea difícil distinguir la información del mismo tipo. En general, use varias instrucciones Write cuando quiera combinar información de varios orígenes para crear un único mensaje informativo. Por otro lado, use la instrucción WriteLine cuando quiera crear un único mensaje completo.
Debug.Write("Debug - ");
Debug.WriteLine("This is a full line.");
Debug.WriteLine("This is another full line.");
Esta salida proviene del registro anterior con Debug:
Debug - This is a full line.
This is another full line.
Definición de las constantes TRACE y DEBUG
De forma predeterminada, cuando una aplicación se ejecuta durante la depuración, se define la constante DEBUG. Puede controlar esta definición agregando una DefineConstants entrada en el archivo de proyecto en un grupo de propiedades. Este es un ejemplo de cómo activar TRACE para las configuraciones de Debug y Release, además de DEBUG para las configuraciones de Debug.
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
Si usa Trace cuando no está asociado al depurador, deberá configurar un cliente de escucha de seguimiento, como dotnet-trace.
Seguimiento condicional
Además de los métodos simples Write y WriteLine, también existe la funcionalidad para agregar condiciones con WriteIf y WriteLineIf. A modo de ejemplo, la siguiente lógica comprueba si el recuento es cero y, luego, escribe un mensaje de depuración:
if(count == 0)
{
Debug.WriteLine("The count is 0 and this may cause an exception.");
}
Puede volver a escribirlo en una misma línea de código:
Debug.WriteLineIf(count == 0, "The count is 0 and this may cause an exception.");
También puede usar estas condiciones con Trace y con las marcas que defina en la aplicación:
bool errorFlag = false;
System.Diagnostics.Trace.WriteIf(errorFlag, "Error in AppendData procedure.");
System.Diagnostics.Debug.WriteIf(errorFlag, "Transaction abandoned.");
System.Diagnostics.Trace.Write("Invalid value for data request");
Comprobación de que determinadas condiciones existen
Una aserción o instrucción Assert prueba una condición, que se especifica como argumento para la instrucción Assert. Si la condición se evalúa como true, no se produce ninguna acción. Si la condición se evalúa como false, se produce un error en la aserción. Si está ejecutando una compilación de depuración, el programa entra en modo de interrupción.
Puede usar el método Assert de Debug o Trace, que se encuentran en el espacio de nombres System.Diagnostics. Los métodos de la clase Debug no se incluyen en una versión de lanzamiento de su programa, de modo que no aumentan el tamaño ni reducen la velocidad de su código de versión.
Use el método System.Diagnostics.Debug.Assert libremente para probar las condiciones que deben ser true si el código es correcto. Por ejemplo, supongamos que escribió una función que divide enteros. De acuerdo con las reglas matemáticas, el divisor nunca puede ser cero. Puede probar esta condición mediante una aserción:
int IntegerDivide(int dividend, int divisor)
{
Debug.Assert(divisor != 0, $"{nameof(divisor)} is 0 and will cause an exception.");
return dividend / divisor;
}
Al ejecutar este código en el depurador, se evalúa la instrucción de aserción, Pero en la versión de lanzamiento, la comparación no se realiza, por lo que no hay ninguna sobrecarga adicional.
Nota
Cuando use System.Diagnostics.Debug.Assert, asegúrese de que cualquier código incluido en Assert no cambie los resultados del programa si se quita Assert. De lo contrario, podría introducir accidentalmente un error que solo se muestra en la versión de lanzamiento del programa. Tenga especial cuidado con las aserciones que contienen llamadas a funciones o procedimientos.
Como puede ver, usar Debug y Trace desde el System.Diagnostics espacio de nombres es una excelente manera de proporcionar contexto importante al ejecutar y depurar la aplicación.