martes, 24 de noviembre de 2009

Un sistema de Log sencillo y flexible

Está bastante claro que es necesario guardar lo que hace el código por dentro. Un buen log puede guardar lo que haga tu código y eso es bastante importante. También debería ser importante el poder invocarlo de manera sencilla, es decir, que no fuera necesario meter toda una suerte de instrucciones para incializarlo en cada archivo fuente en el que necesites guardar mensajes. Y además, se debería poder poner los mensajes en archivos separados o descartarlos para ganar performance.

Hasta ahora tiraba con diferentes códigos que encontraba en la web. Pero casi todos me resultaban algo complicados, o demasiado pobres en cuanto a prestaciones. Ademas yo estaba acostumbrado a Log4Java, pero el port a C++ se me hacia raro, así que siguiendo un modelo parecido me decidí a hacer el mio propio. En principio, los requisitos que quería cumplir eran los siguientes.
  • Los mensajes debían ir a todos a la misma estructura de memoria. No quería buscar donde había puesto un mensaje.
  • Debía ordenar los mensajes por grupos, para asi poder recordar mensajes de un sub sistema separados de otros.
  • Debía poder filtrarse por nivel de importancia.
  • Debía ser portable (en la medida de lo posible)

No miré que fuera thread safe, aunque en un futuro quizás me lio con programación multihilo, por que de momento no tengo muy estudiado el tema, pero por lo demás si que cumplí con las expectativas. Aplique un patron observer-observable, de manera que podía hacer una clase que aceptara todos los mensajes, y por otro lado, aquellas clases que quieran procesar los mensajes, se tienen que añadir como listeners(observer). Cada listener tiene la posibilidad de procesar los mensajes como quiera, es decir, no hay problema para que los mensajes vayan a la consola, a un archivo, a una base de datos o simplemente ser ignorados. Simplemente teniamos que implementar una clase abstracta para que procese el mensaje entrante y lo mande donde sea necesario.

La clase que procesa los mensajes se crea en una sola linea (es un singleton), y sin configuración adicional ya acepta mensajes, con lo que al principio de una clase y con sola una linea, ya puedo añadir mensajes a la cola de mensajes.

// inicializacion del sistema de logs
tools::log::CGlobalLog *theLog = tools::log::CGlobalLog::getInstance();


También es muy fácil añadir grupos nuevos para mensajes de sistemas independientes. Se pueden entender los grupos como filtros, o como asociar un determinado mensaje a un nombre o sistema. Solo hay que añadir un grupo de log.

//el primer grupo lo añadimos explicitamente
theLog->addLoggerGroup(lgroup1);

theLog->addListener(&w2,lgroup2); //este segundo grupo se añade de manera implicita, juto al añadir el listener

y a partir de ahí solo hay que enviar los mensajes a ese grupo de log. En caso de que queramos ganar en performance, simplemente debemos 'aumentar' el nivel minimo de los mensajes. Por ejemplo, cuando estamos depurando podemos poner como nivel minimo de mensaje "debug" que es el nivel minimo. Esto hace que se acepten todos los mensajes. En cambio, cuando ya tenemos el producto final podemos decir que solo acepte los que tengan un nivel igual o superior a 'warning'.

//decimos que el nivel minimo para que un mensaje se guarde es WARNING
theLog->setMinimumLogLevel(tools::log::LOGLEVEL_WARNING);

Le dejo el código para quien quiera usarlo, junto con un main.cpp de prueba. Simplemente, te pido que si encuentras algún error me avises.

Descargar código(5.35KB)

No hay comentarios:

Publicar un comentario