Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





CLogger - Grugnorr

Iniciado por ethernet, 31 de Diciembre de 2002, 07:34:50 PM

« anterior - próximo »

ethernet



    Uff, el rack donte tengo el código antiguo anda medio jodido :S, se desconecta sólo.
    Tras 2 cuelgues, he decidido escribir el código de cabeza. Disculpas si sale algo mal :(

    Un logger simple, singleton. Usa streams en vez de lista de argumentos variable
    ,sintaxis del printf() de C, así que es typesafe, extensible, y cómodo ;)

    Lo fundamental es la idea, ya que el código es un ejemplo, cada uno tiene su
    sistema de loggeo adaptado a su uso particular,excepciones propias, distintos
    logs para cada subsistema,logs en debug al compilador mediante OutputDebugString() etc, etc...

    como todo en esta vida, lo simple puede
    complicarse ;)

    Como el COTD se basa en como usar streams para loggear, no he querido liar el código
    aún más por el asunto del singleton. Está implementado como en el Design Patterns
    así que algunos sabréis que el destructor no se llama :(, un leak que en éste caso
    no importa, pero con otros recursos puede importar. En el Modern C++ design viene
    un capítulo dedicado a implementar singletons.

    Para usar el logger, se recurre normalmente a macros. La mayoría de los logs
    que se usan utilizan los macros__FILE__ y __LINE__, así que hay que usar
    macros por cojones. En éste caso ayudan también ha que se use el logger con
    un sintaxis normal(directamente sería CLogger::Instance().Log()<<"Hola"<, largo  y raro, eh? ;) )

    He hecho distintas distinciones:

    LOG() y LOGLN().  LOGLN() añade un salto de página.

         LOG() y LOG_ERRROR() . EL log de errores añade el fichero y la línea
                    donde se llama.
       
        Existe también LOG_DEBUG() para info que sólo queremos loggear en modo debug






/////////////////////////////

//

// fichero: CLogger.h

//

/////////////////////////////

#ifndef _CLOGGER_H

#define _CLOGGER_H



//-------------INCLUDES--------------------

#include <iostream>

#include <fstream>

#include <string>





class CLogger

{

public:

static CLogger& Instance(const char* FilePath="Log.txt");

std::ofstream& Log(){return m_FileStream;}



private:

void Init(const char* FilePath);



/* La creación y destrucción del singleton de forma explícita se prohibe*/

CLogger(){};

CLogger(const CLogger& Logger);

CLogger& operator=(const CLogger& Logger);

~CLogger();

/**/



/*el fichero donde escribimos el log*/

std::ofstream   m_FileStream;



static CLogger*  ms_pInstance;



};



//---------------------DEFINES----------------



//Por comodidad, podemos tratar al singleton como si fuera una variable global

#define g_Logger  CLogger::Instance()





#define LOG(TEXT) {g_Logger.Log()<<TEXT;}



#define LOGLN(TEXT) {g_Logger.Log()<<TEXT<<std::endl;}







#ifdef _DEBUG

//logs que sólo queremos en modo debug



#define LOG_DEBUG(TEXT) {g_Logger.Log()<<TEXT;}

#define LOGLN_DEBUG(TEXT) {g_Logger.Log()<<TEXT<<std::endl;}



#else

//en release no los escribimos

#define LOG_DEBUG(TEXT) {}

#define LOGLN_DEBUG(TEXT) {}



#endif



//los logs de errores añaden el fichero y la línea donde se llama



#define LOG_ERROR(TEXT) {g_Logger.Log()<<"FATAL_ERROR!: "<< TEXT

 <<" AT FILE: "<<__FILE__<<" IN LINE: "<<__LINE__;}



#define LOGLN_ERROR(TEXT) {g_Logger.Log()<<"FATAL_ERROR!: "<< TEXT

 <<" AT FILE: "<<__FILE__<<" IN LINE: "<<__LINE__<<std::endl;}



#endif //_CLOGGER_H





/////////////////////////////

//

//fichero: CLogger.cpp

//

/////////////////////////////



#include "CLogger.h"

#include <exception>





//Linkamos las variables estáticas

CLogger* CLogger::ms_pInstance=NULL;



//--------------CLOGGER()----------------

void CLogger::Init(const char* FilePath)

{

m_FileStream.open(FilePath,std::ios::out|std::ios::trunc);



if(m_FileStream==NULL)//No podemos crear un fichero de log :(

 throw std::exception("Couldn´t open file stream");

}



//-----------------~CLOGGER()---------------

CLogger::~CLogger()

{

delete ms_pInstance;

ms_pInstance=NULL;

m_FileStream.close();



}

//----------------INSTANCE()----------------

//Punto de acceso al singleton. Se creará en la primera llamada.

CLogger& CLogger::Instance(const char* FilePath)

{

if(ms_pInstance==NULL)

{  

 ms_pInstance=new CLogger();

 ms_pInstance->Init(FilePath);

}





return *ms_pInstance;

}



/////////////////////////////

//

//fichero main.cpp

//

/////////////////////////////



#include "CLogger.h"

#include <iostream>





void main()

{

/*Creamos el fichero de log*/

CLogger::Instance("LogPrueba.txt");



int i=22;





LOGLN("Hola soy Grug, tengo "<<i<<" años ,llego tarde y la novia me mata... chaops


;)");



/*llamada sin macro.*/

g_Logger.Log()<<"Hola soy Grug, tengo "<<i<<" años "<<" y  la novia me mata... chaops


;)"<<std::endl;



LOGLN_ERROR("Error!, kk de ejemplo;)");

}






    Éste código fue enviado por Grugnorr el luneas, 30 de diciembre del 2002.

    Si quieres enviar tu propio código hazlo a  
eth_cotd@lycos.es

    Mars Attacks

                                    Jejeje, menuda prueba más rara. Menos mal que no dice a qué lo mata  :X9:
    Personalmente, recomiendo complicarse un poquito más la vida para hacer logs en html. Desde la primera vez que los vi creo que me enamoré de ellos. Puedes poner los errores en rojo, cabeceras en mayor tamaño para los puntos principales de las listas, letra pequeña para las sublistas, valores en negrita... en fin, para qué contaros qué es un htm  :)
    Pues eso, que modificando un poco un logger ya terminado se puede conseguir algo con mucho más estilo.                                

    ethernet

    Si, para ellos puedes tener  un log con metedos virtuales e implementarlo como quieras:

    CLog *log = new CHTMLLog; // por ejemplo

    Por otro lado un comentario al codigo:
    Aunque no se llame al destructor no quita de q se pueda poner un metodo llamado Shutdown o Release.

    saludos

    Grugnorr

                                    Uff, las 10 de la mañana,Año Nuevo.Me acuesto y me voy de vacaciones a Paris una semana....

    Lo del log en HTML ya lo he hecho alguna vez, simplemente escribir los TAGs en el fichero y guardarlo como HTML

    Lo de destruir el singleton... Lo dejé así por ser los singletons un tema aparte, que puede dar para mucho más de lo que parece(un capítulo del libro más rallante jamás escrito, ModernC++ Design, y así intento que recordéis que el sinfleton del Design Patterns leakea ;)

    Lo fundamental era la idea simple de usar streams para loggear, que no se lo he visto a nadie...


    PD: Que mi rack fuera tan tímido que rehusara dejarme acceder al código antiguo de mi logger no ayuda a dar una versión muy currada, pero como digo, cada cual lo ajusta a sus necesidades. Yo tenía mis excdpciones integradas y alguna cosilla más.                                
    hat the hells!






    Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
    Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
    Muchísimas gracias.