Para agregar un log al nuestro software podemos ayudarnos con el sistema operativo, por ejemplo en UNIX y Linux tenemos Syslog que es muy flexible y que nos hace la vida más fácil. En el caso de no poder (o no querer) utilizar los recursos proporcionados por el OS podemos pensar de escribir nuestro propio sistema de log, como veremos más adelante en este post. Vamos a tratar de emular , más o menos, la sintaxis y la función de Syslog, tratando de hacer un producto sencillo pero de calidad, o sea un producto profesional, porque siempre tratamos de ser profesionales, tal vez sin llegar a los excesos de profesionalidad del protagonista del título.
Me llamo Log, James Log |
Vemos el header file, mylog.h:
Simple y que se explica por sí mismo, ¿no? Nuestro producto se compone de tres funciones canónicas (abre, usa, cierra), y trabaja en niveles de gravedad (actualmente cuatro). Casi no hace falta explicar que, estableciendo un nivel, en el logfile aparecerán todos los mensajes de nivel de gravedad igual o mayor del nivel seleccionado. El nivel de NOLOG, luego, es básicamente una flag de inhabilitación que nos permite iniciar la aplicación sin logfile, para aligerar la ejecución: se supone que debe ser una inhabilitación real, es decir, la CPU y el sistema de I/O deben realimente trabajar menos sin el log habilitado.// niveles de mylog #define MYLOG_NOLOG -1 // ningún mensaje de log #define MYLOG_ERROR 0 // condición de errore #define MYLOG_WARNING 1 // condición de warning #define MYLOG_DEBUG 2 // mensaje de debug // prototipos globales void myOpenLog(const char *fname, int level); void myLog(int level, const char *format, ...); void myCloseLog();
Veamos ahora el ejemplo de uso, main.c:
Sencillo, ¿no? Ejecuto un test de argumentos con ejemplo de uso (usage...), y luego abro, uso, cierro, salgo. Mediante una línea de comandos como "mylog log.log 1", ¿como será el resultado? Creará un file "log.log" que contendrá las siguientes dos líneas:#include <stdio.h> #include <stdlib.h> #include "mylog.h" int main(int argc, char* argv[]) { // test argumentos if (argc != 3) { printf("mylog: wrong arguments counts\n"); printf("usage: mylog logfile loglevel [e.g.: mylog log.txt 1]\n"); return EXIT_FAILURE; } // open log: set logfname y loglevel (0=error/1=warning/2=debug; -1=nolog) myOpenLog(argv[1], atoi(argv[2])); // test mylog() myLog(MYLOG_ERROR, "esto es un msg de tipo %d (el nivel impostado es %d)", MYLOG_ERROR, atoi(argv[2])); myLog(MYLOG_WARNING, "esto es un msg de tipo %d (el nivel impostado es %d)", MYLOG_WARNING, atoi(argv[2])); myLog(MYLOG_DEBUG, "esto es un msg de tipo %d (el nivel impostado es %d)", MYLOG_DEBUG, atoi(argv[2])); // close log myCloseLog(); // exit return EXIT_SUCCESS; }
Añadimos detalles a la específica: usos sucesivos de la aplicación deben colgar líneas al logfile, ya que una clave fundamental de un log es mantener información de lo que pasa (y si cada vez reiniciamos el file la vamos a perder). Y si queremos empezar desde cero, podemos utilizar un otro filename, o borrar el viejo logfile antes de ejecutar. Otro detalle que llama la atención es que necesitamos, además de nuestros textos de traza, también informaciones horarias, tal vez muy precisas (en el ejemplo hay los microsegundos: en el próximo episodio explicaré por qué).2014-01-18 18:39:33.890271 - esto es un msg de tipo 0 (el nivel impostado es 1) 2014-01-18 18:39:33.890407 - esto es un msg de tipo 1 (el nivel impostado es 1)
Para hoy terminamos. Los mas trabajadores podrán, esperando la segunda parte, escribir su propia implementación, y luego compararla con la mía, pero la mía será seguramente mejor... (se aleja riendo).
¡Hasta el próximo post!