XrdSysLogger.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                       X r d S y s L o g g e r . c c                        */
00004 /*                                                                            */
00005 /*(c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University   */
00006 /*       All Rights Reserved. See XrdInfo.cc for complete License Terms       */
00007 /*Produced by Andrew Hanushevsky for Stanford University under contract       */
00008 /*           DE-AC03-76-SFO0515 with the Deprtment of Energy                  */
00009 /******************************************************************************/
00010 
00011 //       $Id: XrdSysLogger.cc 35287 2010-09-14 21:19:35Z ganis $ 
00012 
00013 const char *XrdSysLoggerCVSID = "$Id: XrdSysLogger.cc 35287 2010-09-14 21:19:35Z ganis $";
00014 
00015 #include <errno.h>
00016 #include <fcntl.h>
00017 #include <stdlib.h>
00018 #include <stdio.h>
00019 #include <string.h>
00020 #include <time.h>
00021 #include <sys/stat.h>
00022 #include <sys/types.h>
00023 #ifndef WIN32
00024 #include <dirent.h>
00025 #include <unistd.h>
00026 #include <strings.h>
00027 #include <sys/param.h>
00028 #include <sys/termios.h>
00029 #include <sys/uio.h>
00030 #endif // WIN32
00031 
00032 #include "XrdSys/XrdSysLogger.hh"
00033 #include "XrdSys/XrdSysPlatform.hh"
00034 #include "XrdSys/XrdSysPthread.hh"
00035 #include "XrdSys/XrdSysTimer.hh"
00036  
00037 /******************************************************************************/
00038 /*                               S t a t i c s                                */
00039 /******************************************************************************/
00040   
00041 int XrdSysLogger::extLFD[4] = {-1, -1, -1, -1};
00042 
00043 /******************************************************************************/
00044 /*                           C o n s t r u c t o r                            */
00045 /******************************************************************************/
00046 
00047 XrdSysLogger::XrdSysLogger(int ErrFD, int dorotate)
00048 {
00049    char * logFN;
00050 
00051    ePath = 0;
00052    eNTC  = 0;
00053    eInt  = 0;
00054    eNow  = 0;
00055    eFD   = ErrFD;
00056    eKeep = 0;
00057    doLFR = dorotate;
00058 
00059 // Establish default log file name
00060 //
00061    if (!(logFN = getenv("XrdSysLOGFILE"))) logFN = getenv("XrdOucLOGFILE");
00062 
00063 // Establish message routing
00064 //
00065    if (ErrFD != STDERR_FILENO) baseFD = ErrFD;
00066       else {baseFD = dup(ErrFD);
00067             fcntl(baseFD, F_SETFD, FD_CLOEXEC);
00068             Bind(logFN, 86400);
00069            }
00070 }
00071   
00072 /******************************************************************************/
00073 /*                                  B i n d                                   */
00074 /******************************************************************************/
00075   
00076 int XrdSysLogger::Bind(const char *path, int isec)
00077 {
00078 
00079 // Compute time at midnight
00080 //
00081    eNow = time(0);
00082    eNTC = XrdSysTimer::Midnight(eNow);
00083 
00084 // Bind to the logfile as needed
00085 //
00086    if (path) 
00087       {eInt  = isec;
00088        if (ePath) free(ePath);
00089        ePath = strdup(path);
00090        return ReBind(0);
00091       }
00092    eInt = 0;
00093    ePath = 0;
00094    return 0;
00095 }
00096 
00097 /******************************************************************************/
00098 /*                                   P u t                                    */
00099 /******************************************************************************/
00100   
00101 void XrdSysLogger::Put(int iovcnt, struct iovec *iov)
00102 {
00103     int retc;
00104     char tbuff[24];
00105 
00106 // Prefix message with time if calle wants it so
00107 //
00108    if (iov[0].iov_base) eNow = time(0);
00109       else {iov[0].iov_base = tbuff;
00110             iov[0].iov_len  = (int)Time(tbuff);
00111            }
00112 
00113 // Obtain the serailization mutex if need be
00114 //
00115    Logger_Mutex.Lock();
00116 
00117 // Check if we should close and reopen the output
00118 //
00119    if (eInt && eNow >= eNTC) ReBind();
00120 
00121 // In theory, writev may write out a partial list. This rarely happens in
00122 // practice and so we ignore that possibility (recovery is pretty tough).
00123 //
00124    do { retc = writev(eFD, (const struct iovec *)iov, iovcnt);}
00125                while (retc < 0 && errno == EINTR);
00126 
00127 // Release the serailization mutex if need be
00128 //
00129    Logger_Mutex.UnLock();
00130 }
00131 
00132 /******************************************************************************/
00133 /*                                  T i m e                                   */
00134 /******************************************************************************/
00135   
00136 int XrdSysLogger::Time(char *tbuff)
00137 {
00138     const int minblen = 24;
00139     eNow = time(0);
00140     struct tm tNow;
00141     int i;
00142 
00143 // Format the header
00144 //
00145    tbuff[minblen-1] = '\0'; // tbuff must be at least 24 bytes long
00146    localtime_r((const time_t *) &eNow, &tNow);
00147    i =    snprintf(tbuff, minblen, "%02d%02d%02d %02d:%02d:%02d %03ld ",
00148                   tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
00149                   tNow.tm_hour,     tNow.tm_min,   tNow.tm_sec,
00150                   XrdSysThread::Num());
00151    return (i >= minblen ? minblen-1 : i);
00152 }
00153 
00154 /******************************************************************************/
00155 /*                                x l o g F D                                 */
00156 /******************************************************************************/
00157   
00158 int XrdSysLogger::xlogFD() {return -1;}
00159 
00160 /******************************************************************************/
00161 /*                       P r i v a t e   M e t h o d s                        */
00162 /******************************************************************************/
00163 /******************************************************************************/
00164 /*                               p u t E m s g                                */
00165 /******************************************************************************/
00166   
00167 // This internal logging method is used when the caller already has the mutex!
00168 
00169 void XrdSysLogger::putEmsg(char *msg, int msz)
00170 {
00171     struct iovec eVec[2];
00172     int retc;
00173     char tbuff[24];
00174 
00175 // Prefix message with time
00176 //
00177    eVec[0].iov_base = tbuff;
00178    eVec[0].iov_len  = (int)Time(tbuff);
00179    eVec[1].iov_base = msg;
00180    eVec[1].iov_len  = msz;
00181 
00182 // In theory, writev may write out a partial list. This rarely happens in
00183 // practice and so we ignore that possibility (recovery is pretty tough).
00184 //
00185    do { retc = writev(eFD, (const struct iovec *)eVec, 2);}
00186                while (retc < 0 && errno == EINTR);
00187 }
00188 
00189 /******************************************************************************/
00190 /*                                R e B i n d                                 */
00191 /******************************************************************************/
00192   
00193 int XrdSysLogger::ReBind(int dorename)
00194 {
00195    const char seq[] = "0123456789";
00196    unsigned int i;
00197    int newfd;
00198    struct tm nowtime;
00199    char *bp, buff[MAXPATHLEN+MAXNAMELEN];
00200    struct stat bf;
00201 
00202 // Rename the file to be of the form yyyymmdd corresponding to the date it was
00203 // opened. We will add a sequence number (.x) if a conflict occurs.
00204 //
00205    if (dorename && doLFR)
00206       {strcpy(buff, ePath);
00207        bp = buff+strlen(ePath);
00208        *bp++ = '.';
00209        strncpy(bp, Filesfx, 8);
00210        bp += 8;
00211        *bp = '\0'; *(bp+2) = '\0';
00212        for (i = 0; i < sizeof(seq) && !stat(buff, &bf); i++)
00213            {*bp = '.'; *(bp+1) = (char)seq[i];}
00214        if (i < sizeof(seq)) rename(ePath, buff);
00215       }
00216 
00217 // Compute the new suffix
00218 //
00219    localtime_r((const time_t *) &eNow, &nowtime);
00220    sprintf(buff, "%4d%02d%02d", nowtime.tm_year+1900, nowtime.tm_mon+1,
00221                                 nowtime.tm_mday);
00222    strncpy(Filesfx, buff, 8);
00223 
00224 // Set new close interval
00225 //
00226    if (eInt > 0) while(eNTC <= eNow) eNTC += eInt;
00227 
00228 // Open the file for output. Note that we can still leak a file descriptor
00229 // if a thread forks a process before we are able to do the fcntl(), sigh.
00230 //
00231    if ((newfd = open(ePath,O_WRONLY|O_APPEND|O_CREAT,0644)) < 0) return -errno;
00232    fcntl(newfd, F_SETFD, FD_CLOEXEC);
00233 
00234 // Now set the file descriptor to be the same as the error FD. This will
00235 // close the previously opened file, if any.
00236 //
00237    if (dup2(newfd, eFD) < 0) return -errno;
00238    close(newfd);
00239 
00240 // Check if we should trim log files
00241 //
00242    if (eKeep && doLFR) Trim();
00243    return 0;
00244 }
00245 
00246 /******************************************************************************/
00247 /*                                  T r i m                                   */
00248 /******************************************************************************/
00249 
00250 #ifndef WIN32
00251 void XrdSysLogger::Trim()
00252 {
00253    struct LogFile 
00254           {LogFile *next;
00255            char    *fn;
00256            off_t    sz;
00257            time_t   tm;
00258 
00259            LogFile(char *xfn, off_t xsz, time_t xtm)
00260                   {fn = (xfn ? strdup(xfn) : 0); sz = xsz; tm = xtm; next = 0;}
00261           ~LogFile() 
00262                   {if (fn)   free(fn);
00263                    if (next) delete next;
00264                   }
00265           } logList(0,0,0);
00266 
00267    struct LogFile *logEnt, *logPrev, *logNow;
00268    char eBuff[2048], logFN[MAXNAMELEN+8], logDir[MAXPATHLEN+8], *logSfx;
00269    struct dirent *dp;
00270    struct stat buff;
00271    long long totSz = 0;
00272    int n,rc, totNum= 0;
00273    DIR *DFD;
00274 
00275 // Ignore this call if we are not deleting log files
00276 //
00277    if (!eKeep) return;
00278 
00279 // Construct the directory path
00280 //
00281    if (!ePath) return;
00282    strcpy(logDir, ePath);
00283    if (!(logSfx = rindex(logDir, '/'))) return;
00284    *logSfx = '\0';
00285    strcpy(logFN, logSfx+1);
00286    n = strlen(logFN);
00287 
00288 // Open the directory
00289 //
00290    if (!(DFD = opendir(logDir)))
00291       {int msz = sprintf(eBuff, "Error %d (%s) opening log directory %s\n",
00292                                 errno, strerror(errno), logDir);
00293        putEmsg(eBuff, msz);
00294        return;
00295       }
00296     *logSfx++ = '/';
00297 
00298 // Record all of the log files currently in this directory
00299 //
00300    errno = 0;
00301    while((dp = readdir(DFD)))
00302         {if (strncmp(dp->d_name, logFN, n)) continue;
00303          strcpy(logSfx, dp->d_name);
00304          if (stat(logDir, &buff) || !(buff.st_mode & S_IFREG)) continue;
00305 
00306          totNum++; totSz += buff.st_size;
00307          logEnt = new LogFile(dp->d_name, buff.st_size, buff.st_mtime);
00308          logPrev = &logList; logNow = logList.next;
00309          while(logNow && logNow->tm < buff.st_mtime)
00310               {logPrev = logNow; logNow = logNow->next;}
00311 
00312          logPrev->next = logEnt; 
00313          logEnt->next  = logNow;
00314         }
00315 
00316 // Check if we received an error
00317 //
00318    rc = errno; closedir(DFD);
00319    if (rc)
00320       {int msz = sprintf(eBuff, "Error %d (%s) reading log directory %s\n",
00321                                 rc, strerror(rc), logDir);
00322        putEmsg(eBuff, msz);
00323        return;
00324       }
00325 
00326 // If there is only one log file here no need to
00327 //
00328    if (totNum <= 1) return;
00329 
00330 // Check if we need to trim log files
00331 //
00332    if (eKeep < 0)
00333       {if ((totNum += eKeep) <= 0) return;
00334       } else {
00335        if (totSz <= eKeep)         return;
00336        logNow = logList.next; totNum = 0;
00337        while(logNow && totSz > eKeep)
00338             {totNum++; totSz -= logNow->sz; logNow = logNow->next;}
00339       }
00340 
00341 // Now start deleting log files
00342 //
00343    logNow = logList.next;
00344    while(logNow && totNum--)
00345         {strcpy(logSfx, logNow->fn);
00346          if (unlink(logDir))
00347             rc = sprintf(eBuff, "Error %d (%s) removing log file %s\n",
00348                                 errno, strerror(errno), logDir);
00349             else rc = sprintf(eBuff, "Removed log file %s\n", logDir);
00350          putEmsg(eBuff, rc);
00351          logNow = logNow->next;
00352         }
00353 }
00354 #else
00355 void XrdSysLogger::Trim()
00356 {
00357 }
00358 #endif

Generated on Tue Jul 5 14:47:03 2011 for ROOT_528-00b_version by  doxygen 1.5.1