Introducción
He notado en varias oportunidades que en ciertas circunstancias surgen errores no controlador que son difíciles de rastrear
Estos es consecuencia de un descuido, al no agregar correctamente en todos los puntos importantes el try..catch, o simplemente por la lógica de la aplicación por se grande implicaría un gran esfuerzo poner en cada evento el control de errores.
Es por eso que definir un control global a nivel de aplicación podría ayudar, atrapando el problema y registrando que sucedió y donde, esta información es muy preciada cuando se esta perdido y no se sabe que produce el problema, mas cuando se esta en el entorno de producción y no se cuenta con una herramienta de debug
En este artículo se trataran los siguientes temas:
- Control global de errores
- Log usando System.IO.Log
- Log usado Log4Net
1- Control Global Errores
El implementar la lógica para controlar globalmente los errores no es nada difícil, el truco esta en adjuntarse a un evento, concretamente:
Un buen lugar para realizar esta asignación del evento es el archivos Program.cs, dentro del método Main()
[C#]
01.
[STAThread]
02.
static
void
Main()
03.
{
04.
Application.EnableVisualStyles();
05.
Application.SetCompatibleTextRenderingDefault(
false
);
06.
07.
Application.ThreadException +=
new
ThreadExceptionEventHandler(Application_ThreadException);
08.
09.
Application.Run(
new
Form1());
10.
}
11.
12.
static
void
Application_ThreadException(
object
sender, System.Threading.ThreadExceptionEventArgs e)
13.
{
14.
MessageBox.Show(e.Exception.Message);
15.
}
Para lograr esto mismo en vb.net requiere de algunos paso adicionales, ya que vb.net no brinda un acceso transparente al método Main, ni permite que este sea asignado como inicio de la aplciacion, pero en este articulo
explico como destrabar esta situación para poder así implementarlo como lo harían en c#, definiendo el Main() como inicio de la aplicación.
[VB.NET]
01.
<STAThread()> _
02.
Friend
Shared
Sub
Main()
03.
04.
Application.EnableVisualStyles()
05.
Application.SetCompatibleTextRenderingDefault(
False
)
06.
07.
AddHandler
Application.ThreadException,
AddressOf
Application_ThreadException
08.
09.
Application.Run(
New
Form1())
10.
11.
End
Sub
12.
13.
Private
Shared
Sub
Application_ThreadException(
ByVal
sender
As
Object
,
ByVal
e
As
System.Threading.ThreadExceptionEventArgs)
14.
15.
MessageBox.Show(e.Exception.Message)
16.
17.
End
Sub
El código en ambos lenguajes preserva el mismo concepto, pero la forma en como se adjunta el evento difiera bastante.
Entonces, ahora si sucediera algo como lo reflejado en la imagen
O sea, si se ingresara caracteres en el calculo, el no atrapar el error en un bloque try..catch, haría que la aplicación finalice de forma brusca cerrándose, pero al tener definido el evento ThreadException, entraría en acción tomando el error y mostrando el mensaje.
Con estos simples paso ya tenemos el control global de errores implementado.
2- Log usando System.IO.Log
Si bien en una primer instancia hacer uso de un mensaje podría ayudar a detectar el problema en la aplicación, este podría evolucionar en un log a un archivo para dejar tracking de lo sucedido, en este caso no solo se pondría el mensaje del problema, sino que además se podría agregar el StackTrace para poder analizar que métodos se fueron ejecutando hasta causar el fallo.
En este caso el log a un archivos será muy simple
[C#]
01.
static
void
Application_ThreadException(
object
sender, System.Threading.ThreadExceptionEventArgs e)
02.
{
03.
using
(FileRecordSequence record =
new
FileRecordSequence(
"application.log"
, FileAccess.Write))
04.
{
05.
06.
string
message =
string
.Format(
"[{0}]Message::{1} StackTrace:: {2}"
, DateTime.Now,
07.
e.Exception.Message,
08.
e.Exception.StackTrace);
09.
10.
record.Append(CreateData(message), SequenceNumber.Invalid,
11.
SequenceNumber.Invalid,
12.
RecordAppendOptions.ForceFlush);
13.
}
14.
}
15.
16.
17.
private
static
IList<ArraySegment<
byte
>> CreateData(
string
str)
18.
{
19.
Encoding enc = Encoding.Unicode;
20.
21.
byte
[] array = enc.GetBytes(str);
22.
23.
ArraySegment<
byte
>[] segments =
new
ArraySegment<
byte
>[1];
24.
segments[0] =
new
ArraySegment<
byte
>(array);
25.
26.
return
Array.AsReadOnly<ArraySegment<
byte
>>(segments);
27.
}
[VB.NET]
01.
Private
Shared
Sub
Application_ThreadException(
ByVal
sender
As
Object
,
ByVal
e
As
System.Threading.ThreadExceptionEventArgs)
02.
03.
Using record
As
New
FileRecordSequence(
"application.log"
, FileAccess.Write)
04.
05.
Dim
message
As
String
=
String
.Format(
"[{0}]Message::{1} StackTrace:: {2}"
, DateTime.Now, e.Exception.Message, e.Exception.StackTrace)
06.
07.
record.Append(CreateData(message), SequenceNumber.Invalid, SequenceNumber.Invalid, RecordAppendOptions.ForceFlush)
08.
End
Using
09.
10.
End
Sub
11.
12.
13.
Private
Shared
Function
CreateData(
ByVal
str
As
String
)
As
IList(Of ArraySegment(Of
Byte
))
14.
15.
Dim
enc
As
Encoding = Encoding.
Unicode
16.
17.
Dim
_array
As
Byte
() = enc.GetBytes(str)
18.
19.
Dim
segments
As
ArraySegment(Of
Byte
)() =
New
ArraySegment(Of
Byte
)(0) {}
20.
segments(0) =
New
ArraySegment(Of
Byte
)(_array)
21.
22.
Return
Array.AsReadOnly(Of ArraySegment(Of
Byte
))(segments)
23.
24.
End
Function
Ahora el evento global de errores tiene bastante mas código, en donde se arma un mensaje bastante mas útil, el cual será enviado a la funcionalidad de log para registrar el suceso.
Para recuperar el archivo, solo deben ir a la ubicación donde esta el .exe, en este caso debería esta en la carpeta \bin\Debug del proyecto.
Lo mas probable es que el archivo no se legible a simple vista porque este sistema de log trabaja con el concepto de entradas de registros, es por eso que se confecciono un formulario muy simple para poder recuperar la información de forma visual.
[C#] | [VB.NET] |
3- Log usado Log4Net
Como alternativa siempre es bueno conocer algún otro framework de log, y log4net es uno con muchas posibilidades y configuraciones.
Lo bueno de este es que al ser configurable uno puede activarlo o cambiar el medio donde se quiere loguear sin tocar el código, hoy se loguea a un archivo, el día de mañana al visor de suceso de windows y si esto no converse, se podría enviar a una tabla en una db, y lo bueno de todo esto se puede lograr sin cambiar el código.
Fuente: http://ltuttini.blogspot.com
No hay comentarios:
Publicar un comentario