/************************************************************************** loghandler - generic logfile interface. Copyright (C) 2000,2001 Stein Vråle This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **************************************************************************/ /* INTRO This is a generic log application providing basic log routines, for use in any application that need a simple way to produce logfiles. USAGE To use loghandler in a new application, make sure the header file is included in all source files where log messages will be generated. Then init the needed loghandles during application startup, by providing the filename to be written into and any additional configuration parameters. Finally add one of the message recorders wherever a logmessage is needed, and specify the targeted loglevel/class, a printf formatted message template, and any arguments needed for the current logmessage. The logf method is meant for permanent logmessages, while the debugf method is meant for development logging - to be easy to turn of when the applictions runs in production. Examples: loghandler_init(0,"/tmp/app.log"); logf(MSG_NORMAL,"User %s connected",username); debugf(MSG_VERBOSE || LOG_NET, "Connection params: ip=%s user=%s pw=%s",hostname,username,password); loghandler(MSG_ERROR,LOG_MAIN,"Missing config file %s",filename); LOG CLASSIFICATON logclass: Used to seperate between different parts of program etc. loglevel: Importance of this log message. Higher number is less important. logcode: Combined level and class RECORDER METHODS logf: Record msg by code loghandler: Same as logf, but specify by level and class debugf: Record msg by code, and add debugflag automatically CONTROL METHODS loghandler_init: loghandler_setlevel: loghandler_getlevel: loghandler_setclass: loghandler_getclass: INTERNAL FUNCTIONS logfilter: Process the logmsg recived from recorder and use filter to find the target loghandle ****************************************************************************/ #include #include #include #include #include "loghandler.h" typedef struct { const char *logdevice; int logclass; int loglevel; int logformat; } loghandle_struct; static loghandle_struct loghandle[LOGHANDLE_MAX]; static const char *event_code[] = { "mark", "fatal", "error", "warning", "normal", "notice", "info", "verbose", "08", "09", "10", "11", "12", "13", "14", "15" }; int logfilter(int logcode, const char *logmsg) { char time_str[LOGMSG_MAX]; char date_str[LOGMSG_MAX]; char year_str[LOGMSG_MAX]; time_t log_time; struct tm *time_tm; int logclass; int loglevel; char *str_ptr; /* Decode log code */ loglevel = logcode & 15; logclass = logcode & 240; /* Format timestamp */ log_time = time(NULL); time_tm = localtime(&log_time); strftime(year_str,LOGMSG_MAX,"%G",time_tm); strftime(date_str,LOGMSG_MAX,"%m%d",time_tm); strftime(time_str,LOGMSG_MAX,"%H:%M:%S",time_tm); /* Replace eventual line feeds */ while ((str_ptr=strchr(logmsg,'\n'))){ *str_ptr = ' '; } /* Loop all loghandles and see if they handle this message */ for (int id=0; id <= LOGHANDLE_MAX; id++){ if ((loghandle[id].logdevice != NULL) && // Current loghandle is configured (loghandle[id].logclass & logclass) && // loghandle handles this class (loghandle[id].loglevel >= loglevel)) // loghandle handles this level { /* Format message for output */ char outmsg[LOGMSG_MAX]=""; char buf[LOGMSG_MAX]=""; // Prefix format if (loghandle[id].logformat & SHOW_YEAR){ sprintf(buf,"%s ",year_str); strcat(outmsg,buf); } if (loghandle[id].logformat & SHOW_DATE){ sprintf(buf,"%s ",date_str); strcat(outmsg,buf); } if (loghandle[id].logformat & SHOW_TIME){ sprintf(buf,"%s ",time_str); strcat(outmsg,buf); } strcat(outmsg,"["); if (loghandle[id].logformat & SHOW_ID){ sprintf(buf,"%i.",id); strcat(outmsg,buf); } if (loghandle[id].logformat & SHOW_CLASS){ sprintf(buf,"%i.",logclass); strcat(outmsg,buf); } if (loghandle[id].logformat & SHOW_LEVEL){ sprintf(buf,"%s",event_code[loglevel]); strcat(outmsg,buf); } // Message snprintf(buf,sizeof(buf)-1,"] %s",logmsg); strncat(outmsg,buf,sizeof(outmsg)-strlen(outmsg)-1); /* Write message to logdevice */ FILE *fout = fopen (loghandle[id].logdevice,"a"); if (fout != NULL){ fprintf(fout,"%s\n",outmsg); fclose(fout); } else printf("loghandler FATAL: Could not write to logfile %s",loghandle[id].logdevice); } } return (0); } int loghandler_init(int id, const char *logdevice, int logclass, int loglevel, int logformat) { char msg[LOGMSG_MAX]; // Check parameters if (id > LOGHANDLE_MAX) return(-1); if (logdevice == NULL) return(-1); FILE *fout = fopen (logdevice,"a"); if (fout==NULL) return (-1); else fclose (fout); if (logformat < 0) logformat = DEFAULT_LOGFORMAT; if (logclass < 0) logclass = DEFAULT_LOGCLASS; if (loglevel < 0) loglevel = DEFAULT_LOGLEVEL; // Set config loghandle[id].logdevice = logdevice; loghandle[id].logformat = logformat; loghandle[id].logclass = logclass; loghandle[id].loglevel = loglevel; // Notify snprintf(msg, LOGMSG_MAX, "INIT::loghandle[%i] device[%s] format[%i] classfilter[%i] level[%i]", id, logdevice, logformat, logclass, loglevel); loghandler(logclass,D_CHECK,msg); return(0); } int loghandler_init(int id,const char *logdevice) { return (loghandler_init(id,logdevice,-1,-1,-1)); } int loghandler_setlevel(int id, int loglevel) { loghandler(loghandle[id].logclass, D_CHECK, "loghandle[%i].setlevel %i", id, loglevel); loghandle[id].loglevel = loglevel; return(0); } int loghandler_getlevel(int id) { return (loghandle[id].loglevel); } int loghandler_setclass(int id, int logclass) { loghandle[id].logclass = logclass; return(0); } int loghandler_getclass(int id) { return (loghandle[id].logclass); } void loghandler(int loglevel, int logclass, const char *msg, ...) { char logmsg[LOGMSG_MAX]; int logcode; /* Combine class and level to logcode */ logcode = loglevel | logclass; // Format message va_list list; va_start (list,msg); vsprintf (logmsg,msg,list); va_end (list); logfilter(logcode, logmsg); } void logf(int logcode, const char *msg, ...) { char logmsg[LOGMSG_MAX]; logcode |= MAIN_LOG; // Format message va_list list; va_start (list,msg); vsprintf (logmsg,msg,list); va_end (list); logfilter(logcode, logmsg); } void debugf(int logcode, const char *msg, ...) { char logmsg[LOGMSG_MAX]; logcode |= DEBUG_LOG; // Add debug flag logcode |= MAIN_LOG; // Temporary hack // Format message va_list list; va_start (list,msg); vsprintf (logmsg,msg,list); va_end (list); logfilter(logcode, logmsg); }