37 #include <sys/types.h>
42 #include <sys/param.h>
67 void Snatch(
struct iovec *
iov,
int iovnum)
75 if (iovnum && *((
char *)
iov[iovnum-1].iov_base) ==
'\n') iovnum--;
79 for (
int i = 0; i <iovnum; i++) tLen +=
iov[i].iov_len;
83 if (!(tBuff = (
char *)malloc(tLen+1)))
return;
88 for (
int i = 0; i <iovnum; i++)
89 {strncpy(tbP, (
char *)
iov[i].iov_base,
iov[i].iov_len);
90 tbP +=
iov[i].iov_len;
106 #define BLAB(x) std::cerr <<"Logger " <<x <<"!!!" <<std::endl
108 bool XrdSysLogger::doForward =
false;
116 while(tP) {tP->
Ring(); tP = tP->
Next();}
149 doLFR = (dorotate != 0);
159 if (!(logFN = getenv(
"XrdSysLOGFILE"))) logFN = getenv(
"XrdOucLOGFILE");
163 if (ErrFD != STDERR_FILENO) baseFD = ErrFD;
164 else {baseFD = XrdSysFD_Dup(ErrFD);
175 mmMsg *tP, *nP =
new mmMsg;
180 nP->msg = strdup(msg);
181 nP->mlen = strlen(msg);
185 if (nP->mlen > 1 && nP->msg[nP->mlen-1] !=
'\n')
186 {nP->msg[nP->mlen] =
'\n'; nP->mlen += 1;}
191 if (!(tP = msgList)) msgList = nP;
192 else {
while(tP->next) tP = tP->next;
208 mnTask->next = taskQ;
224 if (lfh > 0) lfh = 1;
225 if (lfhTID && (eInt != lfh || !path))
232 if (ePath) free(ePath);
235 if (fifoFN) free(fifoFN);
236 fifoFN = 0; doLFR =
false;
242 ePath = strdup(path);
244 if ((rc = ReBind(0)))
return rc;
248 rc = HandleLogRotateLock( doLFR );
254 if (eInt ==
onFifo) {
if ((rc = FifoMake()))
return -rc;}
257 BLAB(
"Unable to block logfile signal " <<-eInt <<
"; "
268 return (rc > 0 ? -rc : rc);
303 {
if (!strcmp(arg,
"fifo"))
return onFifo;
309 eKeep = strtoll(arg, &eP, 10);
310 if (!(*eP) || eKeep < 0) {eKeep = -eKeep;
return 1;}
314 if (*(eP+1))
return 0;
315 if (*eP ==
'k' || *eP ==
'K') eKeep *= 1024LL;
316 else if (*eP ==
'm' || *eP ==
'M') eKeep *= 1024LL*1024LL;
317 else if (*eP ==
'g' || *eP ==
'G') eKeep *= 1024LL*1024LL*1024LL;
318 else if (*eP ==
't' || *eP ==
'T') eKeep *= 1024LL*1024LL*1024LL*1024LL;
339 gettimeofday(&tVal, 0);
352 if (!
iov[0].iov_base)
353 {
iov[0].iov_base = tbuff;
354 iov[0].iov_len = TimeStamp(tVal, tID, tbuff,
sizeof(tbuff), hiRes);
364 {Snatch(
iov, iovcnt);
372 do { retc =
writev(eFD, (
const struct iovec *)
iov, iovcnt);}
373 while (retc < 0 && errno == EINTR);
384 int XrdSysLogger::Time(
char *tbuff)
387 const int minblen = 32;
393 gettimeofday(&tVal, 0);
397 localtime_r((
const time_t *) &tVal.tv_sec, &tNow);
402 {i = snprintf(tbuff, minblen,
"%02d%02d%02d %02d:%02d:%02d.%06d %03ld ",
403 tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
404 tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
407 i = snprintf(tbuff, minblen,
"%02d%02d%02d %02d:%02d:%02d %03ld ",
408 tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
409 tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
412 return (i >= minblen ? minblen-1 : i);
419 int XrdSysLogger::TimeStamp(
struct timeval &tVal,
unsigned long tID,
420 char *tbuff,
int tbsz,
bool hires)
427 if (tbsz <= 0)
return 0;
431 localtime_r((
const time_t *) &tVal.tv_sec, &tNow);
436 {i = snprintf(tbuff, tbsz,
"%02d%02d%02d %02d:%02d:%02d.%06d %03ld ",
437 tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
438 tNow.tm_hour, tNow.tm_min, tNow.tm_sec,
439 static_cast<int>(tVal.tv_usec), tID);
441 i = snprintf(tbuff, tbsz,
"%02d%02d%02d %02d:%02d:%02d %03ld ",
442 tNow.tm_year-100, tNow.tm_mon+1, tNow.tm_mday,
443 tNow.tm_hour, tNow.tm_min, tNow.tm_sec, tID);
445 return (i >= tbsz ? tbsz-1 : i);
455 int XrdSysLogger::FifoMake()
458 char buff[2048], *slash;
459 int n, rc, saveInt = eInt;
467 if (!(slash = rindex(ePath,
'/')))
469 strcpy(buff+1, ePath);
471 n = slash - ePath + 1;
472 strncpy(buff, ePath, n);
474 strcpy(&buff[n+1], slash+1);
480 {
if (!S_ISFIFO(
Stat.st_mode))
481 {
BLAB(
"Logfile fifo " <<buff <<
" exists but is not a fifo");
484 else if (
access(buff, R_OK))
485 {
BLAB(
"Unable to access " <<buff);
494 BLAB(buff <<
" has been removed");
509 {
if (mkfifo(buff, S_IRUSR|S_IWUSR))
511 BLAB(
"Unable to create logfile fifo " <<buff <<
"; " <<
XrdSysE2T(rc));
518 fifoFN = strdup(buff);
526 int XrdSysLogger::HandleLogRotateLock(
bool dorotate )
528 if( !ePath )
return 0;
530 char *end = rindex(ePath,
'/');
531 const std::string lckPath = (end ? std::string(ePath,end+1)+
".lock" :
".lock");
532 int rc =
unlink( lckPath.c_str() );
533 if( rc && errno != ENOENT )
535 BLAB(
"The logfile lock (" << lckPath.c_str() <<
") exists and cannot be removed: " <<
XrdSysE2T( errno ) );
541 rc =
open( lckPath.c_str(), O_CREAT, 0644 );
544 BLAB(
"Failed to create the logfile lock (" << lckPath.c_str() <<
"): " <<
XrdSysE2T( errno ) );
556 void XrdSysLogger::RmLogRotateLock()
560 char *end = rindex(ePath,
'/') + 1;
561 const std::string lckPath = std::string( ePath, end ) +
".lock";
562 unlink( lckPath.c_str() );
569 void XrdSysLogger::FifoWait()
577 if ((pipeFD = XrdSysFD_Open(fifoFN, O_RDONLY)) < 0)
579 BLAB(
"Unable to open logfile fifo " <<fifoFN <<
"; " <<
XrdSysE2T(rc));
581 free(fifoFN); fifoFN = 0;
587 if (!
read(pipeFD, buff,
sizeof(buff)))
588 {
BLAB(
"Unexpected EOF on logfile fifo " <<fifoFN);
600 void XrdSysLogger::putEmsg(
char *msg,
int msz)
605 struct iovec eVec[2] = {{tbuff, 0}, {msg, (size_t)msz}};
610 gettimeofday(&tVal, 0);
618 eVec[0].iov_len = TimeStamp(tVal, tID, tbuff,
sizeof(tbuff), hiRes);
623 do { retc =
writev(eFD, (
const struct iovec *)eVec, 2);}
624 while (retc < 0 && errno == EINTR);
631 int XrdSysLogger::ReBind(
int dorename)
633 const char seq[] =
"0123456789";
637 char *bp, buff[MAXPATHLEN+MAXNAMELEN];
643 if (dorename && doLFR)
644 {strcpy(buff, ePath);
645 bp = buff+strlen(ePath);
647 strncpy(bp, Filesfx, 8);
649 *bp =
'\0'; *(bp+2) =
'\0';
650 for (i = 0; i <
sizeof(seq) && !
stat(buff, &bf); i++)
651 {*bp =
'.'; *(bp+1) = (
char)seq[i];}
652 if (i <
sizeof(seq))
rename(ePath, buff);
658 {time_t eNow = time(0);
659 localtime_r((
const time_t *) &eNow, &nowtime);
660 sprintf(buff,
"%4d%02d%02d", nowtime.tm_year+1900, nowtime.tm_mon+1,
662 memcpy(Filesfx, buff, 8);
668 if ((newfd = XrdSysFD_Open(ePath,O_WRONLY|O_APPEND|O_CREAT,0644)) < 0)
674 if (dup2(newfd, eFD) < 0)
683 if (eKeep && doLFR) Trim();
692 void XrdSysLogger::Trim()
700 LogFile(
char *xfn, off_t xsz, time_t xtm)
701 {fn = (xfn ? strdup(xfn) : 0); sz = xsz; tm = xtm; next = 0;}
704 if (next)
delete next;
708 struct LogFile *logEnt, *logPrev, *logNow;
709 char eBuff[2048], logFN[MAXNAMELEN+8], logDir[MAXPATHLEN+8], *logSfx;
723 strcpy(logDir, ePath);
724 if (!(logSfx = rindex(logDir,
'/')))
return;
726 strcpy(logFN, logSfx+1);
732 {
int msz = snprintf(eBuff, 2048,
"Error %d (%s) opening log directory %s\n",
743 {
if (strncmp(dp->d_name, logFN, n))
continue;
744 strcpy(logSfx, dp->d_name);
745 if (
stat(logDir, &buff) || !(buff.st_mode & S_IFREG))
continue;
747 totNum++; totSz += buff.st_size;
748 logEnt =
new LogFile(dp->d_name, buff.st_size, buff.st_mtime);
749 logPrev = &logList; logNow = logList.next;
750 while(logNow && logNow->tm < buff.st_mtime)
751 {logPrev = logNow; logNow = logNow->next;}
753 logPrev->next = logEnt;
754 logEnt->next = logNow;
761 {
int msz = snprintf(eBuff, 2048,
"Error %d (%s) reading log directory %s\n",
769 if (totNum <= 1)
return;
774 {
if ((totNum += eKeep) <= 0)
return;
776 if (totSz <= eKeep)
return;
777 logNow = logList.next; totNum = 0;
778 while(logNow && totSz > eKeep)
779 {totNum++; totSz -= logNow->sz; logNow = logNow->next;}
784 logNow = logList.next;
785 while(logNow && totNum--)
786 {strcpy(logSfx, logNow->fn);
788 rc = snprintf(eBuff, 2048,
"Error %d (%s) removing log file %s\n",
790 else rc = snprintf(eBuff, 2048,
"Removed log file %s\n", logDir);
792 logNow = logNow->next;
796 void XrdSysLogger::Trim()
816 if (eInt < 0 && !fifoFN)
818 if ((sigemptyset(&sigset) == -1)
819 || (sigaddset(&sigset,signo) == -1))
821 BLAB(
"Unable to use logfile signal " <<signo <<
"; " <<
XrdSysE2T(rc));
829 {
if (fifoFN) FifoWait();
831 else if ((sigwait(&sigset, &signo) == -1))
833 BLAB(
"Unable to wait on logfile signal " <<signo
844 {putEmsg(mP->msg, mP->mlen);
852 "Midnight Ringer Task"))
854 rc = sprintf(eBuff,
"Error %d (%s) running ringer task.\n",
int stat(const char *path, struct stat *buf)
struct dirent * readdir(DIR *dirp)
int open(const char *path, int oflag,...)
int unlink(const char *path)
int rename(const char *oldpath, const char *newpath)
int access(const char *path, int amode)
ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
ssize_t read(int fildes, void *buf, size_t nbyte)
DIR * opendir(const char *path)
const char * XrdSysE2T(int errcode)
void * XrdSysLoggerRT(void *carg)
void * XrdSysLoggerMN(void *carg)
void Add(XrdOucTList *tP)
virtual void Ring()=0
This method gets called at midnight.
void Put(int iovcnt, struct iovec *iov)
void AddMsg(const char *msg)
XrdSysLogger(int ErrFD=STDERR_FILENO, int xrotate=1)
void AtMidnight(Task *mnTask)
void Capture(XrdOucTListFIFO *tFIFO)
int Bind(const char *path, int lfh=0)
int ParseKeep(const char *arg)
static bool Forward(struct timeval mtime, unsigned long tID, struct iovec *iov, int iovcnt)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static int Kill(pthread_t tid)
static unsigned long Num(void)
static void Wait4Midnight()
static int GetSigNum(const char *sname)
XrdSysLoggerRP(XrdSysLogger *lp)