dnxLogging.c

Go to the documentation of this file.
00001 /*--------------------------------------------------------------------------
00002 
00003    Copyright (c) 2006-2007, Intellectual Reserve, Inc. All rights reserved.
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License version 2 as
00007    published by the Free Software Foundation.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; if not, write to the Free Software
00016    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018   --------------------------------------------------------------------------*/
00019 
00028 #if HAVE_CONFIG_H
00029 # include <config.h>
00030 #endif
00031 
00032 #include "dnxLogging.h"
00033 #include "dnxError.h"
00034 #include "dnxTransport.h"
00035 #include "dnxDebug.h"
00036 
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <stdio.h>
00040 #include <stdarg.h>
00041 #include <string.h>
00042 #include <time.h>
00043 #include <errno.h>
00044 #include <assert.h>
00045 #include <unistd.h>
00046 #include <syslog.h>
00047 
00048 #ifndef LOCALSTATEDIR
00049 # define LOCALSTATEDIR     "/var"
00050 #endif
00051 
00052 #define LOGDIR             LOCALSTATEDIR "/log"
00053 
00054 #ifndef DEF_LOG_FILE
00055 # define DEF_LOG_FILE      LOGDIR "/dnx.log"
00056 #endif
00057 
00058 #ifndef DEF_DEBUG_FILE
00059 # define DEF_DEBUG_FILE    LOGDIR "/dnx.debug.log"
00060 #endif
00061 
00062 #ifndef DEF_DEBUG_LEVEL
00063 # define DEF_DEBUG_LEVEL   0
00064 #endif
00065 
00067 #define MAX_LOG_LINE       4096
00068 #define SYSLOG_IDENT       "DNX"             
00069 
00070 static char SLTAG[] = "syslog:";             
00071 static int defDebugLevel = DEF_DEBUG_LEVEL;  
00072 
00073 static int s_syslogLog = 0;                  
00074 static int s_syslogDebug = 0;                
00075 static int s_syslogAudit = 0;                
00076 static int * s_debugLevel = &defDebugLevel;  
00077 static char s_logFileName[FILENAME_MAX + 1] = DEF_LOG_FILE;
00078 static char s_dbgFileName[FILENAME_MAX + 1] = DEF_DEBUG_FILE;
00079 static char s_audFileName[FILENAME_MAX + 1] = "";
00080 
00081 /*--------------------------------------------------------------------------
00082                               IMPLEMENTATION
00083   --------------------------------------------------------------------------*/
00084 
00093 static int decodeSyslogFlags(const char * flagstr, int defaultSev)
00094 {
00095    static struct { const char * str; int value; } sevflags[] = 
00096    {
00097       // severities (posix only)
00098       { "LOG_EMERG",    LOG_EMERG   },
00099       { "LOG_ALERT",    LOG_ALERT   },
00100       { "LOG_CRIT",     LOG_CRIT    },
00101       { "LOG_ERR",      LOG_ERR     },
00102       { "LOG_WARNING",  LOG_WARNING },
00103       { "LOG_NOTICE",   LOG_NOTICE  },
00104       { "LOG_INFO",     LOG_INFO    },
00105       { "LOG_DEBUG",    LOG_DEBUG   },
00106    };
00107    static struct { const char * str; int value; } facflags[] = 
00108    {
00109       // facilities (posix only)
00110       { "LOG_USER",     LOG_USER    },
00111       { "LOG_LOCAL0",   LOG_LOCAL0  },
00112       { "LOG_LOCAL1",   LOG_LOCAL1  },
00113       { "LOG_LOCAL2",   LOG_LOCAL2  },
00114       { "LOG_LOCAL3",   LOG_LOCAL3  },
00115       { "LOG_LOCAL4",   LOG_LOCAL4  },
00116       { "LOG_LOCAL5",   LOG_LOCAL5  },
00117       { "LOG_LOCAL6",   LOG_LOCAL6  },
00118       { "LOG_LOCAL7",   LOG_LOCAL7  },
00119    };
00120    char flagcpy[128];
00121    char * cp = flagcpy; // current word pointer
00122    char * ep;           // string end pointer
00123    int sevFound = 0, facFound = 0;
00124    int severity, facility;
00125 
00126    // make a working copy
00127    strncpy(flagcpy, flagstr, sizeof(flagcpy) - 1);
00128    flagcpy[sizeof(flagcpy) - 1] = 0;
00129    ep = cp + strlen(cp);
00130 
00131    // parse requested flag values
00132    while (cp < ep)
00133    {
00134       char * np;  // next word pointer
00135       char * tp;  // temp pointer
00136       int i;
00137 
00138       // remove leading whitespace (if any)
00139       while (isspace(*cp)) cp++;
00140 
00141       // terminate and find start of next
00142       if ((tp = np = strchr(cp, '|')) == 0)
00143          tp = np = ep;
00144       *np++ = 0;
00145 
00146       // remove trailing whitespace
00147       while (tp > --cp && isspace(*tp)) *tp = 0;
00148 
00149       // compare severity strings - ignore unknowns - last one wins
00150       for (i = 0; i < sizeof(sevflags) / sizeof(*sevflags); i++)
00151          if (strcmp(sevflags[i].str, cp) == 0)
00152          {
00153             severity = sevflags[i].value;
00154             sevFound = 1;
00155          }
00156             
00157       // compare facility strings - ignore unknowns - last one wins
00158       for (i = 0; i < sizeof(facflags) / sizeof(*facflags); i++)
00159          if (strcmp(facflags[i].str, cp) == 0)
00160          {
00161             facility = facflags[i].value;
00162             facFound = 1;
00163          }
00164 
00165       // move to next word
00166       cp = np;
00167    }
00168    if (!sevFound) severity = defaultSev;
00169    if (!facFound) facility = LOG_USER;
00170    return severity | facility;
00171 }
00172 
00173 //----------------------------------------------------------------------------
00174 
00182 static FILE * openFile(const char * filename, int * pstd)
00183 {
00184    int std = 1;
00185    FILE * fp = stdout;
00186 
00187    // check first for standard file handle references
00188    if (*filename && strcmp(filename, "STDOUT") != 0)
00189    {
00190       if (strcmp(filename, "STDERR") == 0)
00191          fp = stderr;
00192       else
00193       {
00194          // try 1000 times to open the file (in case it's shared)
00195          int i = 0;
00196          do fp = fopen(filename, "a+"); while (!fp && ++i < 1000);
00197          std = 0;
00198       }
00199    }
00200    *pstd = std;
00201    return fp;
00202 }
00203 
00204 //----------------------------------------------------------------------------
00205 
00212 static void dnx_vsyslog(int pri, const char * fmt, va_list ap)
00213 {
00214 #ifdef _BSD_SOURCE
00215    vsyslog(pri, fmt, ap);
00216 #else
00217    {
00218       char buf[MAX_LOG_LINE];
00219       vsnprintf(buf, sizeof(buf), fmt, ap);
00220       syslog(pri, "%s", buf);
00221    }
00222 #endif
00223 }
00224 
00225 //----------------------------------------------------------------------------
00226 
00235 static int vlogger(FILE * fp, char * fmt, va_list ap)
00236 {
00237    if (!isatty(fileno(fp)))
00238    {
00239       // "Sun Sep 16 01:03:52 1973\n\0"
00240       //  01234567890123456789012345
00241       char clock_buf[26];
00242       struct timespec tspec;
00243       clock_gettime(CLOCK_REALTIME, &tspec); 
00244       ctime_r(&tspec.tv_sec, clock_buf);
00245       if (fprintf(fp, "[%.*s.%-3ld%.*s] ", 
00246             19, clock_buf, 
00247             tspec.tv_nsec / (1000L * 1000L), // convert to milliseconds
00248             5, clock_buf + 19) < 0)
00249          return errno;
00250    }
00251    if (vfprintf(fp, fmt, ap) < 0)
00252       return errno;
00253    if (fputc('\n', fp) == EOF)
00254       return errno;
00255    if (fflush(fp) == EOF)
00256       return errno;
00257    return 0;
00258 }
00259 
00260 /*--------------------------------------------------------------------------
00261                                  INTERFACE
00262   --------------------------------------------------------------------------*/
00263 
00264 void dnxLog(char * fmt, ... )
00265 {
00266    va_list ap;
00267    assert(fmt);
00268 
00269    if (*s_logFileName)
00270    {
00271       if (s_syslogLog)
00272       {
00273          va_start(ap, fmt);
00274          dnx_vsyslog(s_syslogLog, fmt, ap);
00275          va_end(ap);
00276       }
00277       else
00278       {
00279          FILE * fp;
00280          int stdhandle;
00281          if ((fp = openFile(s_logFileName, &stdhandle)) != 0)
00282          {
00283             va_start(ap, fmt);
00284             vlogger(fp, fmt, ap);
00285             va_end(ap);
00286 
00287             if (!stdhandle)
00288                fclose(fp);
00289          }
00290       }
00291    }
00292 }
00293 
00294 //----------------------------------------------------------------------------
00295 
00296 void dnxDebug(int level, char * fmt, ... )
00297 {
00298    va_list ap;
00299    assert(fmt);
00300 
00301    if (*s_dbgFileName && level <= *s_debugLevel)
00302    {
00303       if (s_syslogDebug)
00304       {
00305          va_start(ap, fmt);
00306          dnx_vsyslog(s_syslogDebug, fmt, ap);
00307          va_end(ap);
00308       }
00309       else
00310       {
00311          FILE * fp;
00312          int stdhandle;
00313          if ((fp = openFile(s_dbgFileName, &stdhandle)) != 0)
00314          {
00315             va_start(ap, fmt);
00316             vlogger(fp, fmt, ap);
00317             va_end(ap);
00318 
00319             if (!stdhandle)
00320                fclose(fp);
00321          }
00322       }
00323    }
00324 }
00325 
00326 //----------------------------------------------------------------------------
00327 
00328 int dnxAudit(char * fmt, ... )
00329 {
00330    int ret = 0;
00331    va_list ap;
00332    assert(fmt);
00333 
00334    if (*s_audFileName)
00335    {
00336       if (s_syslogAudit)
00337       {
00338          va_start(ap, fmt);
00339          dnx_vsyslog(s_syslogAudit, fmt, ap);
00340          va_end(ap);
00341       }
00342       else
00343       {
00344          FILE * fp;
00345          int stdhandle;
00346          if ((fp = openFile(s_audFileName, &stdhandle)) != 0)
00347          {
00348             va_start(ap, fmt);
00349             ret = vlogger(fp, fmt, ap);
00350             va_end(ap);
00351 
00352             if (!stdhandle)
00353                fclose(fp);
00354          }
00355       }
00356    }
00357    return ret;
00358 }
00359 
00360 //----------------------------------------------------------------------------
00361 
00362 void dnxLogInit(char * logFile, char * debugFile, char * auditFile,
00363       int * debugLevel)
00364 {
00365    if (logFile)
00366    {
00367       if (strncasecmp(logFile, SLTAG, sizeof SLTAG - 1) == 0)
00368          s_syslogLog = decodeSyslogFlags(logFile 
00369                + sizeof SLTAG - 1, LOG_INFO);
00370       else
00371       {
00372          strncpy(s_logFileName, logFile, sizeof(s_logFileName) - 1);
00373          s_logFileName[sizeof(s_logFileName) - 1] = 0;
00374       }
00375    }
00376    if (debugFile)
00377    {
00378       if (strncasecmp(debugFile, SLTAG, sizeof SLTAG - 1) == 0)
00379          s_syslogDebug = decodeSyslogFlags(debugFile 
00380                + sizeof SLTAG - 1, LOG_DEBUG);
00381       else
00382       {
00383          strncpy(s_dbgFileName, debugFile, sizeof(s_dbgFileName) - 1);
00384          s_dbgFileName[sizeof(s_dbgFileName) - 1] = 0;
00385       }
00386    }
00387    if (auditFile)
00388    {
00389       if (strncasecmp(auditFile, SLTAG, sizeof SLTAG - 1) == 0)
00390          s_syslogDebug = decodeSyslogFlags(auditFile 
00391                + sizeof SLTAG - 1, LOG_NOTICE);
00392       else
00393       {
00394          strncpy(s_audFileName, auditFile, sizeof(s_audFileName) - 1);
00395          s_audFileName[sizeof(s_audFileName) - 1] = 0;
00396       }
00397    }
00398    s_debugLevel = debugLevel;
00399 
00400    // see if syslog is required before opening - we don't want to change
00401    //    the syslog attributes for the Nagios process (for example).
00402    if (s_syslogLog || s_syslogDebug || s_syslogAudit)
00403       openlog(SYSLOG_IDENT, 0, 0);
00404 }
00405 
00406 /*--------------------------------------------------------------------------*/
00407 

Generated on Tue Apr 13 15:48:07 2010 for DNX by  doxygen 1.5.6