00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00039
00040
00041 int XrdSysLogger::extLFD[4] = {-1, -1, -1, -1};
00042
00043
00044
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
00060
00061 if (!(logFN = getenv("XrdSysLOGFILE"))) logFN = getenv("XrdOucLOGFILE");
00062
00063
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
00074
00075
00076 int XrdSysLogger::Bind(const char *path, int isec)
00077 {
00078
00079
00080
00081 eNow = time(0);
00082 eNTC = XrdSysTimer::Midnight(eNow);
00083
00084
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
00099
00100
00101 void XrdSysLogger::Put(int iovcnt, struct iovec *iov)
00102 {
00103 int retc;
00104 char tbuff[24];
00105
00106
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
00114
00115 Logger_Mutex.Lock();
00116
00117
00118
00119 if (eInt && eNow >= eNTC) ReBind();
00120
00121
00122
00123
00124 do { retc = writev(eFD, (const struct iovec *)iov, iovcnt);}
00125 while (retc < 0 && errno == EINTR);
00126
00127
00128
00129 Logger_Mutex.UnLock();
00130 }
00131
00132
00133
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
00144
00145 tbuff[minblen-1] = '\0';
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
00156
00157
00158 int XrdSysLogger::xlogFD() {return -1;}
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 void XrdSysLogger::putEmsg(char *msg, int msz)
00170 {
00171 struct iovec eVec[2];
00172 int retc;
00173 char tbuff[24];
00174
00175
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
00183
00184
00185 do { retc = writev(eFD, (const struct iovec *)eVec, 2);}
00186 while (retc < 0 && errno == EINTR);
00187 }
00188
00189
00190
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
00203
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
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
00225
00226 if (eInt > 0) while(eNTC <= eNow) eNTC += eInt;
00227
00228
00229
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
00235
00236
00237 if (dup2(newfd, eFD) < 0) return -errno;
00238 close(newfd);
00239
00240
00241
00242 if (eKeep && doLFR) Trim();
00243 return 0;
00244 }
00245
00246
00247
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
00276
00277 if (!eKeep) return;
00278
00279
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
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
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
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
00327
00328 if (totNum <= 1) return;
00329
00330
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
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