/* ******************************************** */ /* File Name: log.c */ /* Author: (C) 2007-2009 - Juan José Ponteprino */ /* Description: Loggin API */ /* License: This code is licenced as LGPL */ /* ******************************************** */ #include #include #if WIN32 #define vsnprintf _vsnprintf #endif #include #include #include /* ---------------------------------------------------- */ static char * log_str_priority[] = { "EMERG" , "ALERT" , "CRIT" , "ERR" , "WARN" , "NOTICE" , "INFO" , "DEBUG" , "N/D" }; static int log_level = -1; /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ /* Default Backend */ /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ static FILE * __log_file_roll( log_be_file_t * _privData ) { time_t Moment = time( NULL ); char MomentStr[ 18 ]; struct tm Now ; FILE * filelog; char * nfilename = malloc( strlen( _privData->fullpathname ) + 16 ); #if WIN32 struct tm * _Now = localtime( &Moment ); Now = * _Now; #else localtime_r( &Moment, &Now ); #endif fclose( _privData->handle ); strftime( MomentStr, sizeof( MomentStr ), "%y%m%d%H%M%S", &Now ); sprintf( nfilename, "%s.%s", _privData->fullpathname, MomentStr ); rename( _privData->fullpathname, nfilename ); free( nfilename ); filelog = _privData->handle = fopen( _privData->fullpathname, "a" ); if ( !filelog ) { filelog = stdout; } return filelog; } /* ---------------------------------------------------- */ log_t * log_file_be_create() { log_t * lt = malloc( sizeof( log_t ) ); if ( !lt ) { return NULL; } lt->log_open = log_file_open; lt->log_close = log_file_close; lt->log_write = log_file_write; lt->log_control = log_file_control; return lt; } /* ---------------------------------------------------- */ void * log_file_open( char * name, int flags ) { char * p; log_be_file_t * privData = ( log_be_file_t * ) malloc( sizeof( log_be_file_t ) ); if ( !privData ) { return NULL; } privData->flags = flags; privData->fullpathname = strdup( name ); if ( !privData->fullpathname ) { free( privData ); return NULL; } privData->filename = strrchr( privData->fullpathname, '/' ); if (!privData->filename) { privData->filename = strrchr( privData->fullpathname, '\\' ); } if ( !privData->filename ) privData->filename = privData->fullpathname; else privData->filename++; privData->handle = fopen( name, "a" ); if ( !privData->handle ) { free( privData->fullpathname ); free( privData ); return NULL; } return privData; } /* ---------------------------------------------------- */ void log_file_close( void * privData ) { if ( privData && (( log_be_file_t * ) privData )->handle ) { free((( log_be_file_t * ) privData )->fullpathname ); fclose((( log_be_file_t * ) privData )->handle ); free( privData ); } } /* ---------------------------------------------------- */ void log_file_write( void * privData, int priority, char * message ) { int doroll = 0; time_t Moment = time( NULL ); char MomentStr[ 18 ]; struct tm Now ; log_be_file_t * _privData = privData; FILE * filelog = _privData->handle; #if WIN32 struct tm * _Now = localtime( &Moment ); Now = * _Now; #else localtime_r( &Moment, &Now ); #endif if ( !filelog ) { filelog = stdout; } if ( _privData->flags & LOG_FILE_ROLL_SIZE_MASK ) { long pos = ftell( filelog ); if ( pos / 1024 >= ( _privData->flags & LOG_FILE_ROLL_SIZE_MASK ) ) { doroll = 1; } } if ( _privData->flags & LOG_FILE_ROLL_DAY ) { /* If day of year is different of last log, then roll it (tm_mday is used only for check valid date in internal structs) */ if ( Now.tm_yday != _privData->lastTime.tm_yday && _privData->lastTime.tm_mday != 0 ) { doroll = 1; } } if ( doroll ) { filelog = __log_file_roll( _privData ); } if ( priority >= LOG_PRIO_MAX ) { priority = LOG_PRIO_NODEF ; } if ( message && * message != '\0' ) { strftime( MomentStr, sizeof( MomentStr ), "%y/%m/%d-%H:%M:%S", &Now ); if ( _privData->flags & LOG_FILE_DISPLAY_FNAME ) fprintf( filelog, "%s:%s %7.4f %s %s\n", _privData->filename, MomentStr, clock() / 1000.00, log_str_priority[ priority ], message ); else fprintf( filelog, "%s %7.4f %s %s\n", MomentStr, clock() / 1000.00, log_str_priority[ priority ], message ); if ( !( _privData->flags & LOG_FILE_DONT_FLUSH ) ) fflush( filelog ); } _privData->lastTime = Now; } /* ---------------------------------------------------- */ void log_file_control( void * privData, long kid, char * args ) { switch ( kid ) { case LOG_FILE_ROLL_NOW: __log_file_roll(( log_be_file_t * ) privData ); break; case LOG_FILE_GET_FD: ( ( FILE ** ) args )[0] = ( FILE * )( ( ( log_be_file_t * ) privData )->handle ); break; } } /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ /* Log core functions */ /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ /* ---------------------------------------------------- */ int log_open( log_t * backend, char * name, int flags ) { if ( !backend || !backend->log_open ) { return 0; } backend->internalBuffer = malloc( LOG_INIT_INTERNAL_BUFFER_SIZE ); if ( !backend->internalBuffer ) { return 0; } backend->privData = backend->log_open( name, flags ); if ( !backend->privData ) { free( backend->internalBuffer ) ; return 0; } return 1; /* OK */ } /* ---------------------------------------------------- */ void log_close( log_t * backend ) { if ( backend && backend->privData && backend->log_close ) { backend->log_close( backend->privData ); if ( backend->internalBuffer ) { free( backend->internalBuffer ) ; } } } /* ---------------------------------------------------- */ void log_write( log_t * backend, int priority, char * format, ... ) { /* Suponemos que no necesitamos más de 100 bytes. */ int n; va_list ap; if ( !backend || !backend->privData || !backend->internalBuffer || !backend->log_write ) { return; } if ( log_level != -1 && priority > log_level ) return; /* Intenta imprimir en el espacio reservado. */ va_start( ap, format ); n = vsnprintf( backend->internalBuffer, LOG_INIT_INTERNAL_BUFFER_SIZE, format, ap ); va_end( ap ); if ( n <= -1 || n > LOG_INIT_INTERNAL_BUFFER_SIZE ) { int size = LOG_INIT_INTERNAL_BUFFER_SIZE * 2; char * p, * p1; if (( p = malloc( size ) ) == NULL ) { return; } while ( 1 ) { /* Intenta imprimir en el espacio reservado. */ va_start( ap, format ); n = vsnprintf( p, size, format, ap ); va_end( ap ); /* Si ha funcionado, devuelve la cadena. */ if ( n > -1 && n < size ) { break ; } /* Si no, inténtalo de nuevo con más espacio. */ if ( n > -1 ) /* glibc 2.1 */ { size = n + 1; /* exactamente lo que se necesita */ } else /* glibc 2.0 */ { size *= 2; /* el doble del tamaño anterior*/ } if (( p1 = realloc( p, size ) ) == NULL ) { free( p ); return; } p = p1; } backend->log_write( backend->privData, priority, p ); free( p ); } else { backend->log_write( backend->privData, priority, backend->internalBuffer ); } } /* ---------------------------------------------------- */ void log_control( log_t * backend, long kid, char * args ) { if ( !backend || !backend->privData || !backend->log_control ) { return; } if ( ( kid & LOG_SYSTEM_CTRL ) == LOG_SYSTEM_CTRL ) { switch ( kid ) { case LOG_LEVEL: log_level = ( int ) args; break; } return; } backend->log_control(( void * )( backend->privData ), kid, args ); } /* ---------------------------------------------------- */ FILE * log_get_handle( log_t * backend ) { log_be_file_t * _privData; _privData = ( log_be_file_t * ) backend->privData; return ( FILE *) _privData->handle; } /* ---------------------------------------------------- */