La posibilidad de tener logs en las aplicaciones nos pueden ayudar bastante en el día a día, sobretodo cuando no podemos depurar nuestro código. Por ello, hoy os propongo un código sencillo para llevar un registro de los eventos de nuestra aplicación en VB.NET.
Tabla de Contenidos
El código
Imports System.IO Public Class Logger Public Enum TipoMensaje DEBUG INFO WARNING LERROR End Enum Private Const TAM_FICHERO As Integer = 52428800 Private Const EXTENSION As String = ".log" Private Shared eNivel As TipoMensaje = TipoMensaje.DEBUG Public Shared Property Nivel As TipoMensaje Get Return eNivel End Get Set(eActual As TipoMensaje) eNivel = eActual End Set End Property Private Shared Sub add(ByVal eTipo As TipoMensaje, _ ByVal sMensaje As String, _ Optional ByVal objTraza As StackFrame = Nothing) If eTipo >= eNivel Then Dim sDestino As String = getFileFecha() verificar(sDestino) Dim objFichero As New FileStream(sDestino, FileMode.Append, _ FileAccess.Write) If Not objFichero Is Nothing And objFichero.CanWrite Then Dim sDeb As String = String.Empty Dim objFecha As Date = Date.Now sDeb = objFecha.ToString() + " [" + eTipo.ToString + "] " sDeb &= getTraza(objTraza) & sMensaje Dim objStream As New StreamWriter(objFichero) objStream.WriteLine(sDeb) objStream.Close() objFichero.Close() End If End If End Sub Private Shared Function getFileFecha() As String Dim objFecha As Date = Date.Now Dim sCadena As String = String.Empty sCadena &= objFecha.Year If objFecha.Month < 10 Then sCadena &= "0" End If sCadena &= objFecha.Month If objFecha.Day < 10 Then sCadena &= "0" End If sCadena &= objFecha.Day sCadena &= EXTENSION Return sCadena End Function Private Shared Sub verificar(sFichero As String) Try If My.Computer.FileSystem.GetFileInfo(sFichero).Length >= _ TAM_FICHERO Then My.Computer.FileSystem.MoveFile(sFichero, sFichero & ".old") End If Catch ex As IOException End Try End Sub Public Shared Sub e(sMensaje As String, objExcepcion As Exception, _ Optional ByVal objTraza As StackFrame = Nothing) add(TipoMensaje.LERROR, sMensaje & vbNewLine & _ vbTab & objExcepcion.Message & vbNewLine & _ vbTab & objExcepcion.ToString, objTraza) End Sub Public Shared Sub e(sMensaje As String, _ Optional ByVal objTraza As StackFrame = Nothing) add(TipoMensaje.LERROR, sMensaje, objTraza) End Sub Public Shared Sub w(sMensaje As String, _ Optional ByVal objTraza As StackFrame = Nothing) add(TipoMensaje.WARNING, sMensaje, objTraza) End Sub Public Shared Sub i(sMensaje As String, _ Optional ByVal objTraza As StackFrame = Nothing) add(TipoMensaje.INFO, sMensaje, objTraza) End Sub Public Shared Sub d(sMensaje As String, _ Optional ByVal objTraza As StackFrame = Nothing) add(TipoMensaje.DEBUG, sMensaje, objTraza) End Sub Public Shared Function getTraza(objTraza As StackFrame) As String Dim sTraza As String = String.Empty If Not objTraza Is Nothing Then Dim iPosicion As Integer = objTraza.GetFileName.LastIndexOf("\") If iPosicion < 0 Then sTraza = objTraza.GetFileName() Else sTraza = objTraza.GetFileName().Substring(iPosicion + 1) End If sTraza &= "::" & objTraza.GetFileLineNumber & " - " End If Return sTraza End Function End Class
Explicación
Lo primero que vemos es la enumeración TipoMensaje que contiene los posibles tipos de registro que tendremos. A la hora de guardar nuestro registro se mostrará el nivel de cada evento.
La función getFileFecha() obtiene el nombre del fichero que vamos a utilizar. Por ejemplo, en el día de escritura de este artículo el nombre obtenido sería: 20120724.log.
El método verificar() lo que hace es analizar el tamaño del fichero de registro. Si este excede el límite que viene dado por la constante TAM_FICHERO se realiza una copia de seguridad y se comienza un nuevo fichero. Esta parte la podéis obviar si no os importa el tamaño de los archivos.
El método add() es el que contiene la parte principal del código. Recibe el tipo de registro, así como el mensaje a almacenar y de forma opcional la traza y se encarga de almacenarlos en el fichero de registro con la fecha y hora actuales.
Los métodos d(), i(), w() y e() hacen de interfaz para simplificar la escritura en el registro y son los métodos que utilizará el usuario o usuaria. El método e() puede recibir un parámetro extra que será un objeto de tipo Exception, de esta forma podremos añadir a nuestro log el contenido de la excepción.
Resultado
El resultado de utilizar nuestra clase Logger sería parecido al siguiente:
24/07/2012 16:37:34 [LERROR] - Este no tiene traza 24/07/2012 16:37:35 [DEBUG] FrmPrueba.vb::7 - Este si tiene traza 24/07/2012 16:37:36 [INFO] FrmPrueba.vb::9 - Mensaje de información. 24/07/2012 16:38:02 [LERROR] FrmPrueba.vb::19 - Ocurrió un error Valor demasiado grande o demasiado pequeño para un decimal. System.OverflowException: Valor demasiado grande o demasiado pequeño para un decimal. en System.Decimal..ctor(Double value) en Logger.Form1.btnEnviar_Click(Object sender, EventArgs e) en FrmPrueba.vb:lÃnea 19
Finalmente, veamos como utilizar nuestro sistema de log. Lo primero es indicar el nivel de registro. Por defecto, es DEBUG, pero podemos ponerle un nivel, por ejemplo, de WARNING, esto se haría de la forma siguiente:
Logger.Nivel = Logger.TipoMensaje.WARNING
En este caso sólo se mostrarán los mensajes de WARNING y de ERROR, siendo omitidos los demás.
Ejemplos de uso:
Logger.e("Error con excepción", ex) Logger.d("Debug con traza", New StackFrame(True)) Logger.i("Info sin traza", New StackFrame(True)) Logger.e("Error con excepción y traza", ex, New StackFrame(True))
Tengo puesto el código en Github también, de forma que si hay cambios, en dicha plataforma podréis seguirlos: https://gist.github.com/3170403
Excelente Me salvaste!! muy bueno y sencillo!! Gracias!
Nada, para eso estamos 🙂
Muy bueno el codigo, pero debo ser franco y comentarte que estoy comenzo a programar en vb.net, por lo cual me gustaria usar y entender en profundidad tu codigo, ahora el problema es que cree la clase logger.vb pero no encuentro donde queda el archivo fisico, ademas como hago la inicializacion del archivo? o como se dispara y comienza a registrar informacion?. Se podria mediante un SQL conexion realizar el seguimiento a una Base de Datos (TRACE) con este codigo?
Espero puedas ayudarme y contestar a mis preguntas (novatas). Y Gracias por la información.
Saludos,
Sonyx.
Buenas, por un lado, en la versión de la clase que se indica en este código, el fichero de log se crea en el directorio de trabajo de la aplicación, es decir, si tu aplicación tiene como directorio de trabajo (C:/mi_ruta/), en dicho directorio se almacenaran una serie de ficheros del tipo AAAAMMDD.log (año/mes/día). Dicho archivo es creado automáticamente por la clase en caso de ser necesario, ahorrádonos su gestión.
Por otro, todos los métodos de la clase son estáticos, por lo que no es necesario instanciarla para comenzar a ejecutarla, tan sólo hacer llamadas como las que se indican en Ejemplos de uso al final del artículo.
Finalmente, el método add() es donde se añade la información de registro al fichero, en dicho método si sería posible introducir código que enviará la traza a un servidor de base de datos. Simplemente habría que cambiar los objStream y objFichero por objetos para poder realizar un INSERT sobre una base de datos.
Espero que te haya servido de ayuda.
Saludos:
Muy buen código,pero…¿dónde se guarda el log?
Es que tengo un programa hecho en VB.NET(con un hook de teclado,el cual reproduce un sonido al pulsar una tecla) que al depurarlo funciona bien,pero cuando lo publico,instalo….e inicio; y cuando pulso la tecla me sale un cartel que dice “Application1 dejo de funcionar; Windows está buscando una solución….”pero no dice nada más.
He añadido tu log pero no me aparece,¿qué he hecho mal?
Saludos y muchas gracias
Buenas, en el código expuesto el fichero se guardaría en la ruta de trabajo de la aplicación, es algo que en el futuro debería mejorar, porque si tenemos por ejemplo un acceso directo se almacenaría en el directorio de “Iniciar en”.
Si quieres puedes añadirle una ruta al método getFileFecha() para así tener controlado donde se almacena. Por ejemplo algo del estilo:
Con lo anterior se almacenaría en el directorio donde está la aplicación sin importar el directorio de ejecución.
Si sigue sin aparecerte el log no dudes en avisarme.
Un saludo
disculpa la ignorancia, pero…como lo hago funcionar?
Hola, sin problema para eso estamos 😉
Pues bien, debes añadir la clase que se indica en el código a tu aplicación, es decir, crear un fichero vb y copiar y pegar el código de la clase que se expone arriba.
Una vez hecho esto, tan sólo deberás importarla en el código que quieras usarla y llamar a sus métodos d(), i(), w() y e(), lo cuales recibirán una cadena que mostrarán como DEBUG, INFO, WARNING o ERROR respectivamente. Además, si los llamas con un objeto StackFrame se incluirá en la traza el fichero y línea desde donde se insertó.
Finalmente, si quieres que no se muestren los mensajes inferiores a un nivel determinado, deberás establecer la propiedad nivel. Por ejemplo, si la estableces a WARNING, los mensajes de tipo DEBUG e INFO serán descartados.
¡¡ Muy bueno !! ¡ Muchas gracias ! Te debo unas horas… ¡¡ Gracias !!
Nada, encantado de haberte sido de ayuda 🙂
Buenas! Muchas gracias por el código!
Podrías indicarme un ejemplo de cómo utilizar el objeto StackFrame para debuggear por favor?
Hola, buenas tardes Jose, ¿podrias explicarme porque hay dos Public Shared Sub “e”?
Buenas, el tener dos métodos e, es porque a uno le pasamos una excepción para que la imprima y en el otro método no se recibe dicho parámetro.
Hola Jose, cuando ejecuto la aplicación donde he incorporado tu log, en un equipo que no tiene instalado microsoft visual studio me arroja el siguiente error: Referencia a objeto no establecida como instancia de un objeto.
Buenas, revisa que esté instalado .NET Framework en la misma versión con la que has compilado la aplicación. En caso de que si, si me puedes pasar más información de la traza para analizar el por qué…
Estimado, de acuerdo con Fernando me sale este error ya revise la version en la pc cliente y es la misma
Consulte el final de este mensaje para obtener más detalles sobre cómo invocar a la depuración
Just-In-Time (JIT) en lugar de a este cuadro de diálogo.
************** Texto de la excepción **************
System.NullReferenceException: Referencia a objeto no establecida como instancia de un objeto.
en SistemaOrdenesServicio.Logger.getTraza(StackFrame objTraza)
en SistemaOrdenesServicio.Logger.add(TipoMensaje eTipo, String sMensaje, StackFrame objTraza)
en System.Windows.Forms.Form.CheckCloseDialog(Boolean closingOnly)
gracias desde ya por tu pronta respuesta.
Hola,
A mi me da el mismo problema, uso VS 2019