/* log.c - logging funtions Copyright (C) 2002, 2003, 2008, 2010, 2011 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "log.h" /* set the logname */ #undef PACKAGE #define PACKAGE "nslcd" /* storage for logging modes */ static struct cvsd_log { FILE *fp; /* NULL==syslog */ int loglevel; struct cvsd_log *next; } *cvsd_loglist=NULL; /* default loglevel when no logging is configured */ static int prelogging_loglevel=LOG_INFO; /* the session id that is set for this thread */ static __thread char *sessionid=NULL; /* the request identifier that is set for this thread */ static __thread char *requestid=NULL; #define MAX_REQUESTID_LENGTH 40 /* set loglevel when no logging is configured */ void log_setdefaultloglevel(int loglevel) { prelogging_loglevel=loglevel; } /* add logging method to configuration list */ static void log_addlogging_fp(FILE *fp,int loglevel) { struct cvsd_log *tmp,*lst; /* create new logstruct */ tmp=(struct cvsd_log *)malloc(sizeof(struct cvsd_log)); if (tmp==NULL) { fprintf(stderr,"malloc() failed: %s",strerror(errno)); /* since this is done during initialisation it's best to bail out */ exit(EXIT_FAILURE); } tmp->fp=fp; tmp->loglevel=loglevel; tmp->next=NULL; /* save the struct in the list */ if (cvsd_loglist==NULL) cvsd_loglist=tmp; else { for (lst=cvsd_loglist;lst->next!=NULL;lst=lst->next); lst->next=tmp; } } /* configure logging to a file */ void log_addlogging_file(const char *filename,int loglevel) { FILE *fp; fp=fopen(filename,"a"); if (fp==NULL) { log_log(LOG_ERR,"cannot open logfile (%s) for appending: %s",filename,strerror(errno)); exit(EXIT_FAILURE); } log_addlogging_fp(fp,loglevel); } /* configure logging to syslog */ void log_addlogging_syslog(int loglevel) { openlog(PACKAGE,LOG_PID,LOG_DAEMON); log_addlogging_fp(NULL,loglevel); } /* configure a null logging mode (no logging) */ void log_addlogging_none() { /* this is a hack, but it's so easy */ log_addlogging_fp(NULL,LOG_EMERG); } /* start the logging with the configured logging methods if no method is configured yet, logging is done to syslog */ void log_startlogging(void) { if (cvsd_loglist==NULL) log_addlogging_syslog(LOG_INFO); prelogging_loglevel=-1; } /* indicate that we should clear any session identifiers set by log_newsession */ void log_clearsession(void) { /* set the session id to empty */ if (sessionid!=NULL) sessionid[0]='\0'; /* set the request id to empty */ if (requestid!=NULL) requestid[0]='\0'; } /* indicate that a session id should be included in the output and set it to a new value */ void log_newsession(void) { /* ensure that sessionid can hold a string */ if (sessionid==NULL) { sessionid=(char *)malloc(7); if (sessionid==NULL) { fprintf(stderr,"malloc() failed: %s",strerror(errno)); return; /* silently fail */ } } sprintf(sessionid,"%06x",(int)(rand()&0xffffff)); /* set the request id to empty */ if (requestid!=NULL) requestid[0]='\0'; } /* indicate that a request identifier should be included in the output from this point on, until log_newsession() is called */ void log_setrequest(const char *format, ...) { va_list ap; /* ensure that requestid can hold a string */ if (requestid==NULL) { requestid=(char *)malloc(MAX_REQUESTID_LENGTH); if (requestid==NULL) { fprintf(stderr,"malloc() failed: %s",strerror(errno)); return; /* silently fail */ } } /* make the message */ va_start(ap,format); vsnprintf(requestid,MAX_REQUESTID_LENGTH,format,ap); requestid[MAX_REQUESTID_LENGTH-1]='\0'; va_end(ap); } /* log the given message using the configured logging method */ void log_log(int pri,const char *format, ...) { int res; struct cvsd_log *lst; /* TODO: make this something better */ #define maxbufferlen 200 char buffer[maxbufferlen]; va_list ap; /* make the message */ va_start(ap,format); res=vsnprintf(buffer,maxbufferlen,format,ap); if ((res<0)||(res>=maxbufferlen)) { /* truncate with "..." */ buffer[maxbufferlen-2]='.'; buffer[maxbufferlen-3]='.'; buffer[maxbufferlen-4]='.'; } buffer[maxbufferlen-1]='\0'; va_end(ap); /* do the logging */ if (prelogging_loglevel>=0) { /* if logging is not yet defined, log to stderr */ if (pri<=prelogging_loglevel) { if ((requestid!=NULL)&&(requestid[0]!='\0')) fprintf(stderr,"%s: [%s] <%s> %s%s\n",PACKAGE,sessionid,requestid,pri==LOG_DEBUG?"DEBUG: ":"",buffer); else if ((sessionid!=NULL)&&(sessionid[0]!='\0')) fprintf(stderr,"%s: [%s] %s%s\n",PACKAGE,sessionid,pri==LOG_DEBUG?"DEBUG: ":"",buffer); else fprintf(stderr,"%s: %s%s\n",PACKAGE,pri==LOG_DEBUG?"DEBUG: ":"",buffer); } } else { for (lst=cvsd_loglist;lst!=NULL;lst=lst->next) { if (pri<=lst->loglevel) { if (lst->fp==NULL) /* syslog */ { if ((requestid!=NULL)&&(requestid[0]!='\0')) syslog(pri,"[%s] <%s> %s",sessionid,requestid,buffer); else if ((sessionid!=NULL)&&(sessionid[0]!='\0')) syslog(pri,"[%s] %s",sessionid,buffer); else syslog(pri,"%s",buffer); } else /* file */ { if ((requestid!=NULL)&&(requestid[0]!='\0')) fprintf(lst->fp,"%s: [%s] <%s> %s\n",sessionid,requestid,PACKAGE,buffer); else if ((sessionid!=NULL)&&(sessionid[0]!='\0')) fprintf(lst->fp,"%s: [%s] %s\n",sessionid,PACKAGE,buffer); else fprintf(lst->fp,"%s: %s\n",PACKAGE,buffer); fflush(lst->fp); } } } } } /* return the syslog loglevel represented by the string return -1 on unknown */ int log_getloglevel(const char *lvl) { if ( strcmp(lvl,"crit")==0 ) return LOG_CRIT; else if ( (strcmp(lvl,"error")==0) || (strcmp(lvl,"err")==0) ) return LOG_ERR; else if ( strcmp(lvl,"warning")==0 ) return LOG_WARNING; else if ( strcmp(lvl,"notice")==0 ) return LOG_NOTICE; else if ( strcmp(lvl,"info")==0 ) return LOG_INFO; else if ( strcmp(lvl,"debug")==0 ) return LOG_DEBUG; else return -1; /* unknown */ }